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