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