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