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