From f6b7fe3f5ceb6709363e77efc8a24fb837c9ec6b Mon Sep 17 00:00:00 2001 From: Robert James Kaes Date: Mon, 11 Sep 2000 23:56:32 +0000 Subject: Needed locking in getpeer_string(). Added mutex locking around the dnscache() call. Removed the global sockaddr and setup_fd variables. Added the socket_blocking() and socket_nonblocking() functions. Gutted the readling() function and replaced it with something similar to the 1.0 version. :) --- src/sock.c | 384 ++++++++++++++++--------------------------------------------- src/sock.h | 22 ++-- 2 files changed, 112 insertions(+), 294 deletions(-) diff --git a/src/sock.c b/src/sock.c index bf0614e..1b49b00 100644 --- a/src/sock.c +++ b/src/sock.c @@ -1,4 +1,4 @@ -/* $Id: sock.c,v 1.2 2000-03-31 20:10:13 rjkaes Exp $ +/* $Id: sock.c,v 1.3 2000-09-11 23:56:32 rjkaes Exp $ * * Sockets are created and destroyed here. When a new connection comes in from * a client, we need to copy the socket and the create a second socket to the @@ -21,52 +21,45 @@ * General Public License for more details. */ -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - #include "tinyproxy.h" -#include "sock.h" + +#include "dnscache.h" #include "log.h" +#include "sock.h" #include "utils.h" -#include "dnscache.h" + +#define SA struct sockaddr + +/* + * The mutex is used for locking around the calls to the dnscache since I + * don't want multiple threads accessing the linked list at the same time. + * This should be more fine grained, but it will do for now. + * - rjkaes + */ +pthread_mutex_t sock_mutex = PTHREAD_MUTEX_INITIALIZER; + +#define SOCK_LOCK() pthread_mutex_lock(&sock_mutex); +#define SOCK_UNLOCK() pthread_mutex_unlock(&sock_mutex); + /* This routine is so old I can't even remember writing it. But I do * remember that it was an .h file because I didn't know putting code in a * header was bad magic yet. anyway, this routine opens a connection to a * system and returns the fd. - */ - -/* + * - steve + * * Cleaned up some of the code to use memory routines which are now the * default. Also, the routine first checks to see if the address is in - * dotted-decimal form before it does a name lookup. Finally, the newly - * created socket is made non-blocking. + * dotted-decimal form before it does a name lookup. * - rjkaes */ int opensock(char *ip_addr, int port) { - int sock_fd, flags; + int sock_fd; struct sockaddr_in port_info; + int ret; - assert(ip_addr); - assert(port > 0); - - memset((struct sockaddr *) &port_info, 0, sizeof(port_info)); + memset((SA *) &port_info, 0, sizeof(port_info)); port_info.sin_family = AF_INET; @@ -74,145 +67,84 @@ int opensock(char *ip_addr, int port) * before a non-blocking DNS query happens for this address. Not * relevant in the code as it stands. */ - if (dnscache(&port_info.sin_addr, ip_addr) < 0) { - log("ERROR opensock: Could not lookup address: %s", ip_addr); + SOCK_LOCK(); + ret = dnscache(&port_info.sin_addr, ip_addr); + SOCK_UNLOCK(); + + if (ret < 0) { + log(LOG_ERR, "opensock: Could not lookup address: %s", ip_addr); return -1; } port_info.sin_port = htons(port); if ((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { - log("ERROR opensock: socket (%s)", strerror(errno)); + log(LOG_ERR, "opensock: socket (%s)", strerror(errno)); return -1; } - flags = fcntl(sock_fd, F_GETFL, 0); - fcntl(sock_fd, F_SETFL, flags | O_NONBLOCK); - - if (connect - (sock_fd, (struct sockaddr *) &port_info, sizeof(port_info)) < 0) { - if (errno != EINPROGRESS) { - log("ERROR opensock: connect (%s)", strerror(errno)); - return -1; - } + if (connect(sock_fd, (SA *) &port_info, sizeof(port_info)) < 0) { + log(LOG_ERR, "connecting socket"); + return -1; } return sock_fd; } -/* chris - added this to open a socket given a struct in_addr */ -int opensock_inaddr(struct in_addr *inaddr, int port) +/* + * Set the socket to non blocking -rjkaes + */ +int socket_nonblocking(int sock) { - int sock_fd, flags; - struct sockaddr_in port_info; - - assert(inaddr); - assert(port > 0); - - memset((struct sockaddr *) &port_info, 0, sizeof(port_info)); + int flags; - port_info.sin_family = AF_INET; - - memcpy(&port_info.sin_addr, inaddr, sizeof(struct in_addr)); - - port_info.sin_port = htons(port); - - if ((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { - log("ERROR opensock_inaddr: socket (%s)", strerror(errno)); - return -1; - } - - flags = fcntl(sock_fd, F_GETFL, 0); - fcntl(sock_fd, F_SETFL, flags | O_NONBLOCK); - - if (connect - (sock_fd, (struct sockaddr *) &port_info, sizeof(port_info)) < 0) { - if (errno != EINPROGRESS) { - log("ERROR opensock: connect (%s)", strerror(errno)); - return -1; - } - } - - return sock_fd; + flags = fcntl(sock, F_GETFL, 0); + return fcntl(sock, F_SETFL, flags | O_NONBLOCK); } -int setup_fd; -static struct sockaddr listen_sock_addr; - /* - * Start listening to a socket. + * Set the socket to blocking -rjkaes */ -int init_listen_sock(int port) +int socket_blocking(int sock) { - struct sockaddr_in laddr; - int i = 1; + int flags; - assert(port > 0); + flags = fcntl(sock, F_GETFL, 0); + return fcntl(sock, F_SETFL, flags & ~O_NONBLOCK); +} - if ((setup_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - log("ERROR init_listen_sock: socket (%s)", strerror(errno)); - return -1; - } +/* + * Start listening to a socket. Create a socket with the selected port. + * The size of the socket address will be returned to the caller through + * the pointer, while the socket is returned as a default return. + * - rjkaes + */ +int listen_sock(unsigned int port, socklen_t *addrlen) +{ + int listenfd; + const int on = 1; + struct sockaddr_in addr; - if (setsockopt(setup_fd, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i)) < 0) { - log("ERROR init_listen_sock: setsockopt (%s)", - strerror(errno)); - return -1; - } + listenfd = socket(AF_INET, SOCK_STREAM, 0); + setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); - memset(&listen_sock_addr, 0, sizeof(listen_sock_addr)); - memset(&laddr, 0, sizeof(laddr)); - laddr.sin_family = AF_INET; - laddr.sin_port = htons(port); + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(port); if (config.ipAddr) { - laddr.sin_addr.s_addr = inet_addr(config.ipAddr); + addr.sin_addr.s_addr = inet_addr(config.ipAddr); } else { - laddr.sin_addr.s_addr = inet_addr("0.0.0.0"); - } - if (bind(setup_fd, (struct sockaddr *) &laddr, sizeof(laddr)) < 0) { - log("ERROR init_listen_sock: bind (%s)", strerror(errno)); - return -1; - } - if ((listen(setup_fd, MAXLISTEN)) != 0) { - log("ERROR init_listen_sock: listen (%s)", strerror(errno)); - return -1; + addr.sin_addr.s_addr = inet_addr("0.0.0.0"); } + + bind(listenfd, (struct sockaddr *) &addr, sizeof(addr)); - return 0; -} - -/* - * Grab a pending connection - */ -int listen_sock(void) -{ - static int sock; - int sz = sizeof(listen_sock_addr); - - if ((sock = accept(setup_fd, &listen_sock_addr, &sz)) < 0) { - if (errno != ECONNABORTED -#ifdef EPROTO - && errno != EPROTO -#endif -#ifdef EWOULDBLOCK - && errno != EWOULDBLOCK -#endif - && errno != EINTR) - log("ERROR listen_sock: accept (%s)", strerror(errno)); - return -1; - } - stats.num_listens++; + listen(listenfd, MAXLISTEN); - return sock; -} + *addrlen = sizeof(addr); -/* - * Stop listening on a socket. - */ -void de_init_listen_sock(void) -{ - close(setup_fd); + return listenfd; } /* @@ -224,17 +156,12 @@ char *getpeer_ip(int fd, char *ipaddr) struct sockaddr_in name; int namelen = sizeof(name); - assert(fd >= 0); - assert(ipaddr); - - memset(ipaddr, '\0', PEER_IP_LENGTH); - if (getpeername(fd, (struct sockaddr *) &name, &namelen) != 0) { - log("ERROR Connect: 'could not get peer name'"); + log(LOG_ERR, "Connect: 'could not get peer name'"); } else { - strncpy(ipaddr, + strlcpy(ipaddr, inet_ntoa(*(struct in_addr *) &name.sin_addr.s_addr), - PEER_IP_LENGTH - 1); + PEER_IP_LENGTH); } return ipaddr; @@ -250,153 +177,46 @@ char *getpeer_string(int fd, char *string) int namelen = sizeof(name); struct hostent *peername; - assert(fd >= 0); - assert(string); - - memset(string, '\0', PEER_STRING_LENGTH); - if (getpeername(fd, (struct sockaddr *) &name, &namelen) != 0) { - log("ERROR Connect: 'could not get peer name'"); + log(LOG_ERR, "Connect: 'could not get peer name'"); } else { - if ( - (peername = - gethostbyaddr((char *) &name.sin_addr.s_addr, - sizeof(name.sin_addr.s_addr), - AF_INET)) != NULL) { - strncpy(string, peername->h_name, - PEER_STRING_LENGTH - 1); + SOCK_LOCK(); + peername = gethostbyaddr((char *)&name.sin_addr.s_addr, + sizeof(name.sin_addr.s_addr), + AF_INET); + if (peername) { + strlcpy(string, peername->h_name, PEER_STRING_LENGTH); } + SOCK_UNLOCK(); } return string; } - -/* - * Okay, this is a wacked out function. The basic gist is that we read in one - * line from the socket and return it in "line". However, if we can't pull in - * one complete line (up to an including the '\n') then we need to store it in - * the buffer's "working_string". Fun. :) - * -- rjkaes - */ -int readline(int fd, struct buffer_s *buffer, char **line) +ssize_t readline(int fd, void *vptr, size_t maxlen) { - char inbuf[BUFFER]; - int bytesin; - char *endline = NULL; - char *newline; - unsigned long length; - - assert(fd >= 0); - assert(buffer); - assert(line); - - *line = NULL; - - /* Inspect the queue. */ - if ((bytesin = recv(fd, inbuf, BUFFER - 1, MSG_PEEK)) <= 0) { - goto CONN_ERROR; - } - - if (buffer->working_length == 0) { - /* There is no working line, so read in a line of text. */ - - /* Okay, check to see if there is a '\n' in this. */ - endline = xstrstr(inbuf, "\n", bytesin, FALSE); - - if (endline) { - /* Yes, we have a complete line. */ - *(++endline) = '\0'; - length = strlen(inbuf); - - /* Actually pull the data off the queue */ - if ((bytesin = recv(fd, inbuf, length, 0) <= 0)) { - goto CONN_ERROR; - } - - *line = xstrdup(inbuf); - return strlen(*line); - } - - /* - * Well, we don't have a complete line, so add it to the - * working_string. - */ - if (!(buffer->working_string = xmalloc(bytesin))) { + ssize_t n, rc; + char c, *ptr; + + ptr = vptr; + for (n = 1; n < maxlen; n++) { + again: + if ((rc = read(fd, &c, 1)) == 1) { + *ptr++ = c; + if (c == '\n') + break; + } else if (rc == 0) { + if (n == 1) + return 0; + else + break; + } else { + if (errno == EINTR) + goto again; return -1; } - - if ((bytesin = recv(fd, inbuf, bytesin, 0)) <= 0) { - safefree(buffer->working_string); - goto CONN_ERROR; - } - - memcpy(buffer->working_string, inbuf, bytesin); - buffer->working_length = bytesin; - - return 0; } - /* - * Alright, we do have a working line, so read in more data and see - * if there is a '\n' in it. - */ - endline = xstrstr(inbuf, "\n", bytesin, FALSE); - - if (endline) { - /* - * Great, there was a "\n" found, so combine with - * working_string. - */ - *(++endline) = '\0'; - length = strlen(inbuf); - - if (!(*line = xmalloc(bytesin + buffer->working_length + 1))) { - return -1; - } - - /* Pull the data off */ - if ((bytesin = recv(fd, inbuf, bytesin, 0)) <= 0) { - goto CONN_ERROR; - } - - /* Copy all the data into a new line */ - memcpy(*line, buffer->working_string, buffer->working_length); - memcpy(*line + buffer->working_length, inbuf, bytesin); - - *(*line + buffer->working_length + bytesin + 1) = '\0'; - - safefree(buffer->working_string); - buffer->working_length = 0; - - return strlen(*line); - } - - /* - * Well, we have a working line and still don't have a complete line. - * Add the new data to the working line and return. - */ - if (!(newline = xmalloc(buffer->working_length + bytesin))) { - return -1; - } - - if ((bytesin = recv(fd, inbuf, bytesin, 0)) <= 0) { - goto CONN_ERROR; - } - - memcpy(newline, buffer->working_string, buffer->working_length); - memcpy(newline + buffer->working_length, inbuf, bytesin); - - safefree(buffer->working_string); - buffer->working_string = newline; - buffer->working_length += bytesin; - - return 0; - - /* Handle all the errors a socket could produce. */ - CONN_ERROR: - if (bytesin == 0 || (errno != EAGAIN && errno != EINTR)) { - return -1; - } - return 0; + *ptr = 0; + return n; } diff --git a/src/sock.h b/src/sock.h index 952a673..b0857d7 100644 --- a/src/sock.h +++ b/src/sock.h @@ -1,4 +1,4 @@ -/* $Id: sock.h,v 1.1.1.1 2000-02-16 17:32:23 sdyoung Exp $ +/* $Id: sock.h,v 1.2 2000-09-11 23:56:32 rjkaes Exp $ * * See 'sock.c' for a detailed description. * @@ -16,25 +16,23 @@ * General Public License for more details. */ -#ifndef _SOCK_H_ -#define _SOCK_H_ 1 - -#include "buffer.h" +#ifndef _TINYPROXY_SOCK_H_ +#define _TINYPROXY_SOCK_H_ #define PEER_IP_LENGTH 16 #define PEER_STRING_LENGTH 256 -extern int setup_fd; +#define MAXLINE (1024 * 4) extern int opensock(char *ip_addr, int port); -extern int opensock_inaddr(struct in_addr *inaddr, int port); -extern int init_listen_sock(int port); -extern int listen_sock(void); -extern void de_init_listen_sock(void); -extern int setsocketopt(int *sock_fd, int options, int flip); +extern int listen_sock(unsigned int port, socklen_t *addrlen); + +extern int socket_nonblocking(int sock); +extern int socket_blocking(int sock); extern char *getpeer_ip(int fd, char *ipaddr); extern char *getpeer_string(int fd, char *string); -extern int readline(int fd, struct buffer_s *buffer, char **line); + +extern ssize_t readline(int fd, void *vptr, size_t maxlen); #endif -- cgit v1.2.3