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