dd9e03b84563147896b5c671af9a6e41b43c0447
[yaz-moved-to-github.git] / comstack / tcpip.c
1 /*
2  * Copyright (c) 1995-2000, Index Data
3  * See the file LICENSE for details.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * $Log: tcpip.c,v $
7  * Revision 1.33  2000-09-04 08:27:11  adam
8  * Work on error handling for tcpip_accept.
9  *
10  * Revision 1.32  1999/11/30 13:47:11  adam
11  * Improved installation. Moved header files to include/yaz.
12  *
13  * Revision 1.31  1999/04/29 07:31:23  adam
14  * Changed tcpip_strtoaddr_ex so that only part 'till '/' is considered
15  * part of hostname.
16  *
17  * Revision 1.30  1999/04/20 09:56:48  adam
18  * Added 'name' paramter to encoder/decoder routines (typedef Odr_fun).
19  * Modified all encoders/decoders to reflect this change.
20  *
21  * Revision 1.29  1999/04/16 14:45:55  adam
22  * Added interface for tcpd wrapper for access control.
23  *
24  * Revision 1.28  1999/03/31 11:11:14  adam
25  * Function getprotobyname only called once. Minor change in tcpip_get
26  * to handle multi-threaded conditions.
27  *
28  * Revision 1.27  1999/02/02 13:57:31  adam
29  * Uses preprocessor define WIN32 instead of WINDOWS to build code
30  * for Microsoft WIN32.
31  *
32  * Revision 1.26  1999/01/08 11:23:14  adam
33  * Added const modifier to some of the BER/ODR encoding routines.
34  *
35  * Revision 1.25  1998/07/07 15:49:23  adam
36  * Added braces to avoid warning.
37  *
38  * Revision 1.24  1998/06/29 07:59:17  adam
39  * Minor fix.
40  *
41  * Revision 1.23  1998/06/23 15:37:50  adam
42  * Added type cast to prevent warning.
43  *
44  * Revision 1.22  1998/06/22 11:32:36  adam
45  * Added 'conditional cs_listen' feature.
46  *
47  * Revision 1.21  1998/05/20 09:55:32  adam
48  * Function tcpip_get treats EINPROGRESS error in the same way as
49  * EWOULDBLOCK. EINPROGRESS shouldn't be returned - but it is on
50  * Solaris in some cases.
51  *
52  * Revision 1.20  1998/05/18 10:10:40  adam
53  * Minor change to avoid C++ warning.
54  *
55  * Revision 1.19  1998/02/11 11:53:33  adam
56  * Changed code so that it compiles as C++.
57  *
58  * Revision 1.18  1997/09/29 07:15:25  adam
59  * Changed use of setsockopt to avoid warnings on MSVC.
60  *
61  * Revision 1.17  1997/09/17 12:10:30  adam
62  * YAZ version 1.4.
63  *
64  * Revision 1.16  1997/09/01 08:49:14  adam
65  * New windows NT/95 port using MSV5.0. Minor changes only.
66  *
67  * Revision 1.15  1997/05/14 06:53:33  adam
68  * C++ support.
69  *
70  * Revision 1.14  1997/05/01 15:06:32  adam
71  * Moved WINSOCK init. code to tcpip_init routine.
72  *
73  * Revision 1.13  1996/11/01 08:45:18  adam
74  * Bug fix: used close on MS-Windows. Fixed to closesocket.
75  *
76  * Revision 1.12  1996/07/06 19:58:30  quinn
77  * System headerfiles gathered in yconfig
78  *
79  * Revision 1.11  1996/02/23  10:00:39  quinn
80  * WAIS Work
81  *
82  * Revision 1.10  1996/02/20  12:52:11  quinn
83  * WAIS protocol support.
84  *
85  * Revision 1.9  1996/02/10  12:23:11  quinn
86  * Enablie inetd operations fro TCP/IP stack
87  *
88  * Revision 1.8  1995/11/01  13:54:27  quinn
89  * Minor adjustments
90  *
91  * Revision 1.7  1995/10/30  12:41:16  quinn
92  * Added hostname lookup for server.
93  *
94  * Revision 1.6  1995/09/29  17:12:00  quinn
95  * Smallish
96  *
97  * Revision 1.5  1995/09/29  17:01:48  quinn
98  * More Windows work
99  *
100  * Revision 1.4  1995/09/28  10:12:26  quinn
101  * Windows-support changes
102  *
103  * Revision 1.3  1995/09/27  15:02:45  quinn
104  * Modified function heads & prototypes.
105  *
106  * Revision 1.2  1995/06/15  12:30:06  quinn
107  * Added @ as hostname alias for INADDR ANY.
108  *
109  * Revision 1.1  1995/06/14  09:58:20  quinn
110  * Renamed yazlib to comstack.
111  *
112  * Revision 1.20  1995/05/16  08:51:16  quinn
113  * License, documentation, and memory fixes
114  *
115  * Revision 1.19  1995/04/10  10:24:08  quinn
116  * Some bug-fixes.
117  *
118  * Revision 1.18  1995/03/30  13:29:27  quinn
119  * Added REUSEADDR in tcpip_bind
120  *
121  * Revision 1.17  1995/03/27  08:36:10  quinn
122  * Some work on nonblocking operation in xmosi.c and rfct.c.
123  * Added protocol parameter to cs_create()
124  *
125  * Revision 1.16  1995/03/21  15:53:41  quinn
126  * Added rcvconnect
127  *
128  * Revision 1.15  1995/03/21  12:31:27  quinn
129  * Added check for EINPROGRESS on connect.
130  *
131  * Revision 1.14  1995/03/20  09:47:21  quinn
132  * Added server-side support to xmosi.c
133  * Fixed possible problems in rfct
134  * Other little mods
135  *
136  * Revision 1.13  1995/03/15  16:15:13  adam
137  * Removed p_write.
138  *
139  * Revision 1.12  1995/03/15  15:36:27  quinn
140  * Mods to support nonblocking I/O
141  *
142  * Revision 1.11  1995/03/15  08:37:57  quinn
143  * Now we're pretty much set for nonblocking I/O.
144  *
145  * Revision 1.10  1995/03/14  17:00:07  quinn
146  * Bug-fixes - added tracing info to tcpip.c
147  *
148  * Revision 1.9  1995/03/14  10:28:42  quinn
149  * Adding server-side support to tcpip.c and fixing bugs in nonblocking I/O
150  *
151  * Revision 1.8  1995/03/10  14:22:50  quinn
152  * Removed debug output.
153  *
154  * Revision 1.7  1995/03/10  11:44:59  quinn
155  * Fixes and debugging
156  *
157  * Revision 1.6  1995/03/07  10:26:55  quinn
158  * Initialized type field in the comstacks.
159  *
160  * Revision 1.5  1995/02/14  20:40:07  quinn
161  * Various stuff.
162  *
163  * Revision 1.4  1995/02/14  11:54:49  quinn
164  * Beginning to add full CCL.
165  *
166  * Revision 1.3  1995/02/10  18:58:10  quinn
167  * Fixed tcpip_get (formerly tcpip_read).
168  * Turned tst (cli) into a proper, event-driven thingy.
169  *
170  * Revision 1.2  1995/02/10  15:55:47  quinn
171  * Small things.
172  *
173  * Revision 1.1  1995/02/09  15:51:52  quinn
174  * Works better now.
175  *
176  */
177
178 #include <stdio.h>
179 #include <string.h>
180 #include <stdlib.h>
181 #ifndef WIN32
182 #include <unistd.h>
183 #endif
184 #include <errno.h>
185 #include <fcntl.h>
186
187 #include <yaz/comstack.h>
188 #include <yaz/tcpip.h>
189 #include <yaz/log.h>
190
191 /* Chas added the following, so we get the definition of completeBER */
192 #include <yaz/odr.h>
193
194 int tcpip_close(COMSTACK h);
195 int tcpip_put(COMSTACK h, char *buf, int size);
196 int tcpip_get(COMSTACK h, char **buf, int *bufsize);
197 int tcpip_connect(COMSTACK h, void *address);
198 int tcpip_more(COMSTACK h);
199 int tcpip_rcvconnect(COMSTACK h);
200 int tcpip_bind(COMSTACK h, void *address, int mode);
201 int tcpip_listen(COMSTACK h, char *raddr, int *addrlen,
202                  int (*check_ip)(void *cd, const char *a, int len, int type),
203                  void *cd);
204
205 COMSTACK tcpip_accept(COMSTACK h);
206 char *tcpip_addrstr(COMSTACK h);
207 void *tcpip_straddr(COMSTACK h, const char *str);
208
209 #undef TRACE_TCPIP
210 #ifdef TRACE_TCPIP
211 #define TRC(x) x
212 #else
213 #define TRC(X)
214 #endif
215
216 typedef struct tcpip_state
217 {
218     char *altbuf; /* alternate buffer for surplus data */
219     int altsize;  /* size as xmalloced */
220     int altlen;   /* length of data or 0 if none */
221
222     int written;  /* -1 if we aren't writing */
223     int towrite;  /* to verify against user input */
224     int (*complete)(const unsigned char *buf, int len); /* length/comple. */
225     struct sockaddr_in addr;  /* returned by cs_straddr */
226     char buf[128]; /* returned by cs_addrstr */
227 } tcpip_state;
228
229 #ifdef WIN32
230 static int tcpip_init (void)
231 {
232     static int initialized = 0;
233     if (!initialized)
234     {
235         WORD requested;
236         WSADATA wd;
237
238         requested = MAKEWORD(1, 1);
239         if (WSAStartup(requested, &wd))
240             return 0;
241         initialized = 1;
242     }
243     return 1;
244 }
245 #else
246
247 static int proto_number = 0;
248
249 static int tcpip_init (void)
250 {
251     struct protoent *proto;
252     /* only call getprotobyname once, in case it allocates memory */
253     if (!(proto = getprotobyname("tcp")))
254         return 0;
255     proto_number = proto->p_proto;
256     return 1;
257 }
258 #endif
259 /*
260  * This function is always called through the cs_create() macro.
261  * s >= 0: socket has already been established for us.
262  */
263 COMSTACK tcpip_type(int s, int blocking, int protocol)
264 {
265     COMSTACK p;
266     tcpip_state *state;
267     int new_socket;
268 #ifdef WIN32
269     unsigned long tru = 1;
270 #endif
271
272     if (!tcpip_init ())
273         return 0;
274     if (s < 0)
275     {
276 #ifdef WIN32
277         if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0)
278             return 0;
279 #else
280         if ((s = socket(AF_INET, SOCK_STREAM, proto_number)) < 0)
281             return 0;
282 #endif
283         new_socket = 1;
284     }
285     else
286         new_socket = 0;
287     if (!(p = (struct comstack *)xmalloc(sizeof(struct comstack))))
288         return 0;
289     if (!(state = (struct tcpip_state *)(p->cprivate =
290                                          xmalloc(sizeof(tcpip_state)))))
291         return 0;
292
293 #ifdef WIN32
294     if (!(p->blocking = blocking) && ioctlsocket(s, FIONBIO, &tru) < 0)
295 #else
296     if (!(p->blocking = blocking) && fcntl(s, F_SETFL, O_NONBLOCK) < 0)
297 #endif
298         return 0;
299
300     p->iofile = s;
301     p->type = tcpip_type;
302     p->protocol = (enum oid_proto) protocol;
303
304     p->f_connect = tcpip_connect;
305     p->f_rcvconnect = tcpip_rcvconnect;
306     p->f_get = tcpip_get;
307     p->f_put = tcpip_put;
308     p->f_close = tcpip_close;
309     p->f_more = tcpip_more;
310     p->f_bind = tcpip_bind;
311     p->f_listen = tcpip_listen;
312     p->f_accept = tcpip_accept;
313     p->f_addrstr = tcpip_addrstr;
314     p->f_straddr = tcpip_straddr;
315
316     p->state = new_socket ? CS_UNBND : CS_IDLE; /* state of line */
317     p->event = CS_NONE;
318     p->cerrno = 0;
319     p->stackerr = 0;
320
321     state->altbuf = 0;
322     state->altsize = state->altlen = 0;
323     state->towrite = state->written = -1;
324     if (protocol == PROTO_WAIS)
325         state->complete = completeWAIS;
326     else
327         state->complete = completeBER;
328
329     p->timeout = COMSTACK_DEFAULT_TIMEOUT;
330     TRC(fprintf(stderr, "Created new TCPIP comstack\n"));
331
332     return p;
333 }
334
335 int tcpip_strtoaddr_ex(const char *str, struct sockaddr_in *add)
336 {
337     struct hostent *hp;
338     char *p, buf[512];
339     short int port = 210;
340     unsigned tmpadd;
341
342     if (!tcpip_init ())
343         return 0;
344     TRC(fprintf(stderr, "tcpip_strtoaddress: %s\n", str ? str : "NULL"));
345     add->sin_family = AF_INET;
346     strncpy(buf, str, 511);
347     buf[511] = 0;
348     if ((p = strchr(buf, '/')))
349         *p = 0;
350     if ((p = strchr(buf, ':')))
351     {
352         *p = 0;
353         port = atoi(p + 1);
354     }
355     add->sin_port = htons(port);
356     if (!strcmp("@", buf))
357         add->sin_addr.s_addr = INADDR_ANY;
358     else if ((hp = gethostbyname(buf)))
359         memcpy(&add->sin_addr.s_addr, *hp->h_addr_list,
360                sizeof(struct in_addr));
361     else if ((tmpadd = (unsigned) inet_addr(buf)) != 0)
362         memcpy(&add->sin_addr.s_addr, &tmpadd, sizeof(struct in_addr));
363     else
364         return 0;
365     return 1;
366 }
367
368 void *tcpip_straddr(COMSTACK h, const char *str)
369 {
370     tcpip_state *sp = (tcpip_state *)h->cprivate;
371
372     if (!tcpip_strtoaddr_ex (str, &sp->addr))
373         return 0;
374     return &sp->addr;
375 }
376
377 struct sockaddr_in *tcpip_strtoaddr(const char *str)
378 {
379     static struct sockaddr_in add;
380     
381     if (!tcpip_strtoaddr_ex (str, &add))
382         return 0;
383     return &add;
384 }
385
386 int tcpip_more(COMSTACK h)
387 {
388     tcpip_state *sp = (tcpip_state *)h->cprivate;
389     
390     return sp->altlen && (*sp->complete)((unsigned char *) sp->altbuf,
391         sp->altlen);
392 }
393
394 /*
395  * connect(2) will block (sometimes) - nothing we can do short of doing
396  * weird things like spawning subprocesses or threading or some weird junk
397  * like that.
398  */
399 int tcpip_connect(COMSTACK h, void *address)
400 {
401     struct sockaddr_in *add = (struct sockaddr_in *)address;
402
403     TRC(fprintf(stderr, "tcpip_connect\n"));
404     if (connect(h->iofile, (struct sockaddr *) add, sizeof(*add)) < 0)
405     {
406 #ifdef WIN32
407         if (WSAGetLastError() == WSAEWOULDBLOCK)
408 #else
409         if (errno == EINPROGRESS)
410 #endif
411             return 1;
412         return -1;
413     }
414     h->state = CS_DATAXFER;
415     return 0;
416 }
417
418 /*
419  * nop
420  */
421 int tcpip_rcvconnect(COMSTACK h)
422 {
423     TRC(fprintf(stderr, "tcpip_rcvconnect\n"));
424     return 0;
425 }
426
427 int tcpip_bind(COMSTACK h, void *address, int mode)
428 {
429     struct sockaddr *addr = (struct sockaddr *)address;
430 #ifdef WIN32
431     BOOL one = 1;
432 #else
433     unsigned long one = 1;
434 #endif
435
436     TRC(fprintf(stderr, "tcpip_bind\n"));
437     if (setsockopt(h->iofile, SOL_SOCKET, SO_REUSEADDR, (char*) 
438         &one, sizeof(one)) < 0)
439     {
440         h->cerrno = CSYSERR;
441         return -1;
442     }
443     if (bind(h->iofile, addr, sizeof(struct sockaddr_in)) < 0)
444     {
445         h->cerrno = CSYSERR;
446         return -1;
447     }
448     if (mode == CS_SERVER && listen(h->iofile, 3) < 0)
449     {
450         h->cerrno = CSYSERR;
451         return -1;
452     }
453     h->state = CS_IDLE;
454     return 0;
455 }
456
457 int tcpip_listen(COMSTACK h, char *raddr, int *addrlen,
458                  int (*check_ip)(void *cd, const char *a, int len, int t),
459                  void *cd)
460 {
461     struct sockaddr_in addr;
462     int len = sizeof(addr);
463
464     TRC(fprintf(stderr, "tcpip_listen pid=%d\n", getpid()));
465     if (h->state != CS_IDLE)
466     {
467         h->cerrno = CSOUTSTATE;
468         return -1;
469     }
470     h->newfd = accept(h->iofile, (struct sockaddr*)&addr, &len);
471     if (h->newfd < 0)
472     {
473         if (
474 #ifdef WIN32
475             WSAGetLastError() == WSAEWOULDBLOCK
476 #else
477             errno == EWOULDBLOCK
478 #endif
479             )
480             h->cerrno = CSNODATA;
481         else
482             h->cerrno = CSYSERR;
483         return -1;
484     }
485     if (addrlen && (size_t) (*addrlen) >= sizeof(struct sockaddr_in))
486         memcpy(raddr, &addr, *addrlen = sizeof(struct sockaddr_in));
487     else if (addrlen)
488         *addrlen = 0;
489     if (check_ip && (*check_ip)(cd, (const char *) &addr,
490         sizeof(addr), AF_INET))
491     {
492         h->cerrno = CSDENY;
493 #ifdef WIN32
494         closesocket(h->newfd);
495 #else
496         close(h->newfd);
497 #endif
498         h->newfd = -1;
499         return -1;
500     }
501     h->state = CS_INCON;
502     return 0;
503 }
504
505 COMSTACK tcpip_accept(COMSTACK h)
506 {
507     COMSTACK cnew;
508     tcpip_state *state, *st = (tcpip_state *)h->cprivate;
509 #ifdef WIN32
510     unsigned long tru = 1;
511 #endif
512
513     TRC(fprintf(stderr, "tcpip_accept\n"));
514     if (h->state != CS_INCON)
515     {
516         h->cerrno = CSOUTSTATE;
517         return 0;
518     }
519     if (!(cnew = (COMSTACK)xmalloc(sizeof(*cnew))))
520     {
521         h->cerrno = CSYSERR;
522 #ifdef WIN32
523         closesocket(h->newfd);
524 #else
525         close(h->newfd);
526 #endif
527         h->newfd = -1;
528         return 0;
529     }
530     memcpy(cnew, h, sizeof(*h));
531     cnew->iofile = h->newfd;
532     if (!(state = (tcpip_state *)
533           (cnew->cprivate = xmalloc(sizeof(tcpip_state)))))
534     {
535         h->cerrno = CSYSERR;
536         if (h->newfd != -1)
537         {
538 #ifdef WIN32
539             closesocket(h->newfd);
540 #else
541             close(h->newfd);
542 #endif
543             h->newfd = -1;
544         }
545         return 0;
546     }
547 #ifdef WIN32
548     if (!cnew->blocking && ioctlsocket(cnew->iofile, FIONBIO, &tru) < 0)
549 #else
550     if (!cnew->blocking && fcntl(cnew->iofile, F_SETFL, O_NONBLOCK) < 0)
551 #endif
552     {
553         h->cerrno = CSYSERR;
554         if (h->newfd != -1)
555         {
556 #ifdef WIN32
557             closesocket(h->newfd);
558 #else
559             close(h->newfd);
560 #endif
561             h->newfd = -1;
562         }
563         xfree (cnew);
564         xfree (state);
565         return 0;
566     }
567     h->newfd = -1;
568     state->altbuf = 0;
569     state->altsize = state->altlen = 0;
570     state->towrite = state->written = -1;
571     state->complete = st->complete;
572     cnew->state = CS_DATAXFER;
573     h->state = CS_IDLE;
574     return cnew;
575 }
576
577 #define CS_TCPIP_BUFCHUNK 4096
578
579 /*
580  * Return: -1 error, >1 good, len of buffer, ==1 incomplete buffer,
581  * 0=connection closed.
582  */
583 int tcpip_get(COMSTACK h, char **buf, int *bufsize)
584 {
585     tcpip_state *sp = (tcpip_state *)h->cprivate;
586     char *tmpc;
587     int tmpi, berlen, rest, req, tomove;
588     int hasread = 0, res;
589
590     TRC(fprintf(stderr, "tcpip_get: bufsize=%d\n", *bufsize));
591     if (sp->altlen) /* switch buffers */
592     {
593         TRC(fprintf(stderr, "  %d bytes in altbuf (0x%x)\n", sp->altlen,
594             (unsigned) sp->altbuf));
595         tmpc = *buf;
596         tmpi = *bufsize;
597         *buf = sp->altbuf;
598         *bufsize = sp->altsize;
599         hasread = sp->altlen;
600         sp->altlen = 0;
601         sp->altbuf = tmpc;
602         sp->altsize = tmpi;
603     }
604     while (!(berlen = (*sp->complete)((unsigned char *)*buf, hasread)))
605     {
606         if (!*bufsize)
607         {
608             if (!(*buf = (char *)xmalloc(*bufsize = CS_TCPIP_BUFCHUNK)))
609                 return -1;
610         }
611         else if (*bufsize - hasread < CS_TCPIP_BUFCHUNK)
612             if (!(*buf =(char *)xrealloc(*buf, *bufsize *= 2)))
613                 return -1;
614         if ((res = recv(h->iofile, *buf + hasread, CS_TCPIP_BUFCHUNK, 0)) < 0)
615         {
616 #ifdef WIN32
617             if (WSAGetLastError() == WSAEWOULDBLOCK)
618                 break;
619             else
620                 return -1;
621 #else
622             if (errno == EWOULDBLOCK
623 #ifdef EINPROGRESS
624                 || errno == EINPROGRESS
625 #endif
626                 )
627                 break;
628             else if (errno == 0)
629                 continue;
630             else
631                 return -1;
632 #endif
633         }
634         if (!res)
635             return 0;
636         hasread += res;
637         TRC(fprintf(stderr, "  res=%d, hasread=%d\n", res, hasread));
638     }
639     TRC(fprintf(stderr, "  Out of read loop with hasread=%d, berlen=%d\n",
640         hasread, berlen));
641     /* move surplus buffer (or everything if we didn't get a BER rec.) */
642     if (hasread > berlen)
643     {
644         tomove = req = hasread - berlen;
645         rest = tomove % CS_TCPIP_BUFCHUNK;
646         if (rest)
647             req += CS_TCPIP_BUFCHUNK - rest;
648         if (!sp->altbuf)
649         {
650             if (!(sp->altbuf = (char *)xmalloc(sp->altsize = req)))
651                 return -1;
652         } else if (sp->altsize < req)
653             if (!(sp->altbuf =(char *)xrealloc(sp->altbuf, sp->altsize = req)))
654                 return -1;
655         TRC(fprintf(stderr, "  Moving %d bytes to altbuf(0x%x)\n", tomove,
656             (unsigned) sp->altbuf));
657         memcpy(sp->altbuf, *buf + berlen, sp->altlen = tomove);
658     }
659     if (berlen < CS_TCPIP_BUFCHUNK - 1)
660         *(*buf + berlen) = '\0';
661     return berlen ? berlen : 1;
662 }
663
664 /*
665  * Returns 1, 0 or -1
666  * In nonblocking mode, you must call again with same buffer while
667  * return value is 1.
668  */
669 int tcpip_put(COMSTACK h, char *buf, int size)
670 {
671     int res;
672     struct tcpip_state *state = (struct tcpip_state *)h->cprivate;
673
674     TRC(fprintf(stderr, "tcpip_put: size=%d\n", size));
675     if (state->towrite < 0)
676     {
677         state->towrite = size;
678         state->written = 0;
679     }
680     else if (state->towrite != size)
681     {
682         h->cerrno = CSWRONGBUF;
683         return -1;
684     }
685     while (state->towrite > state->written)
686     {
687         if ((res = send(h->iofile, buf + state->written, size -
688             state->written, 0)) < 0)
689         {
690 #ifdef WIN32
691             if (WSAGetLastError() == WSAEWOULDBLOCK)
692 #else
693             if (errno == EAGAIN)
694 #endif
695             {
696                 TRC(fprintf(stderr, "  Flow control stop\n"));
697                 return 1;
698             }
699             h->cerrno = CSYSERR;
700             return -1;
701         }
702         state->written += res;
703         TRC(fprintf(stderr, "  Wrote %d, written=%d, nbytes=%d\n",
704             res, state->written, size));
705     }
706     state->towrite = state->written = -1;
707     TRC(fprintf(stderr, "  Ok\n"));
708     return 0;
709 }
710
711 int tcpip_close(COMSTACK h)
712 {
713     tcpip_state *sp = (struct tcpip_state *)h->cprivate;
714
715     TRC(fprintf(stderr, "tcpip_close\n"));
716     if (h->iofile != -1)
717 #ifdef WIN32
718         closesocket(h->iofile);
719 #else
720         close(h->iofile);
721 #endif
722     if (sp->altbuf)
723         xfree(sp->altbuf);
724     xfree(sp);
725     xfree(h);
726     return 0;
727 }
728
729 char *tcpip_addrstr(COMSTACK h)
730 {
731     struct sockaddr_in addr;
732     tcpip_state *sp = (struct tcpip_state *)h->cprivate;
733     char *r, *buf = sp->buf;
734     size_t len;
735     struct hostent *host;
736     
737     len = sizeof(addr);
738     if (getpeername(h->iofile, (struct sockaddr*) &addr, &len) < 0)
739     {
740         h->cerrno = CSYSERR;
741         return 0;
742     }
743     if ((host = gethostbyaddr((char*)&addr.sin_addr, sizeof(addr.sin_addr),
744                               AF_INET)))
745         r = (char*) host->h_name;
746     else
747         r = inet_ntoa(addr.sin_addr);
748     sprintf(buf, "tcp:%s", r);
749     return buf;
750 }