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