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