"Fossies" - the Fresh Open Source Software Archive 
Member "sslproxy-1.1.2/ssl_proxy.c" (27 Feb 2009, 20136 Bytes) of package /linux/privat/old/sslproxy-1.1.2.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "ssl_proxy.c" see the
Fossies "Dox" file reference documentation.
1 /* Symbion SSL Proxy
2 * Copyright (C) 2000-2005 Szilard Hajba
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of
7 * the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public
15 * License along with this library; if not, write to the Free
16 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19 //#define VERSION "1.0.7"
20 #define MAX_CONNECTION 32
21 //#define CS_BUFFER_LEN 2
22 //#define SC_BUFFER_LEN 40
23 #define CS_BUFFER_LEN 2048
24 #define SC_BUFFER_LEN 8192
25 #define PEM_DIR "/etc/symbion"
26 #define CERT_FILE "cert.pem"
27 #define KEY_FILE "key.pem"
28 #define SLEEP_US 50000
29
30 #include <stdio.h>
31 #include <stdarg.h>
32 #include <syslog.h>
33 #include <unistd.h>
34 #include <signal.h>
35 #include <netinet/in.h>
36 #include <sys/un.h>
37 #include <sys/types.h>
38 #include <sys/socket.h>
39 #include <netdb.h>
40 #include <fcntl.h>
41 #include <string.h>
42 #include <pwd.h>
43 #include <arpa/inet.h>
44
45 #include <openssl/ssl.h>
46 #include <openssl/err.h>
47 #include <openssl/x509.h>
48 #include <openssl/pem.h>
49 #include <openssl/crypto.h>
50 #include <openssl/rand.h>
51
52 int debug_flag=0;
53 int fg_flag=0;
54 int info_flag=0;
55 int max_conn=MAX_CONNECTION;
56 int cs_buflen=CS_BUFFER_LEN, sc_buflen=SC_BUFFER_LEN;
57 char *server_addr="0.0.0.0";
58 int server_port=443;
59 char *client_addr="localhost";
60 int client_port=80;
61 char *cert_file=PEM_DIR"/"CERT_FILE, *key_file=PEM_DIR"/"KEY_FILE;
62 char *chroot_dir=NULL, *set_uid=NULL;
63 char *verify_ca_file=NULL, *verify_ca_dir=NULL;
64 struct passwd *pass;
65
66 int server_socket;
67 SSL_CTX *server_ssl_ctx;
68 //X509 *ssl_public_cert;
69 //RSA *ssl_private_key;
70
71 int client_s_family=AF_INET;
72 struct sockaddr *client_sa;
73 struct sockaddr_in client_sa_in;
74 struct sockaddr_un client_sa_un;
75 int client_sa_len;
76
77 typedef enum {cs_disconnected, cs_accept, cs_connecting, cs_connected, cs_closing} ConnStatus;
78 typedef struct {
79 ConnStatus stat; // Status of the connection
80 int server_sock; // Server side socket id
81 struct sockaddr_in server_sa; // Server's socket address
82 int server_sa_len; // ^^^^^^^^^^^^^^^^^^^^^^^'s len
83 SSL *ssl_conn; // SSL connection structure pointer
84 int client_sock; // Client side socket id
85 char *csbuf; // Server side write buffer
86 char *csbuf_b; // Server side write buffer begin ptr
87 char *csbuf_e; // Server side write buffer end ptr
88 // int c_end_req; // Client requested connection close
89 char *scbuf; // Client side write buffer
90 char *scbuf_b; // Client side write buffer begin ptr
91 char *scbuf_e; // Client side write buffer end ptr
92 // int s_end_req; // Server requested connection close
93 } Conn;
94 Conn *conn=NULL;
95
96 void conn_close_client(Conn *conn);
97 void conn_close_server(Conn *conn);
98
99 void debug(char *format,...) {
100 if (debug_flag) {
101 va_list args;
102 va_start(args, format);
103 vfprintf(stderr, format, args);
104 putc('\n', stderr);
105 va_end(args);
106 }
107 }
108
109 void plog(int level, const char *cls, const char *format,...) {
110 char str[8192];
111 va_list args;
112 va_start(args, format);
113 vsprintf(str, format, args);
114 va_end(args);
115 syslog(level, "%.256s: %.256s\n", cls, str);
116 if (debug_flag) debug("LOG: %.256s: %.256s", cls, str);
117 }
118
119 void _sleep()
120 {
121 struct timeval tv={0, SLEEP_US};
122 select(0, NULL, NULL, NULL, &tv);
123 }
124
125 // ============================================== Server
126 int server_init(char *addr, int port, int maxconn) {
127 struct sockaddr_in server;
128 long ipaddr;
129
130 server_socket=socket(AF_INET, SOCK_STREAM, 0);
131 if (server_socket<0) {
132 perror("socket()");
133 exit(1);
134 }
135 server.sin_family=AF_INET;
136 inet_pton(AF_INET, addr, &ipaddr);
137 server.sin_addr.s_addr=ipaddr;
138 // server.sin_addr.s_addr=htons(INADDR_ANY);
139 server.sin_port=htons(port);
140 if (bind(server_socket, (struct sockaddr *)&server, sizeof(server)) < 0) {
141 perror("bind()");
142 exit(1);
143 }
144 listen(server_socket, maxconn);
145 fcntl(server_socket, F_SETFL, O_NONBLOCK);
146 return server_socket;
147 }
148
149 void server_done(void) {
150 int ci;
151 shutdown(server_socket, 2);
152 _sleep();
153 close(server_socket);
154 for (ci=0; ci<max_conn; ci++)
155 if (conn[ci].stat==cs_accept && conn[ci].stat==cs_connected) {
156 conn_close_client(&conn[ci]);
157 conn_close_server(&conn[ci]);
158 }
159 }
160
161 // ============================================== Server SSL
162 static RSA *tmp_rsa_cb(SSL *ssl, int export, int key_len) {
163 static RSA *rsa=NULL;
164 debug("Generating new RSA key.. (ex=%d, kl=%d)", export, key_len);
165 if (export) {
166 rsa=RSA_generate_key(key_len, RSA_F4, NULL, NULL);
167 } else {
168 plog(LOG_ERR, "tmp_rsa_callback()", "Export not set");
169 }
170 return rsa;
171 }
172
173 static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
174 {
175 fprintf(stderr, "preverify: %d\n", preverify_ok);
176 return preverify_ok;
177 }
178
179 void server_ssl_init(void) {
180 // FILE *f;
181 SSLeay_add_ssl_algorithms();
182 SSL_load_error_strings();
183 server_ssl_ctx=SSL_CTX_new(SSLv23_server_method());
184 SSL_CTX_set_cipher_list(server_ssl_ctx, "HIGH");
185 if (!SSL_CTX_set_default_verify_paths(server_ssl_ctx)) {
186 fprintf(stderr, "cannot set default path\n");
187 exit(1);
188 }
189
190 if (!SSL_CTX_use_certificate_chain_file(server_ssl_ctx, cert_file)) {
191 fprintf(stderr,"error reading certificate: %.256s\n",
192 ERR_error_string(ERR_get_error(), NULL));
193 exit(1);
194 }
195 if (!SSL_CTX_use_PrivateKey_file(server_ssl_ctx, key_file, SSL_FILETYPE_PEM)) {
196 fprintf(stderr,"error reading private key: %.256s\n",
197 ERR_error_string(ERR_get_error(), NULL));
198 exit(1);
199 }
200 SSL_CTX_set_tmp_rsa_callback(server_ssl_ctx, tmp_rsa_cb);
201
202 if (verify_ca_file || verify_ca_dir) {
203 /*
204 STACK_OF(X509_NAME) *certs;
205 certs=SSL_load_client_CA_file(verify_ca_file);
206 if (certs) {
207 SSL_CTX_set_client_CA_list(server_ssl_ctx, certs);
208 } else {
209 fprintf(stderr,"error reading client CA list: %.256s\n",
210 ERR_error_string(ERR_get_error(), NULL));
211 exit(1);
212 }
213 */
214 SSL_CTX_load_verify_locations(server_ssl_ctx, verify_ca_file, verify_ca_dir);
215 SSL_CTX_set_verify(server_ssl_ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT | SSL_VERIFY_CLIENT_ONCE, verify_callback);
216 }
217
218 // SSL_CTX_set_session_cache_mode(server_ssl_ctx, SSL_SESS_CACHE_OFF);
219 }
220
221 // ============================================== CLient
222 void client_init(char *addr, int port) {
223 if (port) { // TCP connection
224 struct hostent *hp;
225 client_sa_in.sin_family=AF_INET;
226 hp=gethostbyname(addr);
227 if (!hp) {
228 perror("gethostbyname()");
229 exit(1);
230 }
231 bcopy(hp->h_addr, &client_sa_in.sin_addr, hp->h_length);
232 client_sa_in.sin_port=htons(port);
233 client_sa=(struct sockaddr *)&client_sa_in;
234 client_sa_len=sizeof(client_sa_in);
235 } else { // UNIX domain socket
236 client_sa_un.sun_family=AF_UNIX;
237 if (addr) {
238 if (strlen(addr)>=sizeof(client_sa_un.sun_path)) {
239 fprintf(stderr, "client_init(): client address too long (allowed: %d)\n",
240 (int)sizeof(client_sa_un.sun_path));
241 exit(1);
242 } else strcpy(client_sa_un.sun_path, addr);
243 } else {
244 fprintf(stderr, "client_init(): client address missing\n");
245 exit(1);
246 }
247 client_sa=(struct sockaddr *)&client_sa_un;
248 client_sa_len=sizeof(client_sa_un);
249 }
250 }
251
252 // ============================================== Connection
253 struct sockaddr_in server_sa;
254 unsigned int server_sa_len;
255 int conn_accept(void) {
256 int i;
257 // Initialize SSL connection (server side)
258 int s=accept(server_socket, (struct sockaddr *)&server_sa, &server_sa_len);
259 if (s<=0) return 0;
260 debug("conn_accept(): Client connected");
261 for (i=0; i<max_conn && conn[i].stat!=cs_disconnected; i++);
262 if (i==max_conn) {
263 plog(LOG_ERR, "accept()", "Internal error");
264 close(s);
265 return 0;
266 }
267 debug("accept(): sn=%d sock=%d", i, s);
268 conn[i].server_sock=s;
269 bcopy(&server_sa, &conn[i].server_sa, server_sa_len);
270 conn[i].server_sa_len=server_sa_len;
271 conn[i].ssl_conn=SSL_new(server_ssl_ctx);
272 SSL_set_fd(conn[i].ssl_conn, conn[i].server_sock);
273 // if (!SSL_use_RSAPrivateKey(conn[i].ssl_conn, ssl_private_key)) {
274 // plog(LOG_ERR, "accept()", "Error reading private key");
275 // SSL_free(conn[i].ssl_conn);
276 // close(conn[i].server_sock);
277 // return -1;
278 // }
279 // if (!SSL_use_certificate(conn[i].ssl_conn, ssl_public_cert)) {
280 // plog(LOG_ERR, "accept()", "Error reading public certificate");
281 // SSL_free(conn[i].ssl_conn);
282 // close(conn[i].server_sock);
283 // return -1;
284 // }
285 // SSL_set_verify(conn[i].ssl_conn, 0, NULL);
286 BIO_set_nbio(SSL_get_rbio(conn[i].ssl_conn), 0);
287 BIO_set_nbio(SSL_get_wbio(conn[i].ssl_conn), 0);
288 fcntl(conn[i].server_sock, F_SETFL, O_NONBLOCK);
289 conn[i].stat=cs_accept;
290 conn[i].scbuf_b=conn[i].scbuf; conn[i].scbuf_e=conn[i].scbuf;
291 conn[i].csbuf_b=conn[i].csbuf; conn[i].csbuf_e=conn[i].csbuf;
292 return conn[i].server_sock;
293 }
294
295 int conn_ssl_accept(Conn *conn) {
296 int ret=SSL_accept(conn->ssl_conn);
297 // debug("SSL_accept: %d, SSL_want=%d", ret, SSL_want(conn->ssl_conn));
298 if (ret<=0) {
299 unsigned long err=SSL_get_error(conn->ssl_conn, ret);
300 // debug("SSL_accept: error:%d", err);
301 if (err==SSL_ERROR_WANT_READ || err==SSL_ERROR_WANT_WRITE) {
302 return 1;
303 } else {
304 plog(LOG_ERR, "accept()", "Accept failed: %.256s", ERR_error_string(err, NULL));
305 ERR_print_errors_fp(stderr);
306 }
307
308 // if ((err=ERR_get_error())) {
309 // plog(LOG_ERR, "accept()", "Access failed: %.256s", ERR_error_string(err, NULL));
310 // } else if (SSL_want(conn->ssl_conn)>1) return 0;;
311 debug("SSL_accept: disconnected.");
312 SSL_free(conn->ssl_conn);
313 close(conn->server_sock);
314 conn->server_sock=conn->client_sock=0;
315 conn->stat=cs_disconnected;
316 return -1;
317 /*
318 } else if (ret==1) {
319 // Successfull negotiation
320 X509 *peer;
321 if (!(peer=SSL_get_peer_certificate(conn->ssl_conn))
322 || SSL_get_verify_result(conn->ssl_conn)!=X509_V_OK) {
323 unsigned long err=SSL_get_error(conn->ssl_conn, ret);
324 plog(LOG_ERR, "accept()", "SSL handshake: %.256s", ERR_error_string(err, NULL));
325 ERR_print_errors_fp(stderr);
326 debug("SSL_accept: disconnected.");
327 SSL_free(conn->ssl_conn);
328 close(conn->server_sock);
329 conn->stat=cs_disconnected;
330 return -1;
331 }
332 */
333 }
334
335 // Connect to server (client side)
336 conn->client_sock=socket(client_s_family, SOCK_STREAM, 0);
337 if (conn->client_sock<0) {
338 plog(LOG_ERR, "socket()", strerror(errno));
339 SSL_free(conn->ssl_conn);
340 close(conn->server_sock);
341 conn->server_sock=conn->client_sock=0;
342 conn->stat=cs_disconnected;
343 return -1;
344 }
345 fcntl(conn->client_sock, F_SETFL, O_NONBLOCK);
346 conn->stat=cs_connecting;
347 /*
348 ret=connect(conn->client_sock, client_sa, client_sa_len);
349 if (ret<0) {
350 if (errno==EINPROGRESS) return 0;
351 plog(LOG_ERR, "connect()", strerror(errno));
352 close(conn->client_sock);
353 SSL_free(conn->ssl_conn);
354 close(conn->server_sock);
355 conn->stat=cs_disconnected;
356 return -1;
357 } else {
358 conn->stat=cs_connected;
359 debug("Connection negotiated");
360 if (info_flag) {
361 conn->csbuf_e+=snprintf(conn->csbuf_b, cs_buflen, "#@ip=%s \r\n", "1.1.1.1");
362 debug("INFO: %s", conn->csbuf);
363 }
364 }
365 */
366 return 0;
367 }
368
369 /*
370 void conn_close(Conn *conn) {
371 debug("conn_close(): s=%d", conn->server_sock);
372 shutdown(conn->client_sock, 2);
373 close(conn->client_sock);
374 SSL_free(conn->ssl_conn);
375 shutdown(conn->server_sock, 2);
376 close(conn->server_sock);
377 conn->stat=cs_disconnected;
378 }
379 */
380
381 void conn_close_client(Conn *conn) {
382 debug("conn_close_client(): s=%d", conn->client_sock);
383 shutdown(conn->client_sock, 2);
384 close(conn->client_sock);
385 conn->client_sock=-1;
386 if (conn->server_sock==-1) conn->stat=cs_disconnected;
387 }
388
389 void conn_close_server(Conn *conn) {
390 debug("conn_close_server(): s=%d", conn->server_sock);
391 SSL_free(conn->ssl_conn);
392 shutdown(conn->server_sock, 2);
393 close(conn->server_sock);
394 conn->server_sock=-1;
395 if (conn->client_sock==-1) conn->stat=cs_disconnected;
396 }
397
398 void sighandler(int signum) {
399 switch (signum) {
400 case SIGINT:
401 case SIGTERM:
402 plog(LOG_NOTICE, "signal", "Interrupt/terminate");
403 server_done();
404 // If it's possible to remove pid file, try it..
405 // It's not guaranteed to succeed, because of setuid
406 if (!chroot_dir) unlink("/var/run/ssl_proxy.pid");
407 exit(0);
408 default:;
409 }
410 }
411
412 int main(int argc, char **argv) {
413 FILE *pidfile;
414 int c, pid, i;
415 char *p1, *p2;
416
417 while ((c=getopt(argc, argv, "hdfim:s:c:C:K:u:r:v:V:U:D:")) != EOF)
418 switch (c) {
419 case 'h':
420 fprintf(stderr, "Symbion SSL proxy " VERSION "\n"
421 "usage: %.256s [-d] [-f] [-i] [-s <listen address>] [-c <client address>]\n"
422 " [-m <max connection>] [-C <certificate file>] [-K <key file>]\n"
423 " [-u <user/uid>] [-r <chroot dir>]\n"
424 " [-v <trusted CA file>] [-V <trusted CA dir>]\n"
425 " [-U <upward buffer (default 2048)>] [-D <downward buffer (default 8192)>]\n"
426 " <lister address> = [<host>:]<port>\n"
427 " <client address> = [<host>:]<port> | unix:<path>\n", argv[0]);
428 fprintf(stderr, " %.256s -h\n", argv[0]);
429 exit(0);
430 case 'd':
431 debug_flag=1;
432 break;
433 case 'f':
434 fg_flag=1;
435 break;
436 case 'i':
437 info_flag=1;
438 break;
439 case 'm':
440 max_conn=atoi(optarg);
441 break;
442 case 's':
443 server_port=atoi(optarg);
444 p1=strtok(optarg, ":");
445 p2=strtok(NULL, "");
446 if (p2) {
447 server_addr=p1;
448 server_port=atoi(p2);
449 } else {
450 server_addr="0.0.0.0"; server_port=atoi(p1);
451 }
452 break;
453 case 'c':
454 p1=strtok(optarg, ":");
455 p2=strtok(NULL, "");
456 if (p2) {
457 if (!strcmp(p1, "unix")) {
458 client_s_family=AF_UNIX;
459 client_addr=p2;
460 client_port=0;
461 } else {
462 client_addr=p1;
463 client_port=atoi(p2);
464 }
465 } else {
466 client_addr="localhost"; client_port=atoi(p1);
467 }
468 break;
469 case 'C':
470 cert_file=optarg;
471 break;
472 case 'K':
473 key_file=optarg;
474 break;
475 case 'u':
476 set_uid=optarg;
477 break;
478 case 'r':
479 chroot_dir=optarg;
480 break;
481 case 'v':
482 verify_ca_file=optarg;
483 break;
484 case 'V':
485 verify_ca_dir=optarg;
486 break;
487 case 'U':
488 cs_buflen=atoi(optarg);
489 break;
490 case 'D':
491 sc_buflen=atoi(optarg);
492 break;
493 }
494 debug("Symbion SSL proxy " VERSION);
495 signal(SIGINT, sighandler);
496 signal(SIGTERM, sighandler);
497 signal(SIGPIPE, SIG_IGN);
498 // This must be done before process_security_init(), because server_port
499 // can be a privileged port, ssl_init use files from the filesystem.
500 if (client_s_family==AF_INET)
501 debug("Using server: family=INET host=%.256s port=%d", client_addr, client_port);
502 else
503 debug("Using server: family=UNIX path=%.256s", client_addr);
504 server_init(server_addr, server_port, max_conn);
505 server_ssl_init();
506 client_init(client_addr, client_port);
507 if (!debug_flag && !fg_flag && (pid=fork())) {
508 pidfile=fopen("/var/run/ssl_proxy.pid", "w");
509 if (pidfile) {
510 fprintf(pidfile, "%d\n", pid);
511 fclose(pidfile);
512 }
513 exit(0);
514 }
515
516 // Process security
517 if (set_uid) {
518 if (!(pass=getpwnam(set_uid))) {perror("getpwnam()"); exit(1);}
519 }
520 if (chroot_dir) {
521 debug("Changing root directory to '%.256s'..", chroot_dir);
522 if (chroot(chroot_dir)<0) {perror("chroot()"); exit(1);}
523 chdir("/");
524 }
525 if (set_uid) {
526 debug("Changing userID to %.256s..", set_uid);
527 setgid(pass->pw_gid);
528 setuid(pass->pw_uid);
529 }
530
531 conn=malloc(max_conn*sizeof(Conn));
532 bzero(conn, max_conn*sizeof(Conn));
533 for (i=0; i<max_conn; i++) {
534 Conn *c=&conn[i];
535 c->scbuf=malloc(sc_buflen);
536 c->scbuf_b=c->scbuf; c->scbuf_e=c->scbuf;
537 c->csbuf=malloc(cs_buflen);
538 c->csbuf_b=c->csbuf; c->csbuf_e=c->csbuf;
539 }
540
541 openlog("sslproxy", LOG_PID, LOG_DAEMON);
542 if (client_s_family==AF_INET)
543 plog(LOG_NOTICE, "init", "version " VERSION " started (family=INET host=%.256s port=%d).",
544 client_addr, client_port);
545 else
546 plog(LOG_NOTICE, "init", "version " VERSION " started (family=UNIX path=%.256s).",
547 client_addr);
548
549 while (1) {
550 int event=0, ci;
551 // Check for incoming connections
552 if ((i=conn_accept())>0) {
553 debug("Client connected");
554 event=1;
555 }
556 for (ci=0; ci<max_conn; ci++) {
557 Conn *cn=&conn[ci];
558 int l;
559 switch (cn->stat) {
560 case cs_accept:
561 i=conn_ssl_accept(cn);
562 // cn->c_end_req=0; cn->s_end_req=0;
563 event|=(i==0);
564 break;
565 case cs_connecting:
566 if (connect(cn->client_sock, client_sa, client_sa_len)<0) {
567 if (errno==EINPROGRESS) break;
568 // if (errno==EALREADY) break;
569 perror("connecting()");
570 plog(LOG_ERR, "connect()", strerror(errno));
571 close(cn->client_sock);
572 SSL_free(cn->ssl_conn);
573 close(cn->server_sock);
574 cn->stat=cs_disconnected;
575 } else {
576 cn->stat=cs_connected;
577 debug("Connection negotiated");
578 if (info_flag) {
579 struct sockaddr_in client_addr;
580 unsigned int client_addr_len=sizeof(client_addr);
581 X509 *cert;
582 X509_NAME *xn=NULL;
583 char peer_cn[256]="";
584 getpeername(cn->server_sock,
585 (struct sockaddr *)&client_addr,
586 &client_addr_len);
587 cert=SSL_get_peer_certificate(cn->ssl_conn);
588 if (cert) {
589 xn=X509_get_subject_name(cert);
590 X509_NAME_get_text_by_NID(xn, NID_commonName, peer_cn, 256);
591 }
592 cn->csbuf_e+=snprintf(cn->csbuf_b, cs_buflen,
593 "#@ip=%s port=%d%s%s%s\r\n",
594 inet_ntoa(client_addr.sin_addr),
595 htons(client_addr.sin_port), xn?" cn='":"", peer_cn, xn?"'":"");
596 debug("INFO: %p %d %s", cn, cn->server_sock, cn->csbuf);
597 }
598 }
599 break;
600 case cs_connected:
601 // Check if data is available on client side
602 if ((l=cs_buflen-(cn->csbuf_e-cn->csbuf))) {
603 i=SSL_read(cn->ssl_conn, cn->csbuf_e, l);
604 if (!i) { // End of connection
605 debug("Close request: %d", ci);
606 cn->stat=cs_closing; event=1;
607 // cn->c_end_req=1;
608 } else if (i<0) { // Error
609 if (errno!=EAGAIN) {
610 debug("SSL_read() errno: %d", errno);
611 cn->stat=cs_closing; event=1;
612 // cn->c_end_req=1;
613 }
614 } else cn->csbuf_e+=i;
615 }
616 case cs_closing:
617 // Send buffered data to server
618 if ((l=cn->csbuf_e-cn->csbuf_b)>0) {
619 i=write(cn->client_sock, cn->csbuf_b, l); event=1;
620 if (debug_flag) write(2, cn->csbuf_b, l);
621 if (i>=0) {
622 cn->csbuf_b+=i;
623 } else {
624 if (errno!=EAGAIN) {
625 debug("write() errno: %d", errno);
626 cn->csbuf_b=cn->csbuf_e=cn->csbuf;
627 cn->stat=cs_closing;
628 }
629 }
630 if (cn->csbuf_b==cn->csbuf_e) {
631 cn->csbuf_b=cn->csbuf_e=cn->csbuf;
632 // if (cn->c_end_req) conn_close(cn);
633 }
634 }
635 if (cn->stat==cs_closing && cn->csbuf_e==cn->csbuf_b) conn_close_client(cn);
636 default:;
637 }
638 if (cn->stat==cs_connected || cn->stat==cs_closing) {
639 // Check if data is available on server side
640 if ((l=sc_buflen-(cn->scbuf_e-cn->scbuf)) && cn->client_sock>=0) {
641 i=read(cn->client_sock, cn->scbuf_e, l);
642 if (!i) { // End of connection
643 cn->stat=cs_closing; event=1;
644 // cn->s_end_req=1;
645 } else if (i<0) { // Error
646 if (errno!=EAGAIN) {
647 debug("read errno: %d", errno);
648 cn->stat=cs_closing; event=1;
649 // cn->s_end_req=1;
650 }
651 } else cn->scbuf_e+=i;
652 }
653 // Send buffered data to client
654 if ((l=cn->scbuf_e-cn->scbuf_b)>0 && cn->server_sock>=0) {
655 i=SSL_write(cn->ssl_conn, cn->scbuf_b, l);
656 if (i>0) debug("transfer: buf=%d, b=%d, l=%d, i=%d", cn->scbuf,
657 cn->scbuf_b, l, i);
658 if (i>=0) {
659 cn->scbuf_b+=i; event=1;
660 } else if (errno!=EAGAIN) {
661 debug("SSL_write() errno: %d", errno);
662 cn->scbuf_b=cn->scbuf_e=cn->scbuf;
663 event=1;
664 }
665 if (cn->scbuf_b==cn->scbuf_e) {
666 cn->scbuf_b=cn->scbuf_e=cn->scbuf;
667 // if (cn->s_end_req) conn_close(cn);
668 }
669 }
670 if (cn->stat==cs_closing && cn->scbuf_e==cn->scbuf_b) conn_close_server(cn);
671 }
672 }
673 if (!event) _sleep();
674 }
675 return 0;
676 }