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