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