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