Use getaddrinfo on Windows too
[yaz-moved-to-github.git] / src / tcpip.c
1 /*
2  * Copyright (C) 1995-2006, Index Data ApS
3  * See the file LICENSE for details.
4  *
5  * $Id: tcpip.c,v 1.24 2006-08-30 19:26:43 adam Exp $
6  */
7 /**
8  * \file tcpip.c
9  * \brief Implements TCP/IP + SSL COMSTACK.
10  */
11
12 #include <stdio.h>
13 #include <string.h>
14 #include <stdlib.h>
15 #include <errno.h>
16 #include <fcntl.h>
17 #include <signal.h>
18 #if HAVE_SYS_TYPES_H
19 #include <sys/types.h>
20 #endif
21 #if HAVE_SYS_TIME_H
22 #include <sys/time.h>
23 #endif
24 #if HAVE_UNISTD_H
25 #include <unistd.h>
26 #endif
27
28 #ifdef WIN32
29 #include <winsock2.h>
30 #include <ws2tcpip.h>
31 #define HAVE_GETADDRINFO 1
32 #else
33 #include <netinet/in.h>
34 #include <netdb.h>
35 #include <arpa/inet.h>
36 #include <netinet/tcp.h>
37 #endif
38
39 #if HAVE_SYS_SOCKET_H
40 #include <sys/socket.h>
41 #endif
42 #if HAVE_SYS_SELECT_H
43 #include <sys/select.h>
44 #endif
45 #if HAVE_SYS_WAIT_H
46 #include <sys/wait.h>
47 #endif
48
49 #if HAVE_OPENSSL_SSL_H
50 #include <openssl/ssl.h>
51 #include <openssl/err.h>
52 #endif
53
54 #include <yaz/comstack.h>
55 #include <yaz/tcpip.h>
56 #include <yaz/nmem.h>
57
58 static int tcpip_close(COMSTACK h);
59 static int tcpip_put(COMSTACK h, char *buf, int size);
60 static int tcpip_get(COMSTACK h, char **buf, int *bufsize);
61 static int tcpip_connect(COMSTACK h, void *address);
62 static int tcpip_more(COMSTACK h);
63 static int tcpip_rcvconnect(COMSTACK h);
64 static int tcpip_bind(COMSTACK h, void *address, int mode);
65 static int tcpip_listen(COMSTACK h, char *raddr, int *addrlen,
66                  int (*check_ip)(void *cd, const char *a, int len, int type),
67                  void *cd);
68 static int tcpip_set_blocking(COMSTACK p, int blocking);
69
70 #if HAVE_OPENSSL_SSL_H
71 static int ssl_get(COMSTACK h, char **buf, int *bufsize);
72 static int ssl_put(COMSTACK h, char *buf, int size);
73 #endif
74
75 static COMSTACK tcpip_accept(COMSTACK h);
76 static char *tcpip_addrstr(COMSTACK h);
77 static void *tcpip_straddr(COMSTACK h, const char *str);
78
79 #if 0
80 #define TRC(x) x
81 #else
82 #define TRC(X)
83 #endif
84
85 #ifndef YAZ_SOCKLEN_T
86 #define YAZ_SOCKLEN_T int
87 #endif
88
89 /* this state is used for both SSL and straight TCP/IP */
90 typedef struct tcpip_state
91 {
92     char *altbuf; /* alternate buffer for surplus data */
93     int altsize;  /* size as xmalloced */
94     int altlen;   /* length of data or 0 if none */
95
96     int written;  /* -1 if we aren't writing */
97     int towrite;  /* to verify against user input */
98     int (*complete)(const unsigned char *buf, int len); /* length/comple. */
99 #if HAVE_GETADDRINFO
100     struct addrinfo *res;
101 #else
102     struct sockaddr_in addr;  /* returned by cs_straddr */
103 #endif
104     char buf[128]; /* returned by cs_addrstr */
105 #if HAVE_OPENSSL_SSL_H
106     SSL_CTX *ctx;       /* current CTX. */
107     SSL_CTX *ctx_alloc; /* If =ctx it is owned by CS. If 0 it is not owned */
108     SSL *ssl;
109     char cert_fname[256];
110 #endif
111 } tcpip_state;
112
113 #ifdef WIN32
114 static int tcpip_init (void)
115 {
116     static int initialized = 0;
117     if (!initialized)
118     {
119         WORD requested;
120         WSADATA wd;
121
122         requested = MAKEWORD(1, 1);
123         if (WSAStartup(requested, &wd))
124             return 0;
125         initialized = 1;
126     }
127     return 1;
128 }
129 #else
130 static int tcpip_init (void)
131 {
132     return 1;
133 }
134 #endif
135
136 /*
137  * This function is always called through the cs_create() macro.
138  * s >= 0: socket has already been established for us.
139  */
140 COMSTACK tcpip_type(int s, int blocking, int protocol, void *vp)
141 {
142     COMSTACK p;
143     tcpip_state *sp;
144     int new_socket;
145 #ifdef WIN32
146     unsigned long tru = 1;
147 #endif
148
149     if (!tcpip_init ())
150         return 0;
151     if (s < 0)
152     {
153         if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0)
154             return 0;
155         new_socket = 1;
156     }
157     else
158         new_socket = 0;
159     if (!(p = (struct comstack *)xmalloc(sizeof(struct comstack))))
160         return 0;
161     if (!(sp = (struct tcpip_state *)(p->cprivate =
162                                          xmalloc(sizeof(tcpip_state)))))
163         return 0;
164
165     if (!((p->blocking = blocking)&1))
166     {
167 #ifdef WIN32
168         if (ioctlsocket(s, FIONBIO, &tru) < 0)
169             return 0;
170 #else
171         if (fcntl(s, F_SETFL, O_NONBLOCK) < 0)
172             return 0;
173 #ifndef MSG_NOSIGNAL
174         signal (SIGPIPE, SIG_IGN);
175 #endif
176 #endif
177     }
178
179     p->io_pending = 0;
180     p->iofile = s;
181     p->type = tcpip_type;
182     p->protocol = (enum oid_proto) protocol;
183
184     p->f_connect = tcpip_connect;
185     p->f_rcvconnect = tcpip_rcvconnect;
186     p->f_get = tcpip_get;
187     p->f_put = tcpip_put;
188     p->f_close = tcpip_close;
189     p->f_more = tcpip_more;
190     p->f_bind = tcpip_bind;
191     p->f_listen = tcpip_listen;
192     p->f_accept = tcpip_accept;
193     p->f_addrstr = tcpip_addrstr;
194     p->f_straddr = tcpip_straddr;
195     p->f_set_blocking = tcpip_set_blocking;
196     p->max_recv_bytes = 5000000;
197
198     p->state = new_socket ? CS_ST_UNBND : CS_ST_IDLE; /* state of line */
199     p->event = CS_NONE;
200     p->cerrno = 0;
201     p->stackerr = 0;
202     p->user = 0;
203
204 #if HAVE_OPENSSL_SSL_H
205     sp->ctx = sp->ctx_alloc = 0;
206     sp->ssl = 0;
207     strcpy(sp->cert_fname, "yaz.pem");
208 #endif
209
210 #if HAVE_GETADDRINFO
211     sp->res = 0;
212 #endif
213     sp->altbuf = 0;
214     sp->altsize = sp->altlen = 0;
215     sp->towrite = sp->written = -1;
216     if (protocol == PROTO_WAIS)
217         sp->complete = completeWAIS;
218     else
219         sp->complete = cs_complete_auto;
220
221     p->timeout = COMSTACK_DEFAULT_TIMEOUT;
222     TRC(fprintf(stderr, "Created new TCPIP comstack\n"));
223
224     return p;
225 }
226
227 #if HAVE_OPENSSL_SSL_H
228
229 COMSTACK ssl_type(int s, int blocking, int protocol, void *vp)
230 {
231     tcpip_state *sp;
232     COMSTACK p;
233
234     p = tcpip_type (s, blocking, protocol, 0);
235     if (!p)
236         return 0;
237     p->f_get = ssl_get;
238     p->f_put = ssl_put;
239     p->type = ssl_type;
240     sp = (tcpip_state *) p->cprivate;
241
242     sp->ctx = (SSL_CTX *) vp;  /* may be NULL */
243
244     /* note: we don't handle already opened socket in SSL mode - yet */
245     return p;
246 }
247 #endif
248
249 #if HAVE_GETADDRINFO
250 /* resolve using getaddrinfo */
251 struct addrinfo *tcpip_getaddrinfo(const char *str, const char *port)
252 {
253     struct addrinfo hints, *res;
254     int error;
255     char host[512], *p;
256
257     hints.ai_flags = 0;
258     hints.ai_family = AF_UNSPEC;
259     hints.ai_socktype = SOCK_STREAM;
260     hints.ai_protocol = 0;
261     hints.ai_addrlen        = 0;
262     hints.ai_addr           = NULL;
263     hints.ai_canonname      = NULL;
264     hints.ai_next           = NULL;
265
266     strncpy(host, str, sizeof(host)-1);
267     host[sizeof(host)-1] = 0;
268     if ((p = strchr(host, '/')))
269         *p = 0;
270     if ((p = strchr(host, ':')))
271     {
272         *p = '\0';
273         port = p+1;
274     }
275
276     if (!strcmp("@", host))
277     {
278         hints.ai_flags = AI_PASSIVE;
279         error = getaddrinfo(0, port, &hints, &res);
280     }
281     else
282     {
283         error = getaddrinfo(host, port, &hints, &res);
284     }
285     if (error)
286         return 0;
287     return res;
288 }
289
290 #endif
291 /* gethostbyname .. old systems */
292 int tcpip_strtoaddr_ex(const char *str, struct sockaddr_in *add,
293                        int default_port)
294 {
295     struct hostent *hp;
296     char *p, buf[512];
297     short int port = default_port;
298 #ifdef WIN32
299     unsigned long tmpadd;
300 #else
301     in_addr_t tmpadd;
302 #endif
303     TRC(fprintf(stderr, "tcpip_strtoaddress: %s\n", str ? str : "NULL"));
304     add->sin_family = AF_INET;
305     strncpy(buf, str, sizeof(buf)-1);
306     buf[sizeof(buf)-1] = 0;
307     if ((p = strchr(buf, '/')))
308         *p = 0;
309     if ((p = strchr(buf, ':')))
310     {
311         *p = 0;
312         port = atoi(p + 1);
313     }
314     add->sin_port = htons(port);
315     if (!strcmp("@", buf))
316     {
317         add->sin_addr.s_addr = INADDR_ANY;
318     }
319     else if ((tmpadd = inet_addr(buf)) != -1)
320     {
321         memcpy(&add->sin_addr.s_addr, &tmpadd, sizeof(struct in_addr));
322     }
323     else if ((hp = gethostbyname(buf)))
324     {
325         memcpy(&add->sin_addr.s_addr, *hp->h_addr_list,
326                sizeof(struct in_addr));
327     }
328     else
329         return 0;
330     return 1;
331 }
332
333
334 #if HAVE_GETADDRINFO
335 void *tcpip_straddr(COMSTACK h, const char *str)
336 {
337     tcpip_state *sp = (tcpip_state *)h->cprivate;
338     const char *port = "210";
339     if (h->protocol == PROTO_HTTP)
340         port = "80";
341     if (!tcpip_init ())
342         return 0;
343
344     if (sp->res)
345         freeaddrinfo(sp->res);
346     sp->res = tcpip_getaddrinfo(str, port);
347     return sp->res;
348 }
349 #else
350 void *tcpip_straddr(COMSTACK h, const char *str)
351 {
352     tcpip_state *sp = (tcpip_state *)h->cprivate;
353     int port = 210;
354     if (h->protocol == PROTO_HTTP)
355         port = 80;
356
357     if (!tcpip_init ())
358         return 0;
359     if (!tcpip_strtoaddr_ex (str, &sp->addr, port))
360         return 0;
361     return &sp->addr;
362 }
363 #endif
364
365 int tcpip_more(COMSTACK h)
366 {
367     tcpip_state *sp = (tcpip_state *)h->cprivate;
368     
369     return sp->altlen && (*sp->complete)((unsigned char *) sp->altbuf,
370         sp->altlen);
371 }
372
373 /*
374  * connect(2) will block (sometimes) - nothing we can do short of doing
375  * weird things like spawning subprocesses or threading or some weird junk
376  * like that.
377  */
378 int tcpip_connect(COMSTACK h, void *address)
379 {
380 #if HAVE_GETADDRINFO
381     struct addrinfo *ai = (struct addrinfo *) address; 
382 #else
383     struct sockaddr_in *add = (struct sockaddr_in *) address;
384 #endif
385     int r;
386 #ifdef __sun__
387     int recbuflen;
388     YAZ_SOCKLEN_T rbufsize = sizeof(recbuflen);
389 #endif
390     TRC(fprintf(stderr, "tcpip_connect\n"));
391     h->io_pending = 0;
392     if (h->state != CS_ST_UNBND)
393     {
394         h->cerrno = CSOUTSTATE;
395         return -1;
396     }
397 #ifdef __sun__
398     /* On Suns, you must set a bigger Receive Buffer BEFORE a call to connect
399      * This gives the connect a chance to negotiate with the other side
400      * (see 'man tcp') 
401      */
402     if ( getsockopt(h->iofile, SOL_SOCKET, SO_RCVBUF, (void *)&recbuflen, &rbufsize ) < 0 )
403     {
404         h->cerrno = CSYSERR;
405         return -1;
406     }
407     TRC(fprintf( stderr, "Current Size of TCP Receive Buffer= %d\n",
408                  recbuflen ));
409     recbuflen *= 10; /* lets be optimistic */
410     if ( setsockopt(h->iofile, SOL_SOCKET, SO_RCVBUF, (void *)&recbuflen, rbufsize ) < 0 )
411     {
412         h->cerrno = CSYSERR;
413         return -1;
414     }
415     if ( getsockopt(h->iofile, SOL_SOCKET, SO_RCVBUF, (void *)&recbuflen, &rbufsize ) )
416     {
417         h->cerrno = CSYSERR;
418         return -1;
419     }
420     TRC(fprintf( stderr, "New Size of TCP Receive Buffer = %d\n",
421                  recbuflen ));
422 #endif
423
424 #if HAVE_GETADDRINFO
425     r = connect(h->iofile, ai->ai_addr, ai->ai_addrlen);
426 #else
427     r = connect(h->iofile, (struct sockaddr *) add, sizeof(*add));
428 #endif
429     if (r < 0)
430     {
431 #ifdef WIN32
432         if (WSAGetLastError() == WSAEWOULDBLOCK)
433         {
434             h->event = CS_CONNECT;
435             h->state = CS_ST_CONNECTING;
436             h->io_pending = CS_WANT_WRITE;
437             return 1;
438         }
439 #else
440         if (yaz_errno() == EINPROGRESS)
441         {
442             h->event = CS_CONNECT;
443             h->state = CS_ST_CONNECTING;
444             h->io_pending = CS_WANT_WRITE|CS_WANT_READ;
445             return 1;
446         }
447 #endif
448         h->cerrno = CSYSERR;
449         return -1;
450     }
451     h->event = CS_CONNECT;
452     h->state = CS_ST_CONNECTING;
453
454     return tcpip_rcvconnect (h);
455 }
456
457 /*
458  * nop
459  */
460 int tcpip_rcvconnect(COMSTACK h)
461 {
462 #if HAVE_OPENSSL_SSL_H
463     tcpip_state *sp = (tcpip_state *)h->cprivate;
464 #endif
465     TRC(fprintf(stderr, "tcpip_rcvconnect\n"));
466
467     if (h->state == CS_ST_DATAXFER)
468         return 0;
469     if (h->state != CS_ST_CONNECTING)
470     {
471         h->cerrno = CSOUTSTATE;
472         return -1;
473     }
474 #if HAVE_OPENSSL_SSL_H
475     if (h->type == ssl_type && !sp->ctx)
476     {
477         SSL_load_error_strings();
478         SSLeay_add_all_algorithms();
479
480         sp->ctx = sp->ctx_alloc = SSL_CTX_new (SSLv23_method());
481         if (!sp->ctx)
482         {
483             h->cerrno = CSERRORSSL;
484             return -1;
485         }
486     }
487     if (sp->ctx)
488     {
489         int res;
490
491         if (!sp->ssl)
492         {
493             sp->ssl = SSL_new (sp->ctx);
494             SSL_set_fd (sp->ssl, h->iofile);
495         }
496         res = SSL_connect (sp->ssl);
497         if (res <= 0)
498         {
499             int err = SSL_get_error(sp->ssl, res);
500             if (err == SSL_ERROR_WANT_READ)
501             {
502                 h->io_pending = CS_WANT_READ;
503                 return 1;
504             }
505             if (err == SSL_ERROR_WANT_WRITE)
506             {
507                 h->io_pending = CS_WANT_WRITE;
508                 return 1;
509             }
510             h->cerrno = CSERRORSSL;
511             return -1;
512         }
513     }
514 #endif
515     h->event = CS_DATA;
516     h->state = CS_ST_DATAXFER;
517     return 0;
518 }
519
520 #define CERTF "ztest.pem"
521 #define KEYF "ztest.pem"
522
523 static void tcpip_setsockopt (int fd)
524 {
525 #if 0
526     int len = 4096;
527     int set = 1;
528     
529     if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char*)&set, sizeof(int)))
530     {
531         yaz_log(LOG_WARN|LOG_ERRNO, "setsockopt TCP_NODELAY");
532     }
533     if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (char*)&len, sizeof(int)))
534     {
535         yaz_log(LOG_WARN|LOG_ERRNO, "setsockopt SNDBUF");
536     }
537     if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char*)&len, sizeof(int)))
538     {
539         yaz_log(LOG_WARN|LOG_ERRNO, "setsockopt RCVBUF");
540     }
541 #endif
542 }
543
544 static int tcpip_bind(COMSTACK h, void *address, int mode)
545 {
546     int r;
547 #if HAVE_GETADDRINFO
548     struct addrinfo *ai = (struct addrinfo *)address;
549 #else
550     struct sockaddr *addr = (struct sockaddr *)address;
551 #endif
552 #ifdef WIN32
553     BOOL one = 1;
554 #else
555     unsigned long one = 1;
556 #endif
557
558 #if HAVE_OPENSSL_SSL_H
559     tcpip_state *sp = (tcpip_state *)h->cprivate;
560     if (h->type == ssl_type && !sp->ctx)
561     {
562         SSL_load_error_strings();
563         SSLeay_add_all_algorithms();
564
565         sp->ctx = sp->ctx_alloc = SSL_CTX_new (SSLv23_method());
566         if (!sp->ctx)
567         {
568             h->cerrno = CSERRORSSL;
569             return -1;
570         }
571     }
572     if (sp->ctx)
573     {
574         if (sp->ctx_alloc)
575         {
576             int res;
577             res = SSL_CTX_use_certificate_chain_file(sp->ctx, sp->cert_fname);
578             if (res <= 0)
579             {
580                 ERR_print_errors_fp(stderr);
581                 exit (2);
582             }
583             res = SSL_CTX_use_PrivateKey_file (sp->ctx, sp->cert_fname,
584                                                SSL_FILETYPE_PEM);
585             if (res <= 0)
586             {
587                 ERR_print_errors_fp(stderr);
588                 exit (3);
589             }
590             res = SSL_CTX_check_private_key (sp->ctx);
591             if (res <= 0)
592             {
593                 ERR_print_errors_fp(stderr);
594                 exit(5);
595             }
596         }
597         TRC (fprintf (stderr, "ssl_bind\n"));
598     }
599     else
600     {
601         TRC (fprintf (stderr, "tcpip_bind\n"));
602     }
603 #else
604     TRC (fprintf (stderr, "tcpip_bind\n"));
605 #endif
606 #ifndef WIN32
607     if (setsockopt(h->iofile, SOL_SOCKET, SO_REUSEADDR, (char*) 
608         &one, sizeof(one)) < 0)
609     {
610         h->cerrno = CSYSERR;
611         return -1;
612     }
613 #endif
614     tcpip_setsockopt(h->iofile);
615 #if HAVE_GETADDRINFO
616     r = bind(h->iofile, ai->ai_addr, ai->ai_addrlen);
617 #else
618     r = bind(h->iofile, addr, sizeof(struct sockaddr_in));
619 #endif
620     if (r)
621     {
622         h->cerrno = CSYSERR;
623         return -1;
624     }
625     /* Allow a maximum-sized backlog of waiting-to-connect clients */
626     if (mode == CS_SERVER && listen(h->iofile, SOMAXCONN) < 0)
627     {
628         h->cerrno = CSYSERR;
629         return -1;
630     }
631     h->state = CS_ST_IDLE;
632     h->event = CS_LISTEN;
633     return 0;
634 }
635
636 int tcpip_listen(COMSTACK h, char *raddr, int *addrlen,
637                  int (*check_ip)(void *cd, const char *a, int len, int t),
638                  void *cd)
639 {
640     struct sockaddr_in addr;
641     YAZ_SOCKLEN_T len = sizeof(addr);
642
643     TRC(fprintf(stderr, "tcpip_listen pid=%d\n", getpid()));
644     if (h->state != CS_ST_IDLE)
645     {
646         h->cerrno = CSOUTSTATE;
647         return -1;
648     }
649     h->newfd = accept(h->iofile, (struct sockaddr*)&addr, &len);
650     if (h->newfd < 0)
651     {
652         if (
653 #ifdef WIN32
654             WSAGetLastError() == WSAEWOULDBLOCK
655 #else
656             yaz_errno() == EWOULDBLOCK 
657 #ifdef EAGAIN
658 #if EAGAIN != EWOULDBLOCK
659             || yaz_errno() == EAGAIN
660 #endif
661 #endif
662 #endif
663             )
664             h->cerrno = CSNODATA;
665         else
666             h->cerrno = CSYSERR;
667         return -1;
668     }
669     if (addrlen && (size_t) (*addrlen) >= sizeof(struct sockaddr_in))
670         memcpy(raddr, &addr, *addrlen = sizeof(struct sockaddr_in));
671     else if (addrlen)
672         *addrlen = 0;
673     if (check_ip && (*check_ip)(cd, (const char *) &addr,
674         sizeof(addr), AF_INET))
675     {
676         h->cerrno = CSDENY;
677 #ifdef WIN32
678         closesocket(h->newfd);
679 #else
680         close(h->newfd);
681 #endif
682         h->newfd = -1;
683         return -1;
684     }
685     h->state = CS_ST_INCON;
686     tcpip_setsockopt (h->newfd);
687     return 0;
688 }
689
690 COMSTACK tcpip_accept(COMSTACK h)
691 {
692     COMSTACK cnew;
693     tcpip_state *state, *st = (tcpip_state *)h->cprivate;
694 #ifdef WIN32
695     unsigned long tru = 1;
696 #endif
697
698     TRC(fprintf(stderr, "tcpip_accept\n"));
699     if (h->state == CS_ST_INCON)
700     {
701         if (!(cnew = (COMSTACK)xmalloc(sizeof(*cnew))))
702         {
703             h->cerrno = CSYSERR;
704 #ifdef WIN32
705             closesocket(h->newfd);
706 #else
707             close(h->newfd);
708 #endif
709             h->newfd = -1;
710             return 0;
711         }
712         memcpy(cnew, h, sizeof(*h));
713         cnew->iofile = h->newfd;
714         cnew->io_pending = 0;
715         if (!(state = (tcpip_state *)
716               (cnew->cprivate = xmalloc(sizeof(tcpip_state)))))
717         {
718             h->cerrno = CSYSERR;
719             if (h->newfd != -1)
720             {
721 #ifdef WIN32
722                 closesocket(h->newfd);
723 #else
724                 close(h->newfd);
725 #endif
726                 h->newfd = -1;
727             }
728             return 0;
729         }
730         if (!(cnew->blocking&1) && 
731 #ifdef WIN32
732             (ioctlsocket(cnew->iofile, FIONBIO, &tru) < 0)
733 #else
734             (fcntl(cnew->iofile, F_SETFL, O_NONBLOCK) < 0)
735 #endif
736             )
737         {
738             h->cerrno = CSYSERR;
739             if (h->newfd != -1)
740             {
741 #ifdef WIN32
742                 closesocket(h->newfd);
743 #else
744                 close(h->newfd);
745 #endif
746                 h->newfd = -1;
747             }
748             xfree (cnew);
749             xfree (state);
750             return 0;
751         }
752         h->newfd = -1;
753         state->altbuf = 0;
754         state->altsize = state->altlen = 0;
755         state->towrite = state->written = -1;
756         state->complete = st->complete;
757         cnew->state = CS_ST_ACCEPT;
758         h->state = CS_ST_IDLE;
759         
760 #if HAVE_OPENSSL_SSL_H
761         state->ctx = st->ctx;
762         state->ctx_alloc = 0;
763         state->ssl = st->ssl;
764         if (state->ctx)
765         {
766             state->ssl = SSL_new (state->ctx);
767             SSL_set_fd (state->ssl, cnew->iofile);
768         }
769 #endif
770         h = cnew;
771     }
772     if (h->state == CS_ST_ACCEPT)
773     {
774 #if HAVE_OPENSSL_SSL_H
775         tcpip_state *state = (tcpip_state *)h->cprivate;
776         if (state->ctx)
777         {
778             int res = SSL_accept (state->ssl);
779             TRC(fprintf(stderr, "SSL_accept\n"));
780             if (res <= 0)
781             {
782                 int err = SSL_get_error(state->ssl, res);
783                 if (err == SSL_ERROR_WANT_READ)
784                 {
785                     h->io_pending = CS_WANT_READ;
786                     return h;
787                 }
788                 if (err == SSL_ERROR_WANT_WRITE)
789                 {
790                     h->io_pending = CS_WANT_WRITE;
791                     return h;
792                 }
793                 cs_close (h);
794                 return 0;
795             }
796         }
797 #endif
798     }
799     else
800     {
801         h->cerrno = CSOUTSTATE;
802         return 0;
803     }
804     h->io_pending = 0;
805     h->state = CS_ST_DATAXFER;
806     h->event = CS_DATA;
807     return h;
808 }
809
810 #define CS_TCPIP_BUFCHUNK 4096
811
812 /*
813  * Return: -1 error, >1 good, len of buffer, ==1 incomplete buffer,
814  * 0=connection closed.
815  */
816 int tcpip_get(COMSTACK h, char **buf, int *bufsize)
817 {
818     tcpip_state *sp = (tcpip_state *)h->cprivate;
819     char *tmpc;
820     int tmpi, berlen, rest, req, tomove;
821     int hasread = 0, res;
822
823     TRC(fprintf(stderr, "tcpip_get: bufsize=%d\n", *bufsize));
824     if (sp->altlen) /* switch buffers */
825     {
826         TRC(fprintf(stderr, "  %d bytes in altbuf (0x%x)\n", sp->altlen,
827             (unsigned) sp->altbuf));
828         tmpc = *buf;
829         tmpi = *bufsize;
830         *buf = sp->altbuf;
831         *bufsize = sp->altsize;
832         hasread = sp->altlen;
833         sp->altlen = 0;
834         sp->altbuf = tmpc;
835         sp->altsize = tmpi;
836     }
837     h->io_pending = 0;
838     while (!(berlen = (*sp->complete)((unsigned char *)*buf, hasread)))
839     {
840         if (!*bufsize)
841         {
842             if (!(*buf = (char *)xmalloc(*bufsize = CS_TCPIP_BUFCHUNK)))
843             {
844                 h->cerrno = CSYSERR;
845                 return -1;
846             }
847         }
848         else if (*bufsize - hasread < CS_TCPIP_BUFCHUNK)
849             if (!(*buf =(char *)xrealloc(*buf, *bufsize *= 2)))
850             {
851                 h->cerrno = CSYSERR;
852                 return -1;
853             }
854 #ifdef __sun__
855         yaz_set_errno( 0 );
856         /* unfortunatly, sun sometimes forgets to set errno in recv
857            when EWOULDBLOCK etc. would be required (res = -1) */
858 #endif
859         res = recv(h->iofile, *buf + hasread, CS_TCPIP_BUFCHUNK, 0);
860         TRC(fprintf(stderr, "  recv res=%d, hasread=%d\n", res, hasread));
861         if (res < 0)
862         {
863           TRC(fprintf(stderr, "  recv errno=%d, (%s)\n", yaz_errno(), 
864                       strerror(yaz_errno())));
865 #ifdef WIN32
866             if (WSAGetLastError() == WSAEWOULDBLOCK)
867             {
868                 h->io_pending = CS_WANT_READ;
869                 break;
870             }
871             else
872                 return -1;
873 #else
874             if (yaz_errno() == EWOULDBLOCK 
875 #ifdef EAGAIN   
876 #if EAGAIN != EWOULDBLOCK
877                 || yaz_errno() == EAGAIN
878 #endif
879 #endif
880                 || yaz_errno() == EINPROGRESS
881 #ifdef __sun__
882                 || yaz_errno() == ENOENT /* Sun's sometimes set errno to this */
883 #endif
884                 )
885             {
886                 h->io_pending = CS_WANT_READ;
887                 break;
888             }
889             else if (yaz_errno() == 0)
890                 continue;
891             else
892                 return -1;
893 #endif
894         }
895         else if (!res)
896             return hasread;
897         hasread += res;
898         if (hasread > h->max_recv_bytes)
899         {
900             h->cerrno = CSBUFSIZE;
901             return -1;
902         }
903     }
904     TRC (fprintf (stderr, "  Out of read loop with hasread=%d, berlen=%d\n",
905                   hasread, berlen));
906     /* move surplus buffer (or everything if we didn't get a BER rec.) */
907     if (hasread > berlen)
908     {
909         tomove = req = hasread - berlen;
910         rest = tomove % CS_TCPIP_BUFCHUNK;
911         if (rest)
912             req += CS_TCPIP_BUFCHUNK - rest;
913         if (!sp->altbuf)
914         {
915             if (!(sp->altbuf = (char *)xmalloc(sp->altsize = req)))
916                 return -1;
917         } else if (sp->altsize < req)
918             if (!(sp->altbuf =(char *)xrealloc(sp->altbuf, sp->altsize = req)))
919                 return -1;
920         TRC(fprintf(stderr, "  Moving %d bytes to altbuf(0x%x)\n", tomove,
921             (unsigned) sp->altbuf));
922         memcpy(sp->altbuf, *buf + berlen, sp->altlen = tomove);
923     }
924     if (berlen < CS_TCPIP_BUFCHUNK - 1)
925         *(*buf + berlen) = '\0';
926     return berlen ? berlen : 1;
927 }
928
929
930 #if HAVE_OPENSSL_SSL_H
931 /*
932  * Return: -1 error, >1 good, len of buffer, ==1 incomplete buffer,
933  * 0=connection closed.
934  */
935 int ssl_get(COMSTACK h, char **buf, int *bufsize)
936 {
937     tcpip_state *sp = (tcpip_state *)h->cprivate;
938     char *tmpc;
939     int tmpi, berlen, rest, req, tomove;
940     int hasread = 0, res;
941
942     TRC(fprintf(stderr, "ssl_get: bufsize=%d\n", *bufsize));
943     if (sp->altlen) /* switch buffers */
944     {
945         TRC(fprintf(stderr, "  %d bytes in altbuf (0x%x)\n", sp->altlen,
946             (unsigned) sp->altbuf));
947         tmpc = *buf;
948         tmpi = *bufsize;
949         *buf = sp->altbuf;
950         *bufsize = sp->altsize;
951         hasread = sp->altlen;
952         sp->altlen = 0;
953         sp->altbuf = tmpc;
954         sp->altsize = tmpi;
955     }
956     h->io_pending = 0;
957     while (!(berlen = (*sp->complete)((unsigned char *)*buf, hasread)))
958     {
959         if (!*bufsize)
960         {
961             if (!(*buf = (char *)xmalloc(*bufsize = CS_TCPIP_BUFCHUNK)))
962                 return -1;
963         }
964         else if (*bufsize - hasread < CS_TCPIP_BUFCHUNK)
965             if (!(*buf =(char *)xrealloc(*buf, *bufsize *= 2)))
966                 return -1;
967         res = SSL_read (sp->ssl, *buf + hasread, CS_TCPIP_BUFCHUNK);
968         TRC(fprintf(stderr, "  SSL_read res=%d, hasread=%d\n", res, hasread));
969         if (res <= 0)
970         {
971             int ssl_err = SSL_get_error(sp->ssl, res);
972             if (ssl_err == SSL_ERROR_WANT_READ)
973             {
974                 h->io_pending = CS_WANT_READ;
975                 break;
976             }
977             if (ssl_err == SSL_ERROR_WANT_WRITE)
978             {
979                 h->io_pending = CS_WANT_WRITE;
980                 break;
981             }
982             if (res == 0)
983                 return 0;
984             h->cerrno = CSERRORSSL;
985             return -1;
986         }
987         hasread += res;
988     }
989     TRC (fprintf (stderr, "  Out of read loop with hasread=%d, berlen=%d\n",
990         hasread, berlen));
991     /* move surplus buffer (or everything if we didn't get a BER rec.) */
992     if (hasread > berlen)
993     {
994         tomove = req = hasread - berlen;
995         rest = tomove % CS_TCPIP_BUFCHUNK;
996         if (rest)
997             req += CS_TCPIP_BUFCHUNK - rest;
998         if (!sp->altbuf)
999         {
1000             if (!(sp->altbuf = (char *)xmalloc(sp->altsize = req)))
1001                 return -1;
1002         } else if (sp->altsize < req)
1003             if (!(sp->altbuf =(char *)xrealloc(sp->altbuf, sp->altsize = req)))
1004                 return -1;
1005         TRC(fprintf(stderr, "  Moving %d bytes to altbuf(0x%x)\n", tomove,
1006             (unsigned) sp->altbuf));
1007         memcpy(sp->altbuf, *buf + berlen, sp->altlen = tomove);
1008     }
1009     if (berlen < CS_TCPIP_BUFCHUNK - 1)
1010         *(*buf + berlen) = '\0';
1011     return berlen ? berlen : 1;
1012 }
1013 #endif
1014
1015 /*
1016  * Returns 1, 0 or -1
1017  * In nonblocking mode, you must call again with same buffer while
1018  * return value is 1.
1019  */
1020 int tcpip_put(COMSTACK h, char *buf, int size)
1021 {
1022     int res;
1023     struct tcpip_state *state = (struct tcpip_state *)h->cprivate;
1024
1025     TRC(fprintf(stderr, "tcpip_put: size=%d\n", size));
1026     h->io_pending = 0;
1027     h->event = CS_DATA;
1028     if (state->towrite < 0)
1029     {
1030         state->towrite = size;
1031         state->written = 0;
1032     }
1033     else if (state->towrite != size)
1034     {
1035         h->cerrno = CSWRONGBUF;
1036         return -1;
1037     }
1038     while (state->towrite > state->written)
1039     {
1040         if ((res =
1041              send(h->iofile, buf + state->written, size -
1042                   state->written, 
1043 #ifdef MSG_NOSIGNAL
1044                   MSG_NOSIGNAL
1045 #else
1046                   0
1047 #endif
1048                  )) < 0)
1049         {
1050             if (
1051 #ifdef WIN32
1052                 WSAGetLastError() == WSAEWOULDBLOCK
1053 #else
1054                 yaz_errno() == EWOULDBLOCK 
1055 #ifdef EAGAIN
1056 #if EAGAIN != EWOULDBLOCK
1057              || yaz_errno() == EAGAIN
1058 #endif
1059 #endif
1060 #ifdef __sun__
1061                 || yaz_errno() == ENOENT /* Sun's sometimes set errno to this value! */
1062 #endif
1063                 || yaz_errno() == EINPROGRESS
1064 #endif
1065                 )
1066             {
1067                 TRC(fprintf(stderr, "  Flow control stop\n"));
1068                 h->io_pending = CS_WANT_WRITE;
1069                 return 1;
1070             }
1071             h->cerrno = CSYSERR;
1072             return -1;
1073         }
1074         state->written += res;
1075         TRC(fprintf(stderr, "  Wrote %d, written=%d, nbytes=%d\n",
1076                     res, state->written, size));
1077     }
1078     state->towrite = state->written = -1;
1079     TRC(fprintf(stderr, "  Ok\n"));
1080     return 0;
1081 }
1082
1083
1084 #if HAVE_OPENSSL_SSL_H
1085 /*
1086  * Returns 1, 0 or -1
1087  * In nonblocking mode, you must call again with same buffer while
1088  * return value is 1.
1089  */
1090 int ssl_put(COMSTACK h, char *buf, int size)
1091 {
1092     int res;
1093     struct tcpip_state *state = (struct tcpip_state *)h->cprivate;
1094
1095     TRC(fprintf(stderr, "ssl_put: size=%d\n", size));
1096     h->io_pending = 0;
1097     h->event = CS_DATA;
1098     if (state->towrite < 0)
1099     {
1100         state->towrite = size;
1101         state->written = 0;
1102     }
1103     else if (state->towrite != size)
1104     {
1105         h->cerrno = CSWRONGBUF;
1106         return -1;
1107     }
1108     while (state->towrite > state->written)
1109     {
1110         res = SSL_write (state->ssl, buf + state->written,
1111                          size - state->written);
1112         if (res <= 0)
1113         {
1114             int ssl_err = SSL_get_error(state->ssl, res);
1115             if (ssl_err == SSL_ERROR_WANT_READ)
1116             {
1117                 h->io_pending = CS_WANT_READ;
1118                 return 1;
1119             }
1120             if (ssl_err == SSL_ERROR_WANT_WRITE)
1121             {
1122                 h->io_pending = CS_WANT_WRITE;
1123                 return 1;
1124             }
1125             h->cerrno = CSERRORSSL;
1126             return -1;
1127         }
1128         state->written += res;
1129         TRC(fprintf(stderr, "  Wrote %d, written=%d, nbytes=%d\n",
1130                     res, state->written, size));
1131     }
1132     state->towrite = state->written = -1;
1133     TRC(fprintf(stderr, "  Ok\n"));
1134     return 0;
1135 }
1136 #endif
1137
1138 int tcpip_close(COMSTACK h)
1139 {
1140     tcpip_state *sp = (struct tcpip_state *)h->cprivate;
1141
1142     TRC(fprintf(stderr, "tcpip_close\n"));
1143     if (h->iofile != -1)
1144     {
1145 #if HAVE_OPENSSL_SSL_H
1146         if (sp->ssl)
1147         {
1148             SSL_shutdown (sp->ssl);
1149         }
1150 #endif
1151 #ifdef WIN32
1152         closesocket(h->iofile);
1153 #else
1154         close(h->iofile);
1155 #endif
1156     }
1157     if (sp->altbuf)
1158         xfree(sp->altbuf);
1159 #if HAVE_OPENSSL_SSL_H
1160     if (sp->ssl)
1161     {
1162         TRC (fprintf(stderr, "SSL_free\n"));
1163         SSL_free (sp->ssl);
1164     }
1165     sp->ssl = 0;
1166     if (sp->ctx_alloc)
1167         SSL_CTX_free (sp->ctx_alloc);
1168 #endif
1169 #if HAVE_GETADDRINFO
1170     if (sp->res)
1171         freeaddrinfo(sp->res);
1172 #endif
1173     xfree(sp);
1174     xfree(h);
1175     return 0;
1176 }
1177
1178 char *tcpip_addrstr(COMSTACK h)
1179 {
1180     struct sockaddr_in addr;
1181     tcpip_state *sp = (struct tcpip_state *)h->cprivate;
1182     char *r = 0, *buf = sp->buf;
1183     YAZ_SOCKLEN_T len;
1184     struct hostent *host;
1185     
1186     len = sizeof(addr);
1187     if (getpeername(h->iofile, (struct sockaddr*) &addr, &len) < 0)
1188     {
1189         h->cerrno = CSYSERR;
1190         return 0;
1191     }
1192     if (!(h->blocking&2)) {
1193         if ((host = gethostbyaddr((char*)&addr.sin_addr, sizeof(addr.sin_addr),
1194                               AF_INET)))
1195             r = (char*) host->h_name;
1196     }
1197     if (!r)
1198         r = inet_ntoa(addr.sin_addr);
1199     if (h->protocol == PROTO_HTTP)
1200         sprintf(buf, "http:%s", r);
1201     else
1202         sprintf(buf, "tcp:%s", r);
1203 #if HAVE_OPENSSL_SSL_H
1204     if (sp->ctx)
1205     {
1206         if (h->protocol == PROTO_HTTP)
1207             sprintf(buf, "https:%s", r);
1208         else
1209             sprintf(buf, "ssl:%s", r);
1210     }
1211 #endif
1212     return buf;
1213 }
1214
1215 int static tcpip_set_blocking(COMSTACK p, int blocking)
1216 {
1217     unsigned long flag;
1218     
1219     if (p->blocking == blocking)
1220         return 1;
1221 #ifdef WIN32
1222     flag = 1;
1223     if (ioctlsocket(p->iofile, FIONBIO, &flag) < 0)
1224         return 0;
1225 #else
1226     flag = fcntl(p->iofile, F_GETFL, 0);
1227     if(!(blocking&1))
1228         flag = flag & ~O_NONBLOCK;
1229     else
1230         flag = flag | O_NONBLOCK;
1231     if (fcntl(p->iofile, F_SETFL, flag) < 0)
1232         return 0;
1233 #endif
1234     p->blocking = blocking;
1235     return 1;
1236 }
1237
1238 #if HAVE_OPENSSL_SSL_H
1239 int cs_set_ssl_ctx(COMSTACK cs, void *ctx)
1240 {
1241     struct tcpip_state *sp;
1242     if (!cs || cs->type != ssl_type)
1243         return 0;
1244     sp = (struct tcpip_state *) cs->cprivate;
1245     if (sp->ctx_alloc)
1246         return 0;
1247     sp->ctx = (SSL_CTX *) ctx;
1248     return 1;
1249 }
1250
1251 void *cs_get_ssl(COMSTACK cs)
1252 {
1253     struct tcpip_state *sp;
1254     if (!cs || cs->type != ssl_type)
1255         return 0;
1256     sp = (struct tcpip_state *) cs->cprivate;
1257     return sp->ssl;  
1258 }
1259
1260 int cs_set_ssl_certificate_file(COMSTACK cs, const char *fname)
1261 {
1262     struct tcpip_state *sp;
1263     if (!cs || cs->type != ssl_type)
1264         return 0;
1265     sp = (struct tcpip_state *) cs->cprivate;
1266     strncpy(sp->cert_fname, fname, sizeof(sp->cert_fname)-1);
1267     sp->cert_fname[sizeof(sp->cert_fname)-1] = '\0';
1268     return 1;
1269 }
1270
1271 int cs_get_peer_certificate_x509(COMSTACK cs, char **buf, int *len)
1272 {
1273     SSL *ssl = (SSL *) cs_get_ssl(cs);
1274     if (ssl)
1275     {
1276         X509 *server_cert = SSL_get_peer_certificate (ssl);
1277         if (server_cert)
1278         {
1279             BIO *bio = BIO_new(BIO_s_mem());
1280             char *pem_buf;
1281             /* get PEM buffer in memory */
1282             PEM_write_bio_X509(bio, server_cert);
1283             *len = BIO_get_mem_data(bio, &pem_buf);
1284             *buf = (char *) xmalloc(*len);
1285             memcpy(*buf, pem_buf, *len);
1286             BIO_free(bio);
1287             return 1;
1288         }
1289     }
1290     return 0;
1291 }
1292 #else
1293 int cs_set_ssl_ctx(COMSTACK cs, void *ctx)
1294 {
1295     return 0;
1296 }
1297
1298 void *cs_get_ssl(COMSTACK cs)
1299 {
1300     return 0;
1301 }
1302
1303 int cs_get_peer_certificate_x509(COMSTACK cs, char **buf, int *len)
1304 {
1305     return 0;
1306 }
1307
1308 int cs_set_ssl_certificate_file(COMSTACK cs, const char *fname)
1309 {
1310     return 0;
1311 }
1312 #endif
1313
1314 /*
1315  * Local variables:
1316  * c-basic-offset: 4
1317  * indent-tabs-mode: nil
1318  * End:
1319  * vim: shiftwidth=4 tabstop=8 expandtab
1320  */
1321