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