X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=webcit%2Ftcp_sockets.c;h=440178396e7eb67dabb0ebdb19f44d4fdc205928;hb=fcb8c4169baa629eb3c1a4979c7c8c32f1560389;hp=a32285b7d959b08b501d3dcfdb0bc1db8d210e03;hpb=5867a09ba4ea152b1b5deb380a1b287748b565dc;p=citadel.git diff --git a/webcit/tcp_sockets.c b/webcit/tcp_sockets.c index a32285b7d..440178396 100644 --- a/webcit/tcp_sockets.c +++ b/webcit/tcp_sockets.c @@ -1,9 +1,7 @@ /* - * $Id$ + * Copyright (c) 1987-2011 by the citadel.org team * - * Copyright (c) 1987-2010 by the citadel.org team - * - * This program is free software; you can redistribute it and/or modify + * 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. @@ -69,39 +67,81 @@ int uds_connectsock(char *sockpath) /* - * TCP client - connect to a host/port (FIXME this needs to be IPv6 enabled) + * TCP client - connect to a host/port */ -int tcp_connectsock(char *host, int port) +int tcp_connectsock(char *host, char *service) { - struct sockaddr_in stSockAddr; - int rv; - int sock; - - sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); - if (sock < 0) { - lprintf(1, "Can't create socket: %s\n", strerror(errno)); + struct in6_addr serveraddr; + struct addrinfo hints; + struct addrinfo *res = NULL; + struct addrinfo *ai = NULL; + int rc = (-1); + int s = (-1); + + if ((host == NULL) || IsEmptyStr(host)) + return (-1); + if ((service == NULL) || IsEmptyStr(service)) return (-1); - } - memset(&stSockAddr, 0, sizeof(struct sockaddr_in)); - stSockAddr.sin_family = AF_INET; - stSockAddr.sin_port = htons(port); - rv = inet_pton(AF_INET, host, &stSockAddr.sin_addr); + lprintf(9, "tcp_connectsock(%s,%s)\n", host, service); - if (rv <= 0) { - lprintf(1, "Can't grok %s: %s\n", host, strerror(errno)); - return (-1); + memset(&hints, 0x00, sizeof(hints)); + hints.ai_flags = AI_NUMERICSERV; + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + /* + * Handle numeric IPv4 and IPv6 addresses + */ + rc = inet_pton(AF_INET, host, &serveraddr); + if (rc == 1) { /* dotted quad */ + hints.ai_family = AF_INET; + hints.ai_flags |= AI_NUMERICHOST; + } else { + rc = inet_pton(AF_INET6, host, &serveraddr); + if (rc == 1) { /* IPv6 address */ + hints.ai_family = AF_INET6; + hints.ai_flags |= AI_NUMERICHOST; + } } - if (connect(sock, (const struct sockaddr *)&stSockAddr, sizeof(struct sockaddr_in)) != 0) { - lprintf(1, "Can't connect to %s.%d: %s\n", host, port, strerror(errno)); - close(sock); - return (-1); + /* Begin the connection process */ + + rc = getaddrinfo(host, service, &hints, &res); + if (rc != 0) { + lprintf(1, "%s: %s\n", host, gai_strerror(rc)); + freeaddrinfo(res); + return(-1); } - return (sock); -} + /* + * Try all available addresses until we connect to one or until we run out. + */ + for (ai = res; ai != NULL; ai = ai->ai_next) { + + if (ai->ai_family == AF_INET) lprintf(9, "Trying IPv4\n"); + else if (ai->ai_family == AF_INET6) lprintf(9, "Trying IPv6\n"); + else lprintf(9, "This is going to fail.\n"); + s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); + if (s < 0) { + lprintf(1, "socket() failed: %s\n", strerror(errno)); + freeaddrinfo(res); + return(-1); + } + rc = connect(s, ai->ai_addr, ai->ai_addrlen); + if (rc >= 0) { + freeaddrinfo(res); + return(s); + } + else { + lprintf(1, "connect() failed: %s\n", strerror(errno)); + close(s); + } + } + freeaddrinfo(res); + return(-1); +} /* @@ -152,9 +192,9 @@ int StrBuf_ServGetln(StrBuf *buf) #ifdef SERV_TRACE else { - long pos=0; + long pos = 0; if (WCC->ReadPos != NULL) - pos = WCC->ReadPos - ChrPtr(buf); + pos = WCC->ReadPos - ChrPtr(WCC->ReadBuf); lprintf(9, "%3d<<<[%ld]%s\n", WC->serv_sock, pos, ChrPtr(buf)); } #endif @@ -217,6 +257,42 @@ int StrBuf_ServGetBLOB(StrBuf *buf, long BlobSize) return rc; } + +void FlushReadBuf (void) +{ + long len; + const char *pch; + const char *pche; + wcsession *WCC = WC; + + len = StrLength(WCC->ReadBuf); + if ((len > 0) && + (WCC->ReadPos != NULL) && + (WCC->ReadPos != StrBufNOTNULL)) + + { + pch = ChrPtr(WCC->ReadBuf); + pche = pch + len; + if (WCC->ReadPos != pche) + { + lprintf(1, "ERROR: somebody didn't eat his soup! Remaing Chars: %d [%s]\n", + pche - WCC->ReadPos, pche); + lprintf(1, + "--------------------------------------------------------------------------------\n" + "Whole buf: [%s]\n" + "--------------------------------------------------------------------------------\n", + pch); + AppendImportantMessage(HKEY("Suppenkasper alert! watch your webcit logfile and get connected to your favourite opensource Crew.")); + } + } + + FlushStrBuf(WCC->ReadBuf); + WCC->ReadPos = NULL; + + +} + + /* * send binary to server * buf the buffer to write to citadel server @@ -228,8 +304,7 @@ void serv_write(const char *buf, int nbytes) int bytes_written = 0; int retval; - FlushStrBuf(WCC->ReadBuf); - WCC->ReadPos = NULL; + FlushReadBuf(); while (bytes_written < nbytes) { retval = write(WCC->serv_sock, &buf[bytes_written], nbytes - bytes_written); @@ -254,12 +329,10 @@ void serv_write(const char *buf, int nbytes) */ void serv_puts(const char *string) { - wcsession *WCC = WC; #ifdef SERV_TRACE lprintf(9, "%3d>>>%s\n", WC->serv_sock, string); #endif - FlushStrBuf(WCC->ReadBuf); - WCC->ReadPos = NULL; + FlushReadBuf(); serv_write(string, strlen(string)); serv_write("\n", 1); @@ -271,12 +344,10 @@ void serv_puts(const char *string) */ void serv_putbuf(const StrBuf *string) { - wcsession *WCC = WC; #ifdef SERV_TRACE lprintf(9, "%3d>>>%s\n", WC->serv_sock, ChrPtr(string)); #endif - FlushStrBuf(WCC->ReadBuf); - WCC->ReadPos = NULL; + FlushReadBuf(); serv_write(ChrPtr(string), StrLength(string)); serv_write("\n", 1); @@ -290,13 +361,11 @@ void serv_putbuf(const StrBuf *string) */ void serv_printf(const char *format,...) { - wcsession *WCC = WC; va_list arg_ptr; char buf[SIZ]; size_t len; - FlushStrBuf(WCC->ReadBuf); - WCC->ReadPos = NULL; + FlushReadBuf(); va_start(arg_ptr, format); vsnprintf(buf, sizeof buf, format, arg_ptr); @@ -312,116 +381,45 @@ void serv_printf(const char *format,...) } - -/** - * Read binary data from server into memory using a series of - * server READ commands. - * \return the read content as StrBuf +/* + * Read binary data from server into memory using a series of server READ commands. + * returns the read content as StrBuf */ int serv_read_binary(StrBuf *Ret, size_t total_len, StrBuf *Buf) { wcsession *WCC = WC; - size_t bytes = 0; - size_t thisblock = 0; - - if (Ret == NULL) - return -1; + size_t bytes_read = 0; + size_t this_block = 0; + int rc; - if (MaxRead == -1) - { - serv_printf("READ %d|"SIZE_T_FMT, 0, total_len); - if (StrBuf_ServGetln(Buf) > 0) - { - long YetRead; - const char *ErrStr; - const char *pch; - int rc; - - if (GetServerStatus(Buf, NULL) == 6) - { - StrBufCutLeft(Buf, 4); - thisblock = StrTol(Buf); - if (WCC->serv_sock==-1) { - FlushStrBuf(Ret); - return -1; - } - - if (WCC->ReadPos != NULL) { - pch = ChrPtr(WCC->ReadBuf); - - YetRead = WCC->ReadPos - pch; - if (YetRead > 0) - { - long StillThere; - - StillThere = StrLength(WCC->ReadBuf) - - YetRead; - - StrBufPlain(Ret, - WCC->ReadPos, - StillThere); - total_len -= StillThere; - } - FlushStrBuf(WCC->ReadBuf); - WCC->ReadPos = NULL; - } - if (total_len > 0) - { - rc = StrBufReadBLOB(Ret, - &WCC->serv_sock, - 1, - total_len, - &ErrStr); - if (rc < 0) - { - lprintf(1, "Server connection broken: %s\n", - (ErrStr)?ErrStr:""); - wc_backtrace(); - WCC->serv_sock = (-1); - WCC->connected = 0; - WCC->logged_in = 0; - return rc; - } - else - return StrLength(Ret); - } - else - return StrLength(Ret); - } - } - else - return -1; + if (Ret == NULL) { + return -1; } - else while ((WCC->serv_sock!=-1) && - (bytes < total_len)) { - thisblock = MaxRead; - if ((total_len - bytes) < thisblock) { - thisblock = total_len - bytes; - if (thisblock == 0) { - FlushStrBuf(Ret); - return -1; - } + + while (bytes_read < total_len) { + + if (WCC->serv_sock==-1) { + FlushStrBuf(Ret); + return -1; } - serv_printf("READ %d|%d", (int)bytes, (int)thisblock); - if (StrBuf_ServGetln(Buf) > 0) - { - if (GetServerStatus(Buf, NULL) == 6) - { - StrBufCutLeft(Buf, 4); - thisblock = StrTol(Buf); - if (WCC->serv_sock==-1) { - FlushStrBuf(Ret); - return -1; - } - StrBuf_ServGetBLOBBuffered(Ret, thisblock); - bytes += thisblock; - } - else { - lprintf(3, "Error: %s\n", ChrPtr(Buf) + 4); - return -1; - } + + serv_printf("READ %d|%d", bytes_read, total_len-bytes_read); + if ( (StrBuf_ServGetln(Buf) > 0) && (GetServerStatus(Buf, NULL) == 6) ) { + StrBufCutLeft(Buf, 4); + this_block = StrTol(Buf); + rc = StrBuf_ServGetBLOBBuffered(Ret, this_block); + if (rc < 0) { + lprintf(1, "Server connection broken during download\n"); + wc_backtrace(); + WCC->serv_sock = (-1); + WCC->connected = 0; + WCC->logged_in = 0; + return rc; + } + bytes_read += rc; } } + return StrLength(Ret); } @@ -499,30 +497,43 @@ int ClientGetLine(ParsedHttpHdrs *Hdr, StrBuf *Target) * port_number port number to bind * queue_len number of incoming connections to allow in the queue */ -int ig_tcp_server(char *ip_addr, int port_number, int queue_len) +int webcit_tcp_server(char *ip_addr, int port_number, int queue_len) { struct protoent *p; - struct sockaddr_in6 sin; - int s, i; + struct sockaddr_in6 sin6; + struct sockaddr_in sin4; + int s, i, b; + int ip_version = 6; - memset(&sin, 0, sizeof(sin)); - sin.sin6_family = AF_INET6; + memset(&sin6, 0, sizeof(sin6)); + memset(&sin4, 0, sizeof(sin4)); + sin6.sin6_family = AF_INET6; + sin4.sin_family = AF_INET; - if ( (ip_addr == NULL) /* any address */ + if ( (ip_addr == NULL) /* any IPv6 */ || (IsEmptyStr(ip_addr)) - || (!strcmp(ip_addr, "0.0.0.0")) || (!strcmp(ip_addr, "*")) ) { - sin.sin6_addr = in6addr_any; - } else { - char bind_to[256]; - if ((strchr(ip_addr, '.')) && (!strchr(ip_addr, ':'))) { /* specific IPv4 */ - snprintf(bind_to, sizeof bind_to, "::ffff:%s", ip_addr); - } - else { - safestrncpy(bind_to, ip_addr, sizeof bind_to); /* specific IPv6 */ + ip_version = 6; + sin6.sin6_addr = in6addr_any; + } + else if (!strcmp(ip_addr, "0.0.0.0")) /* any IPv4 */ + { + ip_version = 4; + sin4.sin_addr.s_addr = INADDR_ANY; + } + else if ((strchr(ip_addr, '.')) && (!strchr(ip_addr, ':'))) /* specific IPv4 */ + { + ip_version = 4; + if (inet_pton(AF_INET, ip_addr, &sin4.sin_addr) <= 0) { + lprintf(1, "Error binding to [%s] : %s\n", ip_addr, strerror(errno)); + return (-WC_EXIT_BIND); } - if (inet_pton(AF_INET6, bind_to, &sin.sin6_addr) <= 0) { + } + else /* specific IPv6 */ + { + ip_version = 6; + if (inet_pton(AF_INET6, ip_addr, &sin6.sin6_addr) <= 0) { lprintf(1, "Error binding to [%s] : %s\n", ip_addr, strerror(errno)); return (-WC_EXIT_BIND); } @@ -532,23 +543,32 @@ int ig_tcp_server(char *ip_addr, int port_number, int queue_len) lprintf(1, "Cannot start: no port number specified.\n"); return (-WC_EXIT_BIND); } - sin.sin6_port = htons((u_short) port_number); + sin6.sin6_port = htons((u_short) port_number); + sin4.sin_port = htons((u_short) port_number); p = getprotobyname("tcp"); - s = socket(PF_INET6, SOCK_STREAM, (p->p_proto)); + s = socket( ((ip_version == 6) ? PF_INET6 : PF_INET), SOCK_STREAM, (p->p_proto)); if (s < 0) { - lprintf(1, "Can't create an IPv6 socket: %s\n", strerror(errno)); + lprintf(1, "Can't create a listening socket: %s\n", strerror(errno)); return (-WC_EXIT_BIND); } /* Set some socket options that make sense. */ i = 1; setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i)); - if (bind(s, (struct sockaddr *) &sin, sizeof(sin)) < 0) { + if (ip_version == 6) { + b = bind(s, (struct sockaddr *) &sin6, sizeof(sin6)); + } + else { + b = bind(s, (struct sockaddr *) &sin4, sizeof(sin4)); + } + + if (b < 0) { lprintf(1, "Can't bind: %s\n", strerror(errno)); return (-WC_EXIT_BIND); } + if (listen(s, queue_len) < 0) { lprintf(1, "Can't listen: %s\n", strerror(errno)); return (-WC_EXIT_BIND); @@ -562,7 +582,7 @@ int ig_tcp_server(char *ip_addr, int port_number, int queue_len) * sockpath - file name of the unix domain socket * queue_len - Number of incoming connections to allow in the queue */ -int ig_uds_server(char *sockpath, int queue_len) +int webcit_uds_server(char *sockpath, int queue_len) { struct sockaddr_un addr; int s; @@ -718,7 +738,7 @@ long end_burst(void) if (CompressBuffer(WCC->WBuf) > 0) hprintf("Content-encoding: gzip\r\n"); else { - lprintf(CTDL_ALERT, "Compression failed: %d [%s] sending uncompressed\n", errno, strerror(errno)); + syslog(LOG_ALERT, "Compression failed: %d [%s] sending uncompressed\n", errno, strerror(errno)); wc_backtrace(); } }