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