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