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. :)
This commit is contained in:
Robert James Kaes 2000-09-11 23:56:32 +00:00
parent c0ff35dd22
commit f6b7fe3f5c
2 changed files with 116 additions and 298 deletions

View File

@ -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 * 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 * 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. * General Public License for more details.
*/ */
#ifdef HAVE_CONFIG_H
#include <defines.h>
#endif
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include <netdb.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <assert.h>
#include "tinyproxy.h" #include "tinyproxy.h"
#include "sock.h"
#include "log.h"
#include "utils.h"
#include "dnscache.h" #include "dnscache.h"
#include "log.h"
#include "sock.h"
#include "utils.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 /* 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 * 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 * header was bad magic yet. anyway, this routine opens a connection to a
* system and returns the fd. * system and returns the fd.
*/ * - steve
*
/*
* Cleaned up some of the code to use memory routines which are now the * 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 * 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 * dotted-decimal form before it does a name lookup.
* created socket is made non-blocking.
* - rjkaes * - rjkaes
*/ */
int opensock(char *ip_addr, int port) int opensock(char *ip_addr, int port)
{ {
int sock_fd, flags; int sock_fd;
struct sockaddr_in port_info; struct sockaddr_in port_info;
int ret;
assert(ip_addr); memset((SA *) &port_info, 0, sizeof(port_info));
assert(port > 0);
memset((struct sockaddr *) &port_info, 0, sizeof(port_info));
port_info.sin_family = AF_INET; 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 * before a non-blocking DNS query happens for this address. Not
* relevant in the code as it stands. * relevant in the code as it stands.
*/ */
if (dnscache(&port_info.sin_addr, ip_addr) < 0) { SOCK_LOCK();
log("ERROR opensock: Could not lookup address: %s", ip_addr); 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; return -1;
} }
port_info.sin_port = htons(port); port_info.sin_port = htons(port);
if ((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { 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; return -1;
} }
flags = fcntl(sock_fd, F_GETFL, 0); if (connect(sock_fd, (SA *) &port_info, sizeof(port_info)) < 0) {
fcntl(sock_fd, F_SETFL, flags | O_NONBLOCK); log(LOG_ERR, "connecting socket");
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 -1;
} }
}
return sock_fd; return sock_fd;
} }
/* chris - added this to open a socket given a struct in_addr */
int opensock_inaddr(struct in_addr *inaddr, int port)
{
int sock_fd, flags;
struct sockaddr_in port_info;
assert(inaddr);
assert(port > 0);
memset((struct sockaddr *) &port_info, 0, sizeof(port_info));
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;
}
int setup_fd;
static struct sockaddr listen_sock_addr;
/* /*
* Start listening to a socket. * Set the socket to non blocking -rjkaes
*/ */
int init_listen_sock(int port) int socket_nonblocking(int sock)
{ {
struct sockaddr_in laddr; int flags;
int i = 1;
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;
} }
if (setsockopt(setup_fd, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i)) < 0) { /*
log("ERROR init_listen_sock: setsockopt (%s)", * Set the socket to blocking -rjkaes
strerror(errno)); */
return -1; int socket_blocking(int sock)
{
int flags;
flags = fcntl(sock, F_GETFL, 0);
return fcntl(sock, F_SETFL, flags & ~O_NONBLOCK);
} }
memset(&listen_sock_addr, 0, sizeof(listen_sock_addr)); /*
memset(&laddr, 0, sizeof(laddr)); * Start listening to a socket. Create a socket with the selected port.
laddr.sin_family = AF_INET; * The size of the socket address will be returned to the caller through
laddr.sin_port = htons(port); * 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;
listenfd = socket(AF_INET, SOCK_STREAM, 0);
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
if (config.ipAddr) { if (config.ipAddr) {
laddr.sin_addr.s_addr = inet_addr(config.ipAddr); addr.sin_addr.s_addr = inet_addr(config.ipAddr);
} else { } else {
laddr.sin_addr.s_addr = inet_addr("0.0.0.0"); addr.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;
} }
return 0; bind(listenfd, (struct sockaddr *) &addr, sizeof(addr));
}
/* listen(listenfd, MAXLISTEN);
* 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) { *addrlen = sizeof(addr);
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++;
return sock; return listenfd;
}
/*
* Stop listening on a socket.
*/
void de_init_listen_sock(void)
{
close(setup_fd);
} }
/* /*
@ -224,17 +156,12 @@ char *getpeer_ip(int fd, char *ipaddr)
struct sockaddr_in name; struct sockaddr_in name;
int namelen = sizeof(name); int namelen = sizeof(name);
assert(fd >= 0);
assert(ipaddr);
memset(ipaddr, '\0', PEER_IP_LENGTH);
if (getpeername(fd, (struct sockaddr *) &name, &namelen) != 0) { 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 { } else {
strncpy(ipaddr, strlcpy(ipaddr,
inet_ntoa(*(struct in_addr *) &name.sin_addr.s_addr), inet_ntoa(*(struct in_addr *) &name.sin_addr.s_addr),
PEER_IP_LENGTH - 1); PEER_IP_LENGTH);
} }
return ipaddr; return ipaddr;
@ -250,153 +177,46 @@ char *getpeer_string(int fd, char *string)
int namelen = sizeof(name); int namelen = sizeof(name);
struct hostent *peername; struct hostent *peername;
assert(fd >= 0);
assert(string);
memset(string, '\0', PEER_STRING_LENGTH);
if (getpeername(fd, (struct sockaddr *) &name, &namelen) != 0) { 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 { } else {
if ( SOCK_LOCK();
(peername = peername = gethostbyaddr((char *)&name.sin_addr.s_addr,
gethostbyaddr((char *) &name.sin_addr.s_addr,
sizeof(name.sin_addr.s_addr), sizeof(name.sin_addr.s_addr),
AF_INET)) != NULL) { AF_INET);
strncpy(string, peername->h_name, if (peername) {
PEER_STRING_LENGTH - 1); strlcpy(string, peername->h_name, PEER_STRING_LENGTH);
} }
SOCK_UNLOCK();
} }
return string; return string;
} }
ssize_t readline(int fd, void *vptr, size_t maxlen)
/*
* 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)
{ {
char inbuf[BUFFER]; ssize_t n, rc;
int bytesin; char c, *ptr;
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))) {
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;
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; return 0;
} else
break;
/* } else {
* Alright, we do have a working line, so read in more data and see if (errno == EINTR)
* if there is a '\n' in it. goto again;
*/
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; 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 */ *ptr = 0;
memcpy(*line, buffer->working_string, buffer->working_length); return n;
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;
} }

View File

@ -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. * See 'sock.c' for a detailed description.
* *
@ -16,25 +16,23 @@
* General Public License for more details. * General Public License for more details.
*/ */
#ifndef _SOCK_H_ #ifndef _TINYPROXY_SOCK_H_
#define _SOCK_H_ 1 #define _TINYPROXY_SOCK_H_
#include "buffer.h"
#define PEER_IP_LENGTH 16 #define PEER_IP_LENGTH 16
#define PEER_STRING_LENGTH 256 #define PEER_STRING_LENGTH 256
extern int setup_fd; #define MAXLINE (1024 * 4)
extern int opensock(char *ip_addr, int port); extern int opensock(char *ip_addr, int port);
extern int opensock_inaddr(struct in_addr *inaddr, int port); extern int listen_sock(unsigned int port, socklen_t *addrlen);
extern int init_listen_sock(int port);
extern int listen_sock(void); extern int socket_nonblocking(int sock);
extern void de_init_listen_sock(void); extern int socket_blocking(int sock);
extern int setsocketopt(int *sock_fd, int options, int flip);
extern char *getpeer_ip(int fd, char *ipaddr); extern char *getpeer_ip(int fd, char *ipaddr);
extern char *getpeer_string(int fd, char *string); 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 #endif