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