1 /**
2 * SIEGE socket library
3 *
4 * Copyright (C) 2000-2015 by
5 * Jeffrey Fulmer - <jeff@joedog.org>, et al.
6 * This file is distributed as part of Siege
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
22
23 #ifdef HAVE_CONFIG_H
24 # include <config.h>
25 #endif/*HAVE_CONFIG_H*/
26
27 #include <setup.h>
28 #include <sock.h>
29 #include <util.h>
30 #include <memory.h>
31 #include <notify.h>
32 #include <joedog/boolean.h>
33 #include <joedog/defs.h>
34 #include <pthread.h>
35 #include <fcntl.h>
36
37 #ifdef HAVE_POLL
38 # include <poll.h>
39 #endif/*HAVE_POLL*/
40
41 #ifdef HAVE_UNISTD_H
42 # include <unistd.h>
43 #endif/*HAVE_UNISTD_H*/
44
45 #ifdef HAVE_ARPA_INET_H
46 # include <arpa/inet.h>
47 #endif/*HAVE_ARPA_INET_H*/
48
49 #ifdef HAVE_SYS_SOCKET_H
50 # include <sys/socket.h>
51 #endif/*HAVE_SYS_SOCKET_H*/
52
53 #ifdef HAVE_NETINET_IN_H
54 # include <netinet/in.h>
55 #endif/*HAVE_NETINET_IN_H*/
56
57 #ifdef HAVE_NETDB_H
58 # include <netdb.h>
59 #endif/*HAVE_NETDB_H*/
60
61 #ifdef HAVE_SSL
62 # include <openssl/rand.h>
63 #endif/*HAVE_SSL*/
64
65 #define MAX_PORT_NO 65535
66
67 /**
68 * local prototypes
69 */
70 private int __socket_block(int socket, BOOLEAN block);
71 private ssize_t __socket_write(int sock, const void *vbuf, size_t len);
72 private BOOLEAN __socket_check(CONN *C, SDSET mode);
73 private BOOLEAN __socket_select(CONN *C, SDSET mode);
74 private int __socket_create(CONN *C, int domain);
75 private void __hostname_strip(char *hn, int len);
76 #ifdef HAVE_POLL
77 private BOOLEAN __socket_poll(CONN *C, SDSET mode);
78 #endif/*HAVE_POLL*/
79 #ifdef HAVE_SSL
80 private ssize_t __ssl_socket_write(CONN *C, const void *vbuf, size_t len);
81 #endif/*HAVE_SSL*/
82
83 /**
84 * new_socket
85 * returns int, socket handle
86 */
87 int
new_socket(CONN * C,const char * hostparam,int portparam)88 new_socket(CONN *C, const char *hostparam, int portparam)
89 {
90 int conn;
91 int res;
92 int addrlen;
93 struct sockaddr *s_addr;
94 char hn[512];
95 int port;
96 int domain;
97 #if defined(__GLIBC__)
98 char port_str[10];
99 struct addrinfo hints;
100 struct addrinfo *addr_res;
101 struct addrinfo *r;
102 #else
103 struct sockaddr_in cli;
104 struct hostent *hp;
105 int herrno;
106 #endif
107 #if defined(sun)
108 # ifndef HAVE_GETIPNODEBYNAME
109 struct hostent hent;
110 char hbf[8192];
111 # endif/*HAVE_GETIPNODEBYNAME*/
112 #elif defined(_AIX)
113 char *aixbuf;
114 int rc;
115 #endif/*_AIX*/
116
117 if (hostparam == NULL) {
118 NOTIFY(ERROR, "Unable to resolve host %s:%d", __FILE__, __LINE__);
119 return -1;
120 }
121
122 C->encrypt = (C->scheme == HTTPS) ? TRUE: FALSE;
123 C->state = UNDEF;
124 C->ftp.pasv = TRUE;
125 C->ftp.size = 0;
126
127 memset(hn, '\0', sizeof hn);
128
129 /* if we are using a proxy, then we make a socket
130 connection to that server rather then a httpd */
131 if (auth_get_proxy_required(my.auth)) {
132 snprintf(hn, sizeof(hn), "%s", auth_get_proxy_host(my.auth));
133 port = auth_get_proxy_port(my.auth);
134 } else {
135 snprintf(hn, sizeof(hn), "%s", hostparam);
136 port = portparam;
137 }
138 __hostname_strip(hn, 512);
139
140 /* sanity check */
141 if (port < 1 || port > MAX_PORT_NO) {
142 NOTIFY(ERROR, "invalid port number %d in %s:%d", port, __FILE__, __LINE__);
143 return -1;
144 }
145
146 #if defined(__GLIBC__)
147 {
148 snprintf(port_str, sizeof(port_str), "%d", port);
149
150 /* hints for address lookup */
151 memset(&hints, 0, sizeof(struct addrinfo));
152 hints.ai_family=AF_UNSPEC;
153 hints.ai_socktype=SOCK_STREAM;
154 hints.ai_protocol=IPPROTO_TCP;
155
156 res = getaddrinfo(hn, port_str, &hints, &addr_res);
157 if (res != 0) {
158 NOTIFY(ERROR, "Address resolution failed at %s:%d with the following error:", __FILE__, __LINE__);
159 NOTIFY(ERROR, "%s", gai_strerror(res));
160 return -1;
161 }
162 s_addr = addr_res->ai_addr;
163 addrlen = addr_res->ai_addrlen;
164 domain = addr_res->ai_family;
165 }
166 #elif defined(sun) || defined(__FreeBSD__)
167 # ifdef HAVE_GETIPNODEBYNAME
168 hp = getipnodebyname(hn, AF_INET, 0, &herrno);
169 # else /* default use gethostbyname_r*/
170 {
171 memset(hbf, '\0', sizeof hbf);
172 hp = gethostbyname_r(hn, &hent, hbf, sizeof(hbf), &herrno);
173 }
174 # endif/*HAVE_GETIPNODEBYNAME*/
175 #elif defined(_AIX)
176 aixbuf = (char*)xmalloc(8192);
177 rc = gethostbyname_r(hn, (struct hostent *)aixbuf,
178 (struct hostent_data *)(aixbuf + sizeof(struct hostent)));
179 hp = (struct hostent*)aixbuf;
180 #elif (defined(hpux) || defined(__hpux) || defined(__osf__))
181 hp = gethostbyname(hn);
182 herrno = h_errno;
183 #else
184 /**
185 * Let's just hope gethostbyname is tread-safe
186 */
187 hp = gethostbyname(hn);
188 herrno = h_errno;
189 #endif/*OS SPECIFICS*/
190
191 #if !defined(__GLIBC__)
192 /* gethostbyname only offers IPv4 support */
193 domain = AF_INET;
194
195 /**
196 * If hp is NULL, then we did not get good information
197 * from the name server. Let's notify the user and bail
198 */
199 if (hp == NULL) {
200 switch(herrno) {
201 case HOST_NOT_FOUND: { NOTIFY(ERROR, "Host not found: %s\n", hostparam); break; }
202 case NO_ADDRESS: { NOTIFY(ERROR, "Host does not have an IP address: %s\n", hostparam); break; }
203 case NO_RECOVERY: { NOTIFY(ERROR, "A non-recoverable resolution error for %s\n", hostparam); break; }
204 case TRY_AGAIN: { NOTIFY(ERROR, "A temporary resolution error for %s\n", hostparam); break; }
205 default: { NOTIFY(ERROR, "Unknown error code from gethostbyname for %s\n", hostparam); break; }
206 }
207 return -1;
208 }
209
210 memset((void*) &cli, 0, sizeof(cli));
211 memcpy(&cli.sin_addr, hp->h_addr, hp->h_length);
212 #if defined(sun) || defined(__FreeBSD__)
213 # ifdef HAVE_FREEHOSTENT
214 freehostent(hp);
215 # endif/*HAVE_FREEHOSTENT*/
216 #endif
217 cli.sin_family = AF_INET;
218 cli.sin_port = htons(port);
219
220 s_addr = (struct sockaddr *)&cli;
221 addrlen = sizeof(struct sockaddr_in);
222 #endif /* end of __GLIBC__ not defined */
223
224 /* create a socket, return -1 on failure */
225 if (__socket_create(C, domain) < 0) {
226 return -1;
227 }
228
229 /**
230 * connect to the host
231 * evaluate the server response and check for
232 * readability/writeability of the socket....
233 */
234 conn = connect(C->sock, s_addr, addrlen);
235 pthread_testcancel();
236 #if defined(__GLIBC__)
237 /**
238 * The result of getaddrinfo is a linked list. Attempt
239 * to connect to each result until successful
240 */
241 if (conn < 0 && errno != EINPROGRESS) {
242 addr_res = addr_res->ai_next;
243 for (r = addr_res; r; r = r->ai_next) {
244 /* close previously opened socket */
245 socket_close(C);
246
247 /* create a socket, return -1 on failure */
248 if (__socket_create(C, domain) < 0) {
249 return -1;
250 }
251
252 conn = connect(C->sock, s_addr, addrlen);
253 pthread_testcancel();
254 if (conn == 0) {
255 break;
256 }
257 }
258 }
259 #endif
260 if (conn < 0 && errno != EINPROGRESS) {
261 switch (errno) {
262 case EACCES: {NOTIFY(ERROR, "socket: %d EACCES", pthread_self()); break;}
263 case EADDRNOTAVAIL: {NOTIFY(ERROR, "socket: %d address is unavailable.", pthread_self()); break;}
264 case ETIMEDOUT: {NOTIFY(ERROR, "socket: %d connection timed out.", pthread_self()); break;}
265 case ECONNREFUSED: {NOTIFY(ERROR, "socket: %d connection refused.", pthread_self()); break;}
266 case ENETUNREACH: {NOTIFY(ERROR, "socket: %d network is unreachable.", pthread_self()); break;}
267 case EISCONN: {NOTIFY(ERROR, "socket: %d already connected.", pthread_self()); break;}
268 default: {NOTIFY(ERROR, "socket: %d unknown network error.", pthread_self()); break;}
269 } socket_close(C); return -1;
270 } else {
271 if (__socket_check(C, READ) == FALSE) {
272 pthread_testcancel();
273 NOTIFY(WARNING, "socket: read check timed out(%d) %s:%d", my.timeout, __FILE__, __LINE__);
274 socket_close(C);
275 return -1;
276 } else {
277 /**
278 * If we reconnect and receive EISCONN, then we have a successful connection
279 */
280 res = connect(C->sock, s_addr, addrlen);
281 if((res < 0)&&(errno != EISCONN)){
282 NOTIFY(ERROR, "socket: unable to connect %s:%d", __FILE__, __LINE__);
283 socket_close(C);
284 return -1;
285 }
286 C->status = S_READING;
287 }
288 } /* end of connect conditional */
289
290 if ((__socket_block(C->sock, TRUE)) < 0) {
291 NOTIFY(ERROR, "socket: unable to set socket to non-blocking %s:%d", __FILE__, __LINE__);
292 return -1;
293 }
294
295 C->connection.status = 1;
296 return(C->sock);
297 }
298
299 /**
300 * Conditionally determines whether or not a socket is ready.
301 * This function calls __socket_poll if HAVE_POLL is defined in
302 * config.h, else it uses __socket_select
303 */
304 private BOOLEAN
__socket_check(CONN * C,SDSET mode)305 __socket_check(CONN *C, SDSET mode)
306 {
307 #ifdef HAVE_POLL
308 if (C->sock >= FD_SETSIZE) {
309 return __socket_poll(C, mode);
310 } else {
311 return __socket_select(C, mode);
312 }
313 #else
314 return __socket_select(C, mode);
315 #endif/*HAVE_POLL*/
316 }
317
318 #ifdef HAVE_POLL
319 private BOOLEAN
__socket_poll(CONN * C,SDSET mode)320 __socket_poll(CONN *C, SDSET mode)
321 {
322 int res;
323 int timo = (my.timeout) ? my.timeout * 1000 : 15000;
324 __socket_block(C->sock, FALSE);
325
326 C->pfd[0].fd = C->sock + 1;
327 C->pfd[0].events |= POLLIN;
328
329 do {
330 res = poll(C->pfd, 1, timo);
331 pthread_testcancel();
332 if (res < 0) puts("LESS THAN ZERO!");
333 } while (res < 0); // && errno == EINTR);
334
335 if (res == 0) {
336 errno = ETIMEDOUT;
337 }
338
339 if (res <= 0) {
340 C->state = UNDEF;
341 NOTIFY(WARNING,
342 "socket: polled(%d) and discovered it's not ready %s:%d",
343 (my.timeout)?my.timeout:15, __FILE__, __LINE__
344 );
345 return FALSE;
346 } else {
347 C->state = mode;
348 return TRUE;
349 }
350 }
351 #endif/*HAVE_POLL*/
352
353 private BOOLEAN
__socket_select(CONN * C,SDSET mode)354 __socket_select(CONN *C, SDSET mode)
355 {
356 struct timeval timeout;
357 int res;
358 fd_set rs;
359 fd_set ws;
360 memset((void *)&timeout, '\0', sizeof(struct timeval));
361 timeout.tv_sec = (my.timeout > 0)?my.timeout:30;
362 timeout.tv_usec = 0;
363
364 if ((C->sock < 0) || (C->sock >= FD_SETSIZE)) {
365 // FD_SET can't handle it
366 return FALSE;
367 }
368
369 do {
370 FD_ZERO(&rs);
371 FD_ZERO(&ws);
372 FD_SET(C->sock, &rs);
373 FD_SET(C->sock, &ws);
374 res = select(C->sock+1, &rs, &ws, NULL, &timeout);
375 pthread_testcancel();
376 } while (res < 0 && errno == EINTR);
377
378 if (res == 0) {
379 errno = ETIMEDOUT;
380 }
381
382 if (res <= 0) {
383 C->state = UNDEF;
384 NOTIFY(WARNING, "socket: select and discovered it's not ready %s:%d", __FILE__, __LINE__);
385 return FALSE;
386 } else {
387 C->state = mode;
388 return TRUE;
389 }
390 }
391
392 /**
393 * Create new socket and set socket options.
394 * Handle possible error codes.
395 */
396 private int
__socket_create(CONN * C,int domain)397 __socket_create(CONN *C, int domain)
398 {
399 if ((C->sock = socket(domain, SOCK_STREAM, 0)) < 0) {
400 switch (errno) {
401 case EPROTONOSUPPORT: { NOTIFY(ERROR, "unsupported protocol %s:%d", __FILE__, __LINE__); break; }
402 case EMFILE: { NOTIFY(ERROR, "descriptor table full %s:%d", __FILE__, __LINE__); break; }
403 case ENFILE: { NOTIFY(ERROR, "file table full %s:%d", __FILE__, __LINE__); break; }
404 case EACCES: { NOTIFY(ERROR, "permission denied %s:%d", __FILE__, __LINE__); break; }
405 case ENOBUFS: { NOTIFY(ERROR, "insufficient buffer %s:%d", __FILE__, __LINE__); break; }
406 default: { NOTIFY(ERROR, "unknown socket error %s:%d", __FILE__, __LINE__); break; }
407 } socket_close(C); return -1;
408 }
409 if (fcntl(C->sock, F_SETFD, O_NDELAY) < 0) {
410 NOTIFY(ERROR, "unable to set close control %s:%d", __FILE__, __LINE__);
411 }
412
413 if (C->connection.keepalive) {
414 int opt = 1;
415 if (setsockopt(C->sock,SOL_SOCKET,SO_KEEPALIVE,(char *)&opt,sizeof(opt))<0) {
416 switch (errno) {
417 case EBADF: { NOTIFY(ERROR, "invalid descriptor %s:%d", __FILE__, __LINE__); break; }
418 case ENOTSOCK: { NOTIFY(ERROR, "not a socket %s:%d", __FILE__, __LINE__); break; }
419 case ENOPROTOOPT: { NOTIFY(ERROR, "not a protocol option %s:%d", __FILE__, __LINE__); break; }
420 case EFAULT: { NOTIFY(ERROR, "setsockopt unknown %s:%d", __FILE__, __LINE__); break; }
421 default: { NOTIFY(ERROR, "unknown sockopt error %s:%d", __FILE__, __LINE__); break; }
422 } socket_close(C); return -1;
423 }
424 }
425
426 if ((__socket_block(C->sock, FALSE)) < 0) {
427 NOTIFY(ERROR, "socket: unable to set socket to non-blocking %s:%d", __FILE__, __LINE__);
428 return -1;
429 }
430
431 return 0;
432 }
433
434 /**
435 * remove square bracket
436 * around IPv6 addresses
437 */
438 private void
__hostname_strip(char * hn,int len)439 __hostname_strip(char *hn, int len)
440 {
441 int i;
442
443 if (startswith("[", hn)) {
444 memmove(hn, hn + 1, len - 1);
445
446 /* skip to matching square bracket */
447 for (i = 0; hn[i] && hn[i] != ']'; i++);
448
449 if (hn[i] == ']') {
450 memmove(hn + i, hn + i + 1, len - i - 1);
451 }
452 }
453 }
454
455 /**
456 * local function
457 * set socket to non-blocking
458 */
459 private int
__socket_block(int sock,BOOLEAN block)460 __socket_block(int sock, BOOLEAN block)
461 {
462 #if HAVE_FCNTL_H
463 int flags;
464 int retval;
465 #elif defined(FIONBIO)
466 ioctl_t status;
467 #else
468 return sock;
469 #endif
470 // return sock;
471 if (sock==-1) {
472 return sock;
473 }
474
475 #if HAVE_FCNTL_H
476 if ((flags = fcntl(sock, F_GETFL, 0)) < 0) {
477 switch (errno) {
478 case EACCES: { NOTIFY(ERROR, "EACCES %s:%d", __FILE__, __LINE__); break; }
479 case EBADF: { NOTIFY(ERROR, "bad file descriptor %s:%d", __FILE__, __LINE__); break; }
480 case EAGAIN: { NOTIFY(ERROR, "address is unavailable %s:%d", __FILE__, __LINE__); break; }
481 default: { NOTIFY(ERROR, "unknown network error %s:%d", __FILE__, __LINE__); break; }
482 } return -1;
483 }
484
485 if (block) {
486 flags &= ~O_NDELAY;
487 } else {
488 flags |= O_NDELAY;
489 #if (defined(hpux) || defined(__hpux) || defined(__osf__)) || defined(__sun)
490 #else
491 flags |= O_NONBLOCK;
492 #endif
493 }
494
495 if ((retval = fcntl(sock, F_SETFL, flags)) < 0) {
496 NOTIFY(ERROR, "unable to set fcntl flags %s:%d", __FILE__, __LINE__);
497 return -1;
498 }
499 return retval;
500
501 #elif defined(FIONBIO)
502 status = block ? 0 : 1;
503 return ioctl(sock, FIONBIO, &status);
504 #endif
505 }
506
507 /**
508 * returns ssize_t
509 * writes vbuf to sock
510 */
511 private ssize_t
__socket_write(int sock,const void * vbuf,size_t len)512 __socket_write(int sock, const void *vbuf, size_t len)
513 {
514 size_t n;
515 ssize_t w;
516 const char *buf;
517
518 buf = vbuf;
519 n = len;
520 while (n > 0) {
521 if ((w = write( sock, buf, n)) <= 0) {
522 if (errno == EINTR) {
523 w = 0;
524 } else {
525 return -1;
526 }
527 }
528 n -= w;
529 buf += w;
530 }
531 return len;
532 }
533
534 /**
535 * local function
536 * returns ssize_t
537 * writes vbuf to sock
538 */
539 #ifdef HAVE_SSL
540 private ssize_t
__ssl_socket_write(CONN * C,const void * vbuf,size_t len)541 __ssl_socket_write(CONN *C, const void *vbuf, size_t len)
542 {
543 size_t n;
544 ssize_t w;
545 const char *buf;
546 int err;
547
548 buf = vbuf;
549 n = len;
550
551 while (n > 0) {
552 if ((w = SSL_write(C->ssl, buf, n)) <= 0) {
553 if (w < 0) {
554 err = SSL_get_error(C->ssl, w);
555
556 switch (err) {
557 case SSL_ERROR_WANT_READ:
558 case SSL_ERROR_WANT_WRITE:
559 NOTIFY(DEBUG, "SSL_write non-critical error %d", err);
560 return 0;
561 case SSL_ERROR_SYSCALL:
562 NOTIFY(ERROR, "SSL_write() failed (syscall)");
563 return -1;
564 case SSL_ERROR_SSL:
565 return -1;
566 }
567 }
568 NOTIFY(ERROR, "SSL_write() failed.");
569 return -1;
570 }
571 n -= w;
572 buf += w;
573 }
574 return len;
575 }
576 #endif/*HAVE_SSL*/
577
578 ssize_t
socket_read(CONN * C,void * vbuf,size_t len)579 socket_read(CONN *C, void *vbuf, size_t len)
580 {
581 int type;
582 size_t n;
583 ssize_t r;
584 char *buf;
585 int ret_eof = 0;
586
587 pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &type);
588
589 buf = vbuf;
590 n = len;
591 if (C->encrypt == TRUE) {
592 #ifdef HAVE_SSL
593 while (n > 0) {
594 if (__socket_check(C, READ) == FALSE) {
595 NOTIFY(WARNING, "socket: read check timed out(%d) %s:%d", (my.timeout)?my.timeout:15, __FILE__, __LINE__);
596 return -1;
597 }
598 r = SSL_read(C->ssl, buf, n);
599 if (r < 0) {
600 if (errno == EINTR || SSL_get_error(C->ssl, r) == SSL_ERROR_WANT_READ)
601 r = 0;
602 else
603 return -1;
604 }
605 else if (r == 0) break;
606 n -= r;
607 buf += r;
608 } /* end of while */
609 #endif/*HAVE_SSL*/
610 } else {
611 while (n > 0) {
612 if (C->inbuffer < len) {
613 if (__socket_check(C, READ) == FALSE) {
614 NOTIFY(WARNING, "socket: read check timed out(%d) %s:%d", (my.timeout)?my.timeout:15, __FILE__, __LINE__);
615 return -1;
616 }
617 }
618 if (C->inbuffer < n) {
619 int lidos;
620 memmove(C->buffer,&C->buffer[C->pos_ini],C->inbuffer);
621 C->pos_ini = 0;
622 if (__socket_check(C, READ) == FALSE) {
623 NOTIFY(WARNING, "socket: read check timed out(%d) %s:%d", (my.timeout)?my.timeout:15, __FILE__, __LINE__);
624 return -1;
625 }
626 lidos = read(C->sock, &C->buffer[C->inbuffer], sizeof(C->buffer)-C->inbuffer);
627 if (lidos == 0)
628 ret_eof = 1;
629 if (lidos < 0) {
630 if (errno==EINTR || errno==EAGAIN)
631 lidos = 0;
632 if (errno==EPIPE){
633 return 0;
634 } else {
635 NOTIFY(ERROR, "socket: read error %s %s:%d", strerror(errno), __FILE__, __LINE__);
636 return 0; /* was return -1 */
637 }
638 }
639 C->inbuffer += lidos;
640 }
641 if (C->inbuffer >= n) {
642 r = n;
643 } else {
644 r = C->inbuffer;
645 }
646 if (r == 0) break;
647 memmove(buf,&C->buffer[C->pos_ini],r);
648 C->pos_ini += r;
649 C->inbuffer -= r;
650 n -= r;
651 buf += r;
652 if (ret_eof) break;
653 } /* end of while */
654 } /* end of else */
655
656 pthread_setcanceltype(type,NULL);
657 pthread_testcancel();
658 return (len - n);
659 }
660 /**
661 * this function is used for chunked
662 * encoding transfers to acquire the
663 * size of the message check.
664 */
665 ssize_t
socket_readline(CONN * C,char * ptr,size_t maxlen)666 socket_readline(CONN *C, char *ptr, size_t maxlen)
667 {
668 int type;
669 int n, len, res;
670 char c;
671
672 len = maxlen;
673 pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &type);
674
675 for (n = 1; n < len; n ++) {
676 if ((res = socket_read(C, &c, 1)) == 1) {
677 *ptr++ = c;
678 if (c=='\n') break;
679 }
680 else if (res == 0) {
681 if (n == 1)
682 return 0;
683 else
684 break;
685 } else {
686 return -1; /* something bad happened */
687 }
688 } /* end of for loop */
689
690 *ptr=0;
691
692 pthread_setcanceltype(type,NULL);
693 pthread_testcancel();
694
695 return n;
696 }
697
698 /**
699 * returns void
700 * socket_write wrapper function.
701 */
702 int
socket_write(CONN * C,const void * buf,size_t len)703 socket_write(CONN *C, const void *buf, size_t len)
704 {
705 int type;
706 size_t bytes;
707
708 pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &type);
709
710 if (C->encrypt == TRUE) {
711 /* handle HTTPS protocol */
712 #ifdef HAVE_SSL
713 /**
714 * Yeah, sure, this looks like a potential
715 * endless loop, (see: Loop, endless), but
716 * a socket timeout will break it...
717 */
718 do {
719 if ((bytes = __ssl_socket_write(C, buf, len)) != len) {
720 if (bytes == 0)
721 ;
722 else
723 return -1;
724 }
725 } while (bytes == 0);
726 #else
727 NOTIFY(ERROR, "%s:%d protocol NOT supported", __FILE__, __LINE__);
728 return -1;
729 #endif/*HAVE_SSL*/
730 } else {
731 /* assume HTTP */
732 if ((bytes = __socket_write(C->sock, buf, len)) != len) {
733 NOTIFY(ERROR, "unable to write to socket %s:%d", __FILE__, __LINE__);
734 return -1;
735 }
736 }
737
738 pthread_setcanceltype(type,NULL);
739 pthread_testcancel();
740
741 return bytes;
742 }
743
744 /**
745 * returns void
746 * frees ssl resources if using ssl and
747 * closes the connection and the socket.
748 */
749 void
socket_close(CONN * C)750 socket_close(CONN *C)
751 {
752 int type;
753 int ret = 0;
754 #ifdef HAVE_SSL
755 int tries = 0;
756 #endif/*HAVE_SSL*/
757 if (C==NULL) return;
758
759 /* XXX Is this necessary? */
760 pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &type);
761
762 if (C->encrypt == TRUE) {
763 #ifdef HAVE_SSL
764 if (!C->connection.reuse || C->connection.max == 1){
765 if (C->ssl != NULL) {
766 do {
767 ret = SSL_get_shutdown(C->ssl);
768 if (ret < 0) {
769 NOTIFY(WARNING, "socket: SSL Socket closed by server: %s:%d", __FILE__, __LINE__);
770 break; //what an asshole; is this IIS?
771 }
772
773 ret = SSL_shutdown(C->ssl);
774 if (ret == 1) {
775 break;
776 }
777 tries++;
778 } while(tries < 5);
779 }
780 SSL_free(C->ssl);
781 C->ssl = NULL;
782 SSL_CTX_free(C->ctx);
783 C->ctx = NULL;
784 close(C->sock);
785 C->sock = -1;
786 C->connection.status = 0;
787 C->connection.max = 0;
788 C->connection.tested = 0;
789 }
790 #endif/*HAVE_SSL*/
791 } else {
792 if (C->connection.reuse == 0 || C->connection.max == 1) {
793 if (C->sock != -1) {
794 if ((__socket_block(C->sock, FALSE)) < 0)
795 NOTIFY(ERROR, "unable to set to non-blocking %s:%d", __FILE__, __LINE__);
796 if ((C->connection.status > 1)&&(ret = shutdown(C->sock, 2)) < 0)
797 NOTIFY(ERROR, "unable to shutdown the socket %s:%d", __FILE__, __LINE__);
798 if ((ret = close(C->sock)) < 0)
799 NOTIFY(ERROR, "unable to close the socket %s:%d", __FILE__, __LINE__);
800 }
801 C->sock = -1;
802 C->connection.status = 0;
803 C->connection.max = 0;
804 C->connection.tested = 0;
805 }
806 }
807 C = NULL;
808 pthread_setcanceltype(type,NULL);
809 pthread_testcancel();
810
811 return;
812 }
813
814
815