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