Make ifch requests synchronous just like sockd requests.

This change paves the way for allowing ifch to notify the core ndhc
about failures.  It would be far too difficult to reason about the
state machine if the requests to ifch were asynchronous.

Currently ndhc assumes that ifch requests never fail, but this
is not always true because of eg, rfkill.
This commit is contained in:
Nicholas J. Kain 2015-02-14 16:49:50 -05:00
parent 61a48b0fb6
commit 44175bd77c
3 changed files with 28 additions and 31 deletions

View File

@ -192,16 +192,37 @@ static int ifchd_cmd(char b[static 1], size_t bl, uint8_t *od,
return -1;
}
static void ifchwrite(struct client_state_t cs[static 1],
const char buf[static 1], size_t count)
static int ifchwrite(const char buf[static 1], size_t count)
{
cs->ifchWorking = 1;
ssize_t r = safe_write(ifchSock[0], buf, count);
if (r < 0 || (size_t)r != count) {
log_error("%s: (%s) write failed: %d", client_config.interface);
return;
return -1;
}
log_line("%s: Sent to ifchd: '%s'", client_config.interface, buf);
char data[256], control[256];
struct iovec iov = {
.iov_base = data,
.iov_len = sizeof data - 1,
};
struct msghdr msg = {
.msg_iov = &iov,
.msg_iovlen = 1,
.msg_control = control,
.msg_controllen = sizeof control
};
r = safe_recvmsg(ifchSock[0], &msg, 0);
if (r == 0) {
// Remote end hung up.
exit(EXIT_SUCCESS);
} else if (r < 0) {
suicide("%s: (%s) recvmsg failed: %s", client_config.interface,
__func__, strerror(errno));
}
data[iov.iov_len] = '\0';
if (r == 1 && data[0] == '+')
return 0;
return -1;
}
void ifchange_deconfig(struct client_state_t cs[static 1])
@ -214,7 +235,7 @@ void ifchange_deconfig(struct client_state_t cs[static 1])
snprintf(buf, sizeof buf, "ip4:0.0.0.0,255.255.255.255;");
log_line("%s: Resetting IP configuration.", client_config.interface);
ifchwrite(cs, buf, strlen(buf));
ifchwrite(buf, strlen(buf));
memset(&cfg_packet, 0, sizeof cfg_packet);
}
@ -318,7 +339,7 @@ void ifchange_bind(struct client_state_t cs[static 1],
bo += send_cmd(buf + bo, sizeof buf - bo, packet, DCODE_MTU);
bo += send_cmd(buf + bo, sizeof buf - bo, packet, DCODE_WINS);
if (bo)
ifchwrite(cs, buf, bo);
ifchwrite(buf, bo);
cs->ifDeconfig = 0;
memcpy(&cfg_packet, packet, sizeof cfg_packet);

View File

@ -74,7 +74,6 @@
#include "rfkill.h"
struct client_state_t cs = {
.ifchWorking = 0,
.ifDeconfig = 0,
.init = 1,
.epollFd = -1,
@ -260,25 +259,7 @@ static void fail_if_state_dir_dne(void)
suicide("state_dir path '%s' does not specify a directory", state_dir);
}
static void handle_ifch_message(void)
{
char c;
ssize_t r = safe_recv(ifchSock[0], &c, sizeof c, MSG_DONTWAIT);
if (r == 0) {
// Remote end hung up.
exit(EXIT_SUCCESS);
} else if (r < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK)
return;
suicide("%s: (%s) error reading from ifch -> ndhc socket: %s",
client_config.interface, __func__, strerror(errno));
}
if (c == '+')
cs.ifchWorking = 0;
}
#define NDHC_NUM_EP_FDS 8
#define NDHC_NUM_EP_FDS 7
static void do_ndhc_work(void)
{
struct epoll_event events[NDHC_NUM_EP_FDS];
@ -295,7 +276,6 @@ static void do_ndhc_work(void)
setup_signals_ndhc();
epoll_add(cs.epollFd, cs.nlFd);
epoll_add(cs.epollFd, ifchSock[0]);
epoll_add(cs.epollFd, ifchStream[0]);
epoll_add(cs.epollFd, sockdStream[0]);
if (client_config.enable_rfkill && cs.rfkillFd != -1)
@ -326,9 +306,6 @@ static void do_ndhc_work(void)
} else if (fd == cs.nlFd) {
if (events[i].events & EPOLLIN)
handle_nl_message(&cs);
} else if (fd == ifchSock[0]) {
if (events[i].events & EPOLLIN)
handle_ifch_message();
} else if (fd == ifchStream[0]) {
if (events[i].events & (EPOLLHUP|EPOLLERR|EPOLLRDHUP))
exit(EXIT_FAILURE);

View File

@ -38,7 +38,6 @@ struct client_state_t {
int dhcpState;
int arpPrevState;
int ifsPrevState;
int ifchWorking; // ifch is performing interface changes.
int ifDeconfig; // Set if the interface has already been deconfigured.
int epollFd, signalFd, listenFd, arpFd, nlFd, rfkillFd;
int nlPortId;