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