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