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