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