Use memset() rather than OTMemzero(), and hence remove the need to weak link
[sgt/putty] / mac / otnet.c
CommitLineData
27a3458f 1/*
2 * Macintosh OpenTransport networking abstraction
3 */
4
5#include <OpenTransport.h>
6#include <OpenTptInternet.h>
7
40d38714 8#include <string.h>
9
27a3458f 10#define DEFINE_PLUG_METHOD_MACROS
11#include "putty.h"
12#include "network.h"
13#include "mac.h"
14
15struct Socket_tag {
16 struct socket_function_table *fn;
17 /* other stuff... */
b1234a5c 18 OSStatus error;
27a3458f 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
39typedef struct Socket_tag *Actual_Socket;
40
41struct SockAddr_tag {
b1234a5c 42 OSStatus error;
27a3458f 43 DNSAddress address;
44};
45
46/* Globals */
47
48static struct {
49 Actual_Socket socklist;
50} ot;
51
52OSErr ot_init(void)
53{
54 return InitOpenTransport();
55}
56
57void 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
27a3458f 69SockAddr ot_namelookup(char *host, char **canonicalname)
70{
71 SockAddr ret = smalloc(sizeof(struct SockAddr_tag));
72
b1234a5c 73 ret->error = kOTNoError;
27a3458f 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
83SockAddr 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
92void 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
99int ot_hostname_is_local(char *name)
100{
101
102 return !strcmp(name, "localhost");
103}
104
105int ot_address_is_local(SockAddr addr)
106{
107
108 /* FIXME */
109 return FALSE;
110}
111
112int ot_addrtype(SockAddr addr)
113{
114 return ADDRTYPE_IPV4;
115}
116
117void ot_addrcopy(SockAddr addr, char *buf)
118{
119
120}
121
122void ot_addr_free(SockAddr addr)
123{
124 sfree(addr);
125}
126
127
128static 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
137static 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
145static void ot_tcp_close(Socket s);
146static int ot_tcp_write(Socket s, char const *data, int len);
147static int ot_tcp_write_oob(Socket s, char const *data, int len);
148static void ot_tcp_set_private_ptr(Socket s, void *ptr);
149static void *ot_tcp_get_private_ptr(Socket s);
150static void ot_tcp_set_frozen(Socket s, int is_frozen);
151static char *ot_tcp_socket_error(Socket s);
152static void ot_recv(Actual_Socket s);
153void ot_poll(void);
154
155Socket 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;
b1234a5c 173 ret->error = kOTNoError;
27a3458f 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
199Socket 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;
b1234a5c 221 ret->error = kOTNoError;
27a3458f 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) {
b1234a5c 242 ret->error = err;
27a3458f 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) {
b1234a5c 257 ret->error = err;
27a3458f 258 return (Socket) ret;
259 }
260
261 /*
262 * Connect to remote address.
263 */
264
265 /* FIXME: bolt the port onto the end */
266
40d38714 267 memset(&connectCall, 0, sizeof(TCall));
27a3458f 268 connectCall.addr.buf = (UInt8 *) &(addr->address);
269 connectCall.addr.len = sizeof(DNSAddress);
270
271 err = OTConnect(ep, &connectCall, nil);
272
273 if (err) {
b1234a5c 274 ret->error = err;
27a3458f 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
289Socket ot_newlistener(char *foobar, int port, Plug plug, int local_host_only)
290{
291 Actual_Socket s;
292
293 return (Socket) s;
294}
295
296static 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
310static 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
333static 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
344static 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 */
355static 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
361static 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 */
373char *ot_addr_error(SockAddr addr)
374{
b1234a5c 375 static char buf[128];
376
377 if (addr->error == kOTNoError)
378 return NULL;
379 sprintf(buf, "error %d", addr->error);
380 return buf;
27a3458f 381}
382static char *ot_tcp_socket_error(Socket sock)
383{
384 Actual_Socket s = (Actual_Socket) sock;
b1234a5c 385 static char buf[128];
386
387 if (s->error == kOTNoError)
388 return NULL;
389 sprintf(buf, "error %d", s->error);
390 return buf;
27a3458f 391}
392
393static 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
406void 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
425void 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 */