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