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