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