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