/*
File: accept_client.c
Description: function to accept a pending connection from a client.
*/
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include "proxy_protos.h"
extern int errno;
void
accept_client ( struct kevent *ke, struct mdata *md )
{
int client;
int server;
struct kevent sk[2];
socklen_t sl;
struct sockaddr_in sa;
int cn;
/* first test and see if we're out of memory. if we are, then don't
accept any more clients until we get some memory. */
if ( md->out_of_memory ) {
log_msg(md,"pending connection ignored (insufficient memory)");
return;
}
/* accept a pending connection */
sl = sizeof(sa);
if ( (client = accept(ke->ident,(struct sockaddr *)&sa,&sl)) != -1 ) {
inet_ntop(AF_INET,&sa.sin_addr,md->r[client].ip,INET_ADDRSTRLEN);
/* make a socket for connecting to the server */
if ( (server = socket(PF_INET,SOCK_STREAM,0)) != -1 ) {
/* desire nonblocking I/O both ways including nonblocking connect */
if ( fcntl(client,F_SETFL,O_NONBLOCK) == -1 ) perror("fcntl");
if ( fcntl(server,F_SETFL,O_NONBLOCK) == -1 ) perror("fcntl");
/* attempt to open the connection to the server (nonblocking) */
cn = connect(server,(struct sockaddr *)&md->sa,sizeof(md->sa));
/* record the time at which the connection was started */
gettimeofday(&md->r[server].ti_connect,NULL);
/*
either the connection is in progress, or it succeeded
immediately, or it failed immediately.
*/
if ( cn == -1 && errno == EINPROGRESS ) {
md->r[server].status = FD_CLOSE;
} else if ( cn == 0 ) {
md->r[server].status = FD_OPEN;
gettimeofday(&md->r[server].tf_connect,NULL);
log_msg(md,"Connect succeeded immediately on [fd %d]: %.6f seconds",
server,diff_timeval(&md->r[server].ti_connect,
&md->r[server].tf_connect));
} else {
server = -1;
}
/*
if we're either on the way to making a connection or we've
succeeded in making one, set everything up.
*/
if ( server != -1 ) {
log_msg(md,"[%s] connecting to [%s]",
md->r[client].ip,md->server_name);
/* connections are both open */
md->r[client].status = FD_OPEN;
/* set the relay file descriptors */
md->r[client].relay = server;
md->r[server].relay = client;
/* set the connection types */
md->r[client].type = CLIENT;
md->r[server].type = SERVER;
/* increment the number of concurrent clients */
md->num_clients++;
/* possibly a new maximum number of concurrent clients */
if ( md->num_clients > md->max_clients )
md->max_clients = md->num_clients;
/* a kevent for reading data from the client */
sk[0].ident = client;
sk[0].filter = EVFILT_READ;
sk[0].flags = EV_ADD;
sk[0].udata = read_data;
/* a kevent for reading data from the server */
sk[1].ident = server;
sk[1].filter = EVFILT_READ;
sk[1].flags = EV_ADD;
sk[1].udata = read_data;
/* register both events, record an error if failure */
if ( kevent(md->kq,sk,2,NULL,0,NULL) != -1 ) {
md->accepts++;
} else {
perror("kevent");
md->kevent_errors++;
}
} else {
/* connect failed */
perror("connect");
}
} else {
/* unable to create a socket for server connection */
perror("socket");
}
/* if connection to server failed, close connection to client */
if ( server == -1 ) close ( client );
} else {
/* could not accept connection from client */
perror("accept");
}
}
syntax highlighted by Code2HTML, v. 0.9.1