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