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