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