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