Implemented cs_rcvconnect and cs_look as described in the documentation.
[yaz-moved-to-github.git] / comstack / tcpip.c
1 /*
2  * Copyright (c) 1995-2001, Index Data
3  * See the file LICENSE for details.
4  *
5  * $Log: tcpip.c,v $
6  * Revision 1.42  2001-10-22 13:57:24  adam
7  * Implemented cs_rcvconnect and cs_look as described in the documentation.
8  *
9  * Revision 1.41  2001/10/12 21:49:26  adam
10  * For accept/recv/send check for EAGAIN if it's differs from EWOULDBLOCK.
11  *
12  * Revision 1.40  2001/08/23 09:02:46  adam
13  * WIN32 fixes: Socket not re-used for bind. yaz_log logs WIN32 error
14  * message.
15  *
16  * Revision 1.39  2001/07/19 19:49:40  adam
17  * Fixed bug in tcpip_set_blocking.
18  *
19  * Revision 1.38  2001/03/21 12:43:36  adam
20  * Implemented cs_create_host. Better error reporting for SSL comstack.
21  *
22  * Revision 1.37  2001/03/08 20:18:55  adam
23  * Added cs_set_blocking. Patch from Matthew Carey.
24  *
25  * Revision 1.36  2001/02/21 13:46:53  adam
26  * C++ fixes.
27  *
28  * Revision 1.35  2000/11/27 15:17:40  adam
29  * Using SSLeay_add_all_algorithms instead of OpenSSL_add_all_algorithms.
30  *
31  * Revision 1.34  2000/11/23 10:58:32  adam
32  * SSL comstack support. Separate POSIX thread support library.
33  *
34  * Revision 1.33  2000/09/04 08:27:11  adam
35  * Work on error handling for tcpip_accept.
36  *
37  * Revision 1.32  1999/11/30 13:47:11  adam
38  * Improved installation. Moved header files to include/yaz.
39  *
40  * Revision 1.31  1999/04/29 07:31:23  adam
41  * Changed tcpip_strtoaddr_ex so that only part 'till '/' is considered
42  * part of hostname.
43  *
44  * Revision 1.30  1999/04/20 09:56:48  adam
45  * Added 'name' paramter to encoder/decoder routines (typedef Odr_fun).
46  * Modified all encoders/decoders to reflect this change.
47  *
48  * Revision 1.29  1999/04/16 14:45:55  adam
49  * Added interface for tcpd wrapper for access control.
50  *
51  * Revision 1.28  1999/03/31 11:11:14  adam
52  * Function getprotobyname only called once. Minor change in tcpip_get
53  * to handle multi-threaded conditions.
54  *
55  * Revision 1.27  1999/02/02 13:57:31  adam
56  * Uses preprocessor define WIN32 instead of WINDOWS to build code
57  * for Microsoft WIN32.
58  *
59  * Revision 1.26  1999/01/08 11:23:14  adam
60  * Added const modifier to some of the BER/ODR encoding routines.
61  *
62  * Revision 1.25  1998/07/07 15:49:23  adam
63  * Added braces to avoid warning.
64  *
65  * Revision 1.24  1998/06/29 07:59:17  adam
66  * Minor fix.
67  *
68  * Revision 1.23  1998/06/23 15:37:50  adam
69  * Added type cast to prevent warning.
70  *
71  * Revision 1.22  1998/06/22 11:32:36  adam
72  * Added 'conditional cs_listen' feature.
73  *
74  * Revision 1.21  1998/05/20 09:55:32  adam
75  * Function tcpip_get treats EINPROGRESS error in the same way as
76  * EWOULDBLOCK. EINPROGRESS shouldn't be returned - but it is on
77  * Solaris in some cases.
78  *
79  * Revision 1.20  1998/05/18 10:10:40  adam
80  * Minor change to avoid C++ warning.
81  *
82  * Revision 1.19  1998/02/11 11:53:33  adam
83  * Changed code so that it compiles as C++.
84  *
85  * Revision 1.18  1997/09/29 07:15:25  adam
86  * Changed use of setsockopt to avoid warnings on MSVC.
87  *
88  * Revision 1.17  1997/09/17 12:10:30  adam
89  * YAZ version 1.4.
90  *
91  * Revision 1.16  1997/09/01 08:49:14  adam
92  * New windows NT/95 port using MSV5.0. Minor changes only.
93  *
94  * Revision 1.15  1997/05/14 06:53:33  adam
95  * C++ support.
96  *
97  * Revision 1.14  1997/05/01 15:06:32  adam
98  * Moved WINSOCK init. code to tcpip_init routine.
99  *
100  * Revision 1.13  1996/11/01 08:45:18  adam
101  * Bug fix: used close on MS-Windows. Fixed to closesocket.
102  *
103  * Revision 1.12  1996/07/06 19:58:30  quinn
104  * System headerfiles gathered in yconfig
105  *
106  * Revision 1.11  1996/02/23  10:00:39  quinn
107  * WAIS Work
108  *
109  * Revision 1.10  1996/02/20  12:52:11  quinn
110  * WAIS protocol support.
111  *
112  * Revision 1.9  1996/02/10  12:23:11  quinn
113  * Enablie inetd operations fro TCP/IP stack
114  *
115  * Revision 1.8  1995/11/01  13:54:27  quinn
116  * Minor adjustments
117  *
118  * Revision 1.7  1995/10/30  12:41:16  quinn
119  * Added hostname lookup for server.
120  *
121  * Revision 1.6  1995/09/29  17:12:00  quinn
122  * Smallish
123  *
124  * Revision 1.5  1995/09/29  17:01:48  quinn
125  * More Windows work
126  *
127  * Revision 1.4  1995/09/28  10:12:26  quinn
128  * Windows-support changes
129  *
130  * Revision 1.3  1995/09/27  15:02:45  quinn
131  * Modified function heads & prototypes.
132  *
133  * Revision 1.2  1995/06/15  12:30:06  quinn
134  * Added @ as hostname alias for INADDR ANY.
135  *
136  * Revision 1.1  1995/06/14  09:58:20  quinn
137  * Renamed yazlib to comstack.
138  *
139  * Revision 1.20  1995/05/16  08:51:16  quinn
140  * License, documentation, and memory fixes
141  *
142  * Revision 1.19  1995/04/10  10:24:08  quinn
143  * Some bug-fixes.
144  *
145  * Revision 1.18  1995/03/30  13:29:27  quinn
146  * Added REUSEADDR in tcpip_bind
147  *
148  * Revision 1.17  1995/03/27  08:36:10  quinn
149  * Some work on nonblocking operation in xmosi.c and rfct.c.
150  * Added protocol parameter to cs_create()
151  *
152  * Revision 1.16  1995/03/21  15:53:41  quinn
153  * Added rcvconnect
154  *
155  * Revision 1.15  1995/03/21  12:31:27  quinn
156  * Added check for EINPROGRESS on connect.
157  *
158  * Revision 1.14  1995/03/20  09:47:21  quinn
159  * Added server-side support to xmosi.c
160  * Fixed possible problems in rfct
161  * Other little mods
162  *
163  * Revision 1.13  1995/03/15  16:15:13  adam
164  * Removed p_write.
165  *
166  * Revision 1.12  1995/03/15  15:36:27  quinn
167  * Mods to support nonblocking I/O
168  *
169  * Revision 1.11  1995/03/15  08:37:57  quinn
170  * Now we're pretty much set for nonblocking I/O.
171  *
172  * Revision 1.10  1995/03/14  17:00:07  quinn
173  * Bug-fixes - added tracing info to tcpip.c
174  *
175  * Revision 1.9  1995/03/14  10:28:42  quinn
176  * Adding server-side support to tcpip.c and fixing bugs in nonblocking I/O
177  *
178  * Revision 1.8  1995/03/10  14:22:50  quinn
179  * Removed debug output.
180  *
181  * Revision 1.7  1995/03/10  11:44:59  quinn
182  * Fixes and debugging
183  *
184  * Revision 1.6  1995/03/07  10:26:55  quinn
185  * Initialized type field in the comstacks.
186  *
187  * Revision 1.5  1995/02/14  20:40:07  quinn
188  * Various stuff.
189  *
190  * Revision 1.4  1995/02/14  11:54:49  quinn
191  * Beginning to add full CCL.
192  *
193  * Revision 1.3  1995/02/10  18:58:10  quinn
194  * Fixed tcpip_get (formerly tcpip_read).
195  * Turned tst (cli) into a proper, event-driven thingy.
196  *
197  * Revision 1.2  1995/02/10  15:55:47  quinn
198  * Small things.
199  *
200  * Revision 1.1  1995/02/09  15:51:52  quinn
201  * Works better now.
202  *
203  */
204
205 #include <stdio.h>
206 #include <string.h>
207 #include <stdlib.h>
208 #ifndef WIN32
209 #include <unistd.h>
210 #endif
211 #include <errno.h>
212 #include <fcntl.h>
213 #if HAVE_OPENSSL_SSL_H
214 #include <openssl/ssl.h>
215 #include <openssl/err.h>
216 #endif
217
218 #include <yaz/comstack.h>
219 #include <yaz/tcpip.h>
220 #include <yaz/log.h>
221
222 /* Chas added the following, so we get the definition of completeBER */
223 #include <yaz/odr.h>
224
225 int tcpip_close(COMSTACK h);
226 int tcpip_put(COMSTACK h, char *buf, int size);
227 int tcpip_get(COMSTACK h, char **buf, int *bufsize);
228 int tcpip_connect(COMSTACK h, void *address);
229 int tcpip_more(COMSTACK h);
230 int tcpip_rcvconnect(COMSTACK h);
231 int tcpip_bind(COMSTACK h, void *address, int mode);
232 int tcpip_listen(COMSTACK h, char *raddr, int *addrlen,
233                  int (*check_ip)(void *cd, const char *a, int len, int type),
234                  void *cd);
235 int static tcpip_set_blocking(COMSTACK p, int blocking);
236
237 #if HAVE_OPENSSL_SSL_H
238 int ssl_get(COMSTACK h, char **buf, int *bufsize);
239 int ssl_put(COMSTACK h, char *buf, int size);
240 #endif
241
242 COMSTACK tcpip_accept(COMSTACK h);
243 char *tcpip_addrstr(COMSTACK h);
244 void *tcpip_straddr(COMSTACK h, const char *str);
245
246 #if 0
247 #define TRC(x) x
248 #else
249 #define TRC(X)
250 #endif
251
252 /* this state is used for both SSL and straight TCP/IP */
253 typedef struct tcpip_state
254 {
255     char *altbuf; /* alternate buffer for surplus data */
256     int altsize;  /* size as xmalloced */
257     int altlen;   /* length of data or 0 if none */
258
259     int written;  /* -1 if we aren't writing */
260     int towrite;  /* to verify against user input */
261     int (*complete)(const unsigned char *buf, int len); /* length/comple. */
262     struct sockaddr_in addr;  /* returned by cs_straddr */
263     char buf[128]; /* returned by cs_addrstr */
264 #if HAVE_OPENSSL_SSL_H
265     SSL_CTX *ctx;
266     SSL_CTX *ctx_alloc;
267     SSL *ssl;
268 #endif
269 } tcpip_state;
270
271 #ifdef WIN32
272 static int tcpip_init (void)
273 {
274     static int initialized = 0;
275     if (!initialized)
276     {
277         WORD requested;
278         WSADATA wd;
279
280         requested = MAKEWORD(1, 1);
281         if (WSAStartup(requested, &wd))
282             return 0;
283         initialized = 1;
284     }
285     return 1;
286 }
287 #else
288 static int proto_number = 0;
289
290 static int tcpip_init (void)
291 {
292     struct protoent *proto;
293     /* only call getprotobyname once, in case it allocates memory */
294     if (!(proto = getprotobyname("tcp")))
295         return 0;
296     proto_number = proto->p_proto;
297     return 1;
298 }
299 #endif
300
301 /*
302  * This function is always called through the cs_create() macro.
303  * s >= 0: socket has already been established for us.
304  */
305 COMSTACK tcpip_type(int s, int blocking, int protocol, void *vp)
306 {
307     COMSTACK p;
308     tcpip_state *state;
309     int new_socket;
310 #ifdef WIN32
311     unsigned long tru = 1;
312 #endif
313
314     if (!tcpip_init ())
315         return 0;
316     if (s < 0)
317     {
318 #ifdef WIN32
319         if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0)
320             return 0;
321 #else
322         if ((s = socket(AF_INET, SOCK_STREAM, proto_number)) < 0)
323             return 0;
324 #endif
325         new_socket = 1;
326     }
327     else
328         new_socket = 0;
329     if (!(p = (struct comstack *)xmalloc(sizeof(struct comstack))))
330         return 0;
331     if (!(state = (struct tcpip_state *)(p->cprivate =
332                                          xmalloc(sizeof(tcpip_state)))))
333         return 0;
334
335 #ifdef WIN32
336     if (!(p->blocking = blocking) && ioctlsocket(s, FIONBIO, &tru) < 0)
337 #else
338     if (!(p->blocking = blocking) && fcntl(s, F_SETFL, O_NONBLOCK) < 0)
339 #endif
340         return 0;
341
342     p->io_pending = 0;
343     p->iofile = s;
344     p->type = tcpip_type;
345     p->protocol = (enum oid_proto) protocol;
346
347     p->f_connect = tcpip_connect;
348     p->f_rcvconnect = tcpip_rcvconnect;
349     p->f_get = tcpip_get;
350     p->f_put = tcpip_put;
351     p->f_close = tcpip_close;
352     p->f_more = tcpip_more;
353     p->f_bind = tcpip_bind;
354     p->f_listen = tcpip_listen;
355     p->f_accept = tcpip_accept;
356     p->f_addrstr = tcpip_addrstr;
357     p->f_straddr = tcpip_straddr;
358     p->f_set_blocking = tcpip_set_blocking;
359
360     p->state = new_socket ? CS_UNBND : CS_IDLE; /* state of line */
361     p->event = CS_NONE;
362     p->cerrno = 0;
363     p->stackerr = 0;
364
365 #if HAVE_OPENSSL_SSL_H
366     state->ctx = state->ctx_alloc = 0;
367     state->ssl = 0;
368 #endif
369
370     state->altbuf = 0;
371     state->altsize = state->altlen = 0;
372     state->towrite = state->written = -1;
373     if (protocol == PROTO_WAIS)
374         state->complete = completeWAIS;
375     else
376         state->complete = completeBER;
377
378     p->timeout = COMSTACK_DEFAULT_TIMEOUT;
379     TRC(fprintf(stderr, "Created new TCPIP comstack\n"));
380
381     return p;
382 }
383
384 #if HAVE_OPENSSL_SSL_H
385
386 COMSTACK ssl_type(int s, int blocking, int protocol, void *vp)
387 {
388     tcpip_state *state;
389     COMSTACK p;
390     yaz_log(LOG_LOG, "ssl_type begin");
391
392     p = tcpip_type (s, blocking, protocol, 0);
393     if (!p)
394         return 0;
395     p->f_get = ssl_get;
396     p->f_put = ssl_put;
397     p->type = ssl_type;
398     state = (tcpip_state *) p->cprivate;
399     if (vp)
400         state->ctx = vp;
401     else
402     {
403         SSL_load_error_strings();
404         SSLeay_add_all_algorithms();
405
406         state->ctx = state->ctx_alloc = SSL_CTX_new (SSLv23_method());
407         if (!state->ctx)
408         {
409             tcpip_close(p);
410             return 0;
411         }
412     }
413     /* note: we don't handle already opened socket in SSL mode - yet */
414     yaz_log(LOG_LOG, "ssl_type end");
415     return p;
416 }
417 #endif
418
419 int tcpip_strtoaddr_ex(const char *str, struct sockaddr_in *add)
420 {
421     struct hostent *hp;
422     char *p, buf[512];
423     short int port = 210;
424     unsigned tmpadd;
425
426     if (!tcpip_init ())
427         return 0;
428     TRC(fprintf(stderr, "tcpip_strtoaddress: %s\n", str ? str : "NULL"));
429     add->sin_family = AF_INET;
430     strncpy(buf, str, 511);
431     buf[511] = 0;
432     if ((p = strchr(buf, '/')))
433         *p = 0;
434     if ((p = strchr(buf, ':')))
435     {
436         *p = 0;
437         port = atoi(p + 1);
438     }
439     add->sin_port = htons(port);
440     if (!strcmp("@", buf))
441         add->sin_addr.s_addr = INADDR_ANY;
442     else if ((hp = gethostbyname(buf)))
443         memcpy(&add->sin_addr.s_addr, *hp->h_addr_list,
444                sizeof(struct in_addr));
445     else if ((tmpadd = (unsigned) inet_addr(buf)) != 0)
446         memcpy(&add->sin_addr.s_addr, &tmpadd, sizeof(struct in_addr));
447     else
448         return 0;
449     return 1;
450 }
451
452 void *tcpip_straddr(COMSTACK h, const char *str)
453 {
454     tcpip_state *sp = (tcpip_state *)h->cprivate;
455
456     if (!tcpip_strtoaddr_ex (str, &sp->addr))
457         return 0;
458     return &sp->addr;
459 }
460
461 struct sockaddr_in *tcpip_strtoaddr(const char *str)
462 {
463     static struct sockaddr_in add;
464     
465     if (!tcpip_strtoaddr_ex (str, &add))
466         return 0;
467     return &add;
468 }
469
470 int tcpip_more(COMSTACK h)
471 {
472     tcpip_state *sp = (tcpip_state *)h->cprivate;
473     
474     return sp->altlen && (*sp->complete)((unsigned char *) sp->altbuf,
475         sp->altlen);
476 }
477
478 /*
479  * connect(2) will block (sometimes) - nothing we can do short of doing
480  * weird things like spawning subprocesses or threading or some weird junk
481  * like that.
482  */
483 int tcpip_connect(COMSTACK h, void *address)
484 {
485     struct sockaddr_in *add = (struct sockaddr_in *)address;
486 #if HAVE_OPENSSL_SSL_H
487         tcpip_state *sp = (tcpip_state *)h->cprivate;
488 #endif
489     int r;
490
491     TRC(fprintf(stderr, "tcpip_connect\n"));
492     h->io_pending = 0;
493     if (h->state == CS_UNBND)
494     {
495         r = connect(h->iofile, (struct sockaddr *) add, sizeof(*add));
496         if (r < 0)
497         {
498 #ifdef WIN32
499             if (WSAGetLastError() == WSAEWOULDBLOCK)
500             {
501                 h->event = CS_CONNECT;
502                 h->state = CS_CONNECTING;
503                 h->io_pending = CS_WANT_WRITE;
504                 return 1;
505             }
506 #else
507             if (errno == EINPROGRESS)
508             {
509                 h->event = CS_CONNECT;
510                 h->state = CS_CONNECTING;
511                 h->io_pending = CS_WANT_WRITE|CS_WANT_READ;
512                 return 1;
513             }
514 #endif
515             h->cerrno = CSYSERR;
516             return -1;
517         }
518         h->event = CS_CONNECT;
519         h->state = CS_CONNECTING;
520     }
521     if (h->state != CS_CONNECTING)
522     {
523         h->cerrno = CSOUTSTATE;
524         return -1;
525     }
526 #if HAVE_OPENSSL_SSL_H
527     if (sp->ctx)
528     {
529         int res;
530
531         if (!sp->ssl)
532         {
533             sp->ssl = SSL_new (sp->ctx);
534             SSL_set_fd (sp->ssl, h->iofile);
535         }
536         res = SSL_connect (sp->ssl);
537         if (res <= 0)
538         {
539             int err = SSL_get_error(sp->ssl, res);
540             if (err == SSL_ERROR_WANT_READ)
541             {
542                 yaz_log (LOG_LOG, "SSL_connect. want_read");
543                 h->io_pending = CS_WANT_READ;
544                 return 1;
545             }
546             if (err == SSL_ERROR_WANT_WRITE)
547             {
548                 yaz_log (LOG_LOG, "SSL_connect. want_write");
549                 h->io_pending = CS_WANT_WRITE;
550                 return 1;
551             }
552             h->cerrno = CSERRORSSL;
553             return -1;
554         }
555     }
556 #endif
557     h->event = CS_DATA;
558     h->state = CS_DATAXFER;
559     return 0;
560 }
561
562 /*
563  * nop
564  */
565 int tcpip_rcvconnect(COMSTACK cs)
566 {
567     TRC(fprintf(stderr, "tcpip_rcvconnect\n"));
568
569     if (cs->event == CS_CONNECT)
570     {
571         int fd = cs->iofile;
572         fd_set input, output;
573         struct timeval tv;
574         int r;
575         
576         tv.tv_sec = 0;
577         tv.tv_usec = 1;
578         
579         FD_ZERO(&input);
580         FD_ZERO(&output);
581         FD_SET (fd, &input);
582         FD_SET (fd, &output);
583         
584         r = select (fd+1, &input, &output, 0, &tv);
585         if (r > 0)
586         {
587             if (FD_ISSET(cs->iofile, &output))
588             {
589                 cs->state = CS_DATA;
590                 return 0;   /* write OK, we're OK */
591             }
592             else
593                 return -1;  /* an error, for sure */
594         }
595         return 0;  /* timeout - incomplete */
596     }
597     return -1;    /* wrong state */
598 }
599
600 #define CERTF "ztest.pem"
601 #define KEYF "ztest.pem"
602
603 int tcpip_bind(COMSTACK h, void *address, int mode)
604 {
605     struct sockaddr *addr = (struct sockaddr *)address;
606 #ifdef WIN32
607     BOOL one = 1;
608 #else
609     unsigned long one = 1;
610 #endif
611
612 #if HAVE_OPENSSL_SSL_H
613     tcpip_state *sp = (tcpip_state *)h->cprivate;
614     if (sp->ctx)
615     {
616         if (sp->ctx_alloc)
617         {
618             int res;
619             res = SSL_CTX_use_certificate_file (sp->ctx, CERTF,
620                                                 SSL_FILETYPE_PEM);
621             if (res <= 0)
622             {
623                 ERR_print_errors_fp(stderr);
624                 exit (2);
625             }
626             res = SSL_CTX_use_PrivateKey_file (sp->ctx, KEYF,
627                                                SSL_FILETYPE_PEM);
628             if (res <= 0)
629             {
630                 ERR_print_errors_fp(stderr);
631                 exit (3);
632             }
633             res = SSL_CTX_check_private_key (sp->ctx);
634             if (res <= 0)
635             {
636                 ERR_print_errors_fp(stderr);
637                 exit(5);
638             }
639         }
640         TRC (fprintf (stderr, "ssl_bind\n"));
641     }
642     else
643     {
644         TRC (fprintf (stderr, "tcpip_bind\n"));
645     }
646 #else
647     TRC (fprintf (stderr, "tcpip_bind\n"));
648 #endif
649 #ifndef WIN32
650     if (setsockopt(h->iofile, SOL_SOCKET, SO_REUSEADDR, (char*) 
651         &one, sizeof(one)) < 0)
652     {
653         h->cerrno = CSYSERR;
654         return -1;
655     }
656 #endif
657     if (bind(h->iofile, addr, sizeof(struct sockaddr_in)))
658     {
659         h->cerrno = CSYSERR;
660         return -1;
661     }
662     if (mode == CS_SERVER && listen(h->iofile, 3) < 0)
663     {
664         h->cerrno = CSYSERR;
665         return -1;
666     }
667     h->state = CS_IDLE;
668     h->event = CS_LISTEN;
669     return 0;
670 }
671
672 int tcpip_listen(COMSTACK h, char *raddr, int *addrlen,
673                  int (*check_ip)(void *cd, const char *a, int len, int t),
674                  void *cd)
675 {
676     struct sockaddr_in addr;
677 #ifdef __cplusplus
678     socklen_t len = sizeof(addr);
679 #else
680     int len = sizeof(addr);
681 #endif
682
683     TRC(fprintf(stderr, "tcpip_listen pid=%d\n", getpid()));
684     if (h->state != CS_IDLE)
685     {
686         h->cerrno = CSOUTSTATE;
687         return -1;
688     }
689     h->newfd = accept(h->iofile, (struct sockaddr*)&addr, &len);
690     if (h->newfd < 0)
691     {
692         if (
693 #ifdef WIN32
694             WSAGetLastError() == WSAEWOULDBLOCK
695 #else
696             errno == EWOULDBLOCK 
697 #ifdef EAGAIN
698 #if EAGAIN != EWOULDBLOCK
699             || errno == EAGAIN
700 #endif
701 #endif
702 #endif
703             )
704             h->cerrno = CSNODATA;
705         else
706             h->cerrno = CSYSERR;
707         return -1;
708     }
709     if (addrlen && (size_t) (*addrlen) >= sizeof(struct sockaddr_in))
710         memcpy(raddr, &addr, *addrlen = sizeof(struct sockaddr_in));
711     else if (addrlen)
712         *addrlen = 0;
713     if (check_ip && (*check_ip)(cd, (const char *) &addr,
714         sizeof(addr), AF_INET))
715     {
716         h->cerrno = CSDENY;
717 #ifdef WIN32
718         closesocket(h->newfd);
719 #else
720         close(h->newfd);
721 #endif
722         h->newfd = -1;
723         return -1;
724     }
725     h->state = CS_INCON;
726     return 0;
727 }
728
729 COMSTACK tcpip_accept(COMSTACK h)
730 {
731     COMSTACK cnew;
732     tcpip_state *state, *st = (tcpip_state *)h->cprivate;
733 #ifdef WIN32
734     unsigned long tru = 1;
735 #endif
736
737     TRC(fprintf(stderr, "tcpip_accept\n"));
738     if (h->state == CS_INCON)
739     {
740         if (!(cnew = (COMSTACK)xmalloc(sizeof(*cnew))))
741         {
742             h->cerrno = CSYSERR;
743 #ifdef WIN32
744             closesocket(h->newfd);
745 #else
746             close(h->newfd);
747 #endif
748             h->newfd = -1;
749             return 0;
750         }
751         memcpy(cnew, h, sizeof(*h));
752         cnew->iofile = h->newfd;
753         cnew->io_pending = 0;
754         if (!(state = (tcpip_state *)
755               (cnew->cprivate = xmalloc(sizeof(tcpip_state)))))
756         {
757             h->cerrno = CSYSERR;
758             if (h->newfd != -1)
759             {
760 #ifdef WIN32
761                 closesocket(h->newfd);
762 #else
763                 close(h->newfd);
764 #endif
765                 h->newfd = -1;
766             }
767             return 0;
768         }
769         if (!cnew->blocking && 
770 #ifdef WIN32
771             (ioctlsocket(cnew->iofile, FIONBIO, &tru) < 0)
772 #else
773             (!cnew->blocking && fcntl(cnew->iofile, F_SETFL, O_NONBLOCK) < 0)
774 #endif
775             )
776         {
777             h->cerrno = CSYSERR;
778             if (h->newfd != -1)
779             {
780 #ifdef WIN32
781                 closesocket(h->newfd);
782 #else
783                 close(h->newfd);
784 #endif
785                 h->newfd = -1;
786             }
787             xfree (cnew);
788             xfree (state);
789             return 0;
790         }
791         h->newfd = -1;
792         state->altbuf = 0;
793         state->altsize = state->altlen = 0;
794         state->towrite = state->written = -1;
795         state->complete = st->complete;
796         cnew->state = CS_ACCEPT;
797         h->state = CS_IDLE;
798         
799 #if HAVE_OPENSSL_SSL_H
800         state->ctx = st->ctx;
801         state->ctx_alloc = 0;
802         state->ssl = st->ssl;
803         if (state->ctx)
804         {
805             state->ssl = SSL_new (state->ctx);
806             SSL_set_fd (state->ssl, cnew->iofile);
807         }
808 #endif
809         h = cnew;
810     }
811     if (h->state == CS_ACCEPT)
812     {
813 #if HAVE_OPENSSL_SSL_H
814         tcpip_state *state = (tcpip_state *)h->cprivate;
815         if (state->ctx)
816         {
817             int res = SSL_accept (state->ssl);
818             TRC(fprintf(stderr, "SSL_accept\n"));
819             if (res <= 0)
820             {
821                 int err = SSL_get_error(state->ssl, res);
822                 if (err == SSL_ERROR_WANT_READ)
823                 {
824                     h->io_pending = CS_WANT_READ;
825                     yaz_log (LOG_LOG, "SSL_accept. want_read");
826                     return h;
827                 }
828                 if (err == SSL_ERROR_WANT_WRITE)
829                 {
830                     h->io_pending = CS_WANT_WRITE;
831                     yaz_log (LOG_LOG, "SSL_accept. want_write");
832                     return h;
833                 }
834                 cs_close (h);
835                 return 0;
836             }
837         }
838 #endif
839     }
840     else
841     {
842         h->cerrno = CSOUTSTATE;
843         return 0;
844     }
845     h->io_pending = 0;
846     h->state = CS_DATAXFER;
847     h->event = CS_DATA;
848     return h;
849 }
850
851 #define CS_TCPIP_BUFCHUNK 4096
852
853 /*
854  * Return: -1 error, >1 good, len of buffer, ==1 incomplete buffer,
855  * 0=connection closed.
856  */
857 int tcpip_get(COMSTACK h, char **buf, int *bufsize)
858 {
859     tcpip_state *sp = (tcpip_state *)h->cprivate;
860     char *tmpc;
861     int tmpi, berlen, rest, req, tomove;
862     int hasread = 0, res;
863
864     TRC(fprintf(stderr, "tcpip_get: bufsize=%d\n", *bufsize));
865     if (sp->altlen) /* switch buffers */
866     {
867         TRC(fprintf(stderr, "  %d bytes in altbuf (0x%x)\n", sp->altlen,
868             (unsigned) sp->altbuf));
869         tmpc = *buf;
870         tmpi = *bufsize;
871         *buf = sp->altbuf;
872         *bufsize = sp->altsize;
873         hasread = sp->altlen;
874         sp->altlen = 0;
875         sp->altbuf = tmpc;
876         sp->altsize = tmpi;
877     }
878     h->io_pending = 0;
879     while (!(berlen = (*sp->complete)((unsigned char *)*buf, hasread)))
880     {
881         if (!*bufsize)
882         {
883             if (!(*buf = (char *)xmalloc(*bufsize = CS_TCPIP_BUFCHUNK)))
884                 return -1;
885         }
886         else if (*bufsize - hasread < CS_TCPIP_BUFCHUNK)
887             if (!(*buf =(char *)xrealloc(*buf, *bufsize *= 2)))
888                 return -1;
889         res = recv(h->iofile, *buf + hasread, CS_TCPIP_BUFCHUNK, 0);
890         TRC(fprintf(stderr, "  recv res=%d, hasread=%d\n", res, hasread));
891         if (res < 0)
892         {
893 #ifdef WIN32
894             if (WSAGetLastError() == WSAEWOULDBLOCK)
895             {
896                 h->io_pending = CS_WANT_READ;
897                 break;
898             }
899             else
900                 return -1;
901 #else
902             if (errno == EWOULDBLOCK 
903 #ifdef EAGAIN   
904 #if EAGAIN != EWOULDBLOCK
905                 || errno == EAGAIN
906 #endif
907 #endif
908                 || errno == EINPROGRESS
909                 )
910             {
911                 h->io_pending = CS_WANT_READ;
912                 break;
913             }
914             else if (errno == 0)
915                 continue;
916             else
917                 return -1;
918 #endif
919         }
920         else if (!res)
921             return 0;
922         hasread += res;
923     }
924     TRC (fprintf (stderr, "  Out of read loop with hasread=%d, berlen=%d\n",
925                   hasread, berlen));
926     /* move surplus buffer (or everything if we didn't get a BER rec.) */
927     if (hasread > berlen)
928     {
929         tomove = req = hasread - berlen;
930         rest = tomove % CS_TCPIP_BUFCHUNK;
931         if (rest)
932             req += CS_TCPIP_BUFCHUNK - rest;
933         if (!sp->altbuf)
934         {
935             if (!(sp->altbuf = (char *)xmalloc(sp->altsize = req)))
936                 return -1;
937         } else if (sp->altsize < req)
938             if (!(sp->altbuf =(char *)xrealloc(sp->altbuf, sp->altsize = req)))
939                 return -1;
940         TRC(fprintf(stderr, "  Moving %d bytes to altbuf(0x%x)\n", tomove,
941             (unsigned) sp->altbuf));
942         memcpy(sp->altbuf, *buf + berlen, sp->altlen = tomove);
943     }
944     if (berlen < CS_TCPIP_BUFCHUNK - 1)
945         *(*buf + berlen) = '\0';
946     return berlen ? berlen : 1;
947 }
948
949
950 #if HAVE_OPENSSL_SSL_H
951 /*
952  * Return: -1 error, >1 good, len of buffer, ==1 incomplete buffer,
953  * 0=connection closed.
954  */
955 int ssl_get(COMSTACK h, char **buf, int *bufsize)
956 {
957     tcpip_state *sp = (tcpip_state *)h->cprivate;
958     char *tmpc;
959     int tmpi, berlen, rest, req, tomove;
960     int hasread = 0, res;
961
962     TRC(fprintf(stderr, "ssl_get: bufsize=%d\n", *bufsize));
963     if (sp->altlen) /* switch buffers */
964     {
965         TRC(fprintf(stderr, "  %d bytes in altbuf (0x%x)\n", sp->altlen,
966             (unsigned) sp->altbuf));
967         tmpc = *buf;
968         tmpi = *bufsize;
969         *buf = sp->altbuf;
970         *bufsize = sp->altsize;
971         hasread = sp->altlen;
972         sp->altlen = 0;
973         sp->altbuf = tmpc;
974         sp->altsize = tmpi;
975     }
976     h->io_pending = 0;
977     while (!(berlen = (*sp->complete)((unsigned char *)*buf, hasread)))
978     {
979         if (!*bufsize)
980         {
981             if (!(*buf = (char *)xmalloc(*bufsize = CS_TCPIP_BUFCHUNK)))
982                 return -1;
983         }
984         else if (*bufsize - hasread < CS_TCPIP_BUFCHUNK)
985             if (!(*buf =(char *)xrealloc(*buf, *bufsize *= 2)))
986                 return -1;
987         res = SSL_read (sp->ssl, *buf + hasread, CS_TCPIP_BUFCHUNK);
988         TRC(fprintf(stderr, "  SSL_read res=%d, hasread=%d\n", res, hasread));
989         if (res <= 0)
990         {
991             int ssl_err = SSL_get_error(sp->ssl, res);
992             if (ssl_err == SSL_ERROR_WANT_READ)
993             {
994                 h->io_pending = CS_WANT_READ;
995                 yaz_log (LOG_LOG, "SSL_read. want_read");
996                 break;
997             }
998             if (ssl_err == SSL_ERROR_WANT_WRITE)
999             {
1000                 h->io_pending = CS_WANT_WRITE;
1001                 yaz_log (LOG_LOG, "SSL_read. want_write");
1002                 break;
1003             }
1004             if (res == 0)
1005                 return 0;
1006             h->cerrno = CSERRORSSL;
1007             return -1;
1008         }
1009         hasread += res;
1010     }
1011     TRC (fprintf (stderr, "  Out of read loop with hasread=%d, berlen=%d\n",
1012         hasread, berlen));
1013     /* move surplus buffer (or everything if we didn't get a BER rec.) */
1014     if (hasread > berlen)
1015     {
1016         tomove = req = hasread - berlen;
1017         rest = tomove % CS_TCPIP_BUFCHUNK;
1018         if (rest)
1019             req += CS_TCPIP_BUFCHUNK - rest;
1020         if (!sp->altbuf)
1021         {
1022             if (!(sp->altbuf = (char *)xmalloc(sp->altsize = req)))
1023                 return -1;
1024         } else if (sp->altsize < req)
1025             if (!(sp->altbuf =(char *)xrealloc(sp->altbuf, sp->altsize = req)))
1026                 return -1;
1027         TRC(fprintf(stderr, "  Moving %d bytes to altbuf(0x%x)\n", tomove,
1028             (unsigned) sp->altbuf));
1029         memcpy(sp->altbuf, *buf + berlen, sp->altlen = tomove);
1030     }
1031     if (berlen < CS_TCPIP_BUFCHUNK - 1)
1032         *(*buf + berlen) = '\0';
1033     return berlen ? berlen : 1;
1034 }
1035 #endif
1036
1037 /*
1038  * Returns 1, 0 or -1
1039  * In nonblocking mode, you must call again with same buffer while
1040  * return value is 1.
1041  */
1042 int tcpip_put(COMSTACK h, char *buf, int size)
1043 {
1044     int res;
1045     struct tcpip_state *state = (struct tcpip_state *)h->cprivate;
1046
1047     TRC(fprintf(stderr, "tcpip_put: size=%d\n", size));
1048     h->io_pending = 0;
1049     h->event = CS_DATA;
1050     if (state->towrite < 0)
1051     {
1052         state->towrite = size;
1053         state->written = 0;
1054     }
1055     else if (state->towrite != size)
1056     {
1057         h->cerrno = CSWRONGBUF;
1058         return -1;
1059     }
1060     while (state->towrite > state->written)
1061     {
1062         if ((res =
1063              send(h->iofile, buf + state->written, size -
1064                   state->written, 
1065 #ifdef MSG_NOSIGNAL
1066                   MSG_NOSIGNAL
1067 #else
1068                   0
1069 #endif
1070                  )) < 0)
1071         {
1072             if (
1073 #ifdef WIN32
1074                 WSAGetLastError() == WSAEWOULDBLOCK
1075 #else
1076                 errno == EWOULDBLOCK 
1077 #ifdef EAGAIN
1078 #if EAGAIN != EWOULDBLOCK
1079              || errno == EAGAIN
1080 #endif
1081 #endif
1082 #endif
1083                 )
1084             {
1085                 TRC(fprintf(stderr, "  Flow control stop\n"));
1086                 h->io_pending = CS_WANT_WRITE;
1087                 return 1;
1088             }
1089             h->cerrno = CSYSERR;
1090             return -1;
1091         }
1092         state->written += res;
1093         TRC(fprintf(stderr, "  Wrote %d, written=%d, nbytes=%d\n",
1094                     res, state->written, size));
1095     }
1096     state->towrite = state->written = -1;
1097     TRC(fprintf(stderr, "  Ok\n"));
1098     return 0;
1099 }
1100
1101
1102 #if HAVE_OPENSSL_SSL_H
1103 /*
1104  * Returns 1, 0 or -1
1105  * In nonblocking mode, you must call again with same buffer while
1106  * return value is 1.
1107  */
1108 int ssl_put(COMSTACK h, char *buf, int size)
1109 {
1110     int res;
1111     struct tcpip_state *state = (struct tcpip_state *)h->cprivate;
1112
1113     TRC(fprintf(stderr, "ssl_put: size=%d\n", size));
1114     h->io_pending = 0;
1115     h->event = CS_DATA;
1116     if (state->towrite < 0)
1117     {
1118         state->towrite = size;
1119         state->written = 0;
1120     }
1121     else if (state->towrite != size)
1122     {
1123         h->cerrno = CSWRONGBUF;
1124         return -1;
1125     }
1126     while (state->towrite > state->written)
1127     {
1128         res = SSL_write (state->ssl, buf + state->written,
1129                          size - state->written);
1130         if (res <= 0)
1131         {
1132             int ssl_err = SSL_get_error(state->ssl, res);
1133             if (ssl_err == SSL_ERROR_WANT_READ)
1134             {
1135                 h->io_pending = CS_WANT_READ;
1136                 yaz_log (LOG_LOG, "SSL_write. want_read");
1137                 return 1;
1138             }
1139             if (ssl_err == SSL_ERROR_WANT_WRITE)
1140             {
1141                 h->io_pending = CS_WANT_WRITE;
1142                 yaz_log (LOG_LOG, "SSL_write. want_write");
1143                 return 1;
1144             }
1145             h->cerrno = CSERRORSSL;
1146             return -1;
1147         }
1148         state->written += res;
1149         TRC(fprintf(stderr, "  Wrote %d, written=%d, nbytes=%d\n",
1150                     res, state->written, size));
1151     }
1152     state->towrite = state->written = -1;
1153     TRC(fprintf(stderr, "  Ok\n"));
1154     return 0;
1155 }
1156 #endif
1157
1158 int tcpip_close(COMSTACK h)
1159 {
1160     tcpip_state *sp = (struct tcpip_state *)h->cprivate;
1161
1162     TRC(fprintf(stderr, "tcpip_close\n"));
1163     if (h->iofile != -1)
1164     {
1165 #if HAVE_OPENSSL_SSL_H
1166         if (sp->ssl)
1167         {
1168             SSL_shutdown (sp->ssl);
1169         }
1170 #endif
1171 #ifdef WIN32
1172         closesocket(h->iofile);
1173 #else
1174         close(h->iofile);
1175 #endif
1176     }
1177     if (sp->altbuf)
1178         xfree(sp->altbuf);
1179 #if HAVE_OPENSSL_SSL_H
1180     if (sp->ssl)
1181     {
1182         TRC (fprintf(stderr, "SSL_free\n"));
1183         SSL_free (sp->ssl);
1184     }
1185     sp->ssl = 0;
1186     if (sp->ctx_alloc)
1187         SSL_CTX_free (sp->ctx_alloc);
1188 #endif
1189     xfree(sp);
1190     xfree(h);
1191     return 0;
1192 }
1193
1194 char *tcpip_addrstr(COMSTACK h)
1195 {
1196     struct sockaddr_in addr;
1197     tcpip_state *sp = (struct tcpip_state *)h->cprivate;
1198     char *r, *buf = sp->buf;
1199     size_t len;
1200     struct hostent *host;
1201     
1202     len = sizeof(addr);
1203     if (getpeername(h->iofile, (struct sockaddr*) &addr, &len) < 0)
1204     {
1205         h->cerrno = CSYSERR;
1206         return 0;
1207     }
1208     if ((host = gethostbyaddr((char*)&addr.sin_addr, sizeof(addr.sin_addr),
1209                               AF_INET)))
1210         r = (char*) host->h_name;
1211     else
1212         r = inet_ntoa(addr.sin_addr);
1213     sprintf(buf, "tcp:%s", r);
1214 #if HAVE_OPENSSL_SSL_H
1215     if (sp->ctx)
1216         sprintf(buf, "ssl:%s", r);
1217 #endif
1218     return buf;
1219 }
1220
1221 int static tcpip_set_blocking(COMSTACK p, int blocking)
1222 {
1223     unsigned long flag;
1224     
1225     if (p->blocking == blocking)
1226         return 1;
1227 #ifdef WIN32
1228     flag = 1;
1229     if (ioctlsocket(p->iofile, FIONBIO, &flag) < 0)
1230         return 0;
1231 #else
1232     flag = fcntl(p->iofile, F_GETFL, 0);
1233     if(!blocking)
1234         flag = flag & ~O_NONBLOCK;
1235     else
1236         flag = flag | O_NONBLOCK;
1237     if (fcntl(p->iofile, F_SETFL, flag) < 0)
1238         return 0;
1239 #endif
1240     p->blocking = blocking;
1241     return 1;
1242 }