2 * Macintosh OpenTransport networking abstraction
5 #if TARGET_API_MAC_CARBON
6 #define OTCARBONAPPLICATION 1
9 #include <Files.h> /* Needed by OpenTransportInternet.h */
10 #include <OpenTransport.h>
11 #include <OpenTptInternet.h>
15 #define DEFINE_PLUG_METHOD_MACROS
21 struct socket_function_table *fn;
30 int frozen; /* this causes readability notifications to be ignored */
31 int frozen_readable; /* this means we missed at least one readability
32 * notification while we were frozen */
33 int localhost_only; /* for listening sockets */
36 int oobpending; /* is there OOB data available to read?*/
38 int pending_error; /* in case send() returns error */
40 int nodelay, keepalive;
42 struct Socket_tag *next;
43 struct Socket_tag **prev;
46 typedef struct Socket_tag *Actual_Socket;
51 InetHostInfo hostinfo;
58 Actual_Socket socklist;
66 err = InitOpenTransport();
67 if (err != kOTNoError) return err;
68 ot.inetsvc = OTOpenInternetServices(kDefaultInternetServicesPath, 0, &err);
76 for (s = ot.socklist; s !=NULL; s = s->next) {
78 OTCloseProvider(s->ep);
84 SockAddr ot_namelookup(char const *host, char **canonicalname)
86 SockAddr ret = snew(struct SockAddr_tag);
89 /* Casting away const -- hope OTInetStringToAddress is sensible */
90 ret->error = OTInetStringToAddress(ot.inetsvc, (char *)host,
94 if (ret->error == kOTNoError)
95 realhost = ret->hostinfo.name;
98 *canonicalname = snewn(1+strlen(realhost), char);
99 strcpy(*canonicalname, realhost);
103 SockAddr ot_nonamelookup(char const *host)
105 SockAddr ret = snew(struct SockAddr_tag);
107 ret->resolved = FALSE;
108 ret->error = kOTNoError;
109 ret->hostname[0] = '\0';
110 strncat(ret->hostname, host, lenof(ret->hostname) - 1);
114 void ot_getaddr(SockAddr addr, char *buf, int buflen)
119 if (addr->resolved) {
120 /* XXX only return first address */
121 OTInetHostToString(addr->hostinfo.addrs[0], mybuf);
122 strncat(buf, mybuf, buflen - 1);
124 strncat(buf, addr->hostname, buflen - 1);
127 /* I think "local" here really means "loopback" */
129 int ot_hostname_is_local(char *name)
132 return !strcmp(name, "localhost");
135 int ot_address_is_local(SockAddr addr)
140 for (i = 0; i < kMaxHostAddrs; i++)
141 if (addr->hostinfo.addrs[i] & 0xff000000 == 0x7f000000)
146 int ot_addrtype(SockAddr addr)
150 return ADDRTYPE_IPV4;
151 return ADDRTYPE_NAME;
154 void ot_addrcopy(SockAddr addr, char *buf)
157 /* XXX only return first address */
158 memcpy(buf, &addr->hostinfo.addrs[0], 4);
161 void ot_addr_free(SockAddr addr)
167 static Plug ot_tcp_plug(Socket sock, Plug p)
169 Actual_Socket s = (Actual_Socket) sock;
176 static void ot_tcp_flush(Socket s)
179 * We send data to the socket as soon as we can anyway,
180 * so we don't need to do anything here. :-)
184 static void ot_tcp_close(Socket s);
185 static int ot_tcp_write(Socket s, char const *data, int len);
186 static int ot_tcp_write_oob(Socket s, char const *data, int len);
187 static void ot_tcp_set_private_ptr(Socket s, void *ptr);
188 static void *ot_tcp_get_private_ptr(Socket s);
189 static void ot_tcp_set_frozen(Socket s, int is_frozen);
190 static const char *ot_tcp_socket_error(Socket s);
191 static void ot_recv(Actual_Socket s);
192 static void ot_listenaccept(Actual_Socket s);
193 static void ot_setoption(EndpointRef, OTXTILevel, OTXTIName, UInt32);
197 Socket ot_register(void *sock, Plug plug)
199 static struct socket_function_table fn_table = {
205 ot_tcp_set_private_ptr,
206 ot_tcp_get_private_ptr,
213 ret = snew(struct Socket_tag);
215 ret->error = kOTNoError;
217 bufchain_init(&ret->output_data);
218 ret->writable = 1; /* to start with */
219 ret->sending_oob = 0;
221 ret->frozen_readable = 0;
222 ret->localhost_only = 0; /* unused, but best init anyway */
223 ret->pending_error = 0;
224 ret->oobpending = FALSE;
227 ret->ep = (EndpointRef)sock;
229 /* some sort of error checking */
233 /* Add this to the list of all sockets */
234 ret->next = ot.socklist;
235 ret->prev = &ot.socklist;
241 Socket ot_new(SockAddr addr, int port, int privport, int oobinline,
242 int nodelay, int keepalive, Plug plug)
244 static struct socket_function_table fn_table = {
250 ot_tcp_set_private_ptr,
251 ot_tcp_get_private_ptr,
262 ret = snew(struct Socket_tag);
264 ret->error = kOTNoError;
266 bufchain_init(&ret->output_data);
267 ret->connected = 0; /* to start with */
268 ret->writable = 0; /* to start with */
269 ret->sending_oob = 0;
271 ret->frozen_readable = 0;
272 ret->localhost_only = 0; /* unused, but best init anyway */
273 ret->pending_error = 0;
274 ret->oobinline = oobinline;
275 ret->nodelay = nodelay;
276 ret->keepalive = keepalive;
277 ret->oobpending = FALSE;
280 /* Open Endpoint, configure it for TCP over anything */
282 ep = OTOpenEndpoint(OTCreateConfiguration("tcp"), 0, NULL, &err);
292 ot_setoption(ep, INET_TCP, TCP_OOBINLINE, T_YES);
295 ot_setoption(ep, INET_TCP, TCP_NODELAY, T_YES);
297 if (ret->keepalive) {
298 ot_setoption(ep, INET_TCP, TCP_KEEPALIVE, T_YES);
302 * Bind to local address.
305 /* FIXME: pay attention to privport */
307 err = OTBind(ep, NULL, NULL); /* OpenTransport always picks our address */
315 * Connect to remote address.
318 /* XXX Try non-primary addresses */
319 OTInitInetAddress(&dest, port, addr->hostinfo.addrs[0]);
321 memset(&connectCall, 0, sizeof(TCall));
322 connectCall.addr.buf = (UInt8 *) &dest;
323 connectCall.addr.len = sizeof(dest);
325 err = OTConnect(ep, &connectCall, nil);
335 /* Add this to the list of all sockets */
336 ret->next = ot.socklist;
337 ret->prev = &ot.socklist;
338 if (ret->next != NULL)
339 ret->next->prev = &ret->next;
342 /* XXX: don't know whether we can sk_addr_free(addr); */
347 Socket ot_newlistener(char *srcaddr, int port, Plug plug, int local_host_only,
350 static struct socket_function_table fn_table = {
356 ot_tcp_set_private_ptr,
357 ot_tcp_get_private_ptr,
368 ret = snew(struct Socket_tag);
370 ret->error = kOTNoError;
372 bufchain_init(&ret->output_data);
373 ret->writable = 0; /* to start with */
374 ret->sending_oob = 0;
376 ret->frozen_readable = 0;
377 ret->localhost_only = local_host_only;
378 ret->pending_error = 0;
380 ret->oobpending = FALSE;
383 /* Open Endpoint, configure it for TCP over anything, and load the
384 * tilisten module to serialize multiple simultaneous
387 ep = OTOpenEndpoint(OTCreateConfiguration("tilisten,tcp"), 0, NULL, &err);
396 ot_setoption(ep, INET_IP, IP_REUSEADDR, T_YES);
398 OTInitInetAddress(&addr, port, kOTAnyInetAddress);
399 /* XXX: pay attention to local_host_only */
401 tbind.addr.buf = (UInt8 *) &addr;
402 tbind.addr.len = sizeof(addr);
405 err = OTBind(ep, &tbind, NULL); /* XXX: check qlen we got */
412 /* Add this to the list of all sockets */
413 ret->next = ot.socklist;
414 ret->prev = &ot.socklist;
415 if (ret->next != NULL)
416 ret->next->prev = &ret->next;
422 static void ot_tcp_close(Socket sock)
424 Actual_Socket s = (Actual_Socket) sock;
426 OTCloseProvider(s->ep);
428 /* Unhitch from list of sockets */
431 s->next->prev = s->prev;
436 static void try_send(Actual_Socket s)
438 while (bufchain_size(&s->output_data) > 0) {
443 /* Don't care about oob right now */
445 bufchain_prefix(&s->output_data, &data, &len);
447 nsent = OTSnd(s->ep, data, len, 0);
448 noise_ultralight(nsent);
451 /* something bad happened, hey ho */
453 /* still don't care about oob */
454 bufchain_consume(&s->output_data, nsent);
459 static int ot_tcp_write(Socket sock, char const *buf, int len)
461 Actual_Socket s = (Actual_Socket) sock;
463 bufchain_add(&s->output_data, buf, len);
467 return bufchain_size(&s->output_data);
470 static int ot_tcp_write_oob(Socket sock, char const *buf, int len)
472 /* Don't care about oob */
478 * Each socket abstraction contains a `void *' private field in
479 * which the client can keep state.
481 static void ot_tcp_set_private_ptr(Socket sock, void *ptr)
483 Actual_Socket s = (Actual_Socket) sock;
484 s->private_ptr = ptr;
487 static void *ot_tcp_get_private_ptr(Socket sock)
489 Actual_Socket s = (Actual_Socket) sock;
490 return s->private_ptr;
495 * Special error values are returned from ot_namelookup and ot_new
496 * if there's a problem. These functions extract an error message,
497 * or return NULL if there's no problem.
499 char *ot_addr_error(SockAddr addr)
501 static char buf[128];
503 if (addr->error == kOTNoError)
505 sprintf(buf, "error %d", addr->error);
508 static const char *ot_tcp_socket_error(Socket sock)
510 Actual_Socket s = (Actual_Socket) sock;
511 static char buf[128];
513 if (s->error == kOTNoError)
515 sprintf(buf, "error %d", s->error);
519 static void ot_tcp_set_frozen(Socket sock, int is_frozen)
521 Actual_Socket s = (Actual_Socket) sock;
523 if (s->frozen == is_frozen)
525 s->frozen = is_frozen;
529 * Poll all our sockets from an event loop
537 for (s = ot.socklist; s != NULL; s = s->next) {
541 case T_DATA: /* Normal Data */
544 case T_EXDATA: /* Expedited Data (urgent?) */
547 case T_LISTEN: /* Connection attempt */
550 case T_ORDREL: /* Orderly disconnect */
551 plug_closing(s->plug, NULL, 0, 0);
553 case T_DISCONNECT: /* Abortive disconnect*/
554 plug_closing(s->plug, NULL, 0, 0);
560 void ot_recv(Actual_Socket s)
566 if (s->frozen) return;
568 o = OTRcv(s->ep, buf, sizeof(buf), &flags);
570 plug_receive(s->plug, 0, buf, o);
571 if (o < 0 && o != kOTNoDataErr)
572 plug_closing(s->plug, NULL, 0, 0); /* XXX Error msg */
575 void ot_listenaccept(Actual_Socket s)
579 InetAddress remoteaddr;
583 tcall.addr.maxlen = sizeof(InetAddress);
584 tcall.addr.buf = (unsigned char *)&remoteaddr;
585 tcall.opt.maxlen = 0;
586 tcall.opt.buf = NULL;
587 tcall.udata.maxlen = 0;
588 tcall.udata.buf = NULL;
590 o = OTListen(s->ep, &tcall);
595 /* We've found an incoming connection, accept it */
597 ep = OTOpenEndpoint(OTCreateConfiguration("tcp"), 0, NULL, &err);
598 o = OTAccept(s->ep, ep, &tcall);
599 if (plug_accepting(s->plug, ep)) {
605 static void ot_setoption(EndpointRef ep,
614 if (name == TCP_KEEPALIVE) {
615 option.len = sizeof(struct t_kpalive);
616 option.value[1] = T_UNSPEC;
618 option.len = kOTFourByteOptionSize;
619 option.level = level;
622 option.value[0] = value;
624 request.opt.buf = (unsigned char *) &option;
625 request.opt.len = sizeof(option);
626 request.flags = T_NEGOTIATE;
628 result.opt.buf = (unsigned char *) &option;
629 result.opt.maxlen = sizeof(option);
631 OTOptionManagement(ep, &request, &result);
636 * c-file-style: "simon"