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