Make change_listen_mode() create a new socket instantly rather than

waiting for select loop to cycle again.  Works better in practice
and simplifies the select loop, too.
This commit is contained in:
Nicholas J. Kain 2010-11-13 12:30:54 -05:00
parent ccae6e4c8a
commit faa56bb616

View File

@ -108,14 +108,20 @@ static void show_usage(void)
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} }
/* just a little helper */ /* Switch listen socket between raw (if-bound), kernel (ip-bound), and none */
static void change_mode(int new_mode) static void change_listen_mode(int new_mode)
{ {
log_line("entering %s listen mode", log_line("entering %s listen mode",
new_mode ? (new_mode == 1 ? "kernel" : "raw") : "none"); new_mode ? (new_mode == 1 ? "kernel" : "raw") : "none");
close(fd);
fd = -1;
listen_mode = new_mode; listen_mode = new_mode;
if (fd >= 0) {
close(fd);
fd = -1;
}
if (new_mode == LISTEN_KERNEL)
fd = listen_socket(INADDR_ANY, CLIENT_PORT, client_config.interface);
else if (new_mode == LISTEN_RAW)
fd = raw_socket(client_config.ifindex);
} }
/* perform a renew */ /* perform a renew */
@ -124,7 +130,7 @@ static void perform_renew(void)
log_line("Performing a DHCP renew..."); log_line("Performing a DHCP renew...");
switch (state) { switch (state) {
case BOUND: case BOUND:
change_mode(LISTEN_KERNEL); change_listen_mode(LISTEN_KERNEL);
case RENEWING: case RENEWING:
case REBINDING: case REBINDING:
state = RENEW_REQUESTED; state = RENEW_REQUESTED;
@ -133,7 +139,7 @@ static void perform_renew(void)
run_script(NULL, SCRIPT_DECONFIG); run_script(NULL, SCRIPT_DECONFIG);
case REQUESTING: case REQUESTING:
case RELEASED: case RELEASED:
change_mode(LISTEN_RAW); change_listen_mode(LISTEN_RAW);
state = INIT_SELECTING; state = INIT_SELECTING;
break; break;
case INIT_SELECTING: case INIT_SELECTING:
@ -168,7 +174,7 @@ static void perform_release(void)
} }
log_line("Entering released state."); log_line("Entering released state.");
change_mode(LISTEN_NONE); change_listen_mode(LISTEN_NONE);
state = RELEASED; state = RELEASED;
timeout = 0x7fffffff; timeout = 0x7fffffff;
} }
@ -251,13 +257,13 @@ static void handle_timeout(void)
state = INIT_SELECTING; state = INIT_SELECTING;
timeout = now; timeout = now;
packet_num = 0; packet_num = 0;
change_mode(LISTEN_RAW); change_listen_mode(LISTEN_RAW);
} }
break; break;
case BOUND: case BOUND:
/* Lease is starting to run out, time to enter renewing state */ /* Lease is starting to run out, time to enter renewing state */
state = RENEWING; state = RENEWING;
change_mode(LISTEN_KERNEL); change_listen_mode(LISTEN_KERNEL);
log_line("Entering renew state."); log_line("Entering renew state.");
/* fall right through */ /* fall right through */
case RENEWING: case RENEWING:
@ -284,7 +290,7 @@ static void handle_timeout(void)
run_script(NULL, SCRIPT_DECONFIG); run_script(NULL, SCRIPT_DECONFIG);
timeout = now; timeout = now;
packet_num = 0; packet_num = 0;
change_mode(LISTEN_RAW); change_listen_mode(LISTEN_RAW);
} else { } else {
/* send a request packet */ /* send a request packet */
send_renew(xid, 0, requested_ip); /* broadcast */ send_renew(xid, 0, requested_ip); /* broadcast */
@ -304,18 +310,19 @@ static void handle_packet(void)
{ {
unsigned char *temp = NULL, *message = NULL; unsigned char *temp = NULL, *message = NULL;
int len; int len;
time_t now = time(0);
struct in_addr temp_addr; struct in_addr temp_addr;
struct dhcpMessage packet; struct dhcpMessage packet;
if (listen_mode == LISTEN_KERNEL) if (listen_mode == LISTEN_KERNEL)
len = get_packet(&packet, fd); len = get_packet(&packet, fd);
else else if (listen_mode == LISTEN_RAW)
len = get_raw_packet(&packet, fd); len = get_raw_packet(&packet, fd);
else /* LISTEN_NONE */
return;
if (len == -1 && errno != EINTR) { if (len == -1 && errno != EINTR) {
log_error("reopening socket."); log_error("reopening socket.");
change_mode(listen_mode); /* just close and reopen */ change_listen_mode(listen_mode); /* just close and reopen */
} }
if (len < 0) if (len < 0)
@ -332,6 +339,7 @@ static void handle_packet(void)
return; return;
} }
time_t now = time(0);
switch (state) { switch (state) {
case INIT_SELECTING: case INIT_SELECTING:
/* Must be a DHCPOFFER to one of our xid's */ /* Must be a DHCPOFFER to one of our xid's */
@ -379,7 +387,7 @@ static void handle_packet(void)
? SCRIPT_RENEW : SCRIPT_BOUND)); ? SCRIPT_RENEW : SCRIPT_BOUND));
state = BOUND; state = BOUND;
change_mode(LISTEN_NONE); change_listen_mode(LISTEN_NONE);
if (client_config.quit_after_lease) if (client_config.quit_after_lease)
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
if (!client_config.foreground) if (!client_config.foreground)
@ -395,7 +403,7 @@ static void handle_packet(void)
timeout = now; timeout = now;
requested_ip = 0; requested_ip = 0;
packet_num = 0; packet_num = 0;
change_mode(LISTEN_RAW); change_listen_mode(LISTEN_RAW);
sleep(3); /* avoid excessive network traffic */ sleep(3); /* avoid excessive network traffic */
} }
break; break;
@ -425,20 +433,6 @@ static int do_work(void)
tv.tv_sec = timeout - time(0); tv.tv_sec = timeout - time(0);
tv.tv_usec = 0; tv.tv_usec = 0;
if (listen_mode != LISTEN_NONE && fd < 0) {
if (listen_mode == LISTEN_KERNEL)
fd = listen_socket(INADDR_ANY, CLIENT_PORT,
client_config.interface);
else
fd = raw_socket(client_config.ifindex);
if (fd < 0) {
log_error("FATAL: couldn't listen on socket: %s.",
strerror(errno));
exit(EXIT_FAILURE);
}
}
if (tv.tv_sec <= 0) { if (tv.tv_sec <= 0) {
handle_timeout(); handle_timeout();
continue; continue;
@ -459,7 +453,7 @@ static int do_work(void)
} }
} }
if (listen_mode != LISTEN_NONE && FD_ISSET(fd, &rfds)) if (FD_ISSET(fd, &rfds))
handle_packet(); handle_packet();
} }
} }
@ -604,7 +598,7 @@ int main(int argc, char **argv)
state = INIT_SELECTING; state = INIT_SELECTING;
run_script(NULL, SCRIPT_DECONFIG); run_script(NULL, SCRIPT_DECONFIG);
change_mode(LISTEN_RAW); change_listen_mode(LISTEN_RAW);
do_work(); do_work();