Add new mutex create where mutex attribute can be set
[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 #ifdef WIN32
755     /* we don't get peer address on Windows (via accept) */
756 #else
757     struct sockaddr_in addr;
758     YAZ_SOCKLEN_T len = sizeof(addr);
759 #endif
760
761     TRC(fprintf(stderr, "tcpip_listen pid=%d\n", getpid()));
762     if (h->state != CS_ST_IDLE)
763     {
764         h->cerrno = CSOUTSTATE;
765         return -1;
766     }
767 #ifdef WIN32
768     h->newfd = accept(h->iofile, 0, 0);
769 #else
770     h->newfd = accept(h->iofile, (struct sockaddr*)&addr, &len);
771 #endif
772     if (h->newfd < 0)
773     {
774         if (
775 #ifdef WIN32
776             WSAGetLastError() == WSAEWOULDBLOCK
777 #else
778             yaz_errno() == EWOULDBLOCK 
779 #ifdef EAGAIN
780 #if EAGAIN != EWOULDBLOCK
781             || yaz_errno() == EAGAIN
782 #endif
783 #endif
784 #endif
785             )
786             h->cerrno = CSNODATA;
787         else
788         {
789 #ifdef WIN32
790             shutdown(h->iofile, SD_RECEIVE);
791 #else
792             shutdown(h->iofile, SHUT_RD);
793 #endif
794             listen(h->iofile, SOMAXCONN);
795             h->cerrno = CSYSERR;
796         }
797         return -1;
798     }
799 #ifdef WIN32
800     if (addrlen)
801         *addrlen = 0;
802 #else
803     if (addrlen && (size_t) (*addrlen) >= sizeof(struct sockaddr_in))
804         memcpy(raddr, &addr, *addrlen = sizeof(struct sockaddr_in));
805     else if (addrlen)
806         *addrlen = 0;
807     if (check_ip && (*check_ip)(cd, (const char *) &addr,
808         sizeof(addr), AF_INET))
809     {
810         h->cerrno = CSDENY;
811 #ifdef WIN32
812         closesocket(h->newfd);
813 #else
814         close(h->newfd);
815 #endif
816         h->newfd = -1;
817         return -1;
818     }
819 #endif
820     h->state = CS_ST_INCON;
821     return 0;
822 }
823
824 COMSTACK tcpip_accept(COMSTACK h)
825 {
826     COMSTACK cnew;
827 #ifdef WIN32
828     unsigned long tru = 1;
829 #endif
830
831     TRC(fprintf(stderr, "tcpip_accept h=%p pid=%d\n", h, getpid()));
832     if (h->state == CS_ST_INCON)
833     {
834         tcpip_state *state, *st = (tcpip_state *)h->cprivate;
835         if (!(cnew = (COMSTACK)xmalloc(sizeof(*cnew))))
836         {
837             h->cerrno = CSYSERR;
838 #ifdef WIN32
839             closesocket(h->newfd);
840 #else
841             close(h->newfd);
842 #endif
843             h->newfd = -1;
844             return 0;
845         }
846         memcpy(cnew, h, sizeof(*h));
847         cnew->iofile = h->newfd;
848         cnew->io_pending = 0;
849
850         if (!(state = (tcpip_state *)
851               (cnew->cprivate = xmalloc(sizeof(tcpip_state)))))
852         {
853             h->cerrno = CSYSERR;
854             if (h->newfd != -1)
855             {
856 #ifdef WIN32
857                 closesocket(h->newfd);
858 #else
859                 close(h->newfd);
860 #endif
861                 h->newfd = -1;
862             }
863             return 0;
864         }
865         if (!tcpip_set_blocking(cnew, cnew->flags))
866         {
867             h->cerrno = CSYSERR;
868             if (h->newfd != -1)
869             {
870 #ifdef WIN32
871                 closesocket(h->newfd);
872 #else
873                 close(h->newfd);
874 #endif
875                 h->newfd = -1;
876             }
877             xfree(cnew);
878             xfree(state);
879             return 0;
880         }
881         h->newfd = -1;
882         state->altbuf = 0;
883         state->altsize = state->altlen = 0;
884         state->towrite = state->written = -1;
885         state->complete = st->complete;
886 #if HAVE_GETADDRINFO
887         state->ai = 0;
888 #endif
889         cnew->state = CS_ST_ACCEPT;
890         h->state = CS_ST_IDLE;
891         
892 #if HAVE_GNUTLS_H
893         state->cred_ptr = st->cred_ptr;
894         state->session = 0;
895         if (st->cred_ptr)
896         {
897             int res;
898
899             (state->cred_ptr->ref)++;
900             gnutls_init(&state->session, GNUTLS_SERVER);
901             if (!state->session)
902             {
903                 xfree(cnew);
904                 xfree(state);
905                 return 0;
906             }
907             res = gnutls_set_default_priority(state->session);
908             if (res != GNUTLS_E_SUCCESS)
909             {
910                 xfree(cnew);
911                 xfree(state);
912                 return 0;
913             }
914             res = gnutls_credentials_set(state->session,
915                                          GNUTLS_CRD_CERTIFICATE, 
916                                          st->cred_ptr->xcred);
917             if (res != GNUTLS_E_SUCCESS)
918             {
919                 xfree(cnew);
920                 xfree(state);
921                 return 0;
922             }
923             /* cast to intermediate size_t to avoid GCC warning. */
924             gnutls_transport_set_ptr(state->session, 
925                                      (gnutls_transport_ptr_t)
926                                      (size_t) cnew->iofile);
927         }
928 #elif HAVE_OPENSSL_SSL_H
929         state->ctx = st->ctx;
930         state->ctx_alloc = 0;
931         state->ssl = st->ssl;
932         if (state->ctx)
933         {
934             state->ssl = SSL_new(state->ctx);
935             SSL_set_fd(state->ssl, cnew->iofile);
936         }
937 #endif
938         state->connect_request_buf = 0;
939         state->connect_response_buf = 0;
940         h = cnew;
941     }
942     if (h->state == CS_ST_ACCEPT)
943     {
944 #if HAVE_GNUTLS_H
945         tcpip_state *state = (tcpip_state *)h->cprivate;
946         if (state->session)
947         {
948             int res = gnutls_handshake(state->session);
949             if (res < 0)
950             {
951                 if (ssl_check_error(h, state, res))
952                 {
953                     TRC(fprintf(stderr, "gnutls_handshake int in tcpip_accept\n"));
954                     return h;
955                 }
956                 TRC(fprintf(stderr, "gnutls_handshake failed in tcpip_accept\n"));
957                 cs_close(h);
958                 return 0;
959             }
960             TRC(fprintf(stderr, "SSL_accept complete. gnutls\n"));
961         }
962 #elif HAVE_OPENSSL_SSL_H
963         tcpip_state *state = (tcpip_state *)h->cprivate;
964         if (state->ctx)
965         {
966             int res;
967             errno = 0;
968             res = SSL_accept(state->ssl);
969             TRC(fprintf(stderr, "SSL_accept res=%d\n", res));
970             if (res <= 0)
971             {
972                 if (ssl_check_error(h, state, res))
973                 {
974                     return h;
975                 }
976                 cs_close(h);
977                 return 0;
978             }
979             TRC(fprintf(stderr, "SSL_accept complete\n"));
980         }
981 #endif
982     }
983     else
984     {
985         h->cerrno = CSOUTSTATE;
986         return 0;
987     }
988     h->io_pending = 0;
989     h->state = CS_ST_DATAXFER;
990     h->event = CS_DATA;
991     return h;
992 }
993
994 #define CS_TCPIP_BUFCHUNK 4096
995
996 /*
997  * Return: -1 error, >1 good, len of buffer, ==1 incomplete buffer,
998  * 0=connection closed.
999  */
1000 int tcpip_get(COMSTACK h, char **buf, int *bufsize)
1001 {
1002     tcpip_state *sp = (tcpip_state *)h->cprivate;
1003     char *tmpc;
1004     int tmpi, berlen, rest, req, tomove;
1005     int hasread = 0, res;
1006
1007     TRC(fprintf(stderr, "tcpip_get: bufsize=%d\n", *bufsize));
1008     if (sp->altlen) /* switch buffers */
1009     {
1010         TRC(fprintf(stderr, "  %d bytes in altbuf (%p)\n", sp->altlen,
1011                     sp->altbuf));
1012         tmpc = *buf;
1013         tmpi = *bufsize;
1014         *buf = sp->altbuf;
1015         *bufsize = sp->altsize;
1016         hasread = sp->altlen;
1017         sp->altlen = 0;
1018         sp->altbuf = tmpc;
1019         sp->altsize = tmpi;
1020     }
1021     h->io_pending = 0;
1022     while (!(berlen = (*sp->complete)(*buf, hasread)))
1023     {
1024         if (!*bufsize)
1025         {
1026             if (!(*buf = (char *)xmalloc(*bufsize = CS_TCPIP_BUFCHUNK)))
1027             {
1028                 h->cerrno = CSYSERR;
1029                 return -1;
1030             }
1031         }
1032         else if (*bufsize - hasread < CS_TCPIP_BUFCHUNK)
1033             if (!(*buf =(char *)xrealloc(*buf, *bufsize *= 2)))
1034             {
1035                 h->cerrno = CSYSERR;
1036                 return -1;
1037             }
1038 #ifdef __sun__
1039         yaz_set_errno( 0 );
1040         /* unfortunatly, sun sometimes forgets to set errno in recv
1041            when EWOULDBLOCK etc. would be required (res = -1) */
1042 #endif
1043         res = recv(h->iofile, *buf + hasread, CS_TCPIP_BUFCHUNK, 0);
1044         TRC(fprintf(stderr, "  recv res=%d, hasread=%d\n", res, hasread));
1045         if (res < 0)
1046         {
1047             TRC(fprintf(stderr, "  recv errno=%d, (%s)\n", yaz_errno(), 
1048                       strerror(yaz_errno())));
1049 #ifdef WIN32
1050             if (WSAGetLastError() == WSAEWOULDBLOCK)
1051             {
1052                 h->io_pending = CS_WANT_READ;
1053                 break;
1054             }
1055             else
1056             {
1057                 h->cerrno = CSYSERR;
1058                 return -1;
1059             }
1060 #else
1061             if (yaz_errno() == EWOULDBLOCK 
1062 #ifdef EAGAIN   
1063 #if EAGAIN != EWOULDBLOCK
1064                 || yaz_errno() == EAGAIN
1065 #endif
1066 #endif
1067                 || yaz_errno() == EINPROGRESS
1068 #ifdef __sun__
1069                 || yaz_errno() == ENOENT /* Sun's sometimes set errno to this */
1070 #endif
1071                 )
1072             {
1073                 h->io_pending = CS_WANT_READ;
1074                 break;
1075             }
1076             else if (yaz_errno() == 0)
1077                 continue;
1078             else
1079             {
1080                 h->cerrno = CSYSERR;
1081                 return -1;
1082             }
1083 #endif
1084         }
1085         else if (!res)
1086             return hasread;
1087         hasread += res;
1088         if (hasread > h->max_recv_bytes)
1089         {
1090             h->cerrno = CSBUFSIZE;
1091             return -1;
1092         }
1093     }
1094     TRC(fprintf(stderr, "  Out of read loop with hasread=%d, berlen=%d\n",
1095                 hasread, berlen));
1096     /* move surplus buffer (or everything if we didn't get a BER rec.) */
1097     if (hasread > berlen)
1098     {
1099         tomove = req = hasread - berlen;
1100         rest = tomove % CS_TCPIP_BUFCHUNK;
1101         if (rest)
1102             req += CS_TCPIP_BUFCHUNK - rest;
1103         if (!sp->altbuf)
1104         {
1105             if (!(sp->altbuf = (char *)xmalloc(sp->altsize = req)))
1106             {
1107                 h->cerrno = CSYSERR;
1108                 return -1;
1109             }
1110         } else if (sp->altsize < req)
1111             if (!(sp->altbuf =(char *)xrealloc(sp->altbuf, sp->altsize = req)))
1112             {
1113                 h->cerrno = CSYSERR;
1114                 return -1;
1115             }
1116         TRC(fprintf(stderr, "  Moving %d bytes to altbuf(%p)\n", tomove,
1117                     sp->altbuf));
1118         memcpy(sp->altbuf, *buf + berlen, sp->altlen = tomove);
1119     }
1120     if (berlen < CS_TCPIP_BUFCHUNK - 1)
1121         *(*buf + berlen) = '\0';
1122     return berlen ? berlen : 1;
1123 }
1124
1125
1126 #if ENABLE_SSL
1127 /*
1128  * Return: -1 error, >1 good, len of buffer, ==1 incomplete buffer,
1129  * 0=connection closed.
1130  */
1131 int ssl_get(COMSTACK h, char **buf, int *bufsize)
1132 {
1133     tcpip_state *sp = (tcpip_state *)h->cprivate;
1134     char *tmpc;
1135     int tmpi, berlen, rest, req, tomove;
1136     int hasread = 0, res;
1137
1138     TRC(fprintf(stderr, "ssl_get: bufsize=%d\n", *bufsize));
1139     if (sp->altlen) /* switch buffers */
1140     {
1141         TRC(fprintf(stderr, "  %d bytes in altbuf (%p)\n", sp->altlen,
1142                     sp->altbuf));
1143         tmpc = *buf;
1144         tmpi = *bufsize;
1145         *buf = sp->altbuf;
1146         *bufsize = sp->altsize;
1147         hasread = sp->altlen;
1148         sp->altlen = 0;
1149         sp->altbuf = tmpc;
1150         sp->altsize = tmpi;
1151     }
1152     h->io_pending = 0;
1153     while (!(berlen = (*sp->complete)(*buf, hasread)))
1154     {
1155         if (!*bufsize)
1156         {
1157             if (!(*buf = (char *)xmalloc(*bufsize = CS_TCPIP_BUFCHUNK)))
1158                 return -1;
1159         }
1160         else if (*bufsize - hasread < CS_TCPIP_BUFCHUNK)
1161             if (!(*buf =(char *)xrealloc(*buf, *bufsize *= 2)))
1162                 return -1;
1163 #if HAVE_GNUTLS_H
1164         res = gnutls_record_recv(sp->session, *buf + hasread,
1165                                  CS_TCPIP_BUFCHUNK);
1166         if (res < 0)
1167         {
1168             if (ssl_check_error(h, sp, res))
1169                 break;
1170             return -1;
1171         }
1172 #else
1173         res = SSL_read(sp->ssl, *buf + hasread, CS_TCPIP_BUFCHUNK);
1174         TRC(fprintf(stderr, "  SSL_read res=%d, hasread=%d\n", res, hasread));
1175         if (res <= 0)
1176         {
1177             if (ssl_check_error(h, sp, res))
1178                 break;
1179             return -1;
1180         }
1181 #endif
1182         hasread += res;
1183     }
1184     TRC (fprintf (stderr, "  Out of read loop with hasread=%d, berlen=%d\n",
1185         hasread, berlen));
1186     /* move surplus buffer (or everything if we didn't get a BER rec.) */
1187     if (hasread > berlen)
1188     {
1189         tomove = req = hasread - berlen;
1190         rest = tomove % CS_TCPIP_BUFCHUNK;
1191         if (rest)
1192             req += CS_TCPIP_BUFCHUNK - rest;
1193         if (!sp->altbuf)
1194         {
1195             if (!(sp->altbuf = (char *)xmalloc(sp->altsize = req)))
1196                 return -1;
1197         } else if (sp->altsize < req)
1198             if (!(sp->altbuf =(char *)xrealloc(sp->altbuf, sp->altsize = req)))
1199                 return -1;
1200         TRC(fprintf(stderr, "  Moving %d bytes to altbuf(%p)\n", tomove,
1201                     sp->altbuf));
1202         memcpy(sp->altbuf, *buf + berlen, sp->altlen = tomove);
1203     }
1204     if (berlen < CS_TCPIP_BUFCHUNK - 1)
1205         *(*buf + berlen) = '\0';
1206     return berlen ? berlen : 1;
1207 }
1208 #endif
1209
1210 /*
1211  * Returns 1, 0 or -1
1212  * In nonblocking mode, you must call again with same buffer while
1213  * return value is 1.
1214  */
1215 int tcpip_put(COMSTACK h, char *buf, int size)
1216 {
1217     int res;
1218     struct tcpip_state *state = (struct tcpip_state *)h->cprivate;
1219
1220     TRC(fprintf(stderr, "tcpip_put: size=%d\n", size));
1221     h->io_pending = 0;
1222     h->event = CS_DATA;
1223     if (state->towrite < 0)
1224     {
1225         state->towrite = size;
1226         state->written = 0;
1227     }
1228     else if (state->towrite != size)
1229     {
1230         h->cerrno = CSWRONGBUF;
1231         return -1;
1232     }
1233     while (state->towrite > state->written)
1234     {
1235         if ((res =
1236              send(h->iofile, buf + state->written, size -
1237                   state->written, 
1238 #ifdef MSG_NOSIGNAL
1239                   MSG_NOSIGNAL
1240 #else
1241                   0
1242 #endif
1243                  )) < 0)
1244         {
1245             if (
1246 #ifdef WIN32
1247                 WSAGetLastError() == WSAEWOULDBLOCK
1248 #else
1249                 yaz_errno() == EWOULDBLOCK 
1250 #ifdef EAGAIN
1251 #if EAGAIN != EWOULDBLOCK
1252              || yaz_errno() == EAGAIN
1253 #endif
1254 #endif
1255 #ifdef __sun__
1256                 || yaz_errno() == ENOENT /* Sun's sometimes set errno to this value! */
1257 #endif
1258                 || yaz_errno() == EINPROGRESS
1259 #endif
1260                 )
1261             {
1262                 TRC(fprintf(stderr, "  Flow control stop\n"));
1263                 h->io_pending = CS_WANT_WRITE;
1264                 return 1;
1265             }
1266             h->cerrno = CSYSERR;
1267             return -1;
1268         }
1269         state->written += res;
1270         TRC(fprintf(stderr, "  Wrote %d, written=%d, nbytes=%d\n",
1271                     res, state->written, size));
1272     }
1273     state->towrite = state->written = -1;
1274     TRC(fprintf(stderr, "  Ok\n"));
1275     return 0;
1276 }
1277
1278
1279 #if ENABLE_SSL
1280 /*
1281  * Returns 1, 0 or -1
1282  * In nonblocking mode, you must call again with same buffer while
1283  * return value is 1.
1284  */
1285 int ssl_put(COMSTACK h, char *buf, int size)
1286 {
1287     int res;
1288     struct tcpip_state *state = (struct tcpip_state *)h->cprivate;
1289
1290     TRC(fprintf(stderr, "ssl_put: size=%d\n", size));
1291     h->io_pending = 0;
1292     h->event = CS_DATA;
1293     if (state->towrite < 0)
1294     {
1295         state->towrite = size;
1296         state->written = 0;
1297     }
1298     else if (state->towrite != size)
1299     {
1300         h->cerrno = CSWRONGBUF;
1301         return -1;
1302     }
1303     while (state->towrite > state->written)
1304     {
1305 #if HAVE_GNUTLS_H
1306         res = gnutls_record_send(state->session, 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 #else
1315         res = SSL_write(state->ssl, buf + state->written, 
1316                         size - state->written);
1317         if (res <= 0)
1318         {
1319             if (ssl_check_error(h, state, res))
1320                 return 1;
1321             return -1;
1322         }
1323 #endif
1324         state->written += res;
1325         TRC(fprintf(stderr, "  Wrote %d, written=%d, nbytes=%d\n",
1326                     res, state->written, size));
1327     }
1328     state->towrite = state->written = -1;
1329     TRC(fprintf(stderr, "  Ok\n"));
1330     return 0;
1331 }
1332 #endif
1333
1334 void tcpip_close(COMSTACK h)
1335 {
1336     tcpip_state *sp = (struct tcpip_state *)h->cprivate;
1337
1338     TRC(fprintf(stderr, "tcpip_close h=%p pid=%d\n", h, getpid()));
1339     if (h->iofile != -1)
1340     {
1341 #if HAVE_GNUTLS_H
1342         if (sp->session)
1343             gnutls_bye(sp->session, GNUTLS_SHUT_RDWR);
1344 #elif HAVE_OPENSSL_SSL_H
1345         if (sp->ssl)
1346         {
1347             SSL_shutdown(sp->ssl);
1348         }
1349 #endif
1350 #ifdef WIN32
1351         closesocket(h->iofile);
1352 #else
1353         close(h->iofile);
1354 #endif
1355     }
1356     if (sp->altbuf)
1357         xfree(sp->altbuf);
1358 #if HAVE_GNUTLS_H
1359     if (sp->session)
1360     {
1361         gnutls_deinit(sp->session);
1362     }
1363     if (sp->cred_ptr)
1364     {
1365         assert(sp->cred_ptr->ref > 0);
1366
1367         if (--(sp->cred_ptr->ref) == 0)
1368         {
1369             TRC(fprintf(stderr, "Removed credentials %p pid=%d\n", 
1370                         sp->cred_ptr->xcred, getpid()));
1371             gnutls_certificate_free_credentials(sp->cred_ptr->xcred);
1372             xfree(sp->cred_ptr);
1373         }
1374         sp->cred_ptr = 0;
1375     }
1376 #elif HAVE_OPENSSL_SSL_H
1377     if (sp->ssl)
1378     {
1379         TRC(fprintf(stderr, "SSL_free\n"));
1380         SSL_free(sp->ssl);
1381     }
1382     sp->ssl = 0;
1383     if (sp->ctx_alloc)
1384         SSL_CTX_free(sp->ctx_alloc);
1385 #endif
1386 #if HAVE_GETADDRINFO
1387     if (sp->ai)
1388         freeaddrinfo(sp->ai);
1389 #endif
1390     xfree(sp->connect_request_buf);
1391     xfree(sp->connect_response_buf);
1392     xfree(sp);
1393     xfree(h);
1394 }
1395
1396 const char *tcpip_addrstr(COMSTACK h)
1397 {
1398     tcpip_state *sp = (struct tcpip_state *)h->cprivate;
1399     char *r = 0, *buf = sp->buf;
1400
1401 #if HAVE_GETADDRINFO
1402     char host[120];
1403     struct sockaddr_storage addr;
1404     YAZ_SOCKLEN_T len = sizeof(addr);
1405     
1406     if (getpeername(h->iofile, (struct sockaddr *)&addr, &len) < 0)
1407     {
1408         h->cerrno = CSYSERR;
1409         return 0;
1410     }
1411     if (getnameinfo((struct sockaddr *) &addr, len, host, sizeof(host)-1, 
1412                     0, 0, 
1413                     (h->flags & CS_FLAGS_NUMERICHOST) ? NI_NUMERICHOST : 0))
1414     {
1415         r = "unknown";
1416     }
1417     else
1418         r = host;
1419     
1420 #else
1421
1422     struct sockaddr_in addr;
1423     YAZ_SOCKLEN_T len = sizeof(addr);
1424     struct hostent *host;
1425     
1426     if (getpeername(h->iofile, (struct sockaddr*) &addr, &len) < 0)
1427     {
1428         h->cerrno = CSYSERR;
1429         return 0;
1430     }
1431     if (!(h->flags & CS_FLAGS_NUMERICHOST))
1432     {
1433         if ((host = gethostbyaddr((char*)&addr.sin_addr,
1434                                   sizeof(addr.sin_addr),
1435                                   AF_INET)))
1436             r = (char*) host->h_name;
1437     }
1438     if (!r)
1439         r = inet_ntoa(addr.sin_addr);        
1440 #endif
1441
1442     if (h->protocol == PROTO_HTTP)
1443         sprintf(buf, "http:%s", r);
1444     else
1445         sprintf(buf, "tcp:%s", r);
1446 #if HAVE_GNUTLS_H
1447     if (sp->session)
1448     {
1449         if (h->protocol == PROTO_HTTP)
1450             sprintf(buf, "https:%s", r);
1451         else
1452             sprintf(buf, "ssl:%s", r);
1453     }
1454 #elif HAVE_OPENSSL_SSL_H
1455     if (sp->ctx)
1456     {
1457         if (h->protocol == PROTO_HTTP)
1458             sprintf(buf, "https:%s", r);
1459         else
1460             sprintf(buf, "ssl:%s", r);
1461     }
1462 #endif
1463     return buf;
1464 }
1465
1466 static int tcpip_set_blocking(COMSTACK p, int flags)
1467 {
1468     unsigned long flag;
1469     
1470 #ifdef WIN32
1471     flag = (flags & CS_FLAGS_BLOCKING) ? 0 : 1;
1472     if (ioctlsocket(p->iofile, FIONBIO, &flag) < 0)
1473         return 0;
1474 #else
1475     flag = fcntl(p->iofile, F_GETFL, 0);
1476     if (flags & CS_FLAGS_BLOCKING)
1477         flag = flag & ~O_NONBLOCK;  /* blocking */
1478     else
1479     {
1480         flag = flag | O_NONBLOCK;   /* non-blocking */
1481         signal(SIGPIPE, SIG_IGN);
1482     }
1483     if (fcntl(p->iofile, F_SETFL, flag) < 0)
1484         return 0;
1485 #endif
1486     p->flags = flags;
1487     return 1;
1488 }
1489
1490 void cs_print_session_info(COMSTACK cs)
1491 {
1492 #if HAVE_GNUTLS_H
1493     struct tcpip_state *sp = (struct tcpip_state *) cs->cprivate;
1494     if (sp->session)
1495     {
1496         if (gnutls_certificate_type_get(sp->session) != GNUTLS_CRT_X509)
1497             return;
1498         printf("X509 certificate\n");
1499     }
1500 #elif HAVE_OPENSSL_SSL_H
1501     struct tcpip_state *sp = (struct tcpip_state *) cs->cprivate;
1502     SSL *ssl = (SSL *) sp->ssl;
1503     if (ssl)
1504     {
1505         X509 *server_cert = SSL_get_peer_certificate(ssl);
1506         
1507         if (server_cert)
1508         {
1509             char *pem_buf;
1510             int pem_len;
1511             BIO *bio = BIO_new(BIO_s_mem());
1512
1513             /* get PEM buffer in memory */
1514             PEM_write_bio_X509(bio, server_cert);
1515             pem_len = BIO_get_mem_data(bio, &pem_buf);
1516             fwrite(pem_buf, pem_len, 1, stdout);
1517
1518             /* print all info on screen .. */
1519             X509_print_fp(stdout, server_cert);
1520             BIO_free(bio);
1521
1522             X509_free(server_cert);
1523         }
1524     }
1525 #endif
1526 }
1527
1528 void *cs_get_ssl(COMSTACK cs)
1529 {
1530 #if HAVE_OPENSSL_SSL_H
1531     struct tcpip_state *sp;
1532     if (!cs || cs->type != ssl_type)
1533         return 0;
1534     sp = (struct tcpip_state *) cs->cprivate;
1535     return sp->ssl;  
1536 #else
1537     return 0;
1538 #endif
1539 }
1540
1541 int cs_set_ssl_ctx(COMSTACK cs, void *ctx)
1542 {
1543 #if ENABLE_SSL
1544     struct tcpip_state *sp;
1545     if (!cs || cs->type != ssl_type)
1546         return 0;
1547     sp = (struct tcpip_state *) cs->cprivate;
1548 #if HAVE_OPENSSL_SSL_H
1549     if (sp->ctx_alloc)
1550         return 0;
1551     sp->ctx = (SSL_CTX *) ctx;
1552 #endif
1553     return 1;
1554 #else
1555     return 0;
1556 #endif
1557 }
1558
1559 int cs_set_ssl_certificate_file(COMSTACK cs, const char *fname)
1560 {
1561 #if ENABLE_SSL
1562     struct tcpip_state *sp;
1563     if (!cs || cs->type != ssl_type)
1564         return 0;
1565     sp = (struct tcpip_state *) cs->cprivate;
1566     strncpy(sp->cert_fname, fname, sizeof(sp->cert_fname)-1);
1567     sp->cert_fname[sizeof(sp->cert_fname)-1] = '\0';
1568     return 1;
1569 #else
1570     return 0;
1571 #endif
1572 }
1573
1574 int cs_get_peer_certificate_x509(COMSTACK cs, char **buf, int *len)
1575 {
1576 #if HAVE_OPENSSL_SSL_H
1577     SSL *ssl = (SSL *) cs_get_ssl(cs);
1578     if (ssl)
1579     {
1580         X509 *server_cert = SSL_get_peer_certificate(ssl);
1581         if (server_cert)
1582         {
1583             BIO *bio = BIO_new(BIO_s_mem());
1584             char *pem_buf;
1585             /* get PEM buffer in memory */
1586             PEM_write_bio_X509(bio, server_cert);
1587             *len = BIO_get_mem_data(bio, &pem_buf);
1588             *buf = (char *) xmalloc(*len);
1589             memcpy(*buf, pem_buf, *len);
1590             BIO_free(bio);
1591             return 1;
1592         }
1593     }
1594 #endif
1595     return 0;
1596 }
1597
1598 static int tcpip_put_connect(COMSTACK h, char *buf, int size)
1599 {
1600     struct tcpip_state *state = (struct tcpip_state *)h->cprivate;
1601
1602     int r = tcpip_put(h, state->connect_request_buf,
1603                       state->connect_request_len);
1604     if (r == 0)
1605     {
1606         /* it's sent */
1607         h->f_put = tcpip_put; /* switch to normal tcpip put */
1608         r = tcpip_put(h, buf, size);
1609     }
1610     return r;
1611 }
1612
1613 static int tcpip_get_connect(COMSTACK h, char **buf, int *bufsize)
1614 {
1615     struct tcpip_state *state = (struct tcpip_state *)h->cprivate;
1616     int r;
1617
1618     r = tcpip_get(h, &state->connect_response_buf, 
1619                   &state->connect_response_len);
1620     if (r < 1)
1621         return r;
1622     /* got the connect response completely */
1623     state->complete = cs_complete_auto; /* switch to normal tcpip get */
1624     h->f_get = tcpip_get;
1625     return tcpip_get(h, buf, bufsize);
1626 }
1627
1628
1629 /*
1630  * Local variables:
1631  * c-basic-offset: 4
1632  * c-file-style: "Stroustrup"
1633  * indent-tabs-mode: nil
1634  * End:
1635  * vim: shiftwidth=4 tabstop=8 expandtab
1636  */
1637