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