X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=webcit%2Ftcp_sockets.c;h=b5f8adac7e20d5f311eb12b7eb57cb57af3cfa1c;hb=d12a0b0259ca73f15d413f7a4fcd8f953c7c0c28;hp=da483deabceab4b9c1f0162169495d69411b738b;hpb=77d93a35c3508e8f06d3327a742fd5471849a1b2;p=citadel.git diff --git a/webcit/tcp_sockets.c b/webcit/tcp_sockets.c index da483deab..b5f8adac7 100644 --- a/webcit/tcp_sockets.c +++ b/webcit/tcp_sockets.c @@ -1,19 +1,13 @@ /* - * Copyright (c) 1987-2011 by the citadel.org team + * Copyright (c) 1987-2012 by the citadel.org team * * This program is open source software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * + * it under the terms of the GNU General Public License, version 3. + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* @@ -21,11 +15,9 @@ #define SERV_TRACE 1 */ - #include "webcit.h" #include "webserver.h" -extern int DisableGzip; long MaxRead = -1; /* should we do READ scattered or all at once? */ /* @@ -33,7 +25,7 @@ long MaxRead = -1; /* should we do READ scattered or all at once? */ */ RETSIGTYPE timeout(int signum) { - syslog(1, "Connection timed out; unable to reach citserver\n"); + syslog(LOG_WARNING, "Connection timed out; unable to reach citserver\n"); /* no exit here, since we need to server the connection unreachable thing. exit(3); */ } @@ -44,6 +36,7 @@ RETSIGTYPE timeout(int signum) int uds_connectsock(char *sockpath) { struct sockaddr_un addr; + int fdflags; int s; memset(&addr, 0, sizeof(addr)); @@ -52,16 +45,35 @@ int uds_connectsock(char *sockpath) s = socket(AF_UNIX, SOCK_STREAM, 0); if (s < 0) { - syslog(1, "Can't create socket [%s]: %s\n", sockpath, strerror(errno)); + syslog(LOG_WARNING, "Can't create socket [%s]: %s\n", sockpath, strerror(errno)); return(-1); } if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - syslog(1, "Can't connect [%s]: %s\n", sockpath, strerror(errno)); + syslog(LOG_WARNING, "Can't connect [%s]: %s\n", sockpath, strerror(errno)); close(s); return(-1); } + fdflags = fcntl(s, F_GETFL); + if (fdflags < 0) { + syslog(LOG_ERR, + "unable to get socket %d flags! %s \n", + s, + strerror(errno)); + close(s); + return -1; + } + fdflags = fdflags | O_NONBLOCK; + if (fcntl(s, F_SETFL, fdflags) < 0) { + syslog(LOG_ERR, + "unable to set socket %d nonblocking flags! %s \n", + s, + strerror(errno)); + close(s); + return -1; + } + return s; } @@ -83,7 +95,7 @@ int tcp_connectsock(char *host, char *service) if ((service == NULL) || IsEmptyStr(service)) return (-1); - syslog(9, "tcp_connectsock(%s,%s)\n", host, service); + syslog(LOG_DEBUG, "tcp_connectsock(%s,%s)\n", host, service); memset(&hints, 0x00, sizeof(hints)); hints.ai_flags = AI_NUMERICSERV; @@ -109,7 +121,7 @@ int tcp_connectsock(char *host, char *service) rc = getaddrinfo(host, service, &hints, &res); if (rc != 0) { - syslog(1, "%s: %s\n", host, gai_strerror(rc)); + syslog(LOG_DEBUG, "%s: %s\n", host, gai_strerror(rc)); freeaddrinfo(res); return(-1); } @@ -119,23 +131,44 @@ int tcp_connectsock(char *host, char *service) */ for (ai = res; ai != NULL; ai = ai->ai_next) { - if (ai->ai_family == AF_INET) syslog(9, "Trying IPv4\n"); - else if (ai->ai_family == AF_INET6) syslog(9, "Trying IPv6\n"); - else syslog(9, "This is going to fail.\n"); + if (ai->ai_family == AF_INET) syslog(LOG_DEBUG, "Trying IPv4\n"); + else if (ai->ai_family == AF_INET6) syslog(LOG_DEBUG, "Trying IPv6\n"); + else syslog(LOG_WARNING, "This is going to fail.\n"); s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); if (s < 0) { - syslog(1, "socket() failed: %s\n", strerror(errno)); + syslog(LOG_WARNING, "socket() failed: %s\n", strerror(errno)); freeaddrinfo(res); return(-1); } rc = connect(s, ai->ai_addr, ai->ai_addrlen); if (rc >= 0) { + int fdflags; freeaddrinfo(res); + + fdflags = fcntl(rc, F_GETFL); + if (fdflags < 0) { + syslog(LOG_ERR, + "unable to get socket %d flags! %s \n", + rc, + strerror(errno)); + close(rc); + return -1; + } + fdflags = fdflags | O_NONBLOCK; + if (fcntl(rc, F_SETFL, fdflags) < 0) { + syslog(LOG_ERR, + "unable to set socket %d nonblocking flags! %s \n", + rc, + strerror(errno)); + close(s); + return -1; + } + return(s); } else { - syslog(1, "connect() failed: %s\n", strerror(errno)); + syslog(LOG_WARNING, "connect() failed: %s\n", strerror(errno)); close(s); } } @@ -161,7 +194,7 @@ int serv_getln(char *strbuf, int bufsize) FlushStrBuf(WCC->MigrateReadLineBuf); strbuf[len] = '\0'; #ifdef SERV_TRACE - syslog(9, "%3d<<<%s\n", WC->serv_sock, strbuf); + syslog(LOG_DEBUG, "%3d<<<%s\n", WCC->serv_sock, strbuf); #endif return len; } @@ -173,6 +206,9 @@ int StrBuf_ServGetln(StrBuf *buf) const char *ErrStr = NULL; int rc; + if (!WCC->connected) + return -1; + FlushStrBuf(buf); rc = StrBufTCP_read_buffered_line_fast(buf, WCC->ReadBuf, @@ -182,9 +218,9 @@ int StrBuf_ServGetln(StrBuf *buf) &ErrStr); if (rc < 0) { - syslog(1, "StrBuf_ServGetln(): Server connection broken: %s\n", + syslog(LOG_INFO, "StrBuf_ServGetln(): Server connection broken: %s\n", (ErrStr)?ErrStr:""); - wc_backtrace(); + wc_backtrace(LOG_INFO); if (WCC->serv_sock > 0) close(WCC->serv_sock); WCC->serv_sock = (-1); WCC->connected = 0; @@ -196,7 +232,7 @@ int StrBuf_ServGetln(StrBuf *buf) long pos = 0; if (WCC->ReadPos != NULL) pos = WCC->ReadPos - ChrPtr(WCC->ReadBuf); - syslog(9, "%3d<<<[%ld]%s\n", WC->serv_sock, pos, ChrPtr(buf)); + syslog(LOG_DEBUG, "%3d<<<[%ld]%s\n", WC->serv_sock, pos, ChrPtr(buf)); } #endif return rc; @@ -218,9 +254,9 @@ int StrBuf_ServGetBLOBBuffered(StrBuf *buf, long BlobSize) &ErrStr); if (rc < 0) { - syslog(1, "StrBuf_ServGetBLOBBuffered(): Server connection broken: %s\n", + syslog(LOG_INFO, "StrBuf_ServGetBLOBBuffered(): Server connection broken: %s\n", (ErrStr)?ErrStr:""); - wc_backtrace(); + wc_backtrace(LOG_INFO); if (WCC->serv_sock > 0) close(WCC->serv_sock); WCC->serv_sock = (-1); WCC->connected = 0; @@ -228,7 +264,7 @@ int StrBuf_ServGetBLOBBuffered(StrBuf *buf, long BlobSize) } #ifdef SERV_TRACE else - syslog(9, "%3d<<serv_sock, StrLength(buf)); + syslog(LOG_DEBUG, "%3d<<serv_sock, StrLength(buf)); #endif return rc; @@ -244,9 +280,9 @@ int StrBuf_ServGetBLOB(StrBuf *buf, long BlobSize) rc = StrBufReadBLOB(buf, &WCC->serv_sock, 1, BlobSize, &ErrStr); if (rc < 0) { - syslog(1, "StrBuf_ServGetBLOB(): Server connection broken: %s\n", + syslog(LOG_INFO, "StrBuf_ServGetBLOB(): Server connection broken: %s\n", (ErrStr)?ErrStr:""); - wc_backtrace(); + wc_backtrace(LOG_INFO); if (WCC->serv_sock > 0) close(WCC->serv_sock); WCC->serv_sock = (-1); WCC->connected = 0; @@ -254,7 +290,7 @@ int StrBuf_ServGetBLOB(StrBuf *buf, long BlobSize) } #ifdef SERV_TRACE else - syslog(9, "%3d<<serv_sock, StrLength(buf)); + syslog(LOG_DEBUG, "%3d<<serv_sock, StrLength(buf)); #endif return rc; @@ -278,12 +314,12 @@ void FlushReadBuf (void) pche = pch + len; if (WCC->ReadPos != pche) { - syslog(1, + syslog(LOG_EMERG, "ERROR: somebody didn't eat his soup! Remaing Chars: %ld [%s]\n", (long)(pche - WCC->ReadPos), pche ); - syslog(1, + syslog(LOG_EMERG, "--------------------------------------------------------------------------------\n" "Whole buf: [%s]\n" "--------------------------------------------------------------------------------\n", @@ -316,7 +352,7 @@ int serv_write(const char *buf, int nbytes) nbytes - bytes_written); if (retval < 1) { const char *ErrStr = strerror(errno); - syslog(1, "serv_write(): Server connection broken: %s\n", + syslog(LOG_INFO, "serv_write(): Server connection broken: %s\n", (ErrStr)?ErrStr:""); if (WCC->serv_sock > 0) close(WCC->serv_sock); WCC->serv_sock = (-1); @@ -337,7 +373,7 @@ int serv_write(const char *buf, int nbytes) int serv_puts(const char *string) { #ifdef SERV_TRACE - syslog(9, "%3d>>>%s\n", WC->serv_sock, string); + syslog(LOG_DEBUG, "%3d>>>%s\n", WC->serv_sock, string); #endif FlushReadBuf(); @@ -353,7 +389,7 @@ int serv_puts(const char *string) int serv_putbuf(const StrBuf *string) { #ifdef SERV_TRACE - syslog(9, "%3d>>>%s\n", WC->serv_sock, ChrPtr(string)); + syslog(LOG_DEBUG, "%3d>>>%s\n", WC->serv_sock, ChrPtr(string)); #endif FlushReadBuf(); @@ -386,7 +422,7 @@ int serv_printf(const char *format,...) buf[len] = '\0'; rc = serv_write(buf, len); #ifdef SERV_TRACE - syslog(9, ">>>%s", buf); + syslog(LOG_DEBUG, ">>>%s", buf); #endif return rc; } @@ -401,13 +437,14 @@ int serv_read_binary(StrBuf *Ret, size_t total_len, StrBuf *Buf) wcsession *WCC = WC; size_t bytes_read = 0; size_t this_block = 0; - int rc; + int rc = 6; + int ServerRc = 6; if (Ret == NULL) { return -1; } - while (bytes_read < total_len) { + while ((bytes_read < total_len) && (ServerRc == 6)) { if (WCC->serv_sock==-1) { FlushStrBuf(Ret); @@ -415,7 +452,8 @@ int serv_read_binary(StrBuf *Ret, size_t total_len, StrBuf *Buf) } serv_printf("READ "SIZE_T_FMT"|"SIZE_T_FMT, bytes_read, total_len-bytes_read); - if ( (rc = StrBuf_ServGetln(Buf) > 0) && (GetServerStatus(Buf, NULL) == 6) ) + if ( (rc = StrBuf_ServGetln(Buf) > 0) && + (ServerRc = GetServerStatus(Buf, NULL), ServerRc == 6) ) { if (rc < 0) return rc; @@ -423,8 +461,8 @@ int serv_read_binary(StrBuf *Ret, size_t total_len, StrBuf *Buf) this_block = StrTol(Buf); rc = StrBuf_ServGetBLOBBuffered(Ret, this_block); if (rc < 0) { - syslog(1, "Server connection broken during download\n"); - wc_backtrace(); + syslog(LOG_INFO, "Server connection broken during download\n"); + wc_backtrace(LOG_INFO); if (WCC->serv_sock > 0) close(WCC->serv_sock); WCC->serv_sock = (-1); WCC->connected = 0; @@ -448,7 +486,8 @@ int ClientGetLine(ParsedHttpHdrs *Hdr, StrBuf *Target) if (is_https) { int ntries = 0; - if (StrLength(Hdr->ReadBuf) > 0) { + if (StrLength(Hdr->ReadBuf) > 0) + { pchs = ChrPtr(Hdr->ReadBuf); pch = strchr(pchs, '\n'); if (pch != NULL) { @@ -471,6 +510,8 @@ int ClientGetLine(ParsedHttpHdrs *Hdr, StrBuf *Target) retval = client_read_sslbuffer(Hdr->ReadBuf, SLEEPING); pchs = ChrPtr(Hdr->ReadBuf); pch = strchr(pchs, '\n'); + if (pch == NULL) + retval = 0; } if (retval == 0) { sleeeeeeeeeep(1); @@ -512,14 +553,17 @@ int ClientGetLine(ParsedHttpHdrs *Hdr, StrBuf *Target) * port_number port number to bind * queue_len number of incoming connections to allow in the queue */ -int webcit_tcp_server(char *ip_addr, int port_number, int queue_len) +int webcit_tcp_server(const char *ip_addr, int port_number, int queue_len) { + const char *ipv4broadcast = "0.0.0.0"; + int IsDefault = 0; struct protoent *p; struct sockaddr_in6 sin6; struct sockaddr_in sin4; int s, i, b; int ip_version = 6; +retry: memset(&sin6, 0, sizeof(sin6)); memset(&sin4, 0, sizeof(sin4)); sin6.sin6_family = AF_INET6; @@ -529,6 +573,7 @@ int webcit_tcp_server(char *ip_addr, int port_number, int queue_len) || (IsEmptyStr(ip_addr)) || (!strcmp(ip_addr, "*")) ) { + IsDefault = 1; ip_version = 6; sin6.sin6_addr = in6addr_any; } @@ -541,7 +586,7 @@ int webcit_tcp_server(char *ip_addr, int port_number, int queue_len) { ip_version = 4; if (inet_pton(AF_INET, ip_addr, &sin4.sin_addr) <= 0) { - syslog(1, "Error binding to [%s] : %s\n", ip_addr, strerror(errno)); + syslog(LOG_WARNING, "Error binding to [%s] : %s\n", ip_addr, strerror(errno)); return (-WC_EXIT_BIND); } } @@ -549,13 +594,13 @@ int webcit_tcp_server(char *ip_addr, int port_number, int queue_len) { ip_version = 6; if (inet_pton(AF_INET6, ip_addr, &sin6.sin6_addr) <= 0) { - syslog(1, "Error binding to [%s] : %s\n", ip_addr, strerror(errno)); + syslog(LOG_WARNING, "Error binding to [%s] : %s\n", ip_addr, strerror(errno)); return (-WC_EXIT_BIND); } } if (port_number == 0) { - syslog(1, "Cannot start: no port number specified.\n"); + syslog(LOG_WARNING, "Cannot start: no port number specified.\n"); return (-WC_EXIT_BIND); } sin6.sin6_port = htons((u_short) port_number); @@ -565,7 +610,13 @@ int webcit_tcp_server(char *ip_addr, int port_number, int queue_len) s = socket( ((ip_version == 6) ? PF_INET6 : PF_INET), SOCK_STREAM, (p->p_proto)); if (s < 0) { - syslog(1, "Can't create a listening socket: %s\n", strerror(errno)); + if (IsDefault && (errno == EAFNOSUPPORT)) + { + s = 0; + ip_addr = ipv4broadcast; + goto retry; + } + syslog(LOG_WARNING, "Can't create a listening socket: %s\n", strerror(errno)); return (-WC_EXIT_BIND); } /* Set some socket options that make sense. */ @@ -580,13 +631,13 @@ int webcit_tcp_server(char *ip_addr, int port_number, int queue_len) } if (b < 0) { - syslog(1, "Can't bind: %s\n", strerror(errno)); + syslog(LOG_EMERG, "Can't bind: %s\n", strerror(errno)); close(s); return (-WC_EXIT_BIND); } if (listen(s, queue_len) < 0) { - syslog(1, "Can't listen: %s\n", strerror(errno)); + syslog(LOG_EMERG, "Can't listen: %s\n", strerror(errno)); close(s); return (-WC_EXIT_BIND); } @@ -611,7 +662,7 @@ int webcit_uds_server(char *sockpath, int queue_len) i = unlink(sockpath); if ((i != 0) && (errno != ENOENT)) { - syslog(1, "webcit: can't unlink %s: %s\n", + syslog(LOG_WARNING, "webcit: can't unlink %s: %s\n", sockpath, strerror(errno)); return (-WC_EXIT_BIND); } @@ -622,18 +673,18 @@ int webcit_uds_server(char *sockpath, int queue_len) s = socket(AF_UNIX, SOCK_STREAM, 0); if (s < 0) { - syslog(1, "webcit: Can't create a unix domain socket: %s\n", strerror(errno)); + syslog(LOG_WARNING, "webcit: Can't create a unix domain socket: %s\n", strerror(errno)); return (-WC_EXIT_BIND); } if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) { - syslog(1, "webcit: Can't bind: %s\n", strerror(errno)); + syslog(LOG_WARNING, "webcit: Can't bind: %s\n", strerror(errno)); close(s); return (-WC_EXIT_BIND); } if (listen(s, actual_queue_len) < 0) { - syslog(1, "webcit: Can't listen: %s\n", strerror(errno)); + syslog(LOG_WARNING, "webcit: Can't listen: %s\n", strerror(errno)); close(s); return (-WC_EXIT_BIND); } @@ -690,15 +741,10 @@ int client_read_to(ParsedHttpHdrs *Hdr, StrBuf *Target, int bytes, int timeout) retval = client_read_sslbuffer(Hdr->ReadBuf, timeout); if (retval >= 0) { StrBufAppendBuf(Target, Hdr->ReadBuf, 0); /* todo: Buf > bytes? */ -#ifdef HTTP_TRACING - write(2, "\033[32m", 5); - write(2, buf, bytes); - write(2, "\033[30m", 5); -#endif return 1; } else { - syslog(2, "client_read_ssl() failed\n"); + syslog(LOG_INFO, "client_read_ssl() failed\n"); return -1; } } @@ -716,17 +762,12 @@ int client_read_to(ParsedHttpHdrs *Hdr, StrBuf *Target, int bytes, int timeout) O_TERM, &Error); if (retval < 0) { - syslog(2, "client_read() failed: %s\n", + syslog(LOG_INFO, "client_read() failed: %s\n", Error); - wc_backtrace(); + wc_backtrace(LOG_DEBUG); return retval; } -#ifdef HTTP_TRACING - write(2, "\033[32m", 5); - write(2, buf, bytes); - write(2, "\033[30m", 5); -#endif return 1; } @@ -760,7 +801,7 @@ long end_burst(void) hprintf("Content-encoding: gzip\r\n"); else { syslog(LOG_ALERT, "Compression failed: %d [%s] sending uncompressed\n", errno, strerror(errno)); - wc_backtrace(); + wc_backtrace(LOG_INFO); } } @@ -785,13 +826,6 @@ long end_burst(void) } #endif - -#ifdef HTTP_TRACING - - write(2, "\033[34m", 5); - write(2, ptr, StrLength(WCC->WBuf)); - write(2, "\033[30m", 5); -#endif if (WCC->Hdr->http_sock == -1) return -1; fdflags = fcntl(WC->Hdr->http_sock, F_GETFL); @@ -801,7 +835,7 @@ long end_burst(void) FD_ZERO(&wset); FD_SET(WCC->Hdr->http_sock, &wset); if (select(WCC->Hdr->http_sock + 1, NULL, &wset, NULL, NULL) == -1) { - syslog(2, "client_write: Socket select failed (%s)\n", strerror(errno)); + syslog(LOG_DEBUG, "client_write: Socket select failed (%s)\n", strerror(errno)); return -1; } } @@ -810,8 +844,8 @@ long end_burst(void) (res = write(WCC->Hdr->http_sock, ptr, count)) == -1) { - syslog(2, "client_write: Socket write failed (%s)\n", strerror(errno)); - wc_backtrace(); + syslog(LOG_DEBUG, "client_write: Socket write failed (%s)\n", strerror(errno)); + wc_backtrace(LOG_INFO); return res; } count -= res; @@ -822,19 +856,12 @@ long end_burst(void) count = StrLength(WCC->WBuf); eptr = ptr + count; -#ifdef HTTP_TRACING - - write(2, "\033[34m", 5); - write(2, ptr, StrLength(WCC->WBuf)); - write(2, "\033[30m", 5); -#endif - while ((ptr < eptr) && (WCC->Hdr->http_sock != -1)) { if ((fdflags & O_NONBLOCK) == O_NONBLOCK) { FD_ZERO(&wset); FD_SET(WCC->Hdr->http_sock, &wset); if (select(WCC->Hdr->http_sock + 1, NULL, &wset, NULL, NULL) == -1) { - syslog(2, "client_write: Socket select failed (%s)\n", strerror(errno)); + syslog(LOG_INFO, "client_write: Socket select failed (%s)\n", strerror(errno)); return -1; } } @@ -843,8 +870,8 @@ long end_burst(void) (res = write(WCC->Hdr->http_sock, ptr, count)) == -1) { - syslog(2, "client_write: Socket write failed (%s)\n", strerror(errno)); - wc_backtrace(); + syslog(LOG_INFO, "client_write: Socket write failed (%s)\n", strerror(errno)); + wc_backtrace(LOG_INFO); return res; } count -= res; @@ -933,10 +960,12 @@ SessionDestroyModule_TCPSOCKETS { FreeStrBuf(&sess->CLineBuf); FreeStrBuf(&sess->ReadBuf); + sess->connected = 0; sess->ReadPos = NULL; FreeStrBuf(&sess->MigrateReadLineBuf); if (sess->serv_sock > 0) { syslog(LOG_DEBUG, "Closing socket %d", sess->serv_sock); close(sess->serv_sock); } + sess->serv_sock = -1; }