This converts the control connection and the HTTP streaming module to use the makesock() interface.
The specific changes are:
* replace tcp_connect() directly with makesock();
* replace tcp_listen() with para_listen() (in turn a wrapper around makesock());
* init_sockaddr() becomes obsolete;
* replaced use of sockaddr_in in para_accept() with NULL sockaddr argument
-- the `remote' name of the socket is always available via getpeername(2),
-- this is exploited by replacing the reverse-name lookup with remote_name();
* the sockaddr_in field `addr' of `struct http_client' has been replaced with `name' string
-- name is filled in as in para_accept() above, using remote_name(),
-- unlike above, the remote_fd() call can later not be done, due to close_listed_fds().
The one thing I am really not sure about is host_in_access_perm_list():
* It needed to be converted to allow address-independent HTTP streaming.
* The conversion represents the obvious choice for doing this.
* However, I have not (yet) tested it.
* A problem that may arise is that when listening using AF_UNSPEC then _all_ addresses appear
as IPv6 addresses (i.e. the test "family == AF_INET" would never hold true). In this case,
a possible solution is to switch between AF_UNSPEC and AF_INET dependint on whether the
configurable access-list is empty or non-empty, respectively.
* A possible place for this chance would be http_send_init() or any other function calling
open_tcp_port().
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
int ret;
pcd->fd = -1;
- ret = tcp_connect(pcd->conf.hostname_arg, pcd->conf.server_port_arg);
+ ret = makesock(AF_UNSPEC, IPPROTO_TCP, 0, pcd->conf.hostname_arg,
+ pcd->conf.server_port_arg);
if (ret < 0)
return ret;
pcd->fd = ret;
/**
* perform user authentication and execute a command
*
- * \param fd the file descriptor to send output to
- * \param addr socket address info of peer
+ * \param fd The file descriptor to send output to
+ * \param peername Identifies the connecting peer.
*
* \return EXIT_SUCCESS or EXIT_FAILURE
*
*
* \sa alarm(2), rc4(3), crypt.c, crypt.h
*/
-int handle_connect(int fd, struct sockaddr_in *addr)
+int handle_connect(int fd, const char *peername)
{
int ret, argc, use_rc4 = 0;
char buf[4096];
mmd->num_commands++;
mmd_unlock();
PARA_NOTICE_LOG("calling com_%s() for %s@%s\n", cmd->name, u->name,
- inet_ntoa(addr->sin_addr));
+ peername);
ret = cmd->handler(fd, argc, argv);
if (ret >= 0) {
ret = EXIT_SUCCESS;
{
struct private_http_recv_data *phd;
struct http_recv_args_info *conf = rn->conf;
- int ret;
+ int ret = makesock(AF_UNSPEC, IPPROTO_TCP, 0, conf->host_arg, conf->port_arg);
- rn->buf = para_calloc(BUFSIZE);
- rn->private_data = para_calloc(sizeof(struct private_http_recv_data));
- phd = rn->private_data;
- ret = tcp_connect(conf->host_arg, conf->port_arg);
if (ret < 0)
- goto err_out;
+ return ret;
+
+ rn->buf = para_calloc(BUFSIZE);
+ rn->private_data = phd = para_calloc(sizeof(struct private_http_recv_data));
+
phd->fd = ret;
mark_fd_nonblocking(phd->fd);
phd->status = HTTP_CONNECTED;
return 1;
-err_out:
- free(rn->private_data);
- free(rn->buf);
- return ret;
}
/**
#include "fd.h"
#include "chunk_queue.h"
-/** \cond convert sock_addr_in to ascii */
-#define CLIENT_ADDR(hc) inet_ntoa((hc)->addr.sin_addr)
-/* get the port number of a struct http_client */
-#define CLIENT_PORT(hc) (hc)->addr.sin_port
#define HTTP_ERR_MSG "HTTP/1.0 400 Bad Request\n"
/** \endcond */
struct http_client {
/** The file descriptor of the client. */
int fd;
- /** Address information about the client. */
- struct sockaddr_in addr;
+ /** The socket `name' of the client. */
+ char *name;
/** The client's current status. */
enum http_status status;
/** Non-zero if we included \a fd in the read set.*/
static void http_shutdown_client(struct http_client *hc, const char *msg)
{
- PARA_INFO_LOG("shutting down %s on fd %d (%s)\n", CLIENT_ADDR(hc),
- hc->fd, msg);
+ PARA_INFO_LOG("shutting down %s on fd %d (%s)\n",
+ hc->name, hc->fd, msg);
numclients--;
+ free(hc->name);
close(hc->fd);
del_close_on_fork_list(hc->fd);
cq_destroy(hc->cq);
queue_chunk_or_shutdown(hc, current_chunk, 0);
continue;
}
-// PARA_DEBUG_LOG("sending %d -> %s\n", len, CLIENT_ADDR(hc));
+// PARA_DEBUG_LOG("sending %d -> %s\n", len, remote_name(hc->fd));
ret = write(hc->fd, buf, len);
// PARA_DEBUG_LOG("ret: %d\n", ret);
if (ret < 0) {
static int host_in_access_perm_list(struct http_client *hc)
{
- struct access_info *ai, *tmp;
- list_for_each_entry_safe(ai, tmp, &access_perm_list, node) {
- unsigned mask = ((~0U) >> ai->netmask);
- if ((hc->addr.sin_addr.s_addr & mask) == (ai->addr.s_addr & mask))
- return 1;
+ struct sockaddr_storage ss;
+ socklen_t sslen = sizeof(ss);
+
+ if (getpeername(hc->fd, (struct sockaddr *)&ss, &sslen) < 0) {
+ PARA_ERROR_LOG("can not determine address family: %s\n", strerror(errno));
+ } else if (ss.ss_family == AF_INET) {
+ /* FIXME: access restriction is (currently) only supported for IPv4 */
+ struct access_info *ai, *tmp;
+ struct in_addr client_addr = ((struct sockaddr_in *)&ss)->sin_addr;
+
+ list_for_each_entry_safe(ai, tmp, &access_perm_list, node) {
+ unsigned mask = ((~0U) >> ai->netmask);
+ if ((client_addr.s_addr & mask) == (ai->addr.s_addr & mask))
+ return 1;
+ }
}
return 0;
}
list_for_each_entry_safe(hc, tmp, &clients, node) {
i++;
-// PARA_DEBUG_LOG("handling client %d: %s\n", i, CLIENT_ADDR(hc));
+// PARA_DEBUG_LOG("handling client %d: %s\n", i, remote_name(hc->fd));
switch (hc->status) {
case HTTP_STREAMING: /* nothing to do */
case HTTP_READY_TO_STREAM:
return;
hc = para_calloc(sizeof(struct http_client));
err_msg = "accept error";
- hc->fd = para_accept(server_fd, &hc->addr, sizeof(struct sockaddr_in));
+ hc->fd = para_accept(server_fd, NULL, 0);
if (hc->fd <= 0)
goto err_out;
- PARA_NOTICE_LOG("connection from %s (fd %d)\n", CLIENT_ADDR(hc), hc->fd);
+ hc->name = make_message("%s", remote_name(hc->fd));
+ PARA_NOTICE_LOG("connection from %s (fd %d)\n", hc->name, hc->fd);
if (conf.http_max_clients_arg > 0 && numclients >=
conf.http_max_clients_arg) {
err_msg = "server full";
}
hc->status = HTTP_CONNECTED;
hc->cq = cq_new(MAX_BACKLOG);
- PARA_INFO_LOG("accepted client #%d: %s (fd %d)\n", numclients,
- CLIENT_ADDR(hc), hc->fd);
numclients++;
+ PARA_INFO_LOG("accepted client #%d: %s (fd %d)\n", numclients,
+ hc->name, hc->fd);
para_list_add(&hc->node, &clients);
add_close_on_fork_list(hc->fd);
mark_fd_nonblocking(hc->fd);
return;
err_out:
PARA_WARNING_LOG("ignoring connect request from %s (%s)\n",
- CLIENT_ADDR(hc), err_msg);
+ hc->name, err_msg);
if (hc->fd > 0)
close(hc->fd);
free(hc);
{
int ret;
- server_fd = tcp_listen(port);
+ server_fd = para_listen(AF_UNSPEC, IPPROTO_TCP, port);
if (server_fd < 0) {
http_shutdown_clients();
self->status = SENDER_OFF;
ap = tmp;
}
list_for_each_entry_safe(hc, tmp_hc, &clients, node) {
- char *tmp = make_message("%s%s:%d ", clnts? clnts : "",
- CLIENT_ADDR(hc), CLIENT_PORT(hc));
+ char *tmp = make_message("%s%s ", clnts? clnts : "",
+ hc->name);
free(clnts);
clnts = tmp;
}
}
-/**
- * Initialize a struct sockaddr_in.
- *
- * \param addr A pointer to the struct to be initialized.
- * \param port The port number to use.
- * \param he The address to use.
- *
- * If \a he is null (server mode), \a addr->sin_addr is initialized with \p
- * INADDR_ANY. Otherwise, the address given by \a he is copied to addr.
- */
-static void init_sockaddr(struct sockaddr_in *addr, int port, const struct hostent *he)
-{
- /* host byte order */
- addr->sin_family = AF_INET;
- /* short, network byte order */
- addr->sin_port = htons(port);
- if (he)
- addr->sin_addr = *((struct in_addr *)he->h_addr);
- else
- addr->sin_addr.s_addr = INADDR_ANY;
- /* zero the rest of the struct */
- memset(&addr->sin_zero, '\0', 8);
-}
-
/**
* Determine the socket type for a given layer-4 protocol.
*
return n;
}
-/**
- * Establish a tcp connection.
- *
- * \param host Hostname or IPv4 address.
- * \param port The tcp port.
- *
- * \return Negative on errors, a valid file descriptor on success.
- */
-int tcp_connect(char *host, int port)
-{
- struct sockaddr_in addr;
- struct hostent *he;
- int ret, fd;
-
- PARA_INFO_LOG("getting host info of %s\n", host);
- /* FIXME: gethostbyname() is obsolete */
- he = gethostbyname(host);
- if (!he)
- return -ERRNO_TO_PARA_ERROR(h_errno);
- init_sockaddr(&addr, port, he);
- ret = get_stream_socket(AF_INET);
- if (ret < 0)
- return ret;
- fd = ret;
- ret = PARA_CONNECT(fd, &addr);
- if (ret >= 0)
- return fd;
- close(fd);
- return ret;
-}
-
/**
* A wrapper around socket(2).
*
}
#endif /* HAVE_UCRED */
-/**
- * Create a tcp socket, bind it and listen on the given port.
- *
- * \param port The tcp port to listen on.
- *
- * \return The file descriptor of the created socket, negative on errors.
- *
- * \sa get_stream_socket()
- * \sa setsockopt(2)
- * \sa bind(2)
- * \sa listen(2)
- */
-int tcp_listen(int port)
-{
- struct sockaddr_in my_addr;
- int fd, ret = get_stream_socket(AF_INET);
-
- if (ret < 0)
- return ret;
- fd = ret;
- ret = 1;
- ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &ret, sizeof(int));
- if (ret < 0) {
- ret = -ERRNO_TO_PARA_ERROR(errno);
- goto err;
- }
- init_sockaddr(&my_addr, port, NULL);
- ret = bind(fd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr));
- if (ret < 0) {
- ret = -ERRNO_TO_PARA_ERROR(errno);
- goto err;
- }
- ret = listen(fd, BACKLOG);
- if (ret < 0) {
- ret = -ERRNO_TO_PARA_ERROR(errno);
- goto err;
- }
- PARA_INFO_LOG("listening on port %d, fd %d\n", port, fd);
- return fd;
-err:
- close(fd);
- return ret;
-}
-
/**
* receive a buffer and check for a pattern
*
typedef void crypt_function(unsigned long len,
const unsigned char *indata, unsigned char *outdata, void *private_data);
-int tcp_connect(char *host, int port);
int get_stream_socket(int domain);
int send_buffer(int, const char *);
int send_bin_buffer(int, const char *, size_t);
int recv_cred_buffer(int, char *, size_t);
ssize_t send_cred_buffer(int, char*);
int recv_pattern(int fd, const char *pattern, size_t bufsize);
-int tcp_listen(int port);
void enable_crypt(int fd, crypt_function *recv_f, crypt_function *send_f,
void *private_data);
void disable_crypt(int fd);
static unsigned init_network(void)
{
- int fd, ret = tcp_listen(conf.port_arg);
+ int fd, ret = para_listen(AF_UNSPEC, IPPROTO_TCP, conf.port_arg);
if (ret < 0)
goto err;
{
/* listen on sock_fd, new connection on new_fd */
int sockfd, new_fd;
- struct sockaddr_in their_addr;
+ char *peer_name;
int i, max_fileno, ret;
pid_t chld_pid;
fd_set rfds, wfds;
if (!FD_ISSET(sockfd, &rfds))
goto repeat;
- new_fd = para_accept(sockfd, &their_addr, sizeof(struct sockaddr_in));
+ new_fd = para_accept(sockfd, NULL, 0);
if (new_fd < 0)
goto repeat;
- PARA_INFO_LOG("got connection from %s, forking\n",
- inet_ntoa(their_addr.sin_addr));
+ peer_name = remote_name(new_fd);
+ PARA_INFO_LOG("got connection from %s, forking\n", peer_name);
mmd->num_connects++;
mmd->active_connections++;
random();
*/
for (i = argc - 1; i >= 0; i--)
memset(argv[i], 0, strlen(argv[i]));
- sprintf(argv[0], "para_server (serving %s)",
- inet_ntoa(their_addr.sin_addr));
- return handle_connect(new_fd, &their_addr);
+ sprintf(argv[0], "para_server (serving %s)", peer_name);
+ return handle_connect(new_fd, peer_name);
}
/** Socket for afs-server communication. */
extern int afs_socket;
-int handle_connect(int fd, struct sockaddr_in *addr);
+int handle_connect(int fd, const char *peername);
void mmd_unlock(void);
void mmd_lock(void);