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