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