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