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