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