24e205a85f64e1b3766230397393139222e33fe4
[yaz-moved-to-github.git] / src / tcpip.c
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) 1995-2008 Index Data
3  * See the file LICENSE for details.
4  */
5 /**
6  * \file tcpip.c
7  * \brief Implements TCP/IP + SSL COMSTACK.
8  */
9
10 #include <stdio.h>
11 #include <string.h>
12 #include <stdlib.h>
13 #include <errno.h>
14 #include <fcntl.h>
15 #include <signal.h>
16 #if HAVE_SYS_TYPES_H
17 #include <sys/types.h>
18 #endif
19 #if HAVE_SYS_TIME_H
20 #include <sys/time.h>
21 #endif
22 #if HAVE_UNISTD_H
23 #include <unistd.h>
24 #endif
25
26 #ifdef WIN32
27
28 /* VS 2003 or later has getaddrinfo; older versions do not */
29 #include <winsock2.h>
30 #if _MSC_VER >= 1300
31 #include <ws2tcpip.h>
32 #define HAVE_GETADDRINFO 1
33 #else
34 #define HAVE_GETADDRINFO 0
35 #endif
36
37 #else
38 #include <netinet/in.h>
39 #include <netdb.h>
40 #include <arpa/inet.h>
41 #include <netinet/tcp.h>
42 #endif
43
44 #if HAVE_SYS_SOCKET_H
45 #include <sys/socket.h>
46 #endif
47 #if HAVE_SYS_WAIT_H
48 #include <sys/wait.h>
49 #endif
50
51 #if HAVE_GNUTLS_H
52 #include <gnutls/openssl.h>
53 #define ENABLE_SSL 1
54 #endif
55
56 #if HAVE_OPENSSL_SSL_H
57 #include <openssl/ssl.h>
58 #include <openssl/err.h>
59 #define ENABLE_SSL 1
60 #endif
61
62 #include <yaz/comstack.h>
63 #include <yaz/tcpip.h>
64 #include <yaz/nmem.h>
65
66 static int tcpip_close(COMSTACK h);
67 static int tcpip_put(COMSTACK h, char *buf, int size);
68 static int tcpip_get(COMSTACK h, char **buf, int *bufsize);
69 static int tcpip_put_connect(COMSTACK h, char *buf, int size);
70 static int tcpip_get_connect(COMSTACK h, char **buf, int *bufsize);
71 static int tcpip_connect(COMSTACK h, void *address);
72 static int tcpip_more(COMSTACK h);
73 static int tcpip_rcvconnect(COMSTACK h);
74 static int tcpip_bind(COMSTACK h, void *address, int mode);
75 static int tcpip_listen(COMSTACK h, char *raddr, int *addrlen,
76                  int (*check_ip)(void *cd, const char *a, int len, int type),
77                  void *cd);
78 static int tcpip_set_blocking(COMSTACK p, int blocking);
79
80 #if ENABLE_SSL
81 static int ssl_get(COMSTACK h, char **buf, int *bufsize);
82 static int ssl_put(COMSTACK h, char *buf, int size);
83 #endif
84
85 static COMSTACK tcpip_accept(COMSTACK h);
86 static char *tcpip_addrstr(COMSTACK h);
87 static void *tcpip_straddr(COMSTACK h, const char *str);
88
89 #if 0
90 #define TRC(x) x
91 #else
92 #define TRC(X)
93 #endif
94
95 #ifndef YAZ_SOCKLEN_T
96 #define YAZ_SOCKLEN_T int
97 #endif
98
99 /* this state is used for both SSL and straight TCP/IP */
100 typedef struct tcpip_state
101 {
102     char *altbuf; /* alternate buffer for surplus data */
103     int altsize;  /* size as xmalloced */
104     int altlen;   /* length of data or 0 if none */
105
106     int written;  /* -1 if we aren't writing */
107     int towrite;  /* to verify against user input */
108     int (*complete)(const char *buf, int len); /* length/complete. */
109 #if HAVE_GETADDRINFO
110     struct addrinfo *ai;
111 #else
112     struct sockaddr_in addr;  /* returned by cs_straddr */
113 #endif
114     char buf[128]; /* returned by cs_addrstr */
115 #if ENABLE_SSL
116     SSL_CTX *ctx;       /* current CTX. */
117     SSL_CTX *ctx_alloc; /* If =ctx it is owned by CS. If 0 it is not owned */
118     SSL *ssl;
119     char cert_fname[256];
120 #endif
121     char *connect_request_buf;
122     int connect_request_len;
123     char *connect_response_buf;
124     int connect_response_len;
125 } tcpip_state;
126
127 #ifdef WIN32
128 static int tcpip_init (void)
129 {
130     static int initialized = 0;
131     if (!initialized)
132     {
133         WORD requested;
134         WSADATA wd;
135
136         requested = MAKEWORD(1, 1);
137         if (WSAStartup(requested, &wd))
138             return 0;
139         initialized = 1;
140     }
141     return 1;
142 }
143 #else
144 static int tcpip_init (void)
145 {
146     return 1;
147 }
148 #endif
149
150 /*
151  * This function is always called through the cs_create() macro.
152  * s >= 0: socket has already been established for us.
153  */
154 COMSTACK tcpip_type(int s, int flags, int protocol, void *vp)
155 {
156     COMSTACK p;
157     tcpip_state *sp;
158
159     if (!tcpip_init ())
160         return 0;
161     if (!(p = (struct comstack *)xmalloc(sizeof(struct comstack))))
162         return 0;
163     if (!(sp = (struct tcpip_state *)(p->cprivate =
164                                          xmalloc(sizeof(tcpip_state)))))
165         return 0;
166
167     p->flags = flags;
168
169     p->io_pending = 0;
170     p->iofile = s;
171     p->type = tcpip_type;
172     p->protocol = (enum oid_proto) protocol;
173
174     p->f_connect = tcpip_connect;
175     p->f_rcvconnect = tcpip_rcvconnect;
176     p->f_get = tcpip_get;
177     p->f_put = tcpip_put;
178     p->f_close = tcpip_close;
179     p->f_more = tcpip_more;
180     p->f_bind = tcpip_bind;
181     p->f_listen = tcpip_listen;
182     p->f_accept = tcpip_accept;
183     p->f_addrstr = tcpip_addrstr;
184     p->f_straddr = tcpip_straddr;
185     p->f_set_blocking = tcpip_set_blocking;
186     p->max_recv_bytes = 5000000;
187
188     p->state = s < 0 ? CS_ST_UNBND : CS_ST_IDLE; /* state of line */
189     p->event = CS_NONE;
190     p->cerrno = 0;
191     p->stackerr = 0;
192     p->user = 0;
193
194 #if ENABLE_SSL
195     sp->ctx = sp->ctx_alloc = 0;
196     sp->ssl = 0;
197     strcpy(sp->cert_fname, "yaz.pem");
198 #endif
199
200 #if HAVE_GETADDRINFO
201     sp->ai = 0;
202 #endif
203     sp->altbuf = 0;
204     sp->altsize = sp->altlen = 0;
205     sp->towrite = sp->written = -1;
206     if (protocol == PROTO_WAIS)
207         sp->complete = completeWAIS;
208     else
209         sp->complete = cs_complete_auto;
210
211     sp->connect_request_buf = 0;
212     sp->connect_request_len = 0;
213     sp->connect_response_buf = 0;
214     sp->connect_response_len = 0;
215
216     p->timeout = COMSTACK_DEFAULT_TIMEOUT;
217     TRC(fprintf(stderr, "Created new TCPIP comstack\n"));
218
219     return p;
220 }
221
222 COMSTACK yaz_tcpip_create(int s, int flags, int protocol,
223                           const char *connect_host)
224 {
225     COMSTACK p = tcpip_type(s, flags, protocol, 0);
226     if (!p)
227         return 0;
228     if (connect_host)
229     {
230         tcpip_state *sp = (tcpip_state *) p->cprivate;
231         sp->connect_request_buf = (char *) xmalloc(strlen(connect_host) + 30);
232         sprintf(sp->connect_request_buf, "CONNECT %s HTTP/1.0\r\n\r\n",
233                 connect_host);
234         sp->connect_request_len = strlen(sp->connect_request_buf);
235         p->f_put = tcpip_put_connect;
236         p->f_get = tcpip_get_connect;
237         sp->complete = cs_complete_auto_head; /* only want HTTP header */
238     }
239     return p;
240 }
241
242
243 #if ENABLE_SSL
244
245 COMSTACK ssl_type(int s, int flags, int protocol, void *vp)
246 {
247     tcpip_state *sp;
248     COMSTACK p;
249
250     p = tcpip_type (s, flags, protocol, 0);
251     if (!p)
252         return 0;
253     p->f_get = ssl_get;
254     p->f_put = ssl_put;
255     p->type = ssl_type;
256     sp = (tcpip_state *) p->cprivate;
257
258     sp->ctx = (SSL_CTX *) vp;  /* may be NULL */
259
260     /* note: we don't handle already opened socket in SSL mode - yet */
261     return p;
262 }
263 #endif
264
265 #if HAVE_GETADDRINFO
266 /* resolve using getaddrinfo */
267 struct addrinfo *tcpip_getaddrinfo(const char *str, const char *port)
268 {
269     struct addrinfo hints, *res;
270     int error;
271     char host[512], *p;
272
273     hints.ai_flags = 0;
274     hints.ai_family = AF_UNSPEC;
275     hints.ai_socktype = SOCK_STREAM;
276     hints.ai_protocol = 0;
277     hints.ai_addrlen        = 0;
278     hints.ai_addr           = NULL;
279     hints.ai_canonname      = NULL;
280     hints.ai_next           = NULL;
281
282     strncpy(host, str, sizeof(host)-1);
283     host[sizeof(host)-1] = 0;
284     if ((p = strchr(host, '/')))
285         *p = 0;
286     if ((p = strrchr(host, ':')))
287     {
288         *p = '\0';
289         port = p+1;
290     }
291
292     if (!strcmp("@", host))
293     {
294         hints.ai_flags = AI_PASSIVE;
295         error = getaddrinfo(0, port, &hints, &res);
296     }
297     else
298     {
299         error = getaddrinfo(host, port, &hints, &res);
300     }
301     if (error)
302         return 0;
303     return res;
304 }
305
306 #endif
307 /* gethostbyname .. old systems */
308 int tcpip_strtoaddr_ex(const char *str, struct sockaddr_in *add,
309                        int default_port)
310 {
311     struct hostent *hp;
312     char *p, buf[512];
313     short int port = default_port;
314 #ifdef WIN32
315     unsigned long tmpadd;
316 #else
317     in_addr_t tmpadd;
318 #endif
319     TRC(fprintf(stderr, "tcpip_strtoaddress: %s\n", str ? str : "NULL"));
320     add->sin_family = AF_INET;
321     strncpy(buf, str, sizeof(buf)-1);
322     buf[sizeof(buf)-1] = 0;
323     if ((p = strchr(buf, '/')))
324         *p = 0;
325     if ((p = strrchr(buf, ':')))
326     {
327         *p = 0;
328         port = atoi(p + 1);
329     }
330     add->sin_port = htons(port);
331     if (!strcmp("@", buf))
332     {
333         add->sin_addr.s_addr = INADDR_ANY;
334     }
335     else if ((tmpadd = inet_addr(buf)) != -1)
336     {
337         memcpy(&add->sin_addr.s_addr, &tmpadd, sizeof(struct in_addr));
338     }
339     else if ((hp = gethostbyname(buf)))
340     {
341         memcpy(&add->sin_addr.s_addr, *hp->h_addr_list,
342                sizeof(struct in_addr));
343     }
344     else
345         return 0;
346     return 1;
347 }
348
349
350 #if HAVE_GETADDRINFO
351 void *tcpip_straddr(COMSTACK h, const char *str)
352 {
353     tcpip_state *sp = (tcpip_state *)h->cprivate;
354     const char *port = "210";
355     if (h->protocol == PROTO_HTTP)
356         port = "80";
357     if (!tcpip_init ())
358         return 0;
359
360     if (sp->ai)
361         freeaddrinfo(sp->ai);
362     sp->ai = tcpip_getaddrinfo(str, port);
363     if (sp->ai && h->state == CS_ST_UNBND)
364     {
365         int s = -1;
366         struct addrinfo *ai = sp->ai;
367         for (; ai; ai = ai->ai_next)
368         {
369             s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
370             if (s != -1)
371                 break;
372         }
373         if (s == -1)
374             return 0;
375         h->iofile = s;
376         
377         if (!tcpip_set_blocking(h, h->flags))
378             return 0;
379     }
380     return sp->ai;
381 }
382 #else
383 void *tcpip_straddr(COMSTACK h, const char *str)
384 {
385     tcpip_state *sp = (tcpip_state *)h->cprivate;
386     int port = 210;
387     if (h->protocol == PROTO_HTTP)
388         port = 80;
389
390     if (!tcpip_init ())
391         return 0;
392     if (!tcpip_strtoaddr_ex (str, &sp->addr, port))
393         return 0;
394     if (h->state == CS_ST_UNBND)
395     {
396         int s;
397         s = socket(AF_INET, SOCK_STREAM, 0);
398         if (s < 0)
399             return 0;
400         h->iofile = s;
401
402         if (!tcpip_set_blocking(h, h->flags))
403             return 0;
404     }
405     return &sp->addr;
406 }
407 #endif
408
409 int tcpip_more(COMSTACK h)
410 {
411     tcpip_state *sp = (tcpip_state *)h->cprivate;
412     
413     return sp->altlen && (*sp->complete)(sp->altbuf, sp->altlen);
414 }
415
416 /*
417  * connect(2) will block (sometimes) - nothing we can do short of doing
418  * weird things like spawning subprocesses or threading or some weird junk
419  * like that.
420  */
421 int tcpip_connect(COMSTACK h, void *address)
422 {
423 #if HAVE_GETADDRINFO
424     tcpip_state *sp = (tcpip_state *)h->cprivate;
425 #else
426     struct sockaddr_in *add = (struct sockaddr_in *) address;
427 #endif
428     int r;
429 #ifdef __sun__
430     int recbuflen;
431     YAZ_SOCKLEN_T rbufsize = sizeof(recbuflen);
432 #endif
433     TRC(fprintf(stderr, "tcpip_connect\n"));
434     h->io_pending = 0;
435     if (h->state != CS_ST_UNBND)
436     {
437         h->cerrno = CSOUTSTATE;
438         return -1;
439     }
440 #if HAVE_GETADDRINFO
441     if (sp->ai != (struct addrinfo *) address)
442     {
443         h->cerrno = CSOUTSTATE;
444         return -1;
445     }
446 #endif
447 #ifdef __sun__
448     /* On Suns, you must set a bigger Receive Buffer BEFORE a call to connect
449      * This gives the connect a chance to negotiate with the other side
450      * (see 'man tcp') 
451      */
452     if ( getsockopt(h->iofile, SOL_SOCKET, SO_RCVBUF, (void *)&recbuflen, &rbufsize ) < 0 )
453     {
454         h->cerrno = CSYSERR;
455         return -1;
456     }
457     TRC(fprintf( stderr, "Current Size of TCP Receive Buffer= %d\n",
458                  recbuflen ));
459     recbuflen *= 10; /* lets be optimistic */
460     if ( setsockopt(h->iofile, SOL_SOCKET, SO_RCVBUF, (void *)&recbuflen, rbufsize ) < 0 )
461     {
462         h->cerrno = CSYSERR;
463         return -1;
464     }
465     if ( getsockopt(h->iofile, SOL_SOCKET, SO_RCVBUF, (void *)&recbuflen, &rbufsize ) )
466     {
467         h->cerrno = CSYSERR;
468         return -1;
469     }
470     TRC(fprintf( stderr, "New Size of TCP Receive Buffer = %d\n",
471                  recbuflen ));
472 #endif
473
474 #if HAVE_GETADDRINFO
475     r = connect(h->iofile, sp->ai->ai_addr, sp->ai->ai_addrlen);
476     freeaddrinfo(sp->ai);
477     sp->ai = 0;
478 #else
479     r = connect(h->iofile, (struct sockaddr *) add, sizeof(*add));
480 #endif
481     if (r < 0)
482     {
483 #ifdef WIN32
484         if (WSAGetLastError() == WSAEWOULDBLOCK)
485         {
486             h->event = CS_CONNECT;
487             h->state = CS_ST_CONNECTING;
488             h->io_pending = CS_WANT_WRITE;
489             return 1;
490         }
491 #else
492         if (yaz_errno() == EINPROGRESS)
493         {
494             h->event = CS_CONNECT;
495             h->state = CS_ST_CONNECTING;
496             h->io_pending = CS_WANT_WRITE|CS_WANT_READ;
497             return 1;
498         }
499 #endif
500         h->cerrno = CSYSERR;
501         return -1;
502     }
503     h->event = CS_CONNECT;
504     h->state = CS_ST_CONNECTING;
505
506     return tcpip_rcvconnect (h);
507 }
508
509 /*
510  * nop
511  */
512 int tcpip_rcvconnect(COMSTACK h)
513 {
514 #if ENABLE_SSL
515     tcpip_state *sp = (tcpip_state *)h->cprivate;
516 #endif
517     TRC(fprintf(stderr, "tcpip_rcvconnect\n"));
518
519     if (h->state == CS_ST_DATAXFER)
520         return 0;
521     if (h->state != CS_ST_CONNECTING)
522     {
523         h->cerrno = CSOUTSTATE;
524         return -1;
525     }
526 #if ENABLE_SSL
527     if (h->type == ssl_type && !sp->ctx)
528     {
529         SSL_library_init();
530         SSL_load_error_strings();
531
532         sp->ctx = sp->ctx_alloc = SSL_CTX_new (SSLv23_client_method());
533         if (!sp->ctx)
534         {
535             h->cerrno = CSERRORSSL;
536             return -1;
537         }
538     }
539     if (sp->ctx)
540     {
541         int res;
542
543         if (!sp->ssl)
544         {
545             sp->ssl = SSL_new (sp->ctx);
546             SSL_set_fd (sp->ssl, h->iofile);
547         }
548         res = SSL_connect (sp->ssl);
549         if (res <= 0)
550         {
551             int err = SSL_get_error(sp->ssl, res);
552             if (err == SSL_ERROR_WANT_READ)
553             {
554                 h->io_pending = CS_WANT_READ;
555                 return 1;
556             }
557             if (err == SSL_ERROR_WANT_WRITE)
558             {
559                 h->io_pending = CS_WANT_WRITE;
560                 return 1;
561             }
562             h->cerrno = CSERRORSSL;
563             return -1;
564         }
565     }
566 #endif
567     h->event = CS_DATA;
568     h->state = CS_ST_DATAXFER;
569     return 0;
570 }
571
572 #define CERTF "ztest.pem"
573 #define KEYF "ztest.pem"
574
575 static void tcpip_setsockopt (int fd)
576 {
577 #if 0
578     int len = 4096;
579     int set = 1;
580     
581     if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char*)&set, sizeof(int)))
582     {
583         yaz_log(LOG_WARN|LOG_ERRNO, "setsockopt TCP_NODELAY");
584     }
585     if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (char*)&len, sizeof(int)))
586     {
587         yaz_log(LOG_WARN|LOG_ERRNO, "setsockopt SNDBUF");
588     }
589     if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char*)&len, sizeof(int)))
590     {
591         yaz_log(LOG_WARN|LOG_ERRNO, "setsockopt RCVBUF");
592     }
593 #endif
594 }
595
596 static int tcpip_bind(COMSTACK h, void *address, int mode)
597 {
598     int r;
599     tcpip_state *sp = (tcpip_state *)h->cprivate;
600 #if HAVE_GETADDRINFO
601 #else
602     struct sockaddr *addr = (struct sockaddr *)address;
603 #endif
604 #ifdef WIN32
605     BOOL one = 1;
606 #else
607     int one = 1;
608 #endif
609
610 #if HAVE_GETADDRINFO
611     if (sp->ai != (struct addrinfo *) address)
612     {
613         h->cerrno = CSOUTSTATE;
614         return -1;
615     }
616 #endif
617
618 #if ENABLE_SSL
619     if (h->type == ssl_type && !sp->ctx)
620     {
621         SSL_library_init();
622         SSL_load_error_strings();
623
624         sp->ctx = sp->ctx_alloc = SSL_CTX_new (SSLv23_server_method());
625         if (!sp->ctx)
626         {
627             h->cerrno = CSERRORSSL;
628             return -1;
629         }
630     }
631     if (sp->ctx)
632     {
633         if (sp->ctx_alloc)
634         {
635             int res;
636             res = SSL_CTX_use_certificate_file(sp->ctx, sp->cert_fname,
637                                                SSL_FILETYPE_PEM);
638             if (res <= 0)
639             {
640 #if HAVE_OPENSSL_SSL_H
641                 ERR_print_errors_fp(stderr);
642 #else
643                 fprintf(stderr, " SSL_CTX_use_certificate_file %s failed\n",
644                         sp->cert_fname);
645 #endif
646                 exit (2);
647             }
648             res = SSL_CTX_use_PrivateKey_file (sp->ctx, sp->cert_fname,
649                                                SSL_FILETYPE_PEM);
650             if (res <= 0)
651             {
652 #if HAVE_OPENSSL_SSL_H
653                 ERR_print_errors_fp(stderr);
654 #else
655                 fprintf(stderr, " SSL_CTX_use_certificate_file %s failed\n",
656                         sp->cert_fname);
657 #endif
658                 exit (3);
659             }
660 #if HAVE_OPENSSL_SSL_H
661             res = SSL_CTX_check_private_key (sp->ctx);
662             if (res <= 0)
663             {
664                 ERR_print_errors_fp(stderr);
665                 exit(5);
666             }
667 #endif
668         }
669         TRC (fprintf (stderr, "ssl_bind\n"));
670     }
671     else
672     {
673         TRC (fprintf (stderr, "tcpip_bind\n"));
674     }
675 #else
676     TRC (fprintf (stderr, "tcpip_bind\n"));
677 #endif
678 #ifndef WIN32
679     if (setsockopt(h->iofile, SOL_SOCKET, SO_REUSEADDR, (char*) 
680         &one, sizeof(one)) < 0)
681     {
682         h->cerrno = CSYSERR;
683         return -1;
684     }
685 #endif
686     tcpip_setsockopt(h->iofile);
687 #if HAVE_GETADDRINFO
688     r = bind(h->iofile, sp->ai->ai_addr, sp->ai->ai_addrlen);
689     freeaddrinfo(sp->ai);
690     sp->ai = 0;
691 #else
692     r = bind(h->iofile, addr, sizeof(struct sockaddr_in));
693 #endif
694     if (r)
695     {
696         h->cerrno = CSYSERR;
697         return -1;
698     }
699     /* Allow a maximum-sized backlog of waiting-to-connect clients */
700     if (mode == CS_SERVER && listen(h->iofile, SOMAXCONN) < 0)
701     {
702         h->cerrno = CSYSERR;
703         return -1;
704     }
705     h->state = CS_ST_IDLE;
706     h->event = CS_LISTEN;
707     return 0;
708 }
709
710 int tcpip_listen(COMSTACK h, char *raddr, int *addrlen,
711                  int (*check_ip)(void *cd, const char *a, int len, int t),
712                  void *cd)
713 {
714     struct sockaddr_in addr;
715     YAZ_SOCKLEN_T len = sizeof(addr);
716
717     TRC(fprintf(stderr, "tcpip_listen pid=%d\n", getpid()));
718     if (h->state != CS_ST_IDLE)
719     {
720         h->cerrno = CSOUTSTATE;
721         return -1;
722     }
723     h->newfd = accept(h->iofile, (struct sockaddr*)&addr, &len);
724     if (h->newfd < 0)
725     {
726         if (
727 #ifdef WIN32
728             WSAGetLastError() == WSAEWOULDBLOCK
729 #else
730             yaz_errno() == EWOULDBLOCK 
731 #ifdef EAGAIN
732 #if EAGAIN != EWOULDBLOCK
733             || yaz_errno() == EAGAIN
734 #endif
735 #endif
736 #endif
737             )
738             h->cerrno = CSNODATA;
739         else
740         {
741 #ifdef WIN32
742             shutdown(h->iofile, SD_RECEIVE);
743 #else
744             shutdown(h->iofile, SHUT_RD);
745 #endif
746             listen(h->iofile, SOMAXCONN);
747             h->cerrno = CSYSERR;
748         }
749         return -1;
750     }
751     if (addrlen && (size_t) (*addrlen) >= sizeof(struct sockaddr_in))
752         memcpy(raddr, &addr, *addrlen = sizeof(struct sockaddr_in));
753     else if (addrlen)
754         *addrlen = 0;
755     if (check_ip && (*check_ip)(cd, (const char *) &addr,
756         sizeof(addr), AF_INET))
757     {
758         h->cerrno = CSDENY;
759 #ifdef WIN32
760         closesocket(h->newfd);
761 #else
762         close(h->newfd);
763 #endif
764         h->newfd = -1;
765         return -1;
766     }
767     h->state = CS_ST_INCON;
768     tcpip_setsockopt (h->newfd);
769     return 0;
770 }
771
772 COMSTACK tcpip_accept(COMSTACK h)
773 {
774     COMSTACK cnew;
775     tcpip_state *state, *st = (tcpip_state *)h->cprivate;
776 #ifdef WIN32
777     unsigned long tru = 1;
778 #endif
779
780     TRC(fprintf(stderr, "tcpip_accept\n"));
781     if (h->state == CS_ST_INCON)
782     {
783         if (!(cnew = (COMSTACK)xmalloc(sizeof(*cnew))))
784         {
785             h->cerrno = CSYSERR;
786 #ifdef WIN32
787             closesocket(h->newfd);
788 #else
789             close(h->newfd);
790 #endif
791             h->newfd = -1;
792             return 0;
793         }
794         memcpy(cnew, h, sizeof(*h));
795         cnew->iofile = h->newfd;
796         cnew->io_pending = 0;
797         if (!(state = (tcpip_state *)
798               (cnew->cprivate = xmalloc(sizeof(tcpip_state)))))
799         {
800             h->cerrno = CSYSERR;
801             if (h->newfd != -1)
802             {
803 #ifdef WIN32
804                 closesocket(h->newfd);
805 #else
806                 close(h->newfd);
807 #endif
808                 h->newfd = -1;
809             }
810             return 0;
811         }
812         if (!tcpip_set_blocking(cnew, cnew->flags))
813         {
814             h->cerrno = CSYSERR;
815             if (h->newfd != -1)
816             {
817 #ifdef WIN32
818                 closesocket(h->newfd);
819 #else
820                 close(h->newfd);
821 #endif
822                 h->newfd = -1;
823             }
824             xfree (cnew);
825             xfree (state);
826             return 0;
827         }
828         h->newfd = -1;
829         state->altbuf = 0;
830         state->altsize = state->altlen = 0;
831         state->towrite = state->written = -1;
832         state->complete = st->complete;
833 #if HAVE_GETADDRINFO
834         state->ai = 0;
835 #endif
836         cnew->state = CS_ST_ACCEPT;
837         h->state = CS_ST_IDLE;
838         
839 #if ENABLE_SSL
840         state->ctx = st->ctx;
841         state->ctx_alloc = 0;
842         state->ssl = st->ssl;
843         if (state->ctx)
844         {
845             state->ssl = SSL_new (state->ctx);
846             SSL_set_fd (state->ssl, cnew->iofile);
847         }
848 #endif
849         state->connect_request_buf = 0;
850         state->connect_response_buf = 0;
851         h = cnew;
852     }
853     if (h->state == CS_ST_ACCEPT)
854     {
855 #if ENABLE_SSL
856         tcpip_state *state = (tcpip_state *)h->cprivate;
857         if (state->ctx)
858         {
859             int res = SSL_accept (state->ssl);
860             TRC(fprintf(stderr, "SSL_accept\n"));
861             if (res <= 0)
862             {
863                 int err = SSL_get_error(state->ssl, res);
864                 if (err == SSL_ERROR_WANT_READ)
865                 {
866                     h->io_pending = CS_WANT_READ;
867                     return h;
868                 }
869                 if (err == SSL_ERROR_WANT_WRITE)
870                 {
871                     h->io_pending = CS_WANT_WRITE;
872                     return h;
873                 }
874                 cs_close (h);
875                 return 0;
876             }
877         }
878 #endif
879     }
880     else
881     {
882         h->cerrno = CSOUTSTATE;
883         return 0;
884     }
885     h->io_pending = 0;
886     h->state = CS_ST_DATAXFER;
887     h->event = CS_DATA;
888     return h;
889 }
890
891 #define CS_TCPIP_BUFCHUNK 4096
892
893 /*
894  * Return: -1 error, >1 good, len of buffer, ==1 incomplete buffer,
895  * 0=connection closed.
896  */
897 int tcpip_get(COMSTACK h, char **buf, int *bufsize)
898 {
899     tcpip_state *sp = (tcpip_state *)h->cprivate;
900     char *tmpc;
901     int tmpi, berlen, rest, req, tomove;
902     int hasread = 0, res;
903
904     TRC(fprintf(stderr, "tcpip_get: bufsize=%d\n", *bufsize));
905     if (sp->altlen) /* switch buffers */
906     {
907         TRC(fprintf(stderr, "  %d bytes in altbuf (0x%x)\n", sp->altlen,
908             (unsigned) sp->altbuf));
909         tmpc = *buf;
910         tmpi = *bufsize;
911         *buf = sp->altbuf;
912         *bufsize = sp->altsize;
913         hasread = sp->altlen;
914         sp->altlen = 0;
915         sp->altbuf = tmpc;
916         sp->altsize = tmpi;
917     }
918     h->io_pending = 0;
919     while (!(berlen = (*sp->complete)(*buf, hasread)))
920     {
921         if (!*bufsize)
922         {
923             if (!(*buf = (char *)xmalloc(*bufsize = CS_TCPIP_BUFCHUNK)))
924             {
925                 h->cerrno = CSYSERR;
926                 return -1;
927             }
928         }
929         else if (*bufsize - hasread < CS_TCPIP_BUFCHUNK)
930             if (!(*buf =(char *)xrealloc(*buf, *bufsize *= 2)))
931             {
932                 h->cerrno = CSYSERR;
933                 return -1;
934             }
935 #ifdef __sun__
936         yaz_set_errno( 0 );
937         /* unfortunatly, sun sometimes forgets to set errno in recv
938            when EWOULDBLOCK etc. would be required (res = -1) */
939 #endif
940         res = recv(h->iofile, *buf + hasread, CS_TCPIP_BUFCHUNK, 0);
941         TRC(fprintf(stderr, "  recv res=%d, hasread=%d\n", res, hasread));
942         if (res < 0)
943         {
944             TRC(fprintf(stderr, "  recv errno=%d, (%s)\n", yaz_errno(), 
945                       strerror(yaz_errno())));
946 #ifdef WIN32
947             if (WSAGetLastError() == WSAEWOULDBLOCK)
948             {
949                 h->io_pending = CS_WANT_READ;
950                 break;
951             }
952             else
953             {
954                 h->cerrno = CSYSERR;
955                 return -1;
956             }
957 #else
958             if (yaz_errno() == EWOULDBLOCK 
959 #ifdef EAGAIN   
960 #if EAGAIN != EWOULDBLOCK
961                 || yaz_errno() == EAGAIN
962 #endif
963 #endif
964                 || yaz_errno() == EINPROGRESS
965 #ifdef __sun__
966                 || yaz_errno() == ENOENT /* Sun's sometimes set errno to this */
967 #endif
968                 )
969             {
970                 h->io_pending = CS_WANT_READ;
971                 break;
972             }
973             else if (yaz_errno() == 0)
974                 continue;
975             else
976             {
977                 h->cerrno = CSYSERR;
978                 return -1;
979             }
980 #endif
981         }
982         else if (!res)
983             return hasread;
984         hasread += res;
985         if (hasread > h->max_recv_bytes)
986         {
987             h->cerrno = CSBUFSIZE;
988             return -1;
989         }
990     }
991     TRC (fprintf (stderr, "  Out of read loop with hasread=%d, berlen=%d\n",
992                   hasread, berlen));
993     /* move surplus buffer (or everything if we didn't get a BER rec.) */
994     if (hasread > berlen)
995     {
996         tomove = req = hasread - berlen;
997         rest = tomove % CS_TCPIP_BUFCHUNK;
998         if (rest)
999             req += CS_TCPIP_BUFCHUNK - rest;
1000         if (!sp->altbuf)
1001         {
1002             if (!(sp->altbuf = (char *)xmalloc(sp->altsize = req)))
1003             {
1004                 h->cerrno = CSYSERR;
1005                 return -1;
1006             }
1007         } else if (sp->altsize < req)
1008             if (!(sp->altbuf =(char *)xrealloc(sp->altbuf, sp->altsize = req)))
1009             {
1010                 h->cerrno = CSYSERR;
1011                 return -1;
1012             }
1013         TRC(fprintf(stderr, "  Moving %d bytes to altbuf(0x%x)\n", tomove,
1014             (unsigned) sp->altbuf));
1015         memcpy(sp->altbuf, *buf + berlen, sp->altlen = tomove);
1016     }
1017     if (berlen < CS_TCPIP_BUFCHUNK - 1)
1018         *(*buf + berlen) = '\0';
1019     return berlen ? berlen : 1;
1020 }
1021
1022
1023 #if ENABLE_SSL
1024 /*
1025  * Return: -1 error, >1 good, len of buffer, ==1 incomplete buffer,
1026  * 0=connection closed.
1027  */
1028 int ssl_get(COMSTACK h, char **buf, int *bufsize)
1029 {
1030     tcpip_state *sp = (tcpip_state *)h->cprivate;
1031     char *tmpc;
1032     int tmpi, berlen, rest, req, tomove;
1033     int hasread = 0, res;
1034
1035     TRC(fprintf(stderr, "ssl_get: bufsize=%d\n", *bufsize));
1036     if (sp->altlen) /* switch buffers */
1037     {
1038         TRC(fprintf(stderr, "  %d bytes in altbuf (0x%x)\n", sp->altlen,
1039             (unsigned) sp->altbuf));
1040         tmpc = *buf;
1041         tmpi = *bufsize;
1042         *buf = sp->altbuf;
1043         *bufsize = sp->altsize;
1044         hasread = sp->altlen;
1045         sp->altlen = 0;
1046         sp->altbuf = tmpc;
1047         sp->altsize = tmpi;
1048     }
1049     h->io_pending = 0;
1050     while (!(berlen = (*sp->complete)(*buf, hasread)))
1051     {
1052         if (!*bufsize)
1053         {
1054             if (!(*buf = (char *)xmalloc(*bufsize = CS_TCPIP_BUFCHUNK)))
1055                 return -1;
1056         }
1057         else if (*bufsize - hasread < CS_TCPIP_BUFCHUNK)
1058             if (!(*buf =(char *)xrealloc(*buf, *bufsize *= 2)))
1059                 return -1;
1060         res = SSL_read (sp->ssl, *buf + hasread, CS_TCPIP_BUFCHUNK);
1061         TRC(fprintf(stderr, "  SSL_read res=%d, hasread=%d\n", res, hasread));
1062         if (res <= 0)
1063         {
1064             int ssl_err = SSL_get_error(sp->ssl, res);
1065             if (ssl_err == SSL_ERROR_WANT_READ)
1066             {
1067                 h->io_pending = CS_WANT_READ;
1068                 break;
1069             }
1070             if (ssl_err == SSL_ERROR_WANT_WRITE)
1071             {
1072                 h->io_pending = CS_WANT_WRITE;
1073                 break;
1074             }
1075             if (res == 0)
1076                 return 0;
1077             h->cerrno = CSERRORSSL;
1078             return -1;
1079         }
1080         hasread += res;
1081     }
1082     TRC (fprintf (stderr, "  Out of read loop with hasread=%d, berlen=%d\n",
1083         hasread, berlen));
1084     /* move surplus buffer (or everything if we didn't get a BER rec.) */
1085     if (hasread > berlen)
1086     {
1087         tomove = req = hasread - berlen;
1088         rest = tomove % CS_TCPIP_BUFCHUNK;
1089         if (rest)
1090             req += CS_TCPIP_BUFCHUNK - rest;
1091         if (!sp->altbuf)
1092         {
1093             if (!(sp->altbuf = (char *)xmalloc(sp->altsize = req)))
1094                 return -1;
1095         } else if (sp->altsize < req)
1096             if (!(sp->altbuf =(char *)xrealloc(sp->altbuf, sp->altsize = req)))
1097                 return -1;
1098         TRC(fprintf(stderr, "  Moving %d bytes to altbuf(0x%x)\n", tomove,
1099             (unsigned) sp->altbuf));
1100         memcpy(sp->altbuf, *buf + berlen, sp->altlen = tomove);
1101     }
1102     if (berlen < CS_TCPIP_BUFCHUNK - 1)
1103         *(*buf + berlen) = '\0';
1104     return berlen ? berlen : 1;
1105 }
1106 #endif
1107
1108 /*
1109  * Returns 1, 0 or -1
1110  * In nonblocking mode, you must call again with same buffer while
1111  * return value is 1.
1112  */
1113 int tcpip_put(COMSTACK h, char *buf, int size)
1114 {
1115     int res;
1116     struct tcpip_state *state = (struct tcpip_state *)h->cprivate;
1117
1118     TRC(fprintf(stderr, "tcpip_put: size=%d\n", size));
1119     h->io_pending = 0;
1120     h->event = CS_DATA;
1121     if (state->towrite < 0)
1122     {
1123         state->towrite = size;
1124         state->written = 0;
1125     }
1126     else if (state->towrite != size)
1127     {
1128         h->cerrno = CSWRONGBUF;
1129         return -1;
1130     }
1131     while (state->towrite > state->written)
1132     {
1133         if ((res =
1134              send(h->iofile, buf + state->written, size -
1135                   state->written, 
1136 #ifdef MSG_NOSIGNAL
1137                   MSG_NOSIGNAL
1138 #else
1139                   0
1140 #endif
1141                  )) < 0)
1142         {
1143             if (
1144 #ifdef WIN32
1145                 WSAGetLastError() == WSAEWOULDBLOCK
1146 #else
1147                 yaz_errno() == EWOULDBLOCK 
1148 #ifdef EAGAIN
1149 #if EAGAIN != EWOULDBLOCK
1150              || yaz_errno() == EAGAIN
1151 #endif
1152 #endif
1153 #ifdef __sun__
1154                 || yaz_errno() == ENOENT /* Sun's sometimes set errno to this value! */
1155 #endif
1156                 || yaz_errno() == EINPROGRESS
1157 #endif
1158                 )
1159             {
1160                 TRC(fprintf(stderr, "  Flow control stop\n"));
1161                 h->io_pending = CS_WANT_WRITE;
1162                 return 1;
1163             }
1164             h->cerrno = CSYSERR;
1165             return -1;
1166         }
1167         state->written += res;
1168         TRC(fprintf(stderr, "  Wrote %d, written=%d, nbytes=%d\n",
1169                     res, state->written, size));
1170     }
1171     state->towrite = state->written = -1;
1172     TRC(fprintf(stderr, "  Ok\n"));
1173     return 0;
1174 }
1175
1176
1177 #if ENABLE_SSL
1178 /*
1179  * Returns 1, 0 or -1
1180  * In nonblocking mode, you must call again with same buffer while
1181  * return value is 1.
1182  */
1183 int ssl_put(COMSTACK h, char *buf, int size)
1184 {
1185     int res;
1186     struct tcpip_state *state = (struct tcpip_state *)h->cprivate;
1187
1188     TRC(fprintf(stderr, "ssl_put: size=%d\n", size));
1189     h->io_pending = 0;
1190     h->event = CS_DATA;
1191     if (state->towrite < 0)
1192     {
1193         state->towrite = size;
1194         state->written = 0;
1195     }
1196     else if (state->towrite != size)
1197     {
1198         h->cerrno = CSWRONGBUF;
1199         return -1;
1200     }
1201     while (state->towrite > state->written)
1202     {
1203         res = SSL_write (state->ssl, buf + state->written,
1204                          size - state->written);
1205         if (res <= 0)
1206         {
1207             int ssl_err = SSL_get_error(state->ssl, res);
1208             if (ssl_err == SSL_ERROR_WANT_READ)
1209             {
1210                 h->io_pending = CS_WANT_READ;
1211                 return 1;
1212             }
1213             if (ssl_err == SSL_ERROR_WANT_WRITE)
1214             {
1215                 h->io_pending = CS_WANT_WRITE;
1216                 return 1;
1217             }
1218             h->cerrno = CSERRORSSL;
1219             return -1;
1220         }
1221         state->written += res;
1222         TRC(fprintf(stderr, "  Wrote %d, written=%d, nbytes=%d\n",
1223                     res, state->written, size));
1224     }
1225     state->towrite = state->written = -1;
1226     TRC(fprintf(stderr, "  Ok\n"));
1227     return 0;
1228 }
1229 #endif
1230
1231 int tcpip_close(COMSTACK h)
1232 {
1233     tcpip_state *sp = (struct tcpip_state *)h->cprivate;
1234
1235     TRC(fprintf(stderr, "tcpip_close\n"));
1236     if (h->iofile != -1)
1237     {
1238 #if ENABLE_SSL
1239         if (sp->ssl)
1240         {
1241             SSL_shutdown (sp->ssl);
1242         }
1243 #endif
1244 #ifdef WIN32
1245         closesocket(h->iofile);
1246 #else
1247         close(h->iofile);
1248 #endif
1249     }
1250     if (sp->altbuf)
1251         xfree(sp->altbuf);
1252 #if ENABLE_SSL
1253     if (sp->ssl)
1254     {
1255         TRC (fprintf(stderr, "SSL_free\n"));
1256         SSL_free (sp->ssl);
1257     }
1258     sp->ssl = 0;
1259     if (sp->ctx_alloc)
1260         SSL_CTX_free (sp->ctx_alloc);
1261 #endif
1262 #if HAVE_GETADDRINFO
1263     if (sp->ai)
1264         freeaddrinfo(sp->ai);
1265 #endif
1266     xfree(sp->connect_request_buf);
1267     xfree(sp->connect_response_buf);
1268     xfree(sp);
1269     xfree(h);
1270     return 0;
1271 }
1272
1273 char *tcpip_addrstr(COMSTACK h)
1274 {
1275     tcpip_state *sp = (struct tcpip_state *)h->cprivate;
1276     char *r = 0, *buf = sp->buf;
1277
1278 #if HAVE_GETADDRINFO
1279     char host[120];
1280     struct sockaddr_storage addr;
1281     YAZ_SOCKLEN_T len = sizeof(addr);
1282     
1283     if (getpeername(h->iofile, (struct sockaddr *)&addr, &len) < 0)
1284     {
1285         h->cerrno = CSYSERR;
1286         return 0;
1287     }
1288     if (getnameinfo((struct sockaddr *) &addr, len, host, sizeof(host)-1, 
1289                     0, 0, 
1290                     (h->flags & CS_FLAGS_NUMERICHOST) ? NI_NUMERICHOST : 0))
1291     {
1292         r = "unknown";
1293     }
1294     else
1295         r = host;
1296     
1297 #else
1298
1299     struct sockaddr_in addr;
1300     YAZ_SOCKLEN_T len = sizeof(addr);
1301     struct hostent *host;
1302     
1303     if (getpeername(h->iofile, (struct sockaddr*) &addr, &len) < 0)
1304     {
1305         h->cerrno = CSYSERR;
1306         return 0;
1307     }
1308     if (!(h->flags & CS_FLAGS_NUMERICHOST))
1309     {
1310         if ((host = gethostbyaddr((char*)&addr.sin_addr,
1311                                   sizeof(addr.sin_addr),
1312                                   AF_INET)))
1313             r = (char*) host->h_name;
1314     }
1315     if (!r)
1316         r = inet_ntoa(addr.sin_addr);        
1317 #endif
1318
1319     if (h->protocol == PROTO_HTTP)
1320         sprintf(buf, "http:%s", r);
1321     else
1322         sprintf(buf, "tcp:%s", r);
1323 #if ENABLE_SSL
1324     if (sp->ctx)
1325     {
1326         if (h->protocol == PROTO_HTTP)
1327             sprintf(buf, "https:%s", r);
1328         else
1329             sprintf(buf, "ssl:%s", r);
1330     }
1331 #endif
1332     return buf;
1333 }
1334
1335 int static tcpip_set_blocking(COMSTACK p, int flags)
1336 {
1337     unsigned long flag;
1338     
1339 #ifdef WIN32
1340     flag = (flags & CS_FLAGS_BLOCKING) ? 0 : 1;
1341     if (ioctlsocket(p->iofile, FIONBIO, &flag) < 0)
1342         return 0;
1343 #else
1344     flag = fcntl(p->iofile, F_GETFL, 0);
1345     if (flags & CS_FLAGS_BLOCKING)
1346         flag = flag & ~O_NONBLOCK;  /* blocking */
1347     else
1348     {
1349         flag = flag | O_NONBLOCK;   /* non-blocking */
1350         signal(SIGPIPE, SIG_IGN);
1351     }
1352     if (fcntl(p->iofile, F_SETFL, flag) < 0)
1353         return 0;
1354 #endif
1355     p->flags = flags;
1356     return 1;
1357 }
1358
1359 #if ENABLE_SSL
1360 int cs_set_ssl_ctx(COMSTACK cs, void *ctx)
1361 {
1362     struct tcpip_state *sp;
1363     if (!cs || cs->type != ssl_type)
1364         return 0;
1365     sp = (struct tcpip_state *) cs->cprivate;
1366     if (sp->ctx_alloc)
1367         return 0;
1368     sp->ctx = (SSL_CTX *) ctx;
1369     return 1;
1370 }
1371
1372 void *cs_get_ssl(COMSTACK cs)
1373 {
1374     struct tcpip_state *sp;
1375     if (!cs || cs->type != ssl_type)
1376         return 0;
1377     sp = (struct tcpip_state *) cs->cprivate;
1378     return sp->ssl;  
1379 }
1380
1381 int cs_set_ssl_certificate_file(COMSTACK cs, const char *fname)
1382 {
1383     struct tcpip_state *sp;
1384     if (!cs || cs->type != ssl_type)
1385         return 0;
1386     sp = (struct tcpip_state *) cs->cprivate;
1387     strncpy(sp->cert_fname, fname, sizeof(sp->cert_fname)-1);
1388     sp->cert_fname[sizeof(sp->cert_fname)-1] = '\0';
1389     return 1;
1390 }
1391
1392 int cs_get_peer_certificate_x509(COMSTACK cs, char **buf, int *len)
1393 {
1394     SSL *ssl = (SSL *) cs_get_ssl(cs);
1395     if (ssl)
1396     {
1397         X509 *server_cert = SSL_get_peer_certificate (ssl);
1398 #if HAVE_OPENSSL_SSL_H
1399         if (server_cert)
1400         {
1401             BIO *bio = BIO_new(BIO_s_mem());
1402             char *pem_buf;
1403             /* get PEM buffer in memory */
1404             PEM_write_bio_X509(bio, server_cert);
1405             *len = BIO_get_mem_data(bio, &pem_buf);
1406             *buf = (char *) xmalloc(*len);
1407             memcpy(*buf, pem_buf, *len);
1408             BIO_free(bio);
1409             return 1;
1410         }
1411 #endif
1412     }
1413     return 0;
1414 }
1415 #else
1416 int cs_set_ssl_ctx(COMSTACK cs, void *ctx)
1417 {
1418     return 0;
1419 }
1420
1421 void *cs_get_ssl(COMSTACK cs)
1422 {
1423     return 0;
1424 }
1425
1426 int cs_get_peer_certificate_x509(COMSTACK cs, char **buf, int *len)
1427 {
1428     return 0;
1429 }
1430
1431 int cs_set_ssl_certificate_file(COMSTACK cs, const char *fname)
1432 {
1433     return 0;
1434 }
1435 #endif
1436
1437
1438 static int tcpip_put_connect(COMSTACK h, char *buf, int size)
1439 {
1440     struct tcpip_state *state = (struct tcpip_state *)h->cprivate;
1441
1442     int r = tcpip_put(h, state->connect_request_buf,
1443                       state->connect_request_len);
1444     if (r == 0)
1445     {
1446         /* it's sent */
1447         h->f_put = tcpip_put; /* switch to normal tcpip put */
1448         r = tcpip_put(h, buf, size);
1449     }
1450     return r;
1451 }
1452
1453 static int tcpip_get_connect(COMSTACK h, char **buf, int *bufsize)
1454 {
1455     struct tcpip_state *state = (struct tcpip_state *)h->cprivate;
1456     int r;
1457
1458     r = tcpip_get(h, &state->connect_response_buf, 
1459                   &state->connect_response_len);
1460     if (r < 1)
1461         return r;
1462     /* got the connect response completely */
1463     state->complete = cs_complete_auto; /* switch to normal tcpip get */
1464     h->f_get = tcpip_get;
1465     return tcpip_get(h, buf, bufsize);
1466 }
1467
1468
1469 /*
1470  * Local variables:
1471  * c-basic-offset: 4
1472  * indent-tabs-mode: nil
1473  * End:
1474  * vim: shiftwidth=4 tabstop=8 expandtab
1475  */
1476