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