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