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