1 /* $XFree86: xc/lib/xtrans/Xtransmnx.c,v 3.3 1996/05/10 06:55:50 dawes Exp $ */
6 Created: 11 April 1994 by Philip Homburg <philip@cs.vu.nl>
11 #include <sys/ioctl.h>
14 #include <net/netlib.h>
15 #include <net/gen/in.h>
16 #include <net/gen/netdb.h>
17 #include <net/gen/tcp.h>
18 #include <net/gen/tcp_io.h>
39 XtransConnInfo listen_list;
41 #define RD_BUFSIZE 1024
42 #define WR_BUFSIZE 1024
44 static XtransConnInfo listen_list= NULL;
46 static XtransConnInfo alloc_ConnInfo(Xtransport *thistrans);
47 static void free_ConnInfo(XtransConnInfo ciptr);
48 static struct private *alloc_private(size_t rd_size, size_t wr_size);
49 static void free_private(struct private *priv);
50 static void read_cb(nbio_ref_t ref, int res, int err);
51 static void write_cb(nbio_ref_t ref, int res, int err);
52 static void listen_cb(nbio_ref_t ref, int res, int err);
53 static int restart_listen(XtransConnInfo ciptr);
57 TRANS(MnxTcpOpenCOTSClient) (thistrans, protocol, host, port)
59 Xtransport *thistrans;
72 PRMSG(2, "MnxTcpOpenCOTSClient(%s,%s,%s)\n",
73 protocol, host, port);
75 if ((ciptr= alloc_ConnInfo(thistrans)) == NULL)
78 "MnxTcpOpenCOTSClient: alloc_ConnInfo failed\n",
82 if ((ciptr->priv= (char *)alloc_private(RD_BUFSIZE, WR_BUFSIZE)) ==
86 "MnxTcpOpenCOTSClient: alloc_private() failed\n",
94 if ((tcp_device= getenv("TCP_DEVICE")) == NULL)
95 tcp_device= TCP_DEVICE;
96 PRMSG(4, "MnxTcpOpenCOTSClient: tcp_device= '%s'\n",
99 if ((fd= open(tcp_device, O_RDWR)) == -1)
102 "MnxTcpOpenCOTSClient: open '%s' failed: %s\n",
103 tcp_device, strerror(errno), 0);
105 free_ConnInfo(ciptr);
112 nbio_setcallback(fd, ASIO_READ, read_cb, ref);
113 nbio_setcallback(fd, ASIO_WRITE, write_cb, ref);
116 #endif /* TRANS_CLIENT */
119 static XtransConnInfo
120 TRANS(MnxTcpOpenCOTSServer) (thistrans, protocol, host, port)
122 Xtransport *thistrans;
128 XtransConnInfo ciptr;
135 PRMSG(2, "MnxTcpOpenCOTSServer(%s,%s,%s)\n",
136 protocol, host, port);
138 if ((ciptr= alloc_ConnInfo(thistrans)) == NULL)
141 "MnxTcpOpenCOTSServer: alloc_ConnInfo failed\n",
145 if ((ciptr->priv= (char *)alloc_private(RD_BUFSIZE, WR_BUFSIZE)) ==
149 "MnxTcpOpenCOTSServer: alloc_private() failed\n",
152 free_ConnInfo(ciptr);
157 if ((tcp_device= getenv("TCP_DEVICE")) == NULL)
158 tcp_device= TCP_DEVICE;
159 PRMSG(4, "MnxTcpOpenCOTSServer: tcp_device= '%s'\n",
162 if ((fd= open(tcp_device, O_RDWR)) == -1)
165 "MnxTcpOpenCOTSServer: open '%s' failed: %s\n",
166 tcp_device, strerror(errno), 0);
168 free_ConnInfo(ciptr);
172 PRMSG(5, "MnxTcpOpenCOTSServer: fd= '%d'\n", fd, 0, 0);
176 nbio_setcallback(fd, ASIO_IOCTL, listen_cb, ref);
179 #endif /* TRANS_SERVER */
182 static XtransConnInfo
183 TRANS(MnxTcpOpenCLTSClient) (thistrans, protocol, host, port)
185 Xtransport *thistrans;
193 #endif /* TRANS_CLIENT */
196 static XtransConnInfo
197 TRANS(MnxTcpOpenCLTSServer) (thistrans, protocol, host, port)
199 Xtransport *thistrans;
207 #endif /* TRANS_SERVER */
211 static XtransConnInfo
212 TRANS(MnxTcpReopenCOTSServer) (thistrans, fd, port)
214 Xtransport *thistrans;
219 XtransConnInfo ciptr;
223 "MnxTcpReopenCOTSServer(%d, %s)\n", fd, port, 0);
228 static XtransConnInfo
229 TRANS(MnxTcpReopenCLTSServer) (thistrans, fd, port)
231 Xtransport *thistrans;
236 XtransConnInfo ciptr;
241 "MnxTcpReopenCLTSServer(%d, %s)\n", fd, port, 0);
246 #endif /* TRANS_REOPEN */
251 TRANS(MnxTcpSetOption) (ciptr, option, arg)
253 XtransConnInfo ciptr;
259 struct private *priv;
261 PRMSG(2, "MnxTcpSetOption(%d,%d,%d)\n",
262 ciptr->fd, option, arg);
264 priv= (struct private *)ciptr->priv;
267 case TRANS_NONBLOCKING:
268 flags= fcntl(ciptr->fd, F_GETFD);
272 "MnxTcpSetOption: fcntl F_GETFD failed: %s\n",
273 strerror(errno), 0, 0);
277 flags &= ~FD_ASYNCHIO;
279 flags |= FD_ASYNCHIO;
283 "MnxTcpSetOption: bad arg for TRANS_NONBLOCKING: %d\n",
287 if (fcntl(ciptr->fd, F_SETFD, flags) == -1)
290 "MnxTcpSetOption: fcntl F_SETFD failed: %s\n",
291 strerror(errno), 0, 0);
294 priv->nonblocking= arg;
296 case TRANS_CLOSEONEXEC:
297 flags= fcntl(ciptr->fd, F_GETFD);
301 "MnxTcpSetOption: fcntl F_GETFD failed: %s\n",
302 strerror(errno), 0, 0);
306 flags &= ~FD_CLOEXEC;
312 "MnxTcpSetOption: bad arg for TRANS_CLOSEONEXEC: %d\n",
316 if (fcntl(ciptr->fd, F_SETFD, flags) == -1)
319 "MnxTcpSetOption: fcntl F_SETFD failed: %s\n",
320 strerror(errno), 0, 0);
325 PRMSG(1, "MnxTcpSetOption: unknown option '%d'\n",
335 TRANS(MnxTcpCreateListener) (ciptr, port)
337 XtransConnInfo ciptr;
341 struct servent *servp;
344 nwio_tcpconf_t tcpconf;
346 int r, s_errno, flags;
347 struct private *priv;
348 struct sockaddr_in *addr;
350 PRMSG(2, "MnxTcpCreateListener(%d,%s)\n", ciptr->fd, port, 0);
352 priv= (struct private *)ciptr->priv;
358 num_port= strtol(port, &check, 10);
359 num_port= htons(num_port);
360 if (check[0] == '\0')
366 * X has a well known port, that is transport dependent. It is easier
367 * to handle it here, than try and come up with a transport independent
368 * representation that can be passed in and resolved the usual way.
370 * The port that is passed here is really a string containing the
371 * idisplay from ConnectDisplay().
374 num_port= htons(ntohs(num_port) + X_TCP_PORT);
378 if ((servp = getservbyname (port, "tcp")) == NULL)
381 "MnxTcpCreateListener: can't get service for %s\n",
384 return TRANS_CREATE_LISTENER_FAILED;
386 num_port= servp->s_port;
389 tcpconf.nwtc_flags= NWTC_SHARED | NWTC_UNSET_RA | NWTC_UNSET_RP;
392 tcpconf.nwtc_locport= num_port;
393 tcpconf.nwtc_flags |= NWTC_LP_SET;
396 tcpconf.nwtc_flags |= NWTC_LP_SEL;
398 if (ioctl(ciptr->fd, NWIOSTCPCONF, &tcpconf) == -1)
401 "MnxTcpCreateListener: NWIOSTCPCONF failed: %s\n",
402 strerror(errno),0, 0);
403 return TRANS_CREATE_LISTENER_FAILED;
406 if (ioctl(ciptr->fd, NWIOGTCPCONF, &tcpconf) == -1)
409 "MnxTcpListen: NWIOGTCPCONF failed: %s\n",
410 strerror(errno),0, 0);
411 return TRANS_CREATE_LISTENER_FAILED;
414 priv->listen_port= tcpconf.nwtc_locport;
416 if ((addr= (struct sockaddr_in *)xalloc(sizeof(struct sockaddr_in)))
419 PRMSG(1, "MnxTcpAccept: malloc failed\n", 0, 0, 0);
420 return TRANS_CREATE_LISTENER_FAILED;
422 addr->sin_family= AF_INET;
423 addr->sin_addr.s_addr= tcpconf.nwtc_locaddr;
424 addr->sin_port= tcpconf.nwtc_locport;
427 ciptr->addr= (char *)addr;
428 ciptr->addrlen= sizeof(struct sockaddr_in);
430 flags= fcntl(ciptr->fd, F_GETFD);
434 "MnxTcpCreateListener: fcntl F_GETFD failed: %s\n",
435 strerror(errno), 0, 0);
436 return TRANS_CREATE_LISTENER_FAILED;
438 if (fcntl(ciptr->fd, F_SETFD, flags | FD_ASYNCHIO) == -1)
441 "MnxTcpCreateListener: fcntl F_SETFD failed: %s\n",
442 strerror(errno), 0, 0);
443 return TRANS_CREATE_LISTENER_FAILED;
446 tcpcl.nwtcl_flags= 0;
447 r= ioctl(ciptr->fd, NWIOTCPLISTEN, &tcpcl);
450 if (fcntl(ciptr->fd, F_SETFD, flags) == -1)
453 "MnxTcpCreateListener: fcntl F_SETFD failed: %s\n",
454 strerror(errno), 0, 0);
455 return TRANS_CREATE_LISTENER_FAILED;
458 if (r == -1 && s_errno == EINPROGRESS)
460 nbio_inprogress(ciptr->fd, ASIO_IOCTL, 1 /* read */,
461 1 /* write */, 0 /* exception */);
466 priv->listen_completed= 1;
471 PRMSG(1, "MnxTcpCreateListener: NWIOTCPLISTEN failed: %s\n",
472 strerror(errno), 0, 0);
473 return TRANS_CREATE_LISTENER_FAILED;
475 #endif /* TRANS_SERVER */
480 TRANS(MnxTcpResetListener) (ciptr)
482 XtransConnInfo ciptr;
484 PRMSG(2, "MnxTcpResetListener(%d)\n", ciptr->fd, 0, 0);
485 return TRANS_RESET_NOOP;
487 #endif /* TRANS_SERVER */
490 static XtransConnInfo
491 TRANS(MnxTcpAccept) (ciptr_listen, status)
493 XtransConnInfo ciptr_listen;
497 XtransConnInfo ciptr;
501 struct private *priv;
502 nwio_tcpconf_t tcpconf;
503 struct sockaddr_in *addr;
505 PRMSG(2, "MnxTcpAccept(%d,%p)\n", ciptr_listen->fd, status, 0);
507 priv= (struct private *)ciptr_listen->priv;
508 *status= TRANS_ACCEPT_MISC_ERROR;
510 if (!priv->listen_completed)
512 PRMSG(1, "MnxTcpAccept: listen is not completed\n",
514 *status= TRANS_ACCEPT_FAILED;
517 priv->listen_completed= 0;
519 if ((ciptr= alloc_ConnInfo(ciptr_listen->transptr)) == NULL)
522 "MnxTcpAccept: alloc_ConnInfo failed\n",
524 *status= TRANS_ACCEPT_BAD_MALLOC;
527 if ((ciptr->priv= (char *)alloc_private(RD_BUFSIZE, WR_BUFSIZE)) ==
531 "MnxTcpAccept: alloc_private() failed\n",
534 free_ConnInfo(ciptr);
536 *status= TRANS_ACCEPT_BAD_MALLOC;
540 fd= dup(ciptr_listen->fd);
544 PRMSG(1, "MnxTcpAccept: dup failed: %s\n",
545 strerror(errno), 0, 0);
546 free_ConnInfo(ciptr);
547 *status= TRANS_ACCEPT_FAILED;
550 if (restart_listen(ciptr_listen) == -1)
552 priv->listen_list= listen_list;
553 listen_list= ciptr_listen;
554 PRMSG(1, "MnxTcpAccept: unable to restart listen\n",
560 nbio_setcallback(fd, ASIO_WRITE, write_cb, ref);
561 nbio_setcallback(fd, ASIO_READ, read_cb, ref);
563 if (ioctl(ciptr->fd, NWIOGTCPCONF, &tcpconf) == -1)
565 PRMSG(1, "MnxTcpAccept: NWIOGTCPCONF failed: %s\n",
566 strerror(errno),0, 0);
568 free_ConnInfo(ciptr);
569 *status= TRANS_ACCEPT_MISC_ERROR;
572 if ((addr= (struct sockaddr_in *)xalloc(sizeof(struct sockaddr_in)))
575 PRMSG(1, "MnxTcpAccept: malloc failed\n", 0, 0, 0);
577 free_ConnInfo(ciptr);
578 *status= TRANS_ACCEPT_BAD_MALLOC;
581 addr->sin_family= AF_INET;
582 addr->sin_addr.s_addr= tcpconf.nwtc_locaddr;
583 addr->sin_port= tcpconf.nwtc_locport;
586 ciptr->addr= (char *)addr;
587 ciptr->addrlen= sizeof(struct sockaddr_in);
588 if (*(u8_t *)&tcpconf.nwtc_remaddr == 127)
590 /* Make ConvertAddress return FamilyLocal */
591 addr->sin_addr.s_addr= tcpconf.nwtc_remaddr;
594 if ((addr= (struct sockaddr_in *)xalloc(sizeof(struct sockaddr_in)))
597 PRMSG(1, "MnxTcpConnect: malloc failed\n", 0, 0, 0);
599 free_ConnInfo(ciptr);
600 *status= TRANS_ACCEPT_BAD_MALLOC;
603 addr->sin_family= AF_INET;
604 addr->sin_addr.s_addr= tcpconf.nwtc_remaddr;
605 addr->sin_port= tcpconf.nwtc_remport;
606 ciptr->peeraddr= (char *)addr;
607 ciptr->peeraddrlen= sizeof(struct sockaddr_in);
611 #endif /* TRANS_SERVER */
613 TRANS(MnxTcpConnect) (ciptr, host, port)
615 XtransConnInfo ciptr;
620 struct hostent *hostp;
621 struct servent *servp;
622 char hostnamebuf[256]; /* tmp space */
626 nwio_tcpconf_t tcpconf;
628 struct sockaddr_in *addr;
630 PRMSG(2, "MnxTcpConnect(%d,%s,%s)\n", ciptr->fd, host, port);
634 hostnamebuf[0] = '\0';
635 (void) TRANS(GetHostname) (hostnamebuf, sizeof hostnamebuf);
640 num_port= strtol(port, &check, 10);
641 num_port= htons(num_port);
642 if (check[0] == '\0')
646 * X has a well known port, that is transport dependent. It is easier
647 * to handle it here, than try and come up with a transport independent
648 * representation that can be passed in and resolved the usual way.
650 * The port that is passed here is really a string containing the
651 * idisplay from ConnectDisplay().
654 num_port= htons(ntohs(num_port) + X_TCP_PORT);
657 num_addr= inet_addr(host);
663 if ((hostp = gethostbyname(host)) == NULL)
666 "MnxTcpConnect: can't get address for %s\n",
669 return TRANS_CONNECT_FAILED;
671 if (hostp->h_addrtype != AF_INET) /* is IP host? */
673 PRMSG(1, "MnxTcpConnect: %s in not an INET host\n",
676 return TRANS_CONNECT_FAILED;
678 num_addr= *(ipaddr_t *)hostp->h_addr;
683 if ((servp = getservbyname (port, "tcp")) == NULL)
686 "MnxTcpConnect: can't get service for %s\n",
689 return TRANS_CONNECT_FAILED;
691 num_port= servp->s_port;
694 tcpconf.nwtc_flags= NWTC_EXCL | NWTC_LP_SEL | NWTC_SET_RA |
696 tcpconf.nwtc_remaddr= num_addr;
697 tcpconf.nwtc_remport= num_port;
698 if (ioctl(ciptr->fd, NWIOSTCPCONF, &tcpconf) == -1)
700 PRMSG(1, "MnxTcpConnect: NWIOSTCPCONF failed: %s\n",
701 strerror(errno),0, 0);
702 return TRANS_CONNECT_FAILED;
705 tcpcl.nwtcl_flags= 0;
706 if (ioctl(ciptr->fd, NWIOTCPCONN, &tcpcl) == -1)
708 PRMSG(1, "MnxTcpConnect: connect failed: %s\n",
709 strerror(errno),0, 0);
710 if (errno == ECONNREFUSED || errno == EINTR)
711 return TRANS_TRY_CONNECT_AGAIN;
713 return TRANS_CONNECT_FAILED;
716 if (ioctl(ciptr->fd, NWIOGTCPCONF, &tcpconf) == -1)
718 PRMSG(1, "MnxTcpConnect: NWIOGTCPCONF failed: %s\n",
719 strerror(errno),0, 0);
720 return TRANS_CONNECT_FAILED;
722 if ((addr= (struct sockaddr_in *)xalloc(sizeof(struct sockaddr_in)))
725 PRMSG(1, "MnxTcpConnect: malloc failed\n", 0, 0, 0);
726 return TRANS_CONNECT_FAILED;
728 addr->sin_family= AF_INET;
729 addr->sin_addr.s_addr= tcpconf.nwtc_locaddr;
730 addr->sin_port= tcpconf.nwtc_locport;
731 ciptr->addr= (char *)addr;
732 ciptr->addrlen= sizeof(struct sockaddr_in);
733 if (*(u8_t *)&tcpconf.nwtc_remaddr == 127)
735 /* Make ConvertAddress return FamilyLocal */
736 addr->sin_addr.s_addr= tcpconf.nwtc_remaddr;
739 if ((addr= (struct sockaddr_in *)xalloc(sizeof(struct sockaddr_in)))
742 PRMSG(1, "MnxTcpConnect: malloc failed\n", 0, 0, 0);
743 return TRANS_CONNECT_FAILED;
745 addr->sin_family= AF_INET;
746 addr->sin_addr.s_addr= tcpconf.nwtc_remaddr;
747 addr->sin_port= tcpconf.nwtc_remport;
748 ciptr->peeraddr= (char *)addr;
749 ciptr->peeraddrlen= sizeof(struct sockaddr_in);
755 TRANS(MnxTcpBytesReadable) (ciptr, pend)
757 XtransConnInfo ciptr;
758 BytesReadable_t *pend;
761 struct private *priv;
764 PRMSG(2, "MnxTcpBytesReadable(%x,%d,%x)\n",
765 ciptr, ciptr->fd, pend);
769 priv= (struct private *)ciptr->priv;
770 if (priv->read_inprogress)
772 PRMSG(5, "MnxTcpBytesReadable: read inprogress, %d\n",
776 if (priv->read_offset < priv->read_size)
778 *pend= priv->read_size-priv->read_offset;
779 PRMSG(5, "MnxTcpBytesReadable: %d\n",
783 priv->read_offset= 0;
784 r= read(ciptr->fd, priv->read_buffer, priv->read_bufsize);
788 r= 1; /* Signal EOF condition */
791 PRMSG(5, "MnxTcpBytesReadable: %d\n",
795 else if (r == -1 && errno == EINPROGRESS)
797 priv->read_inprogress= 1;
798 nbio_inprogress(ciptr->fd, ASIO_READ, 1 /* read */,
799 0 /* write */, 0 /* exception */);
803 PRMSG(1, "MnxTcpBytesReadable: read failed: %s\n",
804 strerror(errno), 0, 0);
807 PRMSG(5, "MnxTcpBytesReadable: %d\n", *pend, 0, 0);
813 TRANS(MnxTcpRead) (ciptr, buf, size)
815 XtransConnInfo ciptr;
820 int len, r, ret, s_errno;
822 struct private *priv;
823 asio_fd_set_t fd_set;
826 PRMSG(2, "MnxTcpRead(%d,%x,%d)\n", ciptr->fd, buf, size);
828 priv= (struct private *)ciptr->priv;
831 if (priv->read_inprogress)
833 PRMSG(5, "MnxTcpRead: EAGAIN\n", 0, 0, 0);
838 /* Copy any data left in the buffer */
839 if (priv->read_offset < priv->read_size)
841 len= priv->read_size-priv->read_offset;
842 if (len > size-offset)
844 PRMSG(5, "MnxTcpRead: copying %d bytes\n", len, 0, 0);
846 memcpy(buf+offset, priv->read_buffer + priv->read_offset,
849 priv->read_offset += len;
850 if (priv->read_offset < priv->read_size)
854 /* Try to read directly into the user's buffer. */
859 r= read(ciptr->fd, buf+offset, size-offset);
860 if (r == -1 && errno == EINPROGRESS)
862 r= fcancel(ciptr->fd, ASIO_READ);
865 ASIO_FD_ZERO(&fd_set);
866 ASIO_FD_SET(ciptr->fd, ASIO_READ, &fd_set);
867 fw.fw_flags= FWF_NONBLOCK;
868 fw.fw_bits= fd_set.afds_bits;
869 fw.fw_maxfd= ASIO_FD_SETSIZE;
871 if (r == -1 || fw.fw_fd != ciptr->fd ||
872 fw.fw_operation != ASIO_READ)
882 PRMSG(5, "MnxTcpRead: read %d bytes\n", r,
889 PRMSG(5, "MnxTcpRead: read EOF\n", 0, 0, 0);
896 PRMSG(5, "MnxTcpRead: EINTR\n",
902 PRMSG(1, "MnxTcpRead: read error %s\n",
903 strerror(errno), 0, 0);
913 if (priv->read_offset != priv->read_size)
915 priv->read_offset= 0;
917 if (priv->nonblocking)
919 r= read(ciptr->fd, priv->read_buffer, priv->read_bufsize);
922 PRMSG(5, "MnxTcpRead: buffered %d bytes\n",
926 else if (r == -1 && errno == EINPROGRESS)
928 priv->read_inprogress= 1;
929 nbio_inprogress(ciptr->fd, ASIO_READ, 1 /* read */,
930 0 /* write */, 0 /* exception */);
934 PRMSG(1, "MnxTcpRead: read failed: %s\n",
935 strerror(errno), 0, 0);
944 TRANS(MnxTcpWrite) (ciptr, buf, size)
946 XtransConnInfo ciptr;
951 int len, r, ret, s_errno;
953 struct private *priv;
954 asio_fd_set_t fd_set;
957 PRMSG(2, "MnxTcpWrite(%d,%x,%d)\n", ciptr->fd, buf, size);
959 priv= (struct private *)ciptr->priv;
962 if (priv->write_errno)
964 PRMSG(5, "MnxTcpWrite: write_errno %d\n",
965 priv->write_errno, 0, 0);
966 errno= priv->write_errno;
970 if (priv->write_inprogress)
972 PRMSG(5, "MnxTcpWrite: EAGAIN\n", 0, 0, 0);
977 /* Try to write directly out of the user's buffer. */
982 r= write(ciptr->fd, buf+offset, size-offset);
983 if (r == -1 && errno == EINPROGRESS)
985 r= fcancel(ciptr->fd, ASIO_WRITE);
988 ASIO_FD_ZERO(&fd_set);
989 ASIO_FD_SET(ciptr->fd, ASIO_WRITE, &fd_set);
990 fw.fw_flags= FWF_NONBLOCK;
991 fw.fw_bits= fd_set.afds_bits;
992 fw.fw_maxfd= ASIO_FD_SETSIZE;
994 if (r == -1 || fw.fw_fd != ciptr->fd ||
995 fw.fw_operation != ASIO_WRITE)
1004 PRMSG(5, "MnxTcpWrite: wrote %d bytes\n", r,
1015 PRMSG(5, "MnxTcpWrite: EINTR\n",
1022 "MnxTcpWrite: write error: %s\n",
1023 strerror(errno), 0, 0);
1031 /* Copy any data to the buffer */
1034 len= priv->write_bufsize;
1035 if (len > size-offset)
1037 PRMSG(5, "MnxTcpWrite: copying %d bytes\n", len, 0, 0);
1039 memcpy(priv->write_buffer, buf+offset, len);
1041 priv->write_offset= 0;
1042 priv->write_size= len;
1047 while (priv->write_offset < priv->write_size)
1049 r= write(ciptr->fd, priv->write_buffer+priv->write_offset,
1050 priv->write_size-priv->write_offset);
1053 PRMSG(5, "MnxTcpWrite: wrote %d bytes\n",
1055 priv->write_offset += r;
1058 else if (r == -1 && errno == EINPROGRESS)
1060 priv->write_inprogress= 1;
1061 nbio_inprogress(ciptr->fd, ASIO_WRITE, 0 /* read */,
1062 1 /* write */, 0 /* exception */);
1066 PRMSG(1, "MnxTcpWrite: write failed: %s\n",
1067 strerror(errno), 0, 0);
1068 priv->write_errno= errno;
1079 TRANS(MnxTcpReadv) (ciptr, buf, size)
1081 XtransConnInfo ciptr;
1086 int i, offset, total, len, r;
1088 PRMSG(2, "MnxTcpReadv(%d,%x,%d)\n", ciptr->fd, buf, size);
1090 /* Simply call read a number of times. */
1096 PRMSG(5, "MnxTcpReadv: [%d] size %d-%d\n",
1097 i, buf[i].iov_len, offset);
1098 if (offset >= buf[i].iov_len)
1104 len= buf[i].iov_len-offset;
1105 r= TRANS(MnxTcpRead)(ciptr, buf[i].iov_base+offset, len);
1108 if (errno == EAGAIN)
1111 "MnxTcpReadv: read returned: %s\n",
1112 strerror(errno), 0, 0);
1117 "MnxTcpReadv: read failed: %s\n",
1118 strerror(errno), 0, 0);
1136 TRANS(MnxTcpWritev) (ciptr, buf, size)
1138 XtransConnInfo ciptr;
1143 int i, offset, total, len, r;
1145 PRMSG(2, "MnxTcpWritev(%d,%x,%d)\n", ciptr->fd, buf, size);
1147 /* Simply call write a number of times. */
1153 if (offset >= buf[i].iov_len)
1159 len= buf[i].iov_len-offset;
1160 r= TRANS(MnxTcpWrite)(ciptr, buf[i].iov_base+offset, len);
1163 if (errno == EAGAIN)
1165 PRMSG(5, "MnxTcpWritev: AGAIN\n",
1171 "MnxTcpWritev: write failed: %s\n",
1172 strerror(errno), 0, 0);
1179 if (r == 0 || r > len)
1189 TRANS(MnxTcpDisconnect) (ciptr)
1191 XtransConnInfo ciptr;
1194 PRMSG(2, "MnxTcpDisconnect(%x,%d)\n", ciptr, ciptr->fd, 0);
1196 return ioctl(ciptr->fd, NWIOTCPSHUTDOWN, NULL);
1200 TRANS(MnxTcpClose) (ciptr)
1202 XtransConnInfo ciptr;
1205 XtransConnInfo list, t_ciptr;
1206 struct private *priv;
1208 PRMSG(2, "MnxTcpClose(%x,%d)\n", ciptr, ciptr->fd, 0);
1218 priv= (struct private *)t_ciptr->priv;
1219 list= priv->listen_list;
1220 if (t_ciptr == ciptr)
1222 if (restart_listen(t_ciptr) == -1)
1224 priv->listen_list= listen_list;
1225 listen_list= t_ciptr;
1230 free_private((struct private *)ciptr->priv);
1231 nbio_unregister(ciptr->fd);
1232 return close (ciptr->fd);
1236 static XtransConnInfo
1237 alloc_ConnInfo(thistrans)
1238 Xtransport *thistrans;
1240 XtransConnInfo ciptr;
1242 PRMSG(2, " alloc_ConnInfo(%p)\n", thistrans, 0, 0);
1244 if ((ciptr= (XtransConnInfo) xalloc(sizeof(struct _XtransConnInfo)))
1247 PRMSG(1, " alloc_ConnInfo: malloc failed\n", 0, 0, 0);
1250 ciptr->transptr= thistrans;
1255 ciptr->family= AF_INET;
1258 ciptr->peeraddr= NULL;
1259 ciptr->peeraddrlen= 0;
1264 free_ConnInfo(ciptr)
1265 XtransConnInfo ciptr;
1269 free_private((struct private *)ciptr->priv);
1273 static struct private *
1274 alloc_private(rd_size, wr_size)
1278 struct private *priv;
1282 PRMSG(2, ":alloc_private(%d, %d)\n", rd_size, wr_size, 0);
1284 if ((priv= (struct private *)xalloc(sizeof(struct private))) == NULL)
1286 PRMSG(1, ":alloc_private: malloc failed\n", 0, 0, 0);
1289 priv->nonblocking= 0;
1290 priv->read_inprogress= 0;
1291 priv->read_buffer= NULL;
1292 priv->read_bufsize= rd_size;
1294 priv->read_offset= 0;
1298 if ((buf= xalloc(rd_size)) == NULL)
1300 PRMSG(1, ":alloc_private: malloc failed\n", 0, 0, 0);
1306 priv->read_buffer= buf;
1309 priv->write_inprogress= 0;
1310 priv->write_buffer= NULL;
1311 priv->write_bufsize= rd_size;
1312 priv->write_size= 0;
1313 priv->write_offset= 0;
1314 priv->write_errno= 0;
1318 if ((buf= xalloc(wr_size)) == NULL)
1320 PRMSG(1, ":alloc_private: malloc failed\n", 0, 0, 0);
1326 priv->write_buffer= buf;
1329 priv->listen_completed= 0;
1330 priv->listen_port= 0;
1331 priv->listen_list= NULL;
1338 struct private *priv;
1342 xfree(priv->read_buffer);
1343 xfree(priv->write_buffer);
1348 read_cb(ref, res, err)
1353 XtransConnInfo ciptr;
1354 struct private *priv;
1356 PRMSG(2, ":read_cb(%x,%d,%d)\n", ref.ref_ptr, res, err);
1359 priv= (struct private *)ciptr->priv;
1361 priv->read_size= res;
1362 priv->read_inprogress= 0;
1366 write_cb(ref, res, err)
1371 XtransConnInfo ciptr;
1372 struct private *priv;
1375 PRMSG(2, ":write_cb(%x,%d,%d)\n", ref.ref_ptr, res, err);
1378 priv= (struct private *)ciptr->priv;
1380 priv->write_offset += res;
1385 priv->write_errno= err;
1388 priv->write_inprogress= 0;
1390 while (priv->write_offset < priv->write_size)
1392 r= write(ciptr->fd, priv->write_buffer+priv->write_offset,
1393 priv->write_size-priv->write_offset);
1396 PRMSG(5, "MnxTcpWrite: wrote %d bytes\n",
1398 priv->write_offset += r;
1401 else if (r == -1 && errno == EINPROGRESS)
1403 priv->write_inprogress= 1;
1404 nbio_inprogress(ciptr->fd, ASIO_WRITE, 0 /* read */,
1405 1 /* write */, 0 /* exception */);
1409 PRMSG(1, "MnxTcpWrite: write failed: %s\n",
1410 strerror(errno), 0, 0);
1411 priv->write_errno= errno;
1418 listen_cb(ref, res, err)
1423 XtransConnInfo ciptr;
1424 struct private *priv;
1425 struct sockaddr_in *addr;
1426 nwio_tcpconf_t tcpconf;
1428 PRMSG(2, ":listen_cb(%x,%d,%d)\n", ref.ref_ptr, res, err);
1431 priv= (struct private *)ciptr->priv;
1434 if (ioctl(ciptr->fd, NWIOGTCPCONF, &tcpconf) == -1)
1437 ":listen_cb: NWIOGTCPCONF failed: %s\n",
1438 strerror(errno),0, 0);
1441 if ((addr= (struct sockaddr_in *)xalloc(sizeof(struct sockaddr_in)))
1444 PRMSG(1, ":listen_cb: malloc failed\n", 0, 0, 0);
1447 addr->sin_family= AF_INET;
1448 addr->sin_addr.s_addr= tcpconf.nwtc_locaddr;
1449 addr->sin_port= tcpconf.nwtc_locport;
1452 ciptr->addr= (char *)addr;
1453 ciptr->addrlen= sizeof(struct sockaddr_in);
1454 priv->listen_completed= 1;
1457 PRMSG(2, ":listen_cb: listen failed: %s\n", strerror(err), 0, 0);
1458 if (restart_listen(ciptr) == -1)
1460 priv->listen_list= listen_list;
1466 restart_listen(ciptr)
1467 XtransConnInfo ciptr;
1470 nwio_tcpconf_t tcpconf;
1472 int fd, r, s_errno, flags;
1473 struct private *priv;
1476 PRMSG(2, ":restart_listen(%d)\n", ciptr->fd, 0, 0);
1478 nbio_unregister(ciptr->fd);
1480 if ((tcp_device= getenv("TCP_DEVICE")) == NULL)
1481 tcp_device= TCP_DEVICE;
1483 if ((fd= open(tcp_device, O_RDWR)) == -1)
1485 PRMSG(1, ":restart_listen: open '%s' failed: %s\n",
1486 tcp_device, strerror(errno), 0);
1489 PRMSG(5, ":restart_listen: fd= '%d'\n", fd, 0, 0);
1490 if (fd != ciptr->fd)
1492 if (dup2(fd, ciptr->fd) == -1)
1493 abort(); /* no way to recover */
1499 nbio_setcallback(fd, ASIO_IOCTL, listen_cb, ref);
1501 priv= (struct private *)ciptr->priv;
1503 tcpconf.nwtc_flags= NWTC_SHARED | NWTC_UNSET_RA | NWTC_UNSET_RP;
1504 tcpconf.nwtc_locport= priv->listen_port;
1505 tcpconf.nwtc_flags |= NWTC_LP_SET;
1507 if (ioctl(ciptr->fd, NWIOSTCPCONF, &tcpconf) == -1)
1510 ":restart_listen: NWIOSTCPCONF failed: %s\n",
1511 strerror(errno),0, 0);
1515 flags= fcntl(ciptr->fd, F_GETFD);
1519 ":restart_listen: fcntl F_GETFD failed: %s\n",
1520 strerror(errno), 0, 0);
1523 if (fcntl(ciptr->fd, F_SETFD, flags | FD_ASYNCHIO) == -1)
1526 ":restart_listen: fcntl F_SETFD failed: %s\n",
1527 strerror(errno), 0, 0);
1531 tcpcl.nwtcl_flags= 0;
1532 r= ioctl(ciptr->fd, NWIOTCPLISTEN, &tcpcl);
1535 if (fcntl(ciptr->fd, F_SETFD, flags) == -1)
1538 ":restart_listen: fcntl F_SETFD failed: %s\n",
1539 strerror(errno), 0, 0);
1543 if (r == -1 && s_errno == EINPROGRESS)
1545 nbio_inprogress(ciptr->fd, ASIO_IOCTL, 1 /* read */,
1546 1 /* write */, 0 /* exception */);
1551 priv->listen_completed= 1;
1555 PRMSG(1, ":restart_listen: NWIOTCPLISTEN failed: %s\n",
1556 strerror(errno), 0, 0);
1561 Xtransport TRANS(MnxINETFuncs) =
1563 /* Minix TCP Interface */
1567 TRANS(MnxTcpOpenCOTSClient),
1568 #endif /* TRANS_CLIENT */
1570 TRANS(MnxTcpOpenCOTSServer),
1571 #endif /* TRANS_SERVER */
1573 TRANS(MnxTcpOpenCLTSClient),
1574 #endif /* TRANS_CLIENT */
1576 TRANS(MnxTcpOpenCLTSServer),
1577 #endif /* TRANS_SERVER */
1579 TRANS(MnxTcpReopenCOTSServer),
1580 TRANS(MnxTcpReopenCLTSServer),
1582 TRANS(MnxTcpSetOption),
1584 TRANS(MnxTcpCreateListener),
1585 TRANS(MnxTcpResetListener),
1586 TRANS(MnxTcpAccept),
1587 #endif /* TRANS_SERVER */
1589 TRANS(MnxTcpConnect),
1590 #endif /* TRANS_CLIENT */
1591 TRANS(MnxTcpBytesReadable),
1595 TRANS(MnxTcpWritev),
1596 TRANS(MnxTcpDisconnect),
1601 Xtransport TRANS(MnxTCPFuncs) =
1603 /* Minix TCP Interface */
1607 TRANS(MnxTcpOpenCOTSClient),
1608 #endif /* TRANS_CLIENT */
1610 TRANS(MnxTcpOpenCOTSServer),
1611 #endif /* TRANS_SERVER */
1613 TRANS(MnxTcpOpenCLTSClient),
1614 #endif /* TRANS_CLIENT */
1616 TRANS(MnxTcpOpenCLTSServer),
1617 #endif /* TRANS_SERVER */
1619 TRANS(MnxTcpReopenCOTSServer),
1620 TRANS(MnxTcpReopenCLTSServer),
1622 TRANS(MnxTcpSetOption),
1624 TRANS(MnxTcpCreateListener),
1625 TRANS(MnxTcpResetListener),
1626 TRANS(MnxTcpAccept),
1627 #endif /* TRANS_SERVER */
1629 TRANS(MnxTcpConnect),
1630 #endif /* TRANS_CLIENT */
1631 TRANS(MnxTcpBytesReadable),
1635 TRANS(MnxTcpWritev),
1636 TRANS(MnxTcpDisconnect),