Use memset() rather than OTMemzero(), and hence remove the need to weak link
[u/mdw/putty] / 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 */