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