Using results of getaddrinfo to create sockets. This might just be what
[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.25 2006-09-01 10:39:09 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 = strchr(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 = strchr(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                 return -1;
887 #else
888             if (yaz_errno() == EWOULDBLOCK 
889 #ifdef EAGAIN   
890 #if EAGAIN != EWOULDBLOCK
891                 || yaz_errno() == EAGAIN
892 #endif
893 #endif
894                 || yaz_errno() == EINPROGRESS
895 #ifdef __sun__
896                 || yaz_errno() == ENOENT /* Sun's sometimes set errno to this */
897 #endif
898                 )
899             {
900                 h->io_pending = CS_WANT_READ;
901                 break;
902             }
903             else if (yaz_errno() == 0)
904                 continue;
905             else
906                 return -1;
907 #endif
908         }
909         else if (!res)
910             return hasread;
911         hasread += res;
912         if (hasread > h->max_recv_bytes)
913         {
914             h->cerrno = CSBUFSIZE;
915             return -1;
916         }
917     }
918     TRC (fprintf (stderr, "  Out of read loop with hasread=%d, berlen=%d\n",
919                   hasread, berlen));
920     /* move surplus buffer (or everything if we didn't get a BER rec.) */
921     if (hasread > berlen)
922     {
923         tomove = req = hasread - berlen;
924         rest = tomove % CS_TCPIP_BUFCHUNK;
925         if (rest)
926             req += CS_TCPIP_BUFCHUNK - rest;
927         if (!sp->altbuf)
928         {
929             if (!(sp->altbuf = (char *)xmalloc(sp->altsize = req)))
930                 return -1;
931         } else if (sp->altsize < req)
932             if (!(sp->altbuf =(char *)xrealloc(sp->altbuf, sp->altsize = req)))
933                 return -1;
934         TRC(fprintf(stderr, "  Moving %d bytes to altbuf(0x%x)\n", tomove,
935             (unsigned) sp->altbuf));
936         memcpy(sp->altbuf, *buf + berlen, sp->altlen = tomove);
937     }
938     if (berlen < CS_TCPIP_BUFCHUNK - 1)
939         *(*buf + berlen) = '\0';
940     return berlen ? berlen : 1;
941 }
942
943
944 #if HAVE_OPENSSL_SSL_H
945 /*
946  * Return: -1 error, >1 good, len of buffer, ==1 incomplete buffer,
947  * 0=connection closed.
948  */
949 int ssl_get(COMSTACK h, char **buf, int *bufsize)
950 {
951     tcpip_state *sp = (tcpip_state *)h->cprivate;
952     char *tmpc;
953     int tmpi, berlen, rest, req, tomove;
954     int hasread = 0, res;
955
956     TRC(fprintf(stderr, "ssl_get: bufsize=%d\n", *bufsize));
957     if (sp->altlen) /* switch buffers */
958     {
959         TRC(fprintf(stderr, "  %d bytes in altbuf (0x%x)\n", sp->altlen,
960             (unsigned) sp->altbuf));
961         tmpc = *buf;
962         tmpi = *bufsize;
963         *buf = sp->altbuf;
964         *bufsize = sp->altsize;
965         hasread = sp->altlen;
966         sp->altlen = 0;
967         sp->altbuf = tmpc;
968         sp->altsize = tmpi;
969     }
970     h->io_pending = 0;
971     while (!(berlen = (*sp->complete)((unsigned char *)*buf, hasread)))
972     {
973         if (!*bufsize)
974         {
975             if (!(*buf = (char *)xmalloc(*bufsize = CS_TCPIP_BUFCHUNK)))
976                 return -1;
977         }
978         else if (*bufsize - hasread < CS_TCPIP_BUFCHUNK)
979             if (!(*buf =(char *)xrealloc(*buf, *bufsize *= 2)))
980                 return -1;
981         res = SSL_read (sp->ssl, *buf + hasread, CS_TCPIP_BUFCHUNK);
982         TRC(fprintf(stderr, "  SSL_read res=%d, hasread=%d\n", res, hasread));
983         if (res <= 0)
984         {
985             int ssl_err = SSL_get_error(sp->ssl, res);
986             if (ssl_err == SSL_ERROR_WANT_READ)
987             {
988                 h->io_pending = CS_WANT_READ;
989                 break;
990             }
991             if (ssl_err == SSL_ERROR_WANT_WRITE)
992             {
993                 h->io_pending = CS_WANT_WRITE;
994                 break;
995             }
996             if (res == 0)
997                 return 0;
998             h->cerrno = CSERRORSSL;
999             return -1;
1000         }
1001         hasread += res;
1002     }
1003     TRC (fprintf (stderr, "  Out of read loop with hasread=%d, berlen=%d\n",
1004         hasread, berlen));
1005     /* move surplus buffer (or everything if we didn't get a BER rec.) */
1006     if (hasread > berlen)
1007     {
1008         tomove = req = hasread - berlen;
1009         rest = tomove % CS_TCPIP_BUFCHUNK;
1010         if (rest)
1011             req += CS_TCPIP_BUFCHUNK - rest;
1012         if (!sp->altbuf)
1013         {
1014             if (!(sp->altbuf = (char *)xmalloc(sp->altsize = req)))
1015                 return -1;
1016         } else if (sp->altsize < req)
1017             if (!(sp->altbuf =(char *)xrealloc(sp->altbuf, sp->altsize = req)))
1018                 return -1;
1019         TRC(fprintf(stderr, "  Moving %d bytes to altbuf(0x%x)\n", tomove,
1020             (unsigned) sp->altbuf));
1021         memcpy(sp->altbuf, *buf + berlen, sp->altlen = tomove);
1022     }
1023     if (berlen < CS_TCPIP_BUFCHUNK - 1)
1024         *(*buf + berlen) = '\0';
1025     return berlen ? berlen : 1;
1026 }
1027 #endif
1028
1029 /*
1030  * Returns 1, 0 or -1
1031  * In nonblocking mode, you must call again with same buffer while
1032  * return value is 1.
1033  */
1034 int tcpip_put(COMSTACK h, char *buf, int size)
1035 {
1036     int res;
1037     struct tcpip_state *state = (struct tcpip_state *)h->cprivate;
1038
1039     TRC(fprintf(stderr, "tcpip_put: size=%d\n", size));
1040     h->io_pending = 0;
1041     h->event = CS_DATA;
1042     if (state->towrite < 0)
1043     {
1044         state->towrite = size;
1045         state->written = 0;
1046     }
1047     else if (state->towrite != size)
1048     {
1049         h->cerrno = CSWRONGBUF;
1050         return -1;
1051     }
1052     while (state->towrite > state->written)
1053     {
1054         if ((res =
1055              send(h->iofile, buf + state->written, size -
1056                   state->written, 
1057 #ifdef MSG_NOSIGNAL
1058                   MSG_NOSIGNAL
1059 #else
1060                   0
1061 #endif
1062                  )) < 0)
1063         {
1064             if (
1065 #ifdef WIN32
1066                 WSAGetLastError() == WSAEWOULDBLOCK
1067 #else
1068                 yaz_errno() == EWOULDBLOCK 
1069 #ifdef EAGAIN
1070 #if EAGAIN != EWOULDBLOCK
1071              || yaz_errno() == EAGAIN
1072 #endif
1073 #endif
1074 #ifdef __sun__
1075                 || yaz_errno() == ENOENT /* Sun's sometimes set errno to this value! */
1076 #endif
1077                 || yaz_errno() == EINPROGRESS
1078 #endif
1079                 )
1080             {
1081                 TRC(fprintf(stderr, "  Flow control stop\n"));
1082                 h->io_pending = CS_WANT_WRITE;
1083                 return 1;
1084             }
1085             h->cerrno = CSYSERR;
1086             return -1;
1087         }
1088         state->written += res;
1089         TRC(fprintf(stderr, "  Wrote %d, written=%d, nbytes=%d\n",
1090                     res, state->written, size));
1091     }
1092     state->towrite = state->written = -1;
1093     TRC(fprintf(stderr, "  Ok\n"));
1094     return 0;
1095 }
1096
1097
1098 #if HAVE_OPENSSL_SSL_H
1099 /*
1100  * Returns 1, 0 or -1
1101  * In nonblocking mode, you must call again with same buffer while
1102  * return value is 1.
1103  */
1104 int ssl_put(COMSTACK h, char *buf, int size)
1105 {
1106     int res;
1107     struct tcpip_state *state = (struct tcpip_state *)h->cprivate;
1108
1109     TRC(fprintf(stderr, "ssl_put: size=%d\n", size));
1110     h->io_pending = 0;
1111     h->event = CS_DATA;
1112     if (state->towrite < 0)
1113     {
1114         state->towrite = size;
1115         state->written = 0;
1116     }
1117     else if (state->towrite != size)
1118     {
1119         h->cerrno = CSWRONGBUF;
1120         return -1;
1121     }
1122     while (state->towrite > state->written)
1123     {
1124         res = SSL_write (state->ssl, buf + state->written,
1125                          size - state->written);
1126         if (res <= 0)
1127         {
1128             int ssl_err = SSL_get_error(state->ssl, res);
1129             if (ssl_err == SSL_ERROR_WANT_READ)
1130             {
1131                 h->io_pending = CS_WANT_READ;
1132                 return 1;
1133             }
1134             if (ssl_err == SSL_ERROR_WANT_WRITE)
1135             {
1136                 h->io_pending = CS_WANT_WRITE;
1137                 return 1;
1138             }
1139             h->cerrno = CSERRORSSL;
1140             return -1;
1141         }
1142         state->written += res;
1143         TRC(fprintf(stderr, "  Wrote %d, written=%d, nbytes=%d\n",
1144                     res, state->written, size));
1145     }
1146     state->towrite = state->written = -1;
1147     TRC(fprintf(stderr, "  Ok\n"));
1148     return 0;
1149 }
1150 #endif
1151
1152 int tcpip_close(COMSTACK h)
1153 {
1154     tcpip_state *sp = (struct tcpip_state *)h->cprivate;
1155
1156     TRC(fprintf(stderr, "tcpip_close\n"));
1157     if (h->iofile != -1)
1158     {
1159 #if HAVE_OPENSSL_SSL_H
1160         if (sp->ssl)
1161         {
1162             SSL_shutdown (sp->ssl);
1163         }
1164 #endif
1165 #ifdef WIN32
1166         closesocket(h->iofile);
1167 #else
1168         close(h->iofile);
1169 #endif
1170     }
1171     if (sp->altbuf)
1172         xfree(sp->altbuf);
1173 #if HAVE_OPENSSL_SSL_H
1174     if (sp->ssl)
1175     {
1176         TRC (fprintf(stderr, "SSL_free\n"));
1177         SSL_free (sp->ssl);
1178     }
1179     sp->ssl = 0;
1180     if (sp->ctx_alloc)
1181         SSL_CTX_free (sp->ctx_alloc);
1182 #endif
1183 #if HAVE_GETADDRINFO
1184     if (sp->ai)
1185         freeaddrinfo(sp->ai);
1186 #endif
1187     xfree(sp);
1188     xfree(h);
1189     return 0;
1190 }
1191
1192 char *tcpip_addrstr(COMSTACK h)
1193 {
1194     struct sockaddr_in addr;
1195     tcpip_state *sp = (struct tcpip_state *)h->cprivate;
1196     char *r = 0, *buf = sp->buf;
1197     YAZ_SOCKLEN_T len;
1198     struct hostent *host;
1199     
1200     len = sizeof(addr);
1201     if (getpeername(h->iofile, (struct sockaddr*) &addr, &len) < 0)
1202     {
1203         h->cerrno = CSYSERR;
1204         return 0;
1205     }
1206     if (!(h->blocking&2)) {
1207         if ((host = gethostbyaddr((char*)&addr.sin_addr, sizeof(addr.sin_addr),
1208                               AF_INET)))
1209             r = (char*) host->h_name;
1210     }
1211     if (!r)
1212         r = inet_ntoa(addr.sin_addr);
1213     if (h->protocol == PROTO_HTTP)
1214         sprintf(buf, "http:%s", r);
1215     else
1216         sprintf(buf, "tcp:%s", r);
1217 #if HAVE_OPENSSL_SSL_H
1218     if (sp->ctx)
1219     {
1220         if (h->protocol == PROTO_HTTP)
1221             sprintf(buf, "https:%s", r);
1222         else
1223             sprintf(buf, "ssl:%s", r);
1224     }
1225 #endif
1226     return buf;
1227 }
1228
1229 int static tcpip_set_blocking(COMSTACK p, int blocking)
1230 {
1231     unsigned long flag;
1232     
1233 #ifdef WIN32
1234     flag = 1;
1235     if (ioctlsocket(p->iofile, FIONBIO, &flag) < 0)
1236         return 0;
1237 #else
1238     flag = fcntl(p->iofile, F_GETFL, 0);
1239     if (blocking & 1)
1240         flag = flag & ~O_NONBLOCK;  /* blocking */
1241     else
1242     {
1243         flag = flag | O_NONBLOCK;   /* non-blocking */
1244         signal(SIGPIPE, SIG_IGN);
1245     }
1246     if (fcntl(p->iofile, F_SETFL, flag) < 0)
1247         return 0;
1248 #endif
1249     p->blocking = blocking;
1250     return 1;
1251 }
1252
1253 #if HAVE_OPENSSL_SSL_H
1254 int cs_set_ssl_ctx(COMSTACK cs, void *ctx)
1255 {
1256     struct tcpip_state *sp;
1257     if (!cs || cs->type != ssl_type)
1258         return 0;
1259     sp = (struct tcpip_state *) cs->cprivate;
1260     if (sp->ctx_alloc)
1261         return 0;
1262     sp->ctx = (SSL_CTX *) ctx;
1263     return 1;
1264 }
1265
1266 void *cs_get_ssl(COMSTACK cs)
1267 {
1268     struct tcpip_state *sp;
1269     if (!cs || cs->type != ssl_type)
1270         return 0;
1271     sp = (struct tcpip_state *) cs->cprivate;
1272     return sp->ssl;  
1273 }
1274
1275 int cs_set_ssl_certificate_file(COMSTACK cs, const char *fname)
1276 {
1277     struct tcpip_state *sp;
1278     if (!cs || cs->type != ssl_type)
1279         return 0;
1280     sp = (struct tcpip_state *) cs->cprivate;
1281     strncpy(sp->cert_fname, fname, sizeof(sp->cert_fname)-1);
1282     sp->cert_fname[sizeof(sp->cert_fname)-1] = '\0';
1283     return 1;
1284 }
1285
1286 int cs_get_peer_certificate_x509(COMSTACK cs, char **buf, int *len)
1287 {
1288     SSL *ssl = (SSL *) cs_get_ssl(cs);
1289     if (ssl)
1290     {
1291         X509 *server_cert = SSL_get_peer_certificate (ssl);
1292         if (server_cert)
1293         {
1294             BIO *bio = BIO_new(BIO_s_mem());
1295             char *pem_buf;
1296             /* get PEM buffer in memory */
1297             PEM_write_bio_X509(bio, server_cert);
1298             *len = BIO_get_mem_data(bio, &pem_buf);
1299             *buf = (char *) xmalloc(*len);
1300             memcpy(*buf, pem_buf, *len);
1301             BIO_free(bio);
1302             return 1;
1303         }
1304     }
1305     return 0;
1306 }
1307 #else
1308 int cs_set_ssl_ctx(COMSTACK cs, void *ctx)
1309 {
1310     return 0;
1311 }
1312
1313 void *cs_get_ssl(COMSTACK cs)
1314 {
1315     return 0;
1316 }
1317
1318 int cs_get_peer_certificate_x509(COMSTACK cs, char **buf, int *len)
1319 {
1320     return 0;
1321 }
1322
1323 int cs_set_ssl_certificate_file(COMSTACK cs, const char *fname)
1324 {
1325     return 0;
1326 }
1327 #endif
1328
1329 /*
1330  * Local variables:
1331  * c-basic-offset: 4
1332  * indent-tabs-mode: nil
1333  * End:
1334  * vim: shiftwidth=4 tabstop=8 expandtab
1335  */
1336