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