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