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