socketpair signal handling

This commit is contained in:
Russ Dill
2002-09-17 22:44:01 +00:00
parent ee3c1fb219
commit d5b915377b
9 changed files with 110 additions and 56 deletions

View File

@@ -1,9 +1,9 @@
Moreton Bay DHCP Server
udhcp server/client package
-----------------------
Russ Dill <Russ.Dill@asu.edu>
Matthew Ramsay <matthewr@moreton.com.au>
Chris Trew <christ@moreton.com.au>
Russ Dill <Russ.Dill@asu.edu>
Other Credits:
--------------

View File

@@ -1,4 +1,11 @@
0.9.8 (pending)
+ updated client manpage (me)
+ both client and server now use sockets for signal handling,
hopefully, this will be the last needed change in signal
handling, I'm fairly certain all the possible races are now
closed. (me)
+ The server now restarts the auto_time timer when it receives
a SIGUSR1 (write out config file). (me)
+ Improve signal handling (David Poole)
+ Fix to config file parsing (Matt Kraai)
+ Fix load lease logic (me)

20
README
View File

@@ -16,17 +16,21 @@ udhcpd /etc/udhcpd.eth1.conf
The udhcp server employs a number of simple config files:
udhcpd.leased
udhcpd.leases
------------
The udhcpd.leases behavior is designed for an embedded system. The
file is written either every auto_time seconds, or when a SIGUSR1
is received. When the file is written, a script can be optionally
called to commit the file to flash. Lease times are stored in the
file by time remaining in lease (for systems without clock that works
when there is no power), or by the absolute time that it expires in
seconds from epoch. In the remainig format, expired leases are stored
as zero. The file is of the format:
is received (the auto_time timer restarts if a SIGUSR1 is received).
If you send a SIGTERM to udhcpd directly after a SIGUSR1, udhcpd will
finish writing the leases file and wait for the aftermentioned script
to be executed and finish before quiting, so you do not need to sleep
between sending signals. When the file is written, a script can be
optionally called to commit the file to flash. Lease times are stored
in the file by time remaining in lease (for systems without clock
that works when there is no power), or by the absolute time that it
expires in seconds from epoch. In the remainig format, expired leases
are stored as zero. The file is of the format:
16 byte MAC
4 byte ip address
@@ -147,7 +151,7 @@ udhcpc also responds to SIGUSR1 and SIGUSR2. SIGUSR1 will force a renew state,
and SIGUSR2 will force a release of the current lease, and cause udhcpc to
go into an inactive state (until it is killed, or receives a SIGUSR1). You do
not need to sleep between sending signals, as signals received are processed
in a logical order during the main loop (release, then renew, then term).
sequencially in the order they are received.

47
dhcpc.c
View File

@@ -52,9 +52,7 @@ static unsigned long server_addr;
static unsigned long timeout;
static int packet_num; /* = 0 */
static int fd;
static int renew_requested; /* = 0 */
static int release_requested; /* = 0 */
static int term_received; /* = 0 */
static int signal_pipe[2];
#define LISTEN_NONE 0
#define LISTEN_KERNEL 1
@@ -177,10 +175,9 @@ static void exit_client(int retval)
/* Signal handler */
static void signal_handler(int sig)
{
switch (sig) {
case SIGUSR1: renew_requested = 1; break;
case SIGUSR2: release_requested = 1; break;
case SIGTERM: term_received = 1; break;
if (send(signal_pipe[1], &sig, sizeof(sig), MSG_DONTWAIT) < 0) {
LOG(LOG_ERR, "Could not send signal: %s",
strerror(errno));
}
}
@@ -217,6 +214,8 @@ int main(int argc, char *argv[])
struct in_addr temp_addr;
int pid_fd;
time_t now;
int max_fd;
int sig;
static struct option options[] = {
{"clientid", required_argument, 0, 'c'},
@@ -313,6 +312,7 @@ int main(int argc, char *argv[])
}
/* setup signal handlers */
socketpair(AF_UNIX, SOCK_STREAM, 0, signal_pipe);
signal(SIGUSR1, signal_handler);
signal(SIGUSR2, signal_handler);
signal(SIGTERM, signal_handler);
@@ -338,10 +338,12 @@ int main(int argc, char *argv[])
}
}
if (fd >= 0) FD_SET(fd, &rfds);
FD_SET(signal_pipe[0], &rfds);
if (tv.tv_sec > 0) {
DEBUG(LOG_INFO, "Waiting on select...\n");
retval = select(fd + 1, &rfds, NULL, NULL, &tv);
max_fd = signal_pipe[0] > fd ? signal_pipe[0] : fd;
retval = select(max_fd + 1, &rfds, NULL, NULL, &tv);
} else retval = 0; /* If we already timed out, fall through */
now = time(0);
@@ -524,21 +526,26 @@ int main(int argc, char *argv[])
}
break;
/* case BOUND, RELEASED: - ignore all packets */
}
} else if (retval == -1 && errno == EINTR) {
/* a signal was caught */
if (release_requested) {
perform_release();
release_requested = 0;
}
} else if (retval > 0 && FD_ISSET(signal_pipe[0], &rfds)) {
if (read(signal_pipe[0], &sig, sizeof(signal)) < 0) {
DEBUG(LOG_ERR, "Could not read signal: %s",
strerror(errno));
continue; /* probably just EINTR */
}
if (renew_requested) {
switch (sig) {
case SIGUSR1:
perform_renew();
renew_requested = 0;
}
if (term_received) {
break;
case SIGUSR2:
perform_release();
break;
case SIGTERM:
LOG(LOG_INFO, "Received SIGTERM");
exit_client(0);
}
}
} else if (retval == -1 && errno == EINTR) {
/* a signal was caught */
} else {
/* An error occured */
DEBUG(LOG_ERR, "Error on select");

54
dhcpd.c
View File

@@ -1,6 +1,6 @@
/* dhcpd.c
*
* Moreton Bay DHCP Server
* udhcp Server
* Copyright (C) 1999 Matthew Ramsay <matthewr@moreton.com.au>
* Chris Trew <ctrew@moreton.com.au>
*
@@ -54,7 +54,7 @@
/* globals */
struct dhcpOfferedAddr *leases;
struct server_config_t server_config;
static int signal_pipe[2];
/* Exit and cleanup */
static void exit_server(int retval)
@@ -65,12 +65,13 @@ static void exit_server(int retval)
}
/* SIGTERM handler */
static void udhcpd_killed(int sig)
/* Signal handler */
static void signal_handler(int sig)
{
sig = 0;
LOG(LOG_INFO, "Received SIGTERM");
exit_server(0);
if (send(signal_pipe[1], &sig, sizeof(sig), MSG_DONTWAIT) < 0) {
LOG(LOG_ERR, "Could not send signal: %s",
strerror(errno));
}
}
@@ -92,6 +93,8 @@ int main(int argc, char *argv[])
struct option_set *option;
struct dhcpOfferedAddr *lease;
int pid_fd;
int max_sock;
int sig;
OPEN_LOG("udhcpd");
LOG(LOG_INFO, "udhcp server (v%s) started", VERSION);
@@ -129,8 +132,9 @@ int main(int argc, char *argv[])
#endif
signal(SIGUSR1, write_leases);
signal(SIGTERM, udhcpd_killed);
socketpair(AF_UNIX, SOCK_STREAM, 0, signal_pipe);
signal(SIGUSR1, signal_handler);
signal(SIGTERM, signal_handler);
timeout_end = time(0) + server_config.auto_time;
while(1) { /* loop until universe collapses */
@@ -143,26 +147,42 @@ int main(int argc, char *argv[])
FD_ZERO(&rfds);
FD_SET(server_socket, &rfds);
FD_SET(signal_pipe[0], &rfds);
if (server_config.auto_time) {
tv.tv_sec = timeout_end - time(0);
if (tv.tv_sec <= 0) {
tv.tv_sec = server_config.auto_time;
timeout_end = time(0) + server_config.auto_time;
write_leases(0);
}
tv.tv_usec = 0;
}
retval = select(server_socket + 1, &rfds, NULL, NULL, server_config.auto_time ? &tv : NULL);
if (!server_config.auto_time || tv.tv_sec > 0) {
max_sock = server_socket > signal_pipe[0] ? server_socket : signal_pipe[0];
retval = select(max_sock + 1, &rfds, NULL, NULL,
server_config.auto_time ? &tv : NULL);
} else retval = 0; /* If we already timed out, fall through */
if (retval == 0) {
write_leases(0);
write_leases();
timeout_end = time(0) + server_config.auto_time;
continue;
} else if (retval < 0) {
} else if (retval < 0 && errno != EINTR) {
DEBUG(LOG_INFO, "error on select");
continue;
}
if (FD_ISSET(signal_pipe[0], &rfds)) {
if (read(signal_pipe[0], &sig, sizeof(sig)) < 0)
continue; /* probably just EINTR */
switch (sig) {
case SIGUSR1:
LOG(LOG_INFO, "Received a SIGUSR1");
write_leases();
/* why not just reset the timeout, eh */
timeout_end = time(0) + server_config.auto_time;
continue;
case SIGTERM:
LOG(LOG_INFO, "Received a SIGTERM");
exit_server(0);
}
}
if ((bytes = get_packet(&packet, server_socket)) < 0) { /* this waits for a packet - idle */
if (bytes == -1 && errno != EINTR) {
DEBUG(LOG_INFO, "error on read, %s, reopening socket", strerror(errno));

View File

@@ -219,8 +219,7 @@ int read_config(char *file)
}
/* the dummy var is here so this can be a signal handler */
void write_leases(int dummy)
void write_leases(void)
{
FILE *fp;
unsigned int i;
@@ -228,8 +227,6 @@ void write_leases(int dummy)
time_t curr = time(0);
unsigned long lease_time;
dummy = 0;
if (!(fp = fopen(server_config.lease_file, "w"))) {
LOG(LOG_ERR, "Unable to open %s for writing", server_config.lease_file);
return;

View File

@@ -11,7 +11,7 @@ struct config_keyword {
int read_config(char *file);
void write_leases(int dummy);
void write_leases(void);
void read_leases(char *file);
#endif

View File

@@ -1,7 +1,7 @@
/*
* socket.c -- DHCP server client/server socket creation
*
* Moreton Bay DHCP Server
* udhcp client/server
* Copyright (C) 1999 Matthew Ramsay <matthewr@moreton.com.au>
* Chris Trew <ctrew@moreton.com.au>
*
@@ -153,6 +153,5 @@ int raw_socket(int ifindex)
}
return fd;
}

View File

@@ -20,6 +20,10 @@ Do not fork after obtaining a lease.
Send the client hostname
.IR HOSTNAME .
.TP
.BI \-h\ HOSTNAME
Alias for -H
.IR HOSTNAME .
.TP
.BI \-i\ INTERFACE ,\ \-\-interface= INTERFACE
Configure
.IR INTERFACE .
@@ -47,7 +51,7 @@ Display version.
.SH USAGE
When an event occurs,
.B udhcpc
executes a script. There are three possible arguments to this
executes a script. There are four possible arguments to this
script:
.TP
.B deconfig
@@ -68,9 +72,22 @@ configure the interface and set any other relevant parameters
.B renew
.B renew
is used when
.B udhcpc when a lease is renewed. The interface is already
.B udhcpc
when a lease is renewed. The interface is already
configured, so the IP address will not change. Other parameters
(e.g., default gateway, subnet mask, dns server) may.
.TP
.B nak
.B nak
is used when
.B udhcpc
receieves a NAK packet from the server. The
enviromental variable
.B $message
will contain the reason for the
NAK message if the server included one. Processing this message
is optional, as the script will also be called with deconfig if
need be.
.PP
Parameters are passed to the script via the following environment
variables:
@@ -163,6 +180,9 @@ The DHCP message type (safely ignored).
.B serverid
The server IP address.
.TP
.B message
Reason for a DHCPNAK.
.TP
.B tftp
The TFTP server name.
.TP