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