]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - mac/otnet.c
b43147855dead20df28c19d33c756619d44688d4
[PuTTY.git] / mac / otnet.c
1 /*
2  * Macintosh OpenTransport networking abstraction
3  */
4
5 #include <OpenTransport.h>
6 #include <OpenTptInternet.h>
7
8 #define DEFINE_PLUG_METHOD_MACROS
9 #include "putty.h"
10 #include "network.h"
11 #include "mac.h"
12
13 struct Socket_tag {
14     struct socket_function_table *fn;
15     /* other stuff... */
16     char *error;
17     EndpointRef ep;
18     Plug plug;
19     void *private_ptr;
20     bufchain output_data;
21     int connected;
22     int writable;
23     int frozen; /* this causes readability notifications to be ignored */
24     int frozen_readable; /* this means we missed at least one readability
25                           * notification while we were frozen */
26     int localhost_only;                /* for listening sockets */
27     char oobdata[1];
28     int sending_oob;
29     int oobpending;        /* is there OOB data available to read?*/
30     int oobinline;
31     int pending_error;                 /* in case send() returns error */
32     int listener;
33     struct Socket_tag *next;
34     struct Socket_tag **prev;
35 };
36
37 typedef struct Socket_tag *Actual_Socket;
38
39 struct SockAddr_tag {
40     char *error;
41     DNSAddress address;
42 };
43
44 /* Globals */
45
46 static struct {
47     Actual_Socket socklist;
48 } ot;
49
50 OSErr ot_init(void)
51 {
52     return InitOpenTransport();
53 }
54
55 void ot_cleanup(void)
56 {
57     Actual_Socket s;
58
59     for (s = ot.socklist; s !=NULL; s = s->next) {
60         OTUnbind(s->ep);
61         OTCloseProvider(s->ep);
62     }
63
64     CloseOpenTransport();
65 }
66
67 static char *error_string(int error)
68 {
69     return "An error...";
70 }
71
72 SockAddr ot_namelookup(char *host, char **canonicalname)
73 {
74     SockAddr ret = smalloc(sizeof(struct SockAddr_tag));
75     
76     OTInitDNSAddress(&(ret->address), host);
77   
78     /* for now we'll pretend canonicalname is always just host */
79
80     *canonicalname = smalloc(1+strlen(host));
81     strcpy(*canonicalname, host);
82     return ret;
83 }
84
85 SockAddr ot_nonamelookup(char *host)
86 {
87     SockAddr ret = smalloc(sizeof(struct SockAddr_tag));
88     
89     OTInitDNSAddress(&(ret->address), host);
90   
91     return ret;
92 }
93
94 void ot_getaddr(SockAddr addr, char *buf, int buflen)
95 {
96     strncpy(buf, (addr->address).fName, buflen);
97 }
98
99 /* I think "local" here really means "loopback" */
100
101 int ot_hostname_is_local(char *name)
102 {
103
104     return !strcmp(name, "localhost");
105 }
106
107 int ot_address_is_local(SockAddr addr)
108 {
109
110     /* FIXME */
111     return FALSE;
112 }
113
114 int ot_addrtype(SockAddr addr)
115 {
116     return ADDRTYPE_IPV4;
117 }
118
119 void ot_addrcopy(SockAddr addr, char *buf)
120 {
121   
122 }
123
124 void ot_addr_free(SockAddr addr)
125 {
126     sfree(addr);
127 }
128
129
130 static Plug ot_tcp_plug(Socket sock, Plug p)
131 {
132     Actual_Socket s = (Actual_Socket) sock;
133     Plug ret = s->plug;
134     if (p)
135         s->plug = p;
136     return ret;
137 }
138
139 static void ot_tcp_flush(Socket s)
140 {
141     /*
142      * We send data to the socket as soon as we can anyway,
143      * so we don't need to do anything here.  :-)
144      */
145 }
146
147 static void ot_tcp_close(Socket s);
148 static int ot_tcp_write(Socket s, char const *data, int len);
149 static int ot_tcp_write_oob(Socket s, char const *data, int len);
150 static void ot_tcp_set_private_ptr(Socket s, void *ptr);
151 static void *ot_tcp_get_private_ptr(Socket s);
152 static void ot_tcp_set_frozen(Socket s, int is_frozen);
153 static char *ot_tcp_socket_error(Socket s);
154 static void ot_recv(Actual_Socket s);
155 void ot_poll(void);
156
157 Socket ot_register(void *sock, Plug plug)
158 {
159     static struct socket_function_table fn_table = {
160         ot_tcp_plug,
161         ot_tcp_close,
162         ot_tcp_write,
163         ot_tcp_write_oob,
164         ot_tcp_flush,
165         ot_tcp_set_private_ptr,
166         ot_tcp_get_private_ptr,
167         ot_tcp_set_frozen,
168         ot_tcp_socket_error
169     };
170     
171     Actual_Socket ret;
172
173     ret = smalloc(sizeof(struct Socket_tag));
174     ret->fn = &fn_table;
175     ret->error = NULL;
176     ret->plug = plug;
177     bufchain_init(&ret->output_data);
178     ret->writable = 1;                 /* to start with */
179     ret->sending_oob = 0;
180     ret->frozen = 1;
181     ret->frozen_readable = 0;
182     ret->localhost_only = 0;           /* unused, but best init anyway */
183     ret->pending_error = 0;
184     ret->oobpending = FALSE;
185     ret->listener = 0;
186
187     ret->ep = (EndpointRef)sock;
188   
189     /* some sort of error checking */
190
191     ret->oobinline = 0;
192   
193     /* Add this to the list of all sockets */
194     ret->next = ot.socklist;
195     ret->prev = &ot.socklist;
196     ot.socklist = ret;
197
198     return (Socket) ret;
199 }
200
201 Socket ot_new(SockAddr addr, int port, int privport, int oobinline,
202               int nodelay, Plug plug)
203 {
204     static struct socket_function_table fn_table = {
205         ot_tcp_plug,
206         ot_tcp_close,
207         ot_tcp_write,
208         ot_tcp_write_oob,
209         ot_tcp_flush,
210         ot_tcp_set_private_ptr,
211         ot_tcp_get_private_ptr,
212         ot_tcp_set_frozen,
213         ot_tcp_socket_error
214     };
215
216     Actual_Socket ret;
217     EndpointRef ep;
218     OSStatus err;
219     TCall connectCall;
220
221     ret = smalloc(sizeof(struct Socket_tag));
222     ret->fn = &fn_table;
223     ret->error = NULL;
224     ret->plug = plug;
225     bufchain_init(&ret->output_data);
226     ret->connected = 0;                /* to start with */
227     ret->writable = 0;                 /* to start with */
228     ret->sending_oob = 0;
229     ret->frozen = 0;
230     ret->frozen_readable = 0;
231     ret->localhost_only = 0;           /* unused, but best init anyway */
232     ret->pending_error = 0;
233     ret->oobinline = oobinline;
234     ret->oobpending = FALSE;
235     ret->listener = 0;
236
237     /* Open Endpoint, configure it for TCP over anything */
238
239     ep = OTOpenEndpoint(OTCreateConfiguration("tcp"), 0, NULL, &err);
240
241     ret->ep = ep;
242
243     if (err) {
244         ret->error = error_string(err);
245         return (Socket) ret;
246     }
247
248     /* TODO: oobinline, nodelay */
249
250     /*
251      * Bind to local address.
252      */
253   
254     /* FIXME: pay attention to privport */
255
256     err = OTBind(ep, NULL, NULL); /* OpenTransport always picks our address */
257
258     if (err) {
259         ret->error = error_string(err);
260         return (Socket) ret;
261     }
262
263     /*
264      * Connect to remote address.
265      */
266
267     /* FIXME: bolt the port onto the end */
268
269     OTMemzero(&connectCall, sizeof(TCall));
270     connectCall.addr.buf = (UInt8 *) &(addr->address);
271     connectCall.addr.len = sizeof(DNSAddress);
272
273     err = OTConnect(ep, &connectCall, nil);
274   
275     if (err) {
276         ret->error = error_string(err);
277         return (Socket) ret;
278     } else {
279         ret->connected = 1;
280         ret->writable = 1;
281     }
282
283     /* Add this to the list of all sockets */
284     ret->next = ot.socklist;
285     ret->prev = &ot.socklist;
286     ot.socklist = ret;
287
288     return (Socket) ret;
289 }
290     
291 Socket ot_newlistener(char *foobar, int port, Plug plug, int local_host_only)
292 {
293     Actual_Socket s;
294
295     return (Socket) s;
296 }
297
298 static void ot_tcp_close(Socket sock)
299 {
300     Actual_Socket s = (Actual_Socket) sock;
301     
302     OTCloseProvider(s->ep);
303
304     /* Unhitch from list of sockets */
305     *s->prev = s->next;
306     if (s->next != NULL)
307         s->next->prev = s->prev;
308
309     sfree(s);
310 }
311
312 static void try_send(Actual_Socket s)
313 {
314     while (bufchain_size(&s->output_data) > 0) {
315         int nsent;
316         void *data;
317         int len;
318
319         /* Don't care about oob right now */
320
321         bufchain_prefix(&s->output_data, &data, &len);
322
323         nsent = OTSnd(s->ep, data, len, 0);
324         noise_ultralight(nsent);
325
326         if (nsent <= 0) {
327             /* something bad happened, hey ho */
328         } else {
329             /* still don't care about oob */
330             bufchain_consume(&s->output_data, nsent);
331         }
332     }
333 }
334
335 static int ot_tcp_write(Socket sock, char const *buf, int len)
336 {
337     Actual_Socket s = (Actual_Socket) sock;
338
339     bufchain_add(&s->output_data, buf, len);
340
341     if (s->writable)
342         try_send(s);
343     return bufchain_size(&s->output_data);
344 }
345
346 static int ot_tcp_write_oob(Socket sock, char const *buf, int len)
347 {
348     /* Don't care about oob */
349     return 0;
350 }
351
352
353 /*
354  * Each socket abstraction contains a `void *' private field in
355  * which the client can keep state.
356  */
357 static void ot_tcp_set_private_ptr(Socket sock, void *ptr)
358 {
359     Actual_Socket s = (Actual_Socket) sock;
360     s->private_ptr = ptr;
361 }
362
363 static void *ot_tcp_get_private_ptr(Socket sock)
364 {
365     Actual_Socket s = (Actual_Socket) sock;
366     return s->private_ptr;
367 }
368
369
370 /*
371  * Special error values are returned from ot_namelookup and ot_new
372  * if there's a problem. These functions extract an error message,
373  * or return NULL if there's no problem.
374  */
375 char *ot_addr_error(SockAddr addr)
376 {
377     return addr->error;
378 }
379 static char *ot_tcp_socket_error(Socket sock)
380 {
381     Actual_Socket s = (Actual_Socket) sock;
382     return s->error;
383 }
384
385 static void ot_tcp_set_frozen(Socket sock, int is_frozen)
386 {
387     Actual_Socket s = (Actual_Socket) sock;
388
389     if (s->frozen == is_frozen)
390         return;
391     s->frozen = is_frozen;
392 }
393
394 /*
395  * Poll all our sockets from an event loop
396  */
397
398 void ot_poll(void)
399 {
400     Actual_Socket s;
401     OTResult o;
402
403     for (s = ot.socklist; s != NULL; s = s->next) {
404         o = OTLook(s->ep);
405
406         switch(o) {
407           case T_DATA: /* Normal Data */
408             ot_recv(s);
409             break;
410           case T_EXDATA: /* Expedited Data (urgent?) */
411             ot_recv(s);
412             break;
413         }
414     }
415 }
416
417 void ot_recv(Actual_Socket s)
418 {
419     OTResult o;
420     char buf[20480];
421     OTFlags flags;
422
423     if (s->frozen) return;
424
425     while ((o = OTRcv(s->ep, buf, sizeof(buf), &flags)) != kOTNoDataErr) {
426         plug_receive(s->plug, 0, buf, sizeof(buf));
427     }
428 }
429
430
431 /*
432  * Local Variables:
433  * c-file-style: "simon"
434  * End:
435  */