X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=Xserver%2Flib%2Fxtrans%2FXtransmnx.c;fp=Xserver%2Flib%2Fxtrans%2FXtransmnx.c;h=9e5b5e6169cdd7874cadb0685909c6f243475914;hb=b6e6afccf37f4ad0515ef2a698f714fdf1bf23b3;hp=0000000000000000000000000000000000000000;hpb=e3340a110a3b01756b8e67531395a33b40a17d37;p=rdpsrv diff --git a/Xserver/lib/xtrans/Xtransmnx.c b/Xserver/lib/xtrans/Xtransmnx.c new file mode 100644 index 0000000..9e5b5e6 --- /dev/null +++ b/Xserver/lib/xtrans/Xtransmnx.c @@ -0,0 +1,1639 @@ +/* $XFree86: xc/lib/xtrans/Xtransmnx.c,v 3.3 1996/05/10 06:55:50 dawes Exp $ */ + +/* +Xtransmnx.c + +Created: 11 April 1994 by Philip Homburg +*/ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct private +{ + int nonblocking; + + int read_inprogress; + char *read_buffer; + size_t read_bufsize; + size_t read_size; + size_t read_offset; + + int write_inprogress; + char *write_buffer; + size_t write_bufsize; + size_t write_size; + size_t write_offset; + int write_errno; + + int listen_completed; + u16_t listen_port; + XtransConnInfo listen_list; +}; +#define RD_BUFSIZE 1024 +#define WR_BUFSIZE 1024 + +static XtransConnInfo listen_list= NULL; + +static XtransConnInfo alloc_ConnInfo(Xtransport *thistrans); +static void free_ConnInfo(XtransConnInfo ciptr); +static struct private *alloc_private(size_t rd_size, size_t wr_size); +static void free_private(struct private *priv); +static void read_cb(nbio_ref_t ref, int res, int err); +static void write_cb(nbio_ref_t ref, int res, int err); +static void listen_cb(nbio_ref_t ref, int res, int err); +static int restart_listen(XtransConnInfo ciptr); + +#ifdef TRANS_CLIENT +static XtransConnInfo +TRANS(MnxTcpOpenCOTSClient) (thistrans, protocol, host, port) + +Xtransport *thistrans; +char *protocol; +char *host; +char *port; + +{ + XtransConnInfo ciptr; + char *tcp_device; + int s_errno; + int fd; + nbio_ref_t ref; + + + PRMSG(2, "MnxTcpOpenCOTSClient(%s,%s,%s)\n", + protocol, host, port); + + if ((ciptr= alloc_ConnInfo(thistrans)) == NULL) + { + PRMSG(1, + "MnxTcpOpenCOTSClient: alloc_ConnInfo failed\n", + 0, 0, 0); + return NULL; + } + if ((ciptr->priv= (char *)alloc_private(RD_BUFSIZE, WR_BUFSIZE)) == + NULL) + { + PRMSG(1, + "MnxTcpOpenCOTSClient: alloc_private() failed\n", + 0, 0, 0); + s_errno= errno; + free_ConnInfo(ciptr); + errno= s_errno; + return NULL; + } + + if ((tcp_device= getenv("TCP_DEVICE")) == NULL) + tcp_device= TCP_DEVICE; + PRMSG(4, "MnxTcpOpenCOTSClient: tcp_device= '%s'\n", + tcp_device, 0, 0); + + if ((fd= open(tcp_device, O_RDWR)) == -1) + { + PRMSG(1, + "MnxTcpOpenCOTSClient: open '%s' failed: %s\n", + tcp_device, strerror(errno), 0); + s_errno= errno; + free_ConnInfo(ciptr); + errno= s_errno; + return NULL; + } + ciptr->fd= fd; + ref.ref_ptr= ciptr; + nbio_register(fd); + nbio_setcallback(fd, ASIO_READ, read_cb, ref); + nbio_setcallback(fd, ASIO_WRITE, write_cb, ref); + return ciptr; +} +#endif /* TRANS_CLIENT */ + +#ifdef TRANS_SERVER +static XtransConnInfo +TRANS(MnxTcpOpenCOTSServer) (thistrans, protocol, host, port) + +Xtransport *thistrans; +char *protocol; +char *host; +char *port; + +{ + XtransConnInfo ciptr; + char *tcp_device; + int s_errno; + int fd; + nbio_ref_t ref; + + + PRMSG(2, "MnxTcpOpenCOTSServer(%s,%s,%s)\n", + protocol, host, port); + + if ((ciptr= alloc_ConnInfo(thistrans)) == NULL) + { + PRMSG(1, + "MnxTcpOpenCOTSServer: alloc_ConnInfo failed\n", + 0, 0, 0); + return NULL; + } + if ((ciptr->priv= (char *)alloc_private(RD_BUFSIZE, WR_BUFSIZE)) == + NULL) + { + PRMSG(1, + "MnxTcpOpenCOTSServer: alloc_private() failed\n", + 0, 0, 0); + s_errno= errno; + free_ConnInfo(ciptr); + errno= s_errno; + return NULL; + } + + if ((tcp_device= getenv("TCP_DEVICE")) == NULL) + tcp_device= TCP_DEVICE; + PRMSG(4, "MnxTcpOpenCOTSServer: tcp_device= '%s'\n", + tcp_device, 0, 0); + + if ((fd= open(tcp_device, O_RDWR)) == -1) + { + PRMSG(1, + "MnxTcpOpenCOTSServer: open '%s' failed: %s\n", + tcp_device, strerror(errno), 0); + s_errno= errno; + free_ConnInfo(ciptr); + errno= s_errno; + return NULL; + } + PRMSG(5, "MnxTcpOpenCOTSServer: fd= '%d'\n", fd, 0, 0); + ciptr->fd= fd; + ref.ref_ptr= ciptr; + nbio_register(fd); + nbio_setcallback(fd, ASIO_IOCTL, listen_cb, ref); + return ciptr; +} +#endif /* TRANS_SERVER */ + +#ifdef TRANS_CLIENT +static XtransConnInfo +TRANS(MnxTcpOpenCLTSClient) (thistrans, protocol, host, port) + +Xtransport *thistrans; +char *protocol; +char *host; +char *port; + +{ + abort(); +} +#endif /* TRANS_CLIENT */ + +#ifdef TRANS_SERVER +static XtransConnInfo +TRANS(MnxTcpOpenCLTSServer) (thistrans, protocol, host, port) + +Xtransport *thistrans; +char *protocol; +char *host; +char *port; + +{ + abort(); +} +#endif /* TRANS_SERVER */ + +#ifdef TRANS_REOPEN + +static XtransConnInfo +TRANS(MnxTcpReopenCOTSServer) (thistrans, fd, port) + +Xtransport *thistrans; +int fd; +char *port; + +{ + XtransConnInfo ciptr; + int i; + + PRMSG (2, + "MnxTcpReopenCOTSServer(%d, %s)\n", fd, port, 0); + + abort(); +} + +static XtransConnInfo +TRANS(MnxTcpReopenCLTSServer) (thistrans, fd, port) + +Xtransport *thistrans; +int fd; +char *port; + +{ + XtransConnInfo ciptr; + int i; + + + PRMSG (2, + "MnxTcpReopenCLTSServer(%d, %s)\n", fd, port, 0); + + abort(); +} + +#endif /* TRANS_REOPEN */ + + + +static int +TRANS(MnxTcpSetOption) (ciptr, option, arg) + +XtransConnInfo ciptr; +int option; +int arg; + +{ + int flags; + struct private *priv; + + PRMSG(2, "MnxTcpSetOption(%d,%d,%d)\n", + ciptr->fd, option, arg); + + priv= (struct private *)ciptr->priv; + switch(option) + { + case TRANS_NONBLOCKING: + flags= fcntl(ciptr->fd, F_GETFD); + if (flags == -1) + { + PRMSG(1, + "MnxTcpSetOption: fcntl F_GETFD failed: %s\n", + strerror(errno), 0, 0); + return -1; + } + if (arg == 0) + flags &= ~FD_ASYNCHIO; + else if (arg == 1) + flags |= FD_ASYNCHIO; + else + { + PRMSG(1, + "MnxTcpSetOption: bad arg for TRANS_NONBLOCKING: %d\n", + arg, 0, 0); + return -1; + } + if (fcntl(ciptr->fd, F_SETFD, flags) == -1) + { + PRMSG(1, + "MnxTcpSetOption: fcntl F_SETFD failed: %s\n", + strerror(errno), 0, 0); + return -1; + } + priv->nonblocking= arg; + return 0; + case TRANS_CLOSEONEXEC: + flags= fcntl(ciptr->fd, F_GETFD); + if (flags == -1) + { + PRMSG(1, + "MnxTcpSetOption: fcntl F_GETFD failed: %s\n", + strerror(errno), 0, 0); + return -1; + } + if (arg == 0) + flags &= ~FD_CLOEXEC; + else if (arg == 1) + flags |= FD_CLOEXEC; + else + { + PRMSG(1, + "MnxTcpSetOption: bad arg for TRANS_CLOSEONEXEC: %d\n", + arg, 0, 0); + return -1; + } + if (fcntl(ciptr->fd, F_SETFD, flags) == -1) + { + PRMSG(1, + "MnxTcpSetOption: fcntl F_SETFD failed: %s\n", + strerror(errno), 0, 0); + return -1; + } + return 0; + default: + PRMSG(1, "MnxTcpSetOption: unknown option '%d'\n", + option, 0, 0); + errno= EINVAL; + return -1; + } +} + + +#ifdef TRANS_SERVER +static int +TRANS(MnxTcpCreateListener) (ciptr, port) + +XtransConnInfo ciptr; +char *port; + +{ + struct servent *servp; + tcpport_t num_port; + char *check; + nwio_tcpconf_t tcpconf; + nwio_tcpcl_t tcpcl; + int r, s_errno, flags; + struct private *priv; + struct sockaddr_in *addr; + + PRMSG(2, "MnxTcpCreateListener(%d,%s)\n", ciptr->fd, port, 0); + + priv= (struct private *)ciptr->priv; + + if (port == NULL) + num_port= 0; + else + { + num_port= strtol(port, &check, 10); + num_port= htons(num_port); + if (check[0] == '\0') + port= NULL; + } + +#ifdef X11_t + /* + * X has a well known port, that is transport dependent. It is easier + * to handle it here, than try and come up with a transport independent + * representation that can be passed in and resolved the usual way. + * + * The port that is passed here is really a string containing the + * idisplay from ConnectDisplay(). + */ + if (port == NULL) + num_port= htons(ntohs(num_port) + X_TCP_PORT); +#endif + if (port != NULL) + { + if ((servp = getservbyname (port, "tcp")) == NULL) + { + PRMSG(1, + "MnxTcpCreateListener: can't get service for %s\n", + port, 0, 0); + errno= EINVAL; + return TRANS_CREATE_LISTENER_FAILED; + } + num_port= servp->s_port; + } + + tcpconf.nwtc_flags= NWTC_SHARED | NWTC_UNSET_RA | NWTC_UNSET_RP; + if (num_port != 0) + { + tcpconf.nwtc_locport= num_port; + tcpconf.nwtc_flags |= NWTC_LP_SET; + } + else + tcpconf.nwtc_flags |= NWTC_LP_SEL; + + if (ioctl(ciptr->fd, NWIOSTCPCONF, &tcpconf) == -1) + { + PRMSG(1, + "MnxTcpCreateListener: NWIOSTCPCONF failed: %s\n", + strerror(errno),0, 0); + return TRANS_CREATE_LISTENER_FAILED; + } + + if (ioctl(ciptr->fd, NWIOGTCPCONF, &tcpconf) == -1) + { + PRMSG(1, + "MnxTcpListen: NWIOGTCPCONF failed: %s\n", + strerror(errno),0, 0); + return TRANS_CREATE_LISTENER_FAILED; + } + + priv->listen_port= tcpconf.nwtc_locport; + + if ((addr= (struct sockaddr_in *)xalloc(sizeof(struct sockaddr_in))) + == NULL) + { + PRMSG(1, "MnxTcpAccept: malloc failed\n", 0, 0, 0); + return TRANS_CREATE_LISTENER_FAILED; + } + addr->sin_family= AF_INET; + addr->sin_addr.s_addr= tcpconf.nwtc_locaddr; + addr->sin_port= tcpconf.nwtc_locport; + if (ciptr->addr) + xfree(ciptr->addr); + ciptr->addr= (char *)addr; + ciptr->addrlen= sizeof(struct sockaddr_in); + + flags= fcntl(ciptr->fd, F_GETFD); + if (flags == -1) + { + PRMSG(1, + "MnxTcpCreateListener: fcntl F_GETFD failed: %s\n", + strerror(errno), 0, 0); + return TRANS_CREATE_LISTENER_FAILED; + } + if (fcntl(ciptr->fd, F_SETFD, flags | FD_ASYNCHIO) == -1) + { + PRMSG(1, + "MnxTcpCreateListener: fcntl F_SETFD failed: %s\n", + strerror(errno), 0, 0); + return TRANS_CREATE_LISTENER_FAILED; + } + + tcpcl.nwtcl_flags= 0; + r= ioctl(ciptr->fd, NWIOTCPLISTEN, &tcpcl); + s_errno= errno; + + if (fcntl(ciptr->fd, F_SETFD, flags) == -1) + { + PRMSG(1, + "MnxTcpCreateListener: fcntl F_SETFD failed: %s\n", + strerror(errno), 0, 0); + return TRANS_CREATE_LISTENER_FAILED; + } + + if (r == -1 && s_errno == EINPROGRESS) + { + nbio_inprogress(ciptr->fd, ASIO_IOCTL, 1 /* read */, + 1 /* write */, 0 /* exception */); + return 0; + } + if (r == 0) + { + priv->listen_completed= 1; + return 0; + } + + errno= s_errno; + PRMSG(1, "MnxTcpCreateListener: NWIOTCPLISTEN failed: %s\n", + strerror(errno), 0, 0); + return TRANS_CREATE_LISTENER_FAILED; +} +#endif /* TRANS_SERVER */ + + +#ifdef TRANS_SERVER +static int +TRANS(MnxTcpResetListener) (ciptr) + +XtransConnInfo ciptr; +{ + PRMSG(2, "MnxTcpResetListener(%d)\n", ciptr->fd, 0, 0); + return TRANS_RESET_NOOP; +} +#endif /* TRANS_SERVER */ + +#ifdef TRANS_SERVER +static XtransConnInfo +TRANS(MnxTcpAccept) (ciptr_listen, status) + +XtransConnInfo ciptr_listen; +int *status; + +{ + XtransConnInfo ciptr; + int s_errno; + int fd; + nbio_ref_t ref; + struct private *priv; + nwio_tcpconf_t tcpconf; + struct sockaddr_in *addr; + + PRMSG(2, "MnxTcpAccept(%d,%p)\n", ciptr_listen->fd, status, 0); + + priv= (struct private *)ciptr_listen->priv; + *status= TRANS_ACCEPT_MISC_ERROR; + + if (!priv->listen_completed) + { + PRMSG(1, "MnxTcpAccept: listen is not completed\n", + 0, 0, 0); + *status= TRANS_ACCEPT_FAILED; + return NULL; + } + priv->listen_completed= 0; + + if ((ciptr= alloc_ConnInfo(ciptr_listen->transptr)) == NULL) + { + PRMSG(1, + "MnxTcpAccept: alloc_ConnInfo failed\n", + 0, 0, 0); + *status= TRANS_ACCEPT_BAD_MALLOC; + return NULL; + } + if ((ciptr->priv= (char *)alloc_private(RD_BUFSIZE, WR_BUFSIZE)) == + NULL) + { + PRMSG(1, + "MnxTcpAccept: alloc_private() failed\n", + 0, 0, 0); + s_errno= errno; + free_ConnInfo(ciptr); + errno= s_errno; + *status= TRANS_ACCEPT_BAD_MALLOC; + return NULL; + } + + fd= dup(ciptr_listen->fd); + if (fd == -1) + { + s_errno= errno; + PRMSG(1, "MnxTcpAccept: dup failed: %s\n", + strerror(errno), 0, 0); + free_ConnInfo(ciptr); + *status= TRANS_ACCEPT_FAILED; + return NULL; + } + if (restart_listen(ciptr_listen) == -1) + { + priv->listen_list= listen_list; + listen_list= ciptr_listen; + PRMSG(1, "MnxTcpAccept: unable to restart listen\n", + 0, 0, 0); + } + ciptr->fd= fd; + ref.ref_ptr= ciptr; + nbio_register(fd); + nbio_setcallback(fd, ASIO_WRITE, write_cb, ref); + nbio_setcallback(fd, ASIO_READ, read_cb, ref); + + if (ioctl(ciptr->fd, NWIOGTCPCONF, &tcpconf) == -1) + { + PRMSG(1, "MnxTcpAccept: NWIOGTCPCONF failed: %s\n", + strerror(errno),0, 0); + close(fd); + free_ConnInfo(ciptr); + *status= TRANS_ACCEPT_MISC_ERROR; + return NULL; + } + if ((addr= (struct sockaddr_in *)xalloc(sizeof(struct sockaddr_in))) + == NULL) + { + PRMSG(1, "MnxTcpAccept: malloc failed\n", 0, 0, 0); + close(fd); + free_ConnInfo(ciptr); + *status= TRANS_ACCEPT_BAD_MALLOC; + return NULL; + } + addr->sin_family= AF_INET; + addr->sin_addr.s_addr= tcpconf.nwtc_locaddr; + addr->sin_port= tcpconf.nwtc_locport; + if (ciptr->addr) + xfree(ciptr->addr); + ciptr->addr= (char *)addr; + ciptr->addrlen= sizeof(struct sockaddr_in); + if (*(u8_t *)&tcpconf.nwtc_remaddr == 127) + { + /* Make ConvertAddress return FamilyLocal */ + addr->sin_addr.s_addr= tcpconf.nwtc_remaddr; + } + + if ((addr= (struct sockaddr_in *)xalloc(sizeof(struct sockaddr_in))) + == NULL) + { + PRMSG(1, "MnxTcpConnect: malloc failed\n", 0, 0, 0); + close(fd); + free_ConnInfo(ciptr); + *status= TRANS_ACCEPT_BAD_MALLOC; + return NULL; + } + addr->sin_family= AF_INET; + addr->sin_addr.s_addr= tcpconf.nwtc_remaddr; + addr->sin_port= tcpconf.nwtc_remport; + ciptr->peeraddr= (char *)addr; + ciptr->peeraddrlen= sizeof(struct sockaddr_in); + *status= 0; + return ciptr; +} +#endif /* TRANS_SERVER */ + +TRANS(MnxTcpConnect) (ciptr, host, port) + +XtransConnInfo ciptr; +char *host; +char *port; + +{ + struct hostent *hostp; + struct servent *servp; + char hostnamebuf[256]; /* tmp space */ + tcpport_t num_port; + ipaddr_t num_addr; + char *check; + nwio_tcpconf_t tcpconf; + nwio_tcpcl_t tcpcl; + struct sockaddr_in *addr; + + PRMSG(2, "MnxTcpConnect(%d,%s,%s)\n", ciptr->fd, host, port); + + if (!host) + { + hostnamebuf[0] = '\0'; + (void) TRANS(GetHostname) (hostnamebuf, sizeof hostnamebuf); + host = hostnamebuf; + } + + + num_port= strtol(port, &check, 10); + num_port= htons(num_port); + if (check[0] == '\0') + port= NULL; +#ifdef X11_t + /* + * X has a well known port, that is transport dependent. It is easier + * to handle it here, than try and come up with a transport independent + * representation that can be passed in and resolved the usual way. + * + * The port that is passed here is really a string containing the + * idisplay from ConnectDisplay(). + */ + if (port == NULL) + num_port= htons(ntohs(num_port) + X_TCP_PORT); +#endif + + num_addr= inet_addr(host); + if (num_addr != -1) + host= NULL; + + if (host != NULL) + { + if ((hostp = gethostbyname(host)) == NULL) + { + PRMSG(1, + "MnxTcpConnect: can't get address for %s\n", + host, 0, 0); + errno= EINVAL; + return TRANS_CONNECT_FAILED; + } + if (hostp->h_addrtype != AF_INET) /* is IP host? */ + { + PRMSG(1, "MnxTcpConnect: %s in not an INET host\n", + host, 0, 0); + errno= EINVAL; + return TRANS_CONNECT_FAILED; + } + num_addr= *(ipaddr_t *)hostp->h_addr; + } + + if (port != NULL) + { + if ((servp = getservbyname (port, "tcp")) == NULL) + { + PRMSG(1, + "MnxTcpConnect: can't get service for %s\n", + port, 0, 0); + errno= EINVAL; + return TRANS_CONNECT_FAILED; + } + num_port= servp->s_port; + } + + tcpconf.nwtc_flags= NWTC_EXCL | NWTC_LP_SEL | NWTC_SET_RA | + NWTC_SET_RP; + tcpconf.nwtc_remaddr= num_addr; + tcpconf.nwtc_remport= num_port; + if (ioctl(ciptr->fd, NWIOSTCPCONF, &tcpconf) == -1) + { + PRMSG(1, "MnxTcpConnect: NWIOSTCPCONF failed: %s\n", + strerror(errno),0, 0); + return TRANS_CONNECT_FAILED; + } + + tcpcl.nwtcl_flags= 0; + if (ioctl(ciptr->fd, NWIOTCPCONN, &tcpcl) == -1) + { + PRMSG(1, "MnxTcpConnect: connect failed: %s\n", + strerror(errno),0, 0); + if (errno == ECONNREFUSED || errno == EINTR) + return TRANS_TRY_CONNECT_AGAIN; + else + return TRANS_CONNECT_FAILED; + } + + if (ioctl(ciptr->fd, NWIOGTCPCONF, &tcpconf) == -1) + { + PRMSG(1, "MnxTcpConnect: NWIOGTCPCONF failed: %s\n", + strerror(errno),0, 0); + return TRANS_CONNECT_FAILED; + } + if ((addr= (struct sockaddr_in *)xalloc(sizeof(struct sockaddr_in))) + == NULL) + { + PRMSG(1, "MnxTcpConnect: malloc failed\n", 0, 0, 0); + return TRANS_CONNECT_FAILED; + } + addr->sin_family= AF_INET; + addr->sin_addr.s_addr= tcpconf.nwtc_locaddr; + addr->sin_port= tcpconf.nwtc_locport; + ciptr->addr= (char *)addr; + ciptr->addrlen= sizeof(struct sockaddr_in); + if (*(u8_t *)&tcpconf.nwtc_remaddr == 127) + { + /* Make ConvertAddress return FamilyLocal */ + addr->sin_addr.s_addr= tcpconf.nwtc_remaddr; + } + + if ((addr= (struct sockaddr_in *)xalloc(sizeof(struct sockaddr_in))) + == NULL) + { + PRMSG(1, "MnxTcpConnect: malloc failed\n", 0, 0, 0); + return TRANS_CONNECT_FAILED; + } + addr->sin_family= AF_INET; + addr->sin_addr.s_addr= tcpconf.nwtc_remaddr; + addr->sin_port= tcpconf.nwtc_remport; + ciptr->peeraddr= (char *)addr; + ciptr->peeraddrlen= sizeof(struct sockaddr_in); + + return 0; +} + +static int +TRANS(MnxTcpBytesReadable) (ciptr, pend) + +XtransConnInfo ciptr; +BytesReadable_t *pend; + +{ + struct private *priv; + int r; + + PRMSG(2, "MnxTcpBytesReadable(%x,%d,%x)\n", + ciptr, ciptr->fd, pend); + + *pend= 0; + + priv= (struct private *)ciptr->priv; + if (priv->read_inprogress) + { + PRMSG(5, "MnxTcpBytesReadable: read inprogress, %d\n", + *pend, 0, 0); + return *pend; + } + if (priv->read_offset < priv->read_size) + { + *pend= priv->read_size-priv->read_offset; + PRMSG(5, "MnxTcpBytesReadable: %d\n", + *pend, 0, 0); + return *pend; + } + priv->read_offset= 0; + r= read(ciptr->fd, priv->read_buffer, priv->read_bufsize); + if (r >= 0) + { + if (r == 0) + r= 1; /* Signal EOF condition */ + + priv->read_size= r; + PRMSG(5, "MnxTcpBytesReadable: %d\n", + *pend, 0, 0); + *pend= r; + } + else if (r == -1 && errno == EINPROGRESS) + { + priv->read_inprogress= 1; + nbio_inprogress(ciptr->fd, ASIO_READ, 1 /* read */, + 0 /* write */, 0 /* exception */); + } + else + { + PRMSG(1, "MnxTcpBytesReadable: read failed: %s\n", + strerror(errno), 0, 0); + return -1; + } + PRMSG(5, "MnxTcpBytesReadable: %d\n", *pend, 0, 0); + return *pend; +} + + +static int +TRANS(MnxTcpRead) (ciptr, buf, size) + +XtransConnInfo ciptr; +char *buf; +int size; + +{ + int len, r, ret, s_errno; + int offset; + struct private *priv; + asio_fd_set_t fd_set; + fwait_t fw; + + PRMSG(2, "MnxTcpRead(%d,%x,%d)\n", ciptr->fd, buf, size); + + priv= (struct private *)ciptr->priv; + offset= 0; + + if (priv->read_inprogress) + { + PRMSG(5, "MnxTcpRead: EAGAIN\n", 0, 0, 0); + errno= EAGAIN; + return -1; + } + + /* Copy any data left in the buffer */ + if (priv->read_offset < priv->read_size) + { + len= priv->read_size-priv->read_offset; + if (len > size-offset) + len= size-offset; + PRMSG(5, "MnxTcpRead: copying %d bytes\n", len, 0, 0); + + memcpy(buf+offset, priv->read_buffer + priv->read_offset, + len); + offset += len; + priv->read_offset += len; + if (priv->read_offset < priv->read_size) + return offset; + } + + /* Try to read directly into the user's buffer. */ + ret= 0; + s_errno= 0; + while(offset < size) + { + r= read(ciptr->fd, buf+offset, size-offset); + if (r == -1 && errno == EINPROGRESS) + { + r= fcancel(ciptr->fd, ASIO_READ); + if (r == -1) + abort(); + ASIO_FD_ZERO(&fd_set); + ASIO_FD_SET(ciptr->fd, ASIO_READ, &fd_set); + fw.fw_flags= FWF_NONBLOCK; + fw.fw_bits= fd_set.afds_bits; + fw.fw_maxfd= ASIO_FD_SETSIZE; + r= fwait(&fw); + if (r == -1 || fw.fw_fd != ciptr->fd || + fw.fw_operation != ASIO_READ) + { + abort(); + } + r= fw.fw_result; + errno= fw.fw_errno; + } + + if (r > 0) + { + PRMSG(5, "MnxTcpRead: read %d bytes\n", r, + 0, 0); + offset += r; + continue; + } + else if (r == 0) + { + PRMSG(5, "MnxTcpRead: read EOF\n", 0, 0, 0); + break; + } + else + { + if (errno == EINTR) + { + PRMSG(5, "MnxTcpRead: EINTR\n", + 0, 0, 0); + errno= EAGAIN; + } + else + { + PRMSG(1, "MnxTcpRead: read error %s\n", + strerror(errno), 0, 0); + } + s_errno= errno; + ret= -1; + break; + } + } + if (offset != 0) + ret= offset; + + if (priv->read_offset != priv->read_size) + abort(); + priv->read_offset= 0; + priv->read_size= 0; + if (priv->nonblocking) + { + r= read(ciptr->fd, priv->read_buffer, priv->read_bufsize); + if (r >= 0) + { + PRMSG(5, "MnxTcpRead: buffered %d bytes\n", + r, 0, 0); + priv->read_size= r; + } + else if (r == -1 && errno == EINPROGRESS) + { + priv->read_inprogress= 1; + nbio_inprogress(ciptr->fd, ASIO_READ, 1 /* read */, + 0 /* write */, 0 /* exception */); + } + else + { + PRMSG(1, "MnxTcpRead: read failed: %s\n", + strerror(errno), 0, 0); + } + } + errno= s_errno; + return ret; +} + + +static int +TRANS(MnxTcpWrite) (ciptr, buf, size) + +XtransConnInfo ciptr; +char *buf; +int size; + +{ + int len, r, ret, s_errno; + int offset; + struct private *priv; + asio_fd_set_t fd_set; + fwait_t fw; + + PRMSG(2, "MnxTcpWrite(%d,%x,%d)\n", ciptr->fd, buf, size); + + priv= (struct private *)ciptr->priv; + offset= 0; + + if (priv->write_errno) + { + PRMSG(5, "MnxTcpWrite: write_errno %d\n", + priv->write_errno, 0, 0); + errno= priv->write_errno; + return -1; + } + + if (priv->write_inprogress) + { + PRMSG(5, "MnxTcpWrite: EAGAIN\n", 0, 0, 0); + errno= EAGAIN; + return -1; + } + + /* Try to write directly out of the user's buffer. */ + ret= 0; + s_errno= 0; + while(offset < size) + { + r= write(ciptr->fd, buf+offset, size-offset); + if (r == -1 && errno == EINPROGRESS) + { + r= fcancel(ciptr->fd, ASIO_WRITE); + if (r == -1) + abort(); + ASIO_FD_ZERO(&fd_set); + ASIO_FD_SET(ciptr->fd, ASIO_WRITE, &fd_set); + fw.fw_flags= FWF_NONBLOCK; + fw.fw_bits= fd_set.afds_bits; + fw.fw_maxfd= ASIO_FD_SETSIZE; + r= fwait(&fw); + if (r == -1 || fw.fw_fd != ciptr->fd || + fw.fw_operation != ASIO_WRITE) + { + abort(); + } + r= fw.fw_result; + errno= fw.fw_errno; + } + if (r > 0) + { + PRMSG(5, "MnxTcpWrite: wrote %d bytes\n", r, + 0, 0); + offset += r; + continue; + } + else if (r == 0) + abort(); + else + { + if (errno == EINTR) + { + PRMSG(5, "MnxTcpWrite: EINTR\n", + 0, 0, 0); + errno= EAGAIN; + } + else + { + PRMSG(1, + "MnxTcpWrite: write error: %s\n", + strerror(errno), 0, 0); + } + s_errno= errno; + ret= -1; + break; + } + } + + /* Copy any data to the buffer */ + if (offset < size) + { + len= priv->write_bufsize; + if (len > size-offset) + len= size-offset; + PRMSG(5, "MnxTcpWrite: copying %d bytes\n", len, 0, 0); + + memcpy(priv->write_buffer, buf+offset, len); + offset += len; + priv->write_offset= 0; + priv->write_size= len; + } + if (offset != 0) + ret= offset; + + while (priv->write_offset < priv->write_size) + { + r= write(ciptr->fd, priv->write_buffer+priv->write_offset, + priv->write_size-priv->write_offset); + if (r > 0) + { + PRMSG(5, "MnxTcpWrite: wrote %d bytes\n", + r, 0, 0); + priv->write_offset += r; + continue; + } + else if (r == -1 && errno == EINPROGRESS) + { + priv->write_inprogress= 1; + nbio_inprogress(ciptr->fd, ASIO_WRITE, 0 /* read */, + 1 /* write */, 0 /* exception */); + } + else + { + PRMSG(1, "MnxTcpWrite: write failed: %s\n", + strerror(errno), 0, 0); + priv->write_errno= errno; + } + break; + } + + errno= s_errno; + return ret; +} + + +static int +TRANS(MnxTcpReadv) (ciptr, buf, size) + +XtransConnInfo ciptr; +struct iovec *buf; +int size; + +{ + int i, offset, total, len, r; + + PRMSG(2, "MnxTcpReadv(%d,%x,%d)\n", ciptr->fd, buf, size); + + /* Simply call read a number of times. */ + total= 0; + offset= 0; + i= 0; + while(i= buf[i].iov_len) + { + offset= 0; + i++; + continue; + } + len= buf[i].iov_len-offset; + r= TRANS(MnxTcpRead)(ciptr, buf[i].iov_base+offset, len); + if (r == -1) + { + if (errno == EAGAIN) + { + PRMSG(5, + "MnxTcpReadv: read returned: %s\n", + strerror(errno), 0, 0); + } + else + { + PRMSG(1, + "MnxTcpReadv: read failed: %s\n", + strerror(errno), 0, 0); + } + if (total != 0) + return total; + else + return -1; + } + if (r == 0) + break; + if (r > len) + abort(); + total += r; + offset += r; + } + return total; +} + +static int +TRANS(MnxTcpWritev) (ciptr, buf, size) + +XtransConnInfo ciptr; +struct iovec *buf; +int size; + +{ + int i, offset, total, len, r; + + PRMSG(2, "MnxTcpWritev(%d,%x,%d)\n", ciptr->fd, buf, size); + + /* Simply call write a number of times. */ + total= 0; + offset= 0; + i= 0; + while(i= buf[i].iov_len) + { + offset= 0; + i++; + continue; + } + len= buf[i].iov_len-offset; + r= TRANS(MnxTcpWrite)(ciptr, buf[i].iov_base+offset, len); + if (r == -1) + { + if (errno == EAGAIN) + { + PRMSG(5, "MnxTcpWritev: AGAIN\n", + 0, 0, 0); + } + else + { + PRMSG(1, + "MnxTcpWritev: write failed: %s\n", + strerror(errno), 0, 0); + } + if (total != 0) + return total; + else + return -1; + } + if (r == 0 || r > len) + abort(); + total += r; + offset += r; + } + return total; +} + + +static int +TRANS(MnxTcpDisconnect) (ciptr) + +XtransConnInfo ciptr; + +{ + PRMSG(2, "MnxTcpDisconnect(%x,%d)\n", ciptr, ciptr->fd, 0); + + return ioctl(ciptr->fd, NWIOTCPSHUTDOWN, NULL); +} + +static int +TRANS(MnxTcpClose) (ciptr) + +XtransConnInfo ciptr; + +{ + XtransConnInfo list, t_ciptr; + struct private *priv; + + PRMSG(2, "MnxTcpClose(%x,%d)\n", ciptr, ciptr->fd, 0); + + + if (listen_list) + { + list= listen_list; + listen_list= NULL; + while(list) + { + t_ciptr= list; + priv= (struct private *)t_ciptr->priv; + list= priv->listen_list; + if (t_ciptr == ciptr) + continue; + if (restart_listen(t_ciptr) == -1) + { + priv->listen_list= listen_list; + listen_list= t_ciptr; + } + } + } + + free_private((struct private *)ciptr->priv); + nbio_unregister(ciptr->fd); + return close (ciptr->fd); +} + + +static XtransConnInfo +alloc_ConnInfo(thistrans) +Xtransport *thistrans; +{ + XtransConnInfo ciptr; + + PRMSG(2, " alloc_ConnInfo(%p)\n", thistrans, 0, 0); + + if ((ciptr= (XtransConnInfo) xalloc(sizeof(struct _XtransConnInfo))) + == NULL) + { + PRMSG(1, " alloc_ConnInfo: malloc failed\n", 0, 0, 0); + return NULL; + } + ciptr->transptr= thistrans; + ciptr->priv= NULL; + ciptr->flags= 0; + ciptr->fd= -1; + ciptr->port= NULL; + ciptr->family= AF_INET; + ciptr->addr= NULL; + ciptr->addrlen= 0; + ciptr->peeraddr= NULL; + ciptr->peeraddrlen= 0; + return ciptr; +} + +static void +free_ConnInfo(ciptr) +XtransConnInfo ciptr; +{ + if (ciptr == NULL) + return; + free_private((struct private *)ciptr->priv); + xfree(ciptr); +} + +static struct private * +alloc_private(rd_size, wr_size) +size_t rd_size; +size_t wr_size; +{ + struct private *priv; + int s_errno; + char *buf; + + PRMSG(2, ":alloc_private(%d, %d)\n", rd_size, wr_size, 0); + + if ((priv= (struct private *)xalloc(sizeof(struct private))) == NULL) + { + PRMSG(1, ":alloc_private: malloc failed\n", 0, 0, 0); + return NULL; + } + priv->nonblocking= 0; + priv->read_inprogress= 0; + priv->read_buffer= NULL; + priv->read_bufsize= rd_size; + priv->read_size= 0; + priv->read_offset= 0; + + if (rd_size != 0) + { + if ((buf= xalloc(rd_size)) == NULL) + { + PRMSG(1, ":alloc_private: malloc failed\n", 0, 0, 0); + s_errno= errno; + free_private(priv); + errno= s_errno; + return NULL; + } + priv->read_buffer= buf; + } + + priv->write_inprogress= 0; + priv->write_buffer= NULL; + priv->write_bufsize= rd_size; + priv->write_size= 0; + priv->write_offset= 0; + priv->write_errno= 0; + + if (wr_size != 0) + { + if ((buf= xalloc(wr_size)) == NULL) + { + PRMSG(1, ":alloc_private: malloc failed\n", 0, 0, 0); + s_errno= errno; + free_private(priv); + errno= s_errno; + return NULL; + } + priv->write_buffer= buf; + } + + priv->listen_completed= 0; + priv->listen_port= 0; + priv->listen_list= NULL; + + return priv; +} + +static void +free_private(priv) +struct private *priv; +{ + if (priv == NULL) + return; + xfree(priv->read_buffer); + xfree(priv->write_buffer); + xfree(priv); +} + +static void +read_cb(ref, res, err) +nbio_ref_t ref; +int res; +int err; +{ + XtransConnInfo ciptr; + struct private *priv; + + PRMSG(2, ":read_cb(%x,%d,%d)\n", ref.ref_ptr, res, err); + + ciptr= ref.ref_ptr; + priv= (struct private *)ciptr->priv; + if (res > 0) + priv->read_size= res; + priv->read_inprogress= 0; +} + +static void +write_cb(ref, res, err) +nbio_ref_t ref; +int res; +int err; +{ + XtransConnInfo ciptr; + struct private *priv; + int r; + + PRMSG(2, ":write_cb(%x,%d,%d)\n", ref.ref_ptr, res, err); + + ciptr= ref.ref_ptr; + priv= (struct private *)ciptr->priv; + if (res > 0) + priv->write_offset += res; + else if (res == 0) + abort(); + else + { + priv->write_errno= err; + return; + } + priv->write_inprogress= 0; + + while (priv->write_offset < priv->write_size) + { + r= write(ciptr->fd, priv->write_buffer+priv->write_offset, + priv->write_size-priv->write_offset); + if (r > 0) + { + PRMSG(5, "MnxTcpWrite: wrote %d bytes\n", + r, 0, 0); + priv->write_offset += r; + continue; + } + else if (r == -1 && errno == EINPROGRESS) + { + priv->write_inprogress= 1; + nbio_inprogress(ciptr->fd, ASIO_WRITE, 0 /* read */, + 1 /* write */, 0 /* exception */); + } + else + { + PRMSG(1, "MnxTcpWrite: write failed: %s\n", + strerror(errno), 0, 0); + priv->write_errno= errno; + } + break; + } +} + +static void +listen_cb(ref, res, err) +nbio_ref_t ref; +int res; +int err; +{ + XtransConnInfo ciptr; + struct private *priv; + struct sockaddr_in *addr; + nwio_tcpconf_t tcpconf; + + PRMSG(2, ":listen_cb(%x,%d,%d)\n", ref.ref_ptr, res, err); + + ciptr= ref.ref_ptr; + priv= (struct private *)ciptr->priv; + if (res == 0) + { + if (ioctl(ciptr->fd, NWIOGTCPCONF, &tcpconf) == -1) + { + PRMSG(1, + ":listen_cb: NWIOGTCPCONF failed: %s\n", + strerror(errno),0, 0); + return; + } + if ((addr= (struct sockaddr_in *)xalloc(sizeof(struct sockaddr_in))) + == NULL) + { + PRMSG(1, ":listen_cb: malloc failed\n", 0, 0, 0); + return; + } + addr->sin_family= AF_INET; + addr->sin_addr.s_addr= tcpconf.nwtc_locaddr; + addr->sin_port= tcpconf.nwtc_locport; + if (ciptr->addr) + xfree(ciptr->addr); + ciptr->addr= (char *)addr; + ciptr->addrlen= sizeof(struct sockaddr_in); + priv->listen_completed= 1; + return; + } + PRMSG(2, ":listen_cb: listen failed: %s\n", strerror(err), 0, 0); + if (restart_listen(ciptr) == -1) + { + priv->listen_list= listen_list; + listen_list= ciptr; + } +} + +static int +restart_listen(ciptr) +XtransConnInfo ciptr; +{ + char *tcp_device; + nwio_tcpconf_t tcpconf; + nwio_tcpcl_t tcpcl; + int fd, r, s_errno, flags; + struct private *priv; + nbio_ref_t ref; + + PRMSG(2, ":restart_listen(%d)\n", ciptr->fd, 0, 0); + + nbio_unregister(ciptr->fd); + + if ((tcp_device= getenv("TCP_DEVICE")) == NULL) + tcp_device= TCP_DEVICE; + + if ((fd= open(tcp_device, O_RDWR)) == -1) + { + PRMSG(1, ":restart_listen: open '%s' failed: %s\n", + tcp_device, strerror(errno), 0); + return -1; + } + PRMSG(5, ":restart_listen: fd= '%d'\n", fd, 0, 0); + if (fd != ciptr->fd) + { + if (dup2(fd, ciptr->fd) == -1) + abort(); /* no way to recover */ + close(fd); + } + fd= ciptr->fd; + ref.ref_ptr= ciptr; + nbio_register(fd); + nbio_setcallback(fd, ASIO_IOCTL, listen_cb, ref); + + priv= (struct private *)ciptr->priv; + + tcpconf.nwtc_flags= NWTC_SHARED | NWTC_UNSET_RA | NWTC_UNSET_RP; + tcpconf.nwtc_locport= priv->listen_port; + tcpconf.nwtc_flags |= NWTC_LP_SET; + + if (ioctl(ciptr->fd, NWIOSTCPCONF, &tcpconf) == -1) + { + PRMSG(1, + ":restart_listen: NWIOSTCPCONF failed: %s\n", + strerror(errno),0, 0); + return -1; + } + + flags= fcntl(ciptr->fd, F_GETFD); + if (flags == -1) + { + PRMSG(1, + ":restart_listen: fcntl F_GETFD failed: %s\n", + strerror(errno), 0, 0); + return -1; + } + if (fcntl(ciptr->fd, F_SETFD, flags | FD_ASYNCHIO) == -1) + { + PRMSG(1, + ":restart_listen: fcntl F_SETFD failed: %s\n", + strerror(errno), 0, 0); + return -1; + } + + tcpcl.nwtcl_flags= 0; + r= ioctl(ciptr->fd, NWIOTCPLISTEN, &tcpcl); + s_errno= errno; + + if (fcntl(ciptr->fd, F_SETFD, flags) == -1) + { + PRMSG(1, + ":restart_listen: fcntl F_SETFD failed: %s\n", + strerror(errno), 0, 0); + return -1; + } + + if (r == -1 && s_errno == EINPROGRESS) + { + nbio_inprogress(ciptr->fd, ASIO_IOCTL, 1 /* read */, + 1 /* write */, 0 /* exception */); + return 0; + } + if (r == 0) + { + priv->listen_completed= 1; + return 0; + } + errno= s_errno; + PRMSG(1, ":restart_listen: NWIOTCPLISTEN failed: %s\n", + strerror(errno), 0, 0); + return -1; +} + + +Xtransport TRANS(MnxINETFuncs) = +{ + /* Minix TCP Interface */ + "inet", + 0, +#ifdef TRANS_CLIENT + TRANS(MnxTcpOpenCOTSClient), +#endif /* TRANS_CLIENT */ +#ifdef TRANS_SERVER + TRANS(MnxTcpOpenCOTSServer), +#endif /* TRANS_SERVER */ +#ifdef TRANS_CLIENT + TRANS(MnxTcpOpenCLTSClient), +#endif /* TRANS_CLIENT */ +#ifdef TRANS_SERVER + TRANS(MnxTcpOpenCLTSServer), +#endif /* TRANS_SERVER */ +#ifdef TRANS_REOPEN + TRANS(MnxTcpReopenCOTSServer), + TRANS(MnxTcpReopenCLTSServer), +#endif + TRANS(MnxTcpSetOption), +#ifdef TRANS_SERVER + TRANS(MnxTcpCreateListener), + TRANS(MnxTcpResetListener), + TRANS(MnxTcpAccept), +#endif /* TRANS_SERVER */ +#ifdef TRANS_CLIENT + TRANS(MnxTcpConnect), +#endif /* TRANS_CLIENT */ + TRANS(MnxTcpBytesReadable), + TRANS(MnxTcpRead), + TRANS(MnxTcpWrite), + TRANS(MnxTcpReadv), + TRANS(MnxTcpWritev), + TRANS(MnxTcpDisconnect), + TRANS(MnxTcpClose), + TRANS(MnxTcpClose), +}; + +Xtransport TRANS(MnxTCPFuncs) = +{ + /* Minix TCP Interface */ + "tcp", + TRANS_ALIAS, +#ifdef TRANS_CLIENT + TRANS(MnxTcpOpenCOTSClient), +#endif /* TRANS_CLIENT */ +#ifdef TRANS_SERVER + TRANS(MnxTcpOpenCOTSServer), +#endif /* TRANS_SERVER */ +#ifdef TRANS_CLIENT + TRANS(MnxTcpOpenCLTSClient), +#endif /* TRANS_CLIENT */ +#ifdef TRANS_SERVER + TRANS(MnxTcpOpenCLTSServer), +#endif /* TRANS_SERVER */ +#ifdef TRANS_REOPEN + TRANS(MnxTcpReopenCOTSServer), + TRANS(MnxTcpReopenCLTSServer), +#endif + TRANS(MnxTcpSetOption), +#ifdef TRANS_SERVER + TRANS(MnxTcpCreateListener), + TRANS(MnxTcpResetListener), + TRANS(MnxTcpAccept), +#endif /* TRANS_SERVER */ +#ifdef TRANS_CLIENT + TRANS(MnxTcpConnect), +#endif /* TRANS_CLIENT */ + TRANS(MnxTcpBytesReadable), + TRANS(MnxTcpRead), + TRANS(MnxTcpWrite), + TRANS(MnxTcpReadv), + TRANS(MnxTcpWritev), + TRANS(MnxTcpDisconnect), + TRANS(MnxTcpClose), + TRANS(MnxTcpClose), +};