]> git.sesse.net Git - rdpsrv/blob - Xserver/lib/xtrans/Xtransmnx.c
Support RDP5 logon packets.
[rdpsrv] / Xserver / lib / xtrans / Xtransmnx.c
1 /* $XFree86: xc/lib/xtrans/Xtransmnx.c,v 3.3 1996/05/10 06:55:50 dawes Exp $ */
2
3 /*
4 Xtransmnx.c
5
6 Created:        11 April 1994 by Philip Homburg <philip@cs.vu.nl>
7 */
8
9
10 #include <stdlib.h>
11 #include <sys/ioctl.h>
12 #include <sys/nbio.h>
13 #include <net/hton.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>
19
20 struct private
21 {
22         int nonblocking;
23
24         int read_inprogress;
25         char *read_buffer;
26         size_t read_bufsize;
27         size_t read_size;
28         size_t read_offset;
29
30         int write_inprogress;
31         char *write_buffer;
32         size_t write_bufsize;
33         size_t write_size;
34         size_t write_offset;
35         int write_errno;
36
37         int listen_completed;
38         u16_t listen_port;
39         XtransConnInfo listen_list;
40 };
41 #define RD_BUFSIZE      1024
42 #define WR_BUFSIZE      1024
43
44 static XtransConnInfo listen_list= NULL;
45
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);
54
55 #ifdef TRANS_CLIENT
56 static XtransConnInfo
57 TRANS(MnxTcpOpenCOTSClient) (thistrans, protocol, host, port)
58
59 Xtransport *thistrans;
60 char       *protocol;
61 char       *host;
62 char       *port;
63
64 {
65         XtransConnInfo  ciptr;
66         char *tcp_device;
67         int s_errno;
68         int fd;
69         nbio_ref_t ref;
70
71
72         PRMSG(2, "MnxTcpOpenCOTSClient(%s,%s,%s)\n",
73                 protocol, host, port);
74
75         if ((ciptr= alloc_ConnInfo(thistrans)) == NULL)
76         {
77                 PRMSG(1,
78                         "MnxTcpOpenCOTSClient: alloc_ConnInfo failed\n",
79                         0, 0, 0);
80                 return NULL;
81         }
82         if ((ciptr->priv= (char *)alloc_private(RD_BUFSIZE, WR_BUFSIZE)) ==
83                 NULL)
84         {
85                 PRMSG(1,
86                         "MnxTcpOpenCOTSClient: alloc_private() failed\n",
87                         0, 0, 0);
88                 s_errno= errno;
89                 free_ConnInfo(ciptr);
90                 errno= s_errno;
91                 return NULL;
92         }
93
94         if ((tcp_device= getenv("TCP_DEVICE")) == NULL)
95                 tcp_device= TCP_DEVICE;
96         PRMSG(4, "MnxTcpOpenCOTSClient: tcp_device= '%s'\n",
97                 tcp_device, 0, 0);
98
99         if ((fd= open(tcp_device, O_RDWR)) == -1)
100         {
101                 PRMSG(1,
102                         "MnxTcpOpenCOTSClient: open '%s' failed: %s\n",
103                         tcp_device, strerror(errno), 0);
104                 s_errno= errno;
105                 free_ConnInfo(ciptr);
106                 errno= s_errno;
107                 return NULL;
108         }
109         ciptr->fd= fd;
110         ref.ref_ptr= ciptr;
111         nbio_register(fd);
112         nbio_setcallback(fd, ASIO_READ, read_cb, ref);
113         nbio_setcallback(fd, ASIO_WRITE, write_cb, ref);
114         return ciptr;
115 }
116 #endif /* TRANS_CLIENT */
117
118 #ifdef TRANS_SERVER
119 static XtransConnInfo
120 TRANS(MnxTcpOpenCOTSServer) (thistrans, protocol, host, port)
121
122 Xtransport *thistrans;
123 char       *protocol;
124 char       *host;
125 char       *port;
126
127 {
128         XtransConnInfo  ciptr;
129         char *tcp_device;
130         int s_errno;
131         int fd;
132         nbio_ref_t ref;
133
134
135         PRMSG(2, "MnxTcpOpenCOTSServer(%s,%s,%s)\n",
136                 protocol, host, port);
137
138         if ((ciptr= alloc_ConnInfo(thistrans)) == NULL)
139         {
140                 PRMSG(1,
141                         "MnxTcpOpenCOTSServer: alloc_ConnInfo failed\n",
142                         0, 0, 0);
143                 return NULL;
144         }
145         if ((ciptr->priv= (char *)alloc_private(RD_BUFSIZE, WR_BUFSIZE)) ==
146                 NULL)
147         {
148                 PRMSG(1,
149                         "MnxTcpOpenCOTSServer: alloc_private() failed\n",
150                         0, 0, 0);
151                 s_errno= errno;
152                 free_ConnInfo(ciptr);
153                 errno= s_errno;
154                 return NULL;
155         }
156
157         if ((tcp_device= getenv("TCP_DEVICE")) == NULL)
158                 tcp_device= TCP_DEVICE;
159         PRMSG(4, "MnxTcpOpenCOTSServer: tcp_device= '%s'\n",
160                 tcp_device, 0, 0);
161
162         if ((fd= open(tcp_device, O_RDWR)) == -1)
163         {
164                 PRMSG(1,
165                         "MnxTcpOpenCOTSServer: open '%s' failed: %s\n",
166                         tcp_device, strerror(errno), 0);
167                 s_errno= errno;
168                 free_ConnInfo(ciptr);
169                 errno= s_errno;
170                 return NULL;
171         }
172         PRMSG(5, "MnxTcpOpenCOTSServer: fd= '%d'\n", fd, 0, 0);
173         ciptr->fd= fd;
174         ref.ref_ptr= ciptr;
175         nbio_register(fd);
176         nbio_setcallback(fd, ASIO_IOCTL, listen_cb, ref);
177         return ciptr;
178 }
179 #endif /* TRANS_SERVER */
180
181 #ifdef TRANS_CLIENT
182 static XtransConnInfo
183 TRANS(MnxTcpOpenCLTSClient) (thistrans, protocol, host, port)
184
185 Xtransport *thistrans;
186 char       *protocol;
187 char       *host;
188 char       *port;
189
190 {
191         abort();
192 }
193 #endif /* TRANS_CLIENT */
194
195 #ifdef TRANS_SERVER
196 static XtransConnInfo
197 TRANS(MnxTcpOpenCLTSServer) (thistrans, protocol, host, port)
198
199 Xtransport *thistrans;
200 char       *protocol;
201 char       *host;
202 char       *port;
203
204 {
205         abort();
206 }
207 #endif /* TRANS_SERVER */
208
209 #ifdef TRANS_REOPEN
210
211 static XtransConnInfo
212 TRANS(MnxTcpReopenCOTSServer) (thistrans, fd, port)
213
214 Xtransport *thistrans;
215 int        fd;
216 char       *port;
217
218 {
219     XtransConnInfo      ciptr;
220     int                 i;
221
222     PRMSG (2,
223         "MnxTcpReopenCOTSServer(%d, %s)\n", fd, port, 0);
224
225     abort();
226 }
227
228 static XtransConnInfo
229 TRANS(MnxTcpReopenCLTSServer) (thistrans, fd, port)
230
231 Xtransport *thistrans;
232 int        fd;
233 char       *port;
234
235 {
236     XtransConnInfo      ciptr;
237     int                 i;
238
239
240     PRMSG (2,
241         "MnxTcpReopenCLTSServer(%d, %s)\n", fd, port, 0);
242
243     abort();
244 }
245
246 #endif /* TRANS_REOPEN */
247
248
249
250 static int
251 TRANS(MnxTcpSetOption) (ciptr, option, arg)
252
253 XtransConnInfo  ciptr;
254 int             option;
255 int             arg;
256
257 {
258         int flags;
259         struct private *priv;
260
261         PRMSG(2, "MnxTcpSetOption(%d,%d,%d)\n",
262                 ciptr->fd, option, arg);
263
264         priv= (struct private *)ciptr->priv;
265         switch(option)
266         {
267         case TRANS_NONBLOCKING:
268                 flags= fcntl(ciptr->fd, F_GETFD);
269                 if (flags == -1)
270                 {
271                         PRMSG(1,
272                         "MnxTcpSetOption: fcntl F_GETFD failed: %s\n",
273                                 strerror(errno), 0, 0);
274                         return -1;
275                 }
276                 if (arg == 0)
277                         flags &= ~FD_ASYNCHIO;
278                 else if (arg == 1)
279                         flags |= FD_ASYNCHIO;
280                 else
281                 {
282                         PRMSG(1,
283                 "MnxTcpSetOption: bad arg for TRANS_NONBLOCKING: %d\n",
284                                 arg, 0, 0);
285                         return -1;
286                 }
287                 if (fcntl(ciptr->fd, F_SETFD, flags) == -1)
288                 {
289                         PRMSG(1,
290                         "MnxTcpSetOption: fcntl F_SETFD failed: %s\n",
291                                 strerror(errno), 0, 0);
292                         return -1;
293                 }
294                 priv->nonblocking= arg;
295                 return 0;
296         case TRANS_CLOSEONEXEC:
297                 flags= fcntl(ciptr->fd, F_GETFD);
298                 if (flags == -1)
299                 {
300                         PRMSG(1,
301                         "MnxTcpSetOption: fcntl F_GETFD failed: %s\n",
302                                 strerror(errno), 0, 0);
303                         return -1;
304                 }
305                 if (arg == 0)
306                         flags &= ~FD_CLOEXEC;
307                 else if (arg == 1)
308                         flags |= FD_CLOEXEC;
309                 else
310                 {
311                         PRMSG(1,
312                 "MnxTcpSetOption: bad arg for TRANS_CLOSEONEXEC: %d\n",
313                                 arg, 0, 0);
314                         return -1;
315                 }
316                 if (fcntl(ciptr->fd, F_SETFD, flags) == -1)
317                 {
318                         PRMSG(1,
319                         "MnxTcpSetOption: fcntl F_SETFD failed: %s\n",
320                                 strerror(errno), 0, 0);
321                         return -1;
322                 }
323                 return 0;
324         default:
325                 PRMSG(1, "MnxTcpSetOption: unknown option '%d'\n",
326                         option, 0, 0);
327                 errno= EINVAL;
328                 return -1;
329         }
330 }
331
332
333 #ifdef TRANS_SERVER
334 static int
335 TRANS(MnxTcpCreateListener) (ciptr, port)
336
337 XtransConnInfo  ciptr;
338 char            *port;
339
340 {
341         struct servent *servp;
342         tcpport_t num_port;
343         char *check;
344         nwio_tcpconf_t tcpconf;
345         nwio_tcpcl_t tcpcl;
346         int r, s_errno, flags;
347         struct private *priv;
348         struct sockaddr_in *addr;
349
350         PRMSG(2, "MnxTcpCreateListener(%d,%s)\n", ciptr->fd, port, 0);
351
352         priv= (struct private *)ciptr->priv;
353
354         if (port == NULL)
355                 num_port= 0;
356         else
357         {
358                 num_port= strtol(port, &check, 10);
359                 num_port= htons(num_port);
360                 if (check[0] == '\0')
361                         port= NULL;
362         }
363
364 #ifdef X11_t
365         /*
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.
369          *
370          * The port that is passed here is really a string containing the
371          * idisplay from ConnectDisplay().
372          */
373         if (port == NULL)
374                 num_port= htons(ntohs(num_port) + X_TCP_PORT);
375 #endif
376         if (port != NULL)
377         {
378                 if ((servp = getservbyname (port, "tcp")) == NULL)
379                 {
380                         PRMSG(1,
381                 "MnxTcpCreateListener: can't get service for %s\n",
382                                 port, 0, 0);
383                         errno= EINVAL;
384                         return TRANS_CREATE_LISTENER_FAILED;
385                 }
386                 num_port= servp->s_port;
387         }
388
389         tcpconf.nwtc_flags= NWTC_SHARED | NWTC_UNSET_RA | NWTC_UNSET_RP;
390         if (num_port != 0)
391         {
392                 tcpconf.nwtc_locport= num_port;
393                 tcpconf.nwtc_flags |= NWTC_LP_SET;
394         }
395         else
396                 tcpconf.nwtc_flags |= NWTC_LP_SEL;
397
398         if (ioctl(ciptr->fd, NWIOSTCPCONF, &tcpconf) == -1)
399         {
400                 PRMSG(1,
401                 "MnxTcpCreateListener: NWIOSTCPCONF failed: %s\n",
402                         strerror(errno),0, 0);
403                 return TRANS_CREATE_LISTENER_FAILED;
404         }
405
406         if (ioctl(ciptr->fd, NWIOGTCPCONF, &tcpconf) == -1)
407         {
408                 PRMSG(1,
409                 "MnxTcpListen: NWIOGTCPCONF failed: %s\n",
410                         strerror(errno),0, 0);
411                 return TRANS_CREATE_LISTENER_FAILED;
412         }
413
414         priv->listen_port= tcpconf.nwtc_locport;
415
416         if ((addr= (struct sockaddr_in *)xalloc(sizeof(struct sockaddr_in)))
417                 == NULL)
418         {
419                 PRMSG(1, "MnxTcpAccept: malloc failed\n", 0, 0, 0);
420                 return TRANS_CREATE_LISTENER_FAILED;
421         }
422         addr->sin_family= AF_INET;
423         addr->sin_addr.s_addr= tcpconf.nwtc_locaddr;
424         addr->sin_port= tcpconf.nwtc_locport;
425         if (ciptr->addr)
426                 xfree(ciptr->addr);
427         ciptr->addr= (char *)addr;
428         ciptr->addrlen= sizeof(struct sockaddr_in);
429
430         flags= fcntl(ciptr->fd, F_GETFD);
431         if (flags == -1)
432         {
433                 PRMSG(1,
434                 "MnxTcpCreateListener: fcntl F_GETFD failed: %s\n",
435                         strerror(errno), 0, 0);
436                 return TRANS_CREATE_LISTENER_FAILED;
437         }
438         if (fcntl(ciptr->fd, F_SETFD, flags | FD_ASYNCHIO) == -1)
439         {
440                 PRMSG(1,
441                 "MnxTcpCreateListener: fcntl F_SETFD failed: %s\n",
442                         strerror(errno), 0, 0);
443                 return TRANS_CREATE_LISTENER_FAILED;
444         }
445
446         tcpcl.nwtcl_flags= 0;
447         r= ioctl(ciptr->fd, NWIOTCPLISTEN, &tcpcl);
448         s_errno= errno;
449
450         if (fcntl(ciptr->fd, F_SETFD, flags) == -1)
451         {
452                 PRMSG(1,
453                 "MnxTcpCreateListener: fcntl F_SETFD failed: %s\n",
454                         strerror(errno), 0, 0);
455                 return TRANS_CREATE_LISTENER_FAILED;
456         }
457
458         if (r == -1 && s_errno == EINPROGRESS)
459         {
460                 nbio_inprogress(ciptr->fd, ASIO_IOCTL, 1 /* read */,
461                         1 /* write */, 0 /* exception */);
462                 return 0;
463         }
464         if (r == 0)
465         {
466                 priv->listen_completed= 1;
467                 return 0;
468         }
469
470         errno= s_errno;
471         PRMSG(1, "MnxTcpCreateListener: NWIOTCPLISTEN failed: %s\n",
472                 strerror(errno), 0, 0);
473         return TRANS_CREATE_LISTENER_FAILED;
474 }
475 #endif /* TRANS_SERVER */
476
477
478 #ifdef TRANS_SERVER
479 static int
480 TRANS(MnxTcpResetListener) (ciptr)
481
482 XtransConnInfo  ciptr;
483 {
484         PRMSG(2, "MnxTcpResetListener(%d)\n", ciptr->fd, 0, 0);
485         return TRANS_RESET_NOOP;
486 }
487 #endif /* TRANS_SERVER */
488
489 #ifdef TRANS_SERVER
490 static XtransConnInfo
491 TRANS(MnxTcpAccept) (ciptr_listen, status)
492
493 XtransConnInfo ciptr_listen;
494 int            *status;
495
496 {
497         XtransConnInfo  ciptr;
498         int s_errno;
499         int fd;
500         nbio_ref_t ref;
501         struct private *priv;
502         nwio_tcpconf_t tcpconf;
503         struct sockaddr_in *addr;
504
505         PRMSG(2, "MnxTcpAccept(%d,%p)\n", ciptr_listen->fd, status, 0);
506
507         priv= (struct private *)ciptr_listen->priv;
508         *status= TRANS_ACCEPT_MISC_ERROR;
509
510         if (!priv->listen_completed)
511         {
512                 PRMSG(1, "MnxTcpAccept: listen is not completed\n",
513                         0, 0, 0);
514                 *status= TRANS_ACCEPT_FAILED;
515                 return NULL;
516         }
517         priv->listen_completed= 0;
518
519         if ((ciptr= alloc_ConnInfo(ciptr_listen->transptr)) == NULL)
520         {
521                 PRMSG(1,
522                         "MnxTcpAccept: alloc_ConnInfo failed\n",
523                         0, 0, 0);
524                 *status= TRANS_ACCEPT_BAD_MALLOC;
525                 return NULL;
526         }
527         if ((ciptr->priv= (char *)alloc_private(RD_BUFSIZE, WR_BUFSIZE)) ==
528                 NULL)
529         {
530                 PRMSG(1,
531                         "MnxTcpAccept: alloc_private() failed\n",
532                         0, 0, 0);
533                 s_errno= errno;
534                 free_ConnInfo(ciptr);
535                 errno= s_errno;
536                 *status= TRANS_ACCEPT_BAD_MALLOC;
537                 return NULL;
538         }
539
540         fd= dup(ciptr_listen->fd);
541         if (fd == -1)
542         {
543                 s_errno= errno;
544                 PRMSG(1, "MnxTcpAccept: dup failed: %s\n",
545                         strerror(errno), 0, 0);
546                 free_ConnInfo(ciptr);
547                 *status= TRANS_ACCEPT_FAILED;
548                 return NULL;
549         }
550         if (restart_listen(ciptr_listen) == -1)
551         {
552                 priv->listen_list= listen_list;
553                 listen_list= ciptr_listen;
554                 PRMSG(1, "MnxTcpAccept: unable to restart listen\n",
555                         0, 0, 0);
556         }
557         ciptr->fd= fd;
558         ref.ref_ptr= ciptr;
559         nbio_register(fd);
560         nbio_setcallback(fd, ASIO_WRITE, write_cb, ref);
561         nbio_setcallback(fd, ASIO_READ, read_cb, ref);
562
563         if (ioctl(ciptr->fd, NWIOGTCPCONF, &tcpconf) == -1)
564         {
565                 PRMSG(1, "MnxTcpAccept: NWIOGTCPCONF failed: %s\n",
566                         strerror(errno),0, 0);
567                 close(fd);
568                 free_ConnInfo(ciptr);
569                 *status= TRANS_ACCEPT_MISC_ERROR;
570                 return NULL;
571         }
572         if ((addr= (struct sockaddr_in *)xalloc(sizeof(struct sockaddr_in)))
573                 == NULL)
574         {
575                 PRMSG(1, "MnxTcpAccept: malloc failed\n", 0, 0, 0);
576                 close(fd);
577                 free_ConnInfo(ciptr);
578                 *status= TRANS_ACCEPT_BAD_MALLOC;
579                 return NULL;
580         }
581         addr->sin_family= AF_INET;
582         addr->sin_addr.s_addr= tcpconf.nwtc_locaddr;
583         addr->sin_port= tcpconf.nwtc_locport;
584         if (ciptr->addr)
585                 xfree(ciptr->addr);
586         ciptr->addr= (char *)addr;
587         ciptr->addrlen= sizeof(struct sockaddr_in);
588         if (*(u8_t *)&tcpconf.nwtc_remaddr == 127)
589         {
590                 /* Make ConvertAddress return FamilyLocal */
591                 addr->sin_addr.s_addr= tcpconf.nwtc_remaddr;
592         }
593
594         if ((addr= (struct sockaddr_in *)xalloc(sizeof(struct sockaddr_in)))
595                 == NULL)
596         {
597                 PRMSG(1, "MnxTcpConnect: malloc failed\n", 0, 0, 0);
598                 close(fd);
599                 free_ConnInfo(ciptr);
600                 *status= TRANS_ACCEPT_BAD_MALLOC;
601                 return NULL;
602         }
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);
608         *status= 0;
609         return ciptr;
610 }
611 #endif /* TRANS_SERVER */
612
613 TRANS(MnxTcpConnect) (ciptr, host, port)
614
615 XtransConnInfo  ciptr;
616 char            *host;
617 char            *port;
618
619 {
620         struct hostent *hostp;
621         struct servent *servp;
622         char hostnamebuf[256];          /* tmp space */
623         tcpport_t num_port;
624         ipaddr_t num_addr;
625         char *check;
626         nwio_tcpconf_t tcpconf;
627         nwio_tcpcl_t tcpcl;
628         struct sockaddr_in *addr;
629
630         PRMSG(2, "MnxTcpConnect(%d,%s,%s)\n", ciptr->fd, host, port);
631
632         if (!host)
633         {
634                 hostnamebuf[0] = '\0';
635                 (void) TRANS(GetHostname) (hostnamebuf, sizeof hostnamebuf);
636                 host = hostnamebuf;
637         }
638
639
640         num_port= strtol(port, &check, 10);
641         num_port= htons(num_port);
642         if (check[0] == '\0')
643                 port= NULL;
644 #ifdef X11_t
645         /*
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.
649          *
650          * The port that is passed here is really a string containing the
651          * idisplay from ConnectDisplay().
652          */
653         if (port == NULL)
654                 num_port= htons(ntohs(num_port) + X_TCP_PORT);
655 #endif
656
657         num_addr= inet_addr(host);
658         if (num_addr != -1)
659                 host= NULL;
660
661         if (host != NULL)
662         {
663                 if ((hostp = gethostbyname(host)) == NULL)
664                 {
665                         PRMSG(1,
666                         "MnxTcpConnect: can't get address for %s\n",
667                                 host, 0, 0);
668                         errno= EINVAL;
669                         return TRANS_CONNECT_FAILED;
670                 }
671                 if (hostp->h_addrtype != AF_INET)  /* is IP host? */
672                 {
673                     PRMSG(1, "MnxTcpConnect: %s in not an INET host\n",
674                           host, 0, 0);
675                     errno= EINVAL;
676                     return TRANS_CONNECT_FAILED;
677                 }
678                 num_addr= *(ipaddr_t *)hostp->h_addr;
679         }
680
681         if (port != NULL)
682         {
683                 if ((servp = getservbyname (port, "tcp")) == NULL)
684                 {
685                         PRMSG(1,
686                         "MnxTcpConnect: can't get service for %s\n",
687                                 port, 0, 0);
688                         errno= EINVAL;
689                         return TRANS_CONNECT_FAILED;
690                 }
691                 num_port= servp->s_port;
692         }
693
694         tcpconf.nwtc_flags= NWTC_EXCL | NWTC_LP_SEL | NWTC_SET_RA |
695                 NWTC_SET_RP;
696         tcpconf.nwtc_remaddr= num_addr;
697         tcpconf.nwtc_remport= num_port;
698         if (ioctl(ciptr->fd, NWIOSTCPCONF, &tcpconf) == -1)
699         {
700                 PRMSG(1, "MnxTcpConnect: NWIOSTCPCONF failed: %s\n",
701                         strerror(errno),0, 0);
702                 return TRANS_CONNECT_FAILED;
703         }
704
705         tcpcl.nwtcl_flags= 0;
706         if (ioctl(ciptr->fd, NWIOTCPCONN, &tcpcl) == -1)
707         {
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;
712                 else
713                         return TRANS_CONNECT_FAILED;
714         }
715
716         if (ioctl(ciptr->fd, NWIOGTCPCONF, &tcpconf) == -1)
717         {
718                 PRMSG(1, "MnxTcpConnect: NWIOGTCPCONF failed: %s\n",
719                         strerror(errno),0, 0);
720                 return TRANS_CONNECT_FAILED;
721         }
722         if ((addr= (struct sockaddr_in *)xalloc(sizeof(struct sockaddr_in)))
723                 == NULL)
724         {
725                 PRMSG(1, "MnxTcpConnect: malloc failed\n", 0, 0, 0);
726                 return TRANS_CONNECT_FAILED;
727         }
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)
734         {
735                 /* Make ConvertAddress return FamilyLocal */
736                 addr->sin_addr.s_addr= tcpconf.nwtc_remaddr;
737         }
738
739         if ((addr= (struct sockaddr_in *)xalloc(sizeof(struct sockaddr_in)))
740                 == NULL)
741         {
742                 PRMSG(1, "MnxTcpConnect: malloc failed\n", 0, 0, 0);
743                 return TRANS_CONNECT_FAILED;
744         }
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);
750
751         return 0;
752 }
753
754 static int
755 TRANS(MnxTcpBytesReadable) (ciptr, pend)
756
757 XtransConnInfo ciptr;
758 BytesReadable_t *pend;
759
760 {
761         struct private *priv;
762         int r;
763
764         PRMSG(2, "MnxTcpBytesReadable(%x,%d,%x)\n",
765                 ciptr, ciptr->fd, pend);
766
767         *pend= 0;
768
769         priv= (struct private *)ciptr->priv;
770         if (priv->read_inprogress)
771         {
772                 PRMSG(5, "MnxTcpBytesReadable: read inprogress, %d\n",
773                         *pend, 0, 0);
774                 return *pend;
775         }
776         if (priv->read_offset < priv->read_size)
777         {
778                 *pend= priv->read_size-priv->read_offset;
779                 PRMSG(5, "MnxTcpBytesReadable: %d\n",
780                         *pend, 0, 0);
781                 return *pend;
782         }
783         priv->read_offset= 0;
784         r= read(ciptr->fd, priv->read_buffer, priv->read_bufsize);
785         if (r >= 0)
786         {
787                 if (r == 0)
788                         r= 1;   /* Signal EOF condition */
789
790                 priv->read_size= r;
791                 PRMSG(5, "MnxTcpBytesReadable: %d\n",
792                         *pend, 0, 0);
793                 *pend= r;
794         }
795         else if (r == -1 && errno == EINPROGRESS)
796         {
797                 priv->read_inprogress= 1;
798                 nbio_inprogress(ciptr->fd, ASIO_READ, 1 /* read */,
799                         0 /* write */, 0 /* exception */);
800         }
801         else
802         {
803                 PRMSG(1, "MnxTcpBytesReadable: read failed: %s\n",
804                         strerror(errno), 0, 0);
805                 return -1;
806         }
807         PRMSG(5, "MnxTcpBytesReadable: %d\n", *pend, 0, 0);
808         return *pend;
809 }
810
811
812 static int
813 TRANS(MnxTcpRead) (ciptr, buf, size)
814
815 XtransConnInfo  ciptr;
816 char            *buf;
817 int             size;
818
819 {
820         int len, r, ret, s_errno;
821         int offset;
822         struct private *priv;
823         asio_fd_set_t fd_set;
824         fwait_t fw;
825
826         PRMSG(2, "MnxTcpRead(%d,%x,%d)\n", ciptr->fd, buf, size);
827
828         priv= (struct private *)ciptr->priv;
829         offset= 0;
830
831         if (priv->read_inprogress)
832         {
833                 PRMSG(5, "MnxTcpRead: EAGAIN\n", 0, 0, 0);
834                 errno= EAGAIN;
835                 return -1;
836         }
837
838         /* Copy any data left in the buffer */
839         if (priv->read_offset < priv->read_size)
840         {
841                 len= priv->read_size-priv->read_offset;
842                 if (len > size-offset)
843                         len= size-offset;
844                 PRMSG(5, "MnxTcpRead: copying %d bytes\n", len, 0, 0);
845
846                 memcpy(buf+offset, priv->read_buffer + priv->read_offset,
847                         len);
848                 offset += len;
849                 priv->read_offset += len;
850                 if (priv->read_offset < priv->read_size)
851                         return offset;
852         }
853
854         /* Try to read directly into the user's buffer. */
855         ret= 0;
856         s_errno= 0;
857         while(offset < size)
858         {
859                 r= read(ciptr->fd, buf+offset, size-offset);
860                 if (r == -1 && errno == EINPROGRESS)
861                 {
862                         r= fcancel(ciptr->fd, ASIO_READ);
863                         if (r == -1)
864                                 abort();
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;
870                         r= fwait(&fw);
871                         if (r == -1 || fw.fw_fd != ciptr->fd ||
872                                 fw.fw_operation != ASIO_READ)
873                         {
874                                 abort();
875                         }
876                         r= fw.fw_result;
877                         errno= fw.fw_errno;
878                 }
879
880                 if (r > 0)
881                 {
882                         PRMSG(5, "MnxTcpRead: read %d bytes\n", r,
883                                 0, 0);
884                         offset += r;
885                         continue;
886                 }
887                 else if (r == 0)
888                 {
889                         PRMSG(5, "MnxTcpRead: read EOF\n", 0, 0, 0);
890                         break;
891                 }
892                 else
893                 {
894                         if (errno == EINTR)
895                         {
896                                 PRMSG(5, "MnxTcpRead: EINTR\n",
897                                         0, 0, 0);
898                                 errno= EAGAIN;
899                         }
900                         else
901                         {
902                                 PRMSG(1, "MnxTcpRead: read error %s\n",
903                                         strerror(errno), 0, 0);
904                         }
905                         s_errno= errno;
906                         ret= -1;
907                         break;
908                 }
909         }
910         if (offset != 0)
911                 ret= offset;
912
913         if (priv->read_offset != priv->read_size)
914                 abort();
915         priv->read_offset= 0;
916         priv->read_size= 0;
917         if (priv->nonblocking)
918         {
919                 r= read(ciptr->fd, priv->read_buffer, priv->read_bufsize);
920                 if (r >= 0)
921                 {
922                         PRMSG(5, "MnxTcpRead: buffered %d bytes\n",
923                                 r, 0, 0);
924                         priv->read_size= r;
925                 }
926                 else if (r == -1 && errno == EINPROGRESS)
927                 {
928                         priv->read_inprogress= 1;
929                         nbio_inprogress(ciptr->fd, ASIO_READ, 1 /* read */,
930                                 0 /* write */, 0 /* exception */);
931                 }
932                 else
933                 {
934                         PRMSG(1, "MnxTcpRead: read failed: %s\n",
935                                 strerror(errno), 0, 0);
936                 }
937         }
938         errno= s_errno;
939         return ret;
940 }
941
942
943 static int
944 TRANS(MnxTcpWrite) (ciptr, buf, size)
945
946 XtransConnInfo ciptr;
947 char           *buf;
948 int            size;
949
950 {
951         int len, r, ret, s_errno;
952         int offset;
953         struct private *priv;
954         asio_fd_set_t fd_set;
955         fwait_t fw;
956
957         PRMSG(2, "MnxTcpWrite(%d,%x,%d)\n", ciptr->fd, buf, size);
958
959         priv= (struct private *)ciptr->priv;
960         offset= 0;
961
962         if (priv->write_errno)
963         {
964                 PRMSG(5, "MnxTcpWrite: write_errno %d\n",
965                         priv->write_errno, 0, 0);
966                 errno= priv->write_errno;
967                 return -1;
968         }
969
970         if (priv->write_inprogress)
971         {
972                 PRMSG(5, "MnxTcpWrite: EAGAIN\n", 0, 0, 0);
973                 errno= EAGAIN;
974                 return -1;
975         }
976
977         /* Try to write directly out of the user's buffer. */
978         ret= 0;
979         s_errno= 0;
980         while(offset < size)
981         {
982                 r= write(ciptr->fd, buf+offset, size-offset);
983                 if (r == -1 && errno == EINPROGRESS)
984                 {
985                         r= fcancel(ciptr->fd, ASIO_WRITE);
986                         if (r == -1)
987                                 abort();
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;
993                         r= fwait(&fw);
994                         if (r == -1 || fw.fw_fd != ciptr->fd ||
995                                 fw.fw_operation != ASIO_WRITE)
996                         {
997                                 abort();
998                         }
999                         r= fw.fw_result;
1000                         errno= fw.fw_errno;
1001                 }
1002                 if (r > 0)
1003                 {
1004                         PRMSG(5, "MnxTcpWrite: wrote %d bytes\n", r,
1005                                 0, 0);
1006                         offset += r;
1007                         continue;
1008                 }
1009                 else if (r == 0)
1010                         abort();
1011                 else
1012                 {
1013                         if (errno == EINTR)
1014                         {
1015                                 PRMSG(5, "MnxTcpWrite: EINTR\n",
1016                                         0, 0, 0);
1017                                 errno= EAGAIN;
1018                         }
1019                         else
1020                         {
1021                                 PRMSG(1,
1022                                 "MnxTcpWrite: write error: %s\n",
1023                                         strerror(errno), 0, 0);
1024                         }
1025                         s_errno= errno;
1026                         ret= -1;
1027                         break;
1028                 }
1029         }
1030
1031         /* Copy any data to the buffer */
1032         if (offset < size)
1033         {
1034                 len= priv->write_bufsize;
1035                 if (len > size-offset)
1036                         len= size-offset;
1037                 PRMSG(5, "MnxTcpWrite: copying %d bytes\n", len, 0, 0);
1038
1039                 memcpy(priv->write_buffer, buf+offset, len);
1040                 offset += len;
1041                 priv->write_offset= 0;
1042                 priv->write_size= len;
1043         }
1044         if (offset != 0)
1045                 ret= offset;
1046
1047         while (priv->write_offset < priv->write_size)
1048         {
1049                 r= write(ciptr->fd, priv->write_buffer+priv->write_offset,
1050                         priv->write_size-priv->write_offset);
1051                 if (r > 0)
1052                 {
1053                         PRMSG(5, "MnxTcpWrite: wrote %d bytes\n",
1054                                 r, 0, 0);
1055                         priv->write_offset += r;
1056                         continue;
1057                 }
1058                 else if (r == -1 && errno == EINPROGRESS)
1059                 {
1060                         priv->write_inprogress= 1;
1061                         nbio_inprogress(ciptr->fd, ASIO_WRITE, 0 /* read */,
1062                                 1 /* write */, 0 /* exception */);
1063                 }
1064                 else
1065                 {
1066                         PRMSG(1, "MnxTcpWrite: write failed: %s\n",
1067                                 strerror(errno), 0, 0);
1068                         priv->write_errno= errno;
1069                 }
1070                 break;
1071         }
1072
1073         errno= s_errno;
1074         return ret;
1075 }
1076
1077
1078 static int
1079 TRANS(MnxTcpReadv) (ciptr, buf, size)
1080
1081 XtransConnInfo  ciptr;
1082 struct iovec    *buf;
1083 int             size;
1084
1085 {
1086         int i, offset, total, len, r;
1087
1088         PRMSG(2, "MnxTcpReadv(%d,%x,%d)\n", ciptr->fd, buf, size);
1089
1090         /* Simply call read a number of times. */
1091         total= 0;
1092         offset= 0;
1093         i= 0;
1094         while(i<size)
1095         {
1096                 PRMSG(5, "MnxTcpReadv: [%d] size %d-%d\n",
1097                         i, buf[i].iov_len, offset);
1098                 if (offset >= buf[i].iov_len)
1099                 {
1100                         offset= 0;
1101                         i++;
1102                         continue;
1103                 }
1104                 len= buf[i].iov_len-offset;
1105                 r= TRANS(MnxTcpRead)(ciptr, buf[i].iov_base+offset, len);
1106                 if (r == -1)
1107                 {
1108                         if (errno == EAGAIN)
1109                         {
1110                                 PRMSG(5,
1111                                 "MnxTcpReadv: read returned: %s\n",
1112                                         strerror(errno), 0, 0);
1113                         }
1114                         else
1115                         {
1116                                 PRMSG(1,
1117                                 "MnxTcpReadv: read failed: %s\n",
1118                                         strerror(errno), 0, 0);
1119                         }
1120                         if (total != 0)
1121                                 return total;
1122                         else
1123                                 return -1;
1124                 }
1125                 if (r == 0)
1126                         break;
1127                 if (r > len)
1128                         abort();
1129                 total += r;
1130                 offset += r;
1131         }
1132         return total;
1133 }
1134
1135 static int
1136 TRANS(MnxTcpWritev) (ciptr, buf, size)
1137
1138 XtransConnInfo  ciptr;
1139 struct iovec    *buf;
1140 int             size;
1141
1142 {
1143         int i, offset, total, len, r;
1144
1145         PRMSG(2, "MnxTcpWritev(%d,%x,%d)\n", ciptr->fd, buf, size);
1146
1147         /* Simply call write a number of times. */
1148         total= 0;
1149         offset= 0;
1150         i= 0;
1151         while(i<size)
1152         {
1153                 if (offset >= buf[i].iov_len)
1154                 {
1155                         offset= 0;
1156                         i++;
1157                         continue;
1158                 }
1159                 len= buf[i].iov_len-offset;
1160                 r= TRANS(MnxTcpWrite)(ciptr, buf[i].iov_base+offset, len);
1161                 if (r == -1)
1162                 {
1163                         if (errno == EAGAIN)
1164                         {
1165                                 PRMSG(5, "MnxTcpWritev: AGAIN\n",
1166                                         0, 0, 0);
1167                         }
1168                         else
1169                         {
1170                                 PRMSG(1,
1171                                 "MnxTcpWritev: write failed: %s\n",
1172                                         strerror(errno), 0, 0);
1173                         }
1174                         if (total != 0)
1175                                 return total;
1176                         else
1177                                 return -1;
1178                 }
1179                 if (r == 0 || r > len)
1180                         abort();
1181                 total += r;
1182                 offset += r;
1183         }
1184         return total;
1185 }
1186
1187
1188 static int
1189 TRANS(MnxTcpDisconnect) (ciptr)
1190
1191 XtransConnInfo ciptr;
1192
1193 {
1194         PRMSG(2, "MnxTcpDisconnect(%x,%d)\n", ciptr, ciptr->fd, 0);
1195
1196         return ioctl(ciptr->fd, NWIOTCPSHUTDOWN, NULL);
1197 }
1198
1199 static int
1200 TRANS(MnxTcpClose) (ciptr)
1201
1202 XtransConnInfo ciptr;
1203
1204 {
1205         XtransConnInfo list, t_ciptr;
1206         struct private *priv;
1207
1208         PRMSG(2, "MnxTcpClose(%x,%d)\n", ciptr, ciptr->fd, 0);
1209
1210
1211         if (listen_list)
1212         {
1213                 list= listen_list;
1214                 listen_list= NULL;
1215                 while(list)
1216                 {
1217                         t_ciptr= list;
1218                         priv= (struct private *)t_ciptr->priv;
1219                         list= priv->listen_list;
1220                         if (t_ciptr == ciptr)
1221                                 continue;
1222                         if (restart_listen(t_ciptr) == -1)
1223                         {
1224                                 priv->listen_list= listen_list;
1225                                 listen_list= t_ciptr;
1226                         }
1227                 }
1228         }
1229
1230         free_private((struct private *)ciptr->priv);
1231         nbio_unregister(ciptr->fd);
1232         return close (ciptr->fd);
1233 }
1234
1235
1236 static XtransConnInfo
1237 alloc_ConnInfo(thistrans)
1238 Xtransport *thistrans;
1239 {
1240         XtransConnInfo ciptr;
1241
1242         PRMSG(2, " alloc_ConnInfo(%p)\n", thistrans, 0, 0);
1243
1244         if ((ciptr= (XtransConnInfo) xalloc(sizeof(struct _XtransConnInfo)))
1245                 == NULL)
1246         {
1247                 PRMSG(1, " alloc_ConnInfo: malloc failed\n", 0, 0, 0);
1248                 return NULL;
1249         }
1250         ciptr->transptr= thistrans;
1251         ciptr->priv= NULL;
1252         ciptr->flags= 0;
1253         ciptr->fd= -1;
1254         ciptr->port= NULL;
1255         ciptr->family= AF_INET;
1256         ciptr->addr= NULL;
1257         ciptr->addrlen= 0;
1258         ciptr->peeraddr= NULL;
1259         ciptr->peeraddrlen= 0;
1260         return ciptr;
1261 }
1262
1263 static void
1264 free_ConnInfo(ciptr)
1265 XtransConnInfo ciptr;
1266 {
1267         if (ciptr == NULL)
1268                 return;
1269         free_private((struct private *)ciptr->priv);
1270         xfree(ciptr);
1271 }
1272
1273 static struct private *
1274 alloc_private(rd_size, wr_size)
1275 size_t rd_size;
1276 size_t wr_size;
1277 {
1278         struct private *priv;
1279         int s_errno;
1280         char *buf;
1281
1282         PRMSG(2, ":alloc_private(%d, %d)\n", rd_size, wr_size, 0);
1283
1284         if ((priv= (struct private *)xalloc(sizeof(struct private))) == NULL)
1285         {
1286                 PRMSG(1, ":alloc_private: malloc failed\n", 0, 0, 0);
1287                 return NULL;
1288         }
1289         priv->nonblocking= 0;
1290         priv->read_inprogress= 0;
1291         priv->read_buffer= NULL;
1292         priv->read_bufsize= rd_size;
1293         priv->read_size= 0;
1294         priv->read_offset= 0;
1295
1296         if (rd_size != 0)
1297         {
1298                 if ((buf= xalloc(rd_size)) == NULL)
1299                 {
1300                         PRMSG(1, ":alloc_private: malloc failed\n", 0, 0, 0);
1301                         s_errno= errno;
1302                         free_private(priv);
1303                         errno= s_errno;
1304                         return NULL;
1305                 }
1306                 priv->read_buffer= buf;
1307         }
1308
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;
1315
1316         if (wr_size != 0)
1317         {
1318                 if ((buf= xalloc(wr_size)) == NULL)
1319                 {
1320                         PRMSG(1, ":alloc_private: malloc failed\n", 0, 0, 0);
1321                         s_errno= errno;
1322                         free_private(priv);
1323                         errno= s_errno;
1324                         return NULL;
1325                 }
1326                 priv->write_buffer= buf;
1327         }
1328
1329         priv->listen_completed= 0;
1330         priv->listen_port= 0;
1331         priv->listen_list= NULL;
1332
1333         return priv;
1334 }
1335
1336 static void
1337 free_private(priv)
1338 struct private *priv;
1339 {
1340         if (priv == NULL)
1341                 return;
1342         xfree(priv->read_buffer);
1343         xfree(priv->write_buffer);
1344         xfree(priv);
1345 }
1346
1347 static void
1348 read_cb(ref, res, err)
1349 nbio_ref_t ref;
1350 int res;
1351 int err;
1352 {
1353         XtransConnInfo ciptr;
1354         struct private *priv;
1355
1356         PRMSG(2, ":read_cb(%x,%d,%d)\n", ref.ref_ptr, res, err);
1357
1358         ciptr= ref.ref_ptr;
1359         priv= (struct private *)ciptr->priv;
1360         if (res > 0)
1361                 priv->read_size= res;
1362         priv->read_inprogress= 0;
1363 }
1364
1365 static void
1366 write_cb(ref, res, err)
1367 nbio_ref_t ref;
1368 int res;
1369 int err;
1370 {
1371         XtransConnInfo ciptr;
1372         struct private *priv;
1373         int r;
1374
1375         PRMSG(2, ":write_cb(%x,%d,%d)\n", ref.ref_ptr, res, err);
1376
1377         ciptr= ref.ref_ptr;
1378         priv= (struct private *)ciptr->priv;
1379         if (res > 0)
1380                 priv->write_offset += res;
1381         else if (res == 0)
1382                 abort();
1383         else
1384         {
1385                 priv->write_errno= err;
1386                 return;
1387         }
1388         priv->write_inprogress= 0;
1389
1390         while (priv->write_offset < priv->write_size)
1391         {
1392                 r= write(ciptr->fd, priv->write_buffer+priv->write_offset,
1393                         priv->write_size-priv->write_offset);
1394                 if (r > 0)
1395                 {
1396                         PRMSG(5, "MnxTcpWrite: wrote %d bytes\n",
1397                                 r, 0, 0);
1398                         priv->write_offset += r;
1399                         continue;
1400                 }
1401                 else if (r == -1 && errno == EINPROGRESS)
1402                 {
1403                         priv->write_inprogress= 1;
1404                         nbio_inprogress(ciptr->fd, ASIO_WRITE, 0 /* read */,
1405                                 1 /* write */, 0 /* exception */);
1406                 }
1407                 else
1408                 {
1409                         PRMSG(1, "MnxTcpWrite: write failed: %s\n",
1410                                 strerror(errno), 0, 0);
1411                         priv->write_errno= errno;
1412                 }
1413                 break;
1414         }
1415 }
1416
1417 static void
1418 listen_cb(ref, res, err)
1419 nbio_ref_t ref;
1420 int res;
1421 int err;
1422 {
1423         XtransConnInfo ciptr;
1424         struct private *priv;
1425         struct sockaddr_in *addr;
1426         nwio_tcpconf_t tcpconf;
1427
1428         PRMSG(2, ":listen_cb(%x,%d,%d)\n", ref.ref_ptr, res, err);
1429
1430         ciptr= ref.ref_ptr;
1431         priv= (struct private *)ciptr->priv;
1432         if (res == 0)
1433         {
1434                 if (ioctl(ciptr->fd, NWIOGTCPCONF, &tcpconf) == -1)
1435                 {
1436                         PRMSG(1,
1437                         ":listen_cb: NWIOGTCPCONF failed: %s\n",
1438                                 strerror(errno),0, 0);
1439                         return;
1440                 }
1441                 if ((addr= (struct sockaddr_in *)xalloc(sizeof(struct sockaddr_in)))
1442                         == NULL)
1443                 {
1444                         PRMSG(1, ":listen_cb: malloc failed\n", 0, 0, 0);
1445                         return;
1446                 }
1447                 addr->sin_family= AF_INET;
1448                 addr->sin_addr.s_addr= tcpconf.nwtc_locaddr;
1449                 addr->sin_port= tcpconf.nwtc_locport;
1450                 if (ciptr->addr)
1451                         xfree(ciptr->addr);
1452                 ciptr->addr= (char *)addr;
1453                 ciptr->addrlen= sizeof(struct sockaddr_in);
1454                 priv->listen_completed= 1;
1455                 return;
1456         }
1457         PRMSG(2, ":listen_cb: listen failed: %s\n", strerror(err), 0, 0);
1458         if (restart_listen(ciptr) == -1)
1459         {
1460                 priv->listen_list= listen_list;
1461                 listen_list= ciptr;
1462         }
1463 }
1464
1465 static int
1466 restart_listen(ciptr)
1467 XtransConnInfo  ciptr;
1468 {
1469         char *tcp_device;
1470         nwio_tcpconf_t tcpconf;
1471         nwio_tcpcl_t tcpcl;
1472         int fd, r, s_errno, flags;
1473         struct private *priv;
1474         nbio_ref_t ref;
1475
1476         PRMSG(2, ":restart_listen(%d)\n", ciptr->fd, 0, 0);
1477
1478         nbio_unregister(ciptr->fd);
1479
1480         if ((tcp_device= getenv("TCP_DEVICE")) == NULL)
1481                 tcp_device= TCP_DEVICE;
1482
1483         if ((fd= open(tcp_device, O_RDWR)) == -1)
1484         {
1485                 PRMSG(1, ":restart_listen: open '%s' failed: %s\n",
1486                         tcp_device, strerror(errno), 0);
1487                 return -1;
1488         }
1489         PRMSG(5, ":restart_listen: fd= '%d'\n", fd, 0, 0);
1490         if (fd != ciptr->fd)
1491         {
1492                 if (dup2(fd, ciptr->fd) == -1)
1493                         abort();        /* no way to recover */
1494                 close(fd);
1495         }
1496         fd= ciptr->fd;
1497         ref.ref_ptr= ciptr;
1498         nbio_register(fd);
1499         nbio_setcallback(fd, ASIO_IOCTL, listen_cb, ref);
1500
1501         priv= (struct private *)ciptr->priv;
1502
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;
1506
1507         if (ioctl(ciptr->fd, NWIOSTCPCONF, &tcpconf) == -1)
1508         {
1509                 PRMSG(1,
1510                 ":restart_listen: NWIOSTCPCONF failed: %s\n",
1511                         strerror(errno),0, 0);
1512                 return -1;
1513         }
1514
1515         flags= fcntl(ciptr->fd, F_GETFD);
1516         if (flags == -1)
1517         {
1518                 PRMSG(1,
1519                 ":restart_listen: fcntl F_GETFD failed: %s\n",
1520                         strerror(errno), 0, 0);
1521                 return -1;
1522         }
1523         if (fcntl(ciptr->fd, F_SETFD, flags | FD_ASYNCHIO) == -1)
1524         {
1525                 PRMSG(1,
1526                 ":restart_listen: fcntl F_SETFD failed: %s\n",
1527                         strerror(errno), 0, 0);
1528                 return -1;
1529         }
1530
1531         tcpcl.nwtcl_flags= 0;
1532         r= ioctl(ciptr->fd, NWIOTCPLISTEN, &tcpcl);
1533         s_errno= errno;
1534
1535         if (fcntl(ciptr->fd, F_SETFD, flags) == -1)
1536         {
1537                 PRMSG(1,
1538                 ":restart_listen: fcntl F_SETFD failed: %s\n",
1539                         strerror(errno), 0, 0);
1540                 return -1;
1541         }
1542
1543         if (r == -1 && s_errno == EINPROGRESS)
1544         {
1545                 nbio_inprogress(ciptr->fd, ASIO_IOCTL, 1 /* read */,
1546                         1 /* write */, 0 /* exception */);
1547                 return 0;
1548         }
1549         if (r == 0)
1550         {
1551                 priv->listen_completed= 1;
1552                 return 0;
1553         }
1554         errno= s_errno;
1555         PRMSG(1, ":restart_listen: NWIOTCPLISTEN failed: %s\n",
1556                 strerror(errno), 0, 0);
1557         return -1;
1558 }
1559
1560
1561 Xtransport      TRANS(MnxINETFuncs) =
1562 {
1563         /* Minix TCP Interface */
1564         "inet",
1565         0,
1566 #ifdef TRANS_CLIENT
1567         TRANS(MnxTcpOpenCOTSClient),
1568 #endif /* TRANS_CLIENT */
1569 #ifdef TRANS_SERVER
1570         TRANS(MnxTcpOpenCOTSServer),
1571 #endif /* TRANS_SERVER */
1572 #ifdef TRANS_CLIENT
1573         TRANS(MnxTcpOpenCLTSClient),
1574 #endif /* TRANS_CLIENT */
1575 #ifdef TRANS_SERVER
1576         TRANS(MnxTcpOpenCLTSServer),
1577 #endif /* TRANS_SERVER */
1578 #ifdef TRANS_REOPEN
1579         TRANS(MnxTcpReopenCOTSServer),
1580         TRANS(MnxTcpReopenCLTSServer),
1581 #endif
1582         TRANS(MnxTcpSetOption),
1583 #ifdef TRANS_SERVER
1584         TRANS(MnxTcpCreateListener),
1585         TRANS(MnxTcpResetListener),
1586         TRANS(MnxTcpAccept),
1587 #endif /* TRANS_SERVER */
1588 #ifdef TRANS_CLIENT
1589         TRANS(MnxTcpConnect),
1590 #endif /* TRANS_CLIENT */
1591         TRANS(MnxTcpBytesReadable),
1592         TRANS(MnxTcpRead),
1593         TRANS(MnxTcpWrite),
1594         TRANS(MnxTcpReadv),
1595         TRANS(MnxTcpWritev),
1596         TRANS(MnxTcpDisconnect),
1597         TRANS(MnxTcpClose),
1598         TRANS(MnxTcpClose),
1599 };
1600
1601 Xtransport      TRANS(MnxTCPFuncs) =
1602 {
1603         /* Minix TCP Interface */
1604         "tcp",
1605         TRANS_ALIAS,
1606 #ifdef TRANS_CLIENT
1607         TRANS(MnxTcpOpenCOTSClient),
1608 #endif /* TRANS_CLIENT */
1609 #ifdef TRANS_SERVER
1610         TRANS(MnxTcpOpenCOTSServer),
1611 #endif /* TRANS_SERVER */
1612 #ifdef TRANS_CLIENT
1613         TRANS(MnxTcpOpenCLTSClient),
1614 #endif /* TRANS_CLIENT */
1615 #ifdef TRANS_SERVER
1616         TRANS(MnxTcpOpenCLTSServer),
1617 #endif /* TRANS_SERVER */
1618 #ifdef TRANS_REOPEN
1619         TRANS(MnxTcpReopenCOTSServer),
1620         TRANS(MnxTcpReopenCLTSServer),
1621 #endif
1622         TRANS(MnxTcpSetOption),
1623 #ifdef TRANS_SERVER
1624         TRANS(MnxTcpCreateListener),
1625         TRANS(MnxTcpResetListener),
1626         TRANS(MnxTcpAccept),
1627 #endif /* TRANS_SERVER */
1628 #ifdef TRANS_CLIENT
1629         TRANS(MnxTcpConnect),
1630 #endif /* TRANS_CLIENT */
1631         TRANS(MnxTcpBytesReadable),
1632         TRANS(MnxTcpRead),
1633         TRANS(MnxTcpWrite),
1634         TRANS(MnxTcpReadv),
1635         TRANS(MnxTcpWritev),
1636         TRANS(MnxTcpDisconnect),
1637         TRANS(MnxTcpClose),
1638         TRANS(MnxTcpClose),
1639 };