/* File: accept_client.c Description: function to accept a pending connection from a client. */ #include #include #include #include #include #include #include #include #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"); } }