* This file is part of door_daemon.
*
* door_daemon is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
*
* door_daemon is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
#include "client_list.h"
#include "daemon.h"
-#include "sysexec.h"
int init_command_socket(const char* path)
{
} while(!ret || (ret == -1 && errno == EINTR));
if(ret > 0) {
- cmd->sent = 1;
+ cmd_sent(cmd);
return 0;
}
int offset = 0;
int ret;
for(;;) {
- ret = write(fd, &response[offset], strlen(response));
+ ret = write(fd, &response[offset], len - offset);
if(ret < 0) {
if(errno != EINTR)
return ret;
else if(!strncmp(cmd, "log", 3))
cmd_id = LOG;
else if(!strncmp(cmd, "listen", 6)) {
- client_t* listener = client_find(client_lst, fd);
- if(listener) {
- log_printf(DEBUG, "adding status listener %d", fd);
- listener->status_listener = 1;
- }
- else
- log_printf(ERROR, "unable to add status listener %d", fd);
-
- return 0;
+ cmd_id = LISTEN;
}
else {
log_printf(WARNING, "unknown command '%s'", cmd);
if(param)
param++;
+ if(cmd_id == OPEN || cmd_id == CLOSE || cmd_id == TOGGLE) {
+ char* resp;
+ asprintf(&resp, "Request: %s", cmd);
+ if(resp) {
+ char* linefeed = strchr(resp, '\n');
+ if(linefeed) linefeed[0] = 0;
+ client_t* client;
+ int listener_cnt = 0;
+ for(client = client_lst; client; client = client->next)
+ if(client->request_listener && client->fd != fd) {
+ send_response(client->fd, resp);
+ listener_cnt++;
+ }
+ free(resp);
+ log_printf(DEBUG, "sent request to %d additional listeners", listener_cnt);
+ }
+// else silently ignore memory alloc error
+ }
+
switch(cmd_id) {
case OPEN:
case CLOSE:
log_printf(DEBUG, "ignoring empty ext log message");
break;
}
+ case LISTEN: {
+ client_t* listener = client_find(client_lst, fd);
+ if(listener) {
+ if(!param) {
+ listener->status_listener = 1;
+ listener->error_listener = 1;
+ listener->request_listener = 1;
+ }
+ else {
+ if(!strncmp(param, "status", 6))
+ listener->status_listener = 1;
+ else if(!strncmp(param, "error", 5))
+ listener->error_listener = 1;
+ else if(!strncmp(param, "request", 7))
+ listener->request_listener = 1;
+ else {
+ log_printf(DEBUG, "unkown listener type '%s'", param);
+ break;
+ }
+ }
+ log_printf(DEBUG, "listener %d requests %s messages", fd, param ? param:"all");
+ }
+ else {
+ log_printf(ERROR, "unable to add listener %d", fd);
+ }
+ break;
+ }
}
return 0;
}
-int process_door(const char* str, int door_fd, cmd_t **cmd_q, client_t* client_lst)
+int nonblock_recvline(read_buffer_t* buffer, int fd, cmd_t** cmd_q, client_t* client_lst)
{
- log_printf(NOTICE, "door-firmware: %s", str);
+ int ret = 0;
+ for(;;) {
+ ret = recv(fd, &buffer->buf[buffer->offset], 1, 0);
+ if(!ret)
+ return 2;
+ if(ret == -1 && errno == EAGAIN)
+ return 0;
+ else if(ret < 0)
+ break;
- int cmd_fd = -1;
- if(cmd_q && (*cmd_q)) {
- cmd_fd = (*cmd_q)->fd;
- send_response(cmd_fd, str);
- }
-
- if(!strncmp(str, "Status:", 7)) {
- client_t* client;
- for(client = client_lst; client; client = client->next)
- if(client->status_listener && client->fd != cmd_fd)
- send_response(client->fd, str);
+ if(buffer->buf[buffer->offset] == '\n') {
+ buffer->buf[buffer->offset] = 0;
+ ret = process_cmd(buffer->buf, fd, cmd_q, client_lst);
+ buffer->offset = 0;
+ break;
+ }
+
+ buffer->offset++;
+ if(buffer->offset >= sizeof(buffer->buf)) {
+ log_printf(DEBUG, "string too long (fd=%d)", fd);
+ buffer->offset = 0;
+ return 0;
+ }
}
-
- cmd_pop(cmd_q);
- return 0;
+ return ret;
}
-int nonblock_readline(read_buffer_t* buffer, int fd, cmd_t** cmd_q, client_t* client_lst, int (*cb)(const char*, int, cmd_t**, client_t*))
+int process_door(read_buffer_t* buffer, int door_fd, cmd_t **cmd_q, client_t* client_lst)
{
int ret = 0;
+ struct timeval tv;
+ fd_set fds;
+ FD_ZERO(&fds);
+ FD_SET(door_fd, &fds);
+
for(;;) {
- ret = read(fd, &buffer->buf[buffer->offset], 1);
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ ret = select(door_fd+1, &fds, NULL, NULL, &tv);
+ if(!ret)
+ return 0;
+ else if(ret < 0)
+ return ret;
+
+ ret = read(door_fd, &buffer->buf[buffer->offset], 1);
+ if(!ret)
+ return 2;
if(ret == -1 && errno == EAGAIN)
return 0;
- else if(ret <= 0)
+ else if(ret < 0)
break;
if(buffer->buf[buffer->offset] == '\n') {
buffer->buf[buffer->offset] = 0;
- ret = (cb)(buffer->buf, fd, cmd_q, client_lst);
+
+ if(buffer->offset > 0 && buffer->buf[buffer->offset-1] == '\r')
+ buffer->buf[buffer->offset-1] = 0;
+
+ log_printf(NOTICE, "door-firmware: %s", buffer->buf);
+
+ int cmd_fd = -1;
+ if(cmd_q && (*cmd_q)) {
+ cmd_fd = (*cmd_q)->fd;
+ send_response(cmd_fd, buffer->buf);
+ }
+
+ if(!strncmp(buffer->buf, "Status:", 7)) {
+ client_t* client;
+ int listener_cnt = 0;
+ for(client = client_lst; client; client = client->next)
+ if(client->status_listener && client->fd != cmd_fd) {
+ send_response(client->fd, buffer->buf);
+ listener_cnt++;
+ }
+ log_printf(DEBUG, "sent status to %d additional listeners", listener_cnt);
+ }
+
+ if(!strncmp(buffer->buf, "Error:", 6)) {
+ client_t* client;
+ int listener_cnt = 0;
+ for(client = client_lst; client; client = client->next)
+ if(client->error_listener && client->fd != cmd_fd) {
+ send_response(client->fd, buffer->buf);
+ listener_cnt++;
+ }
+ log_printf(DEBUG, "sent error to %d additional listeners", listener_cnt);
+ }
+
+ cmd_pop(cmd_q);
buffer->offset = 0;
- break;
+ return 0;
}
buffer->offset++;
if(buffer->offset >= sizeof(buffer->buf)) {
- log_printf(DEBUG, "string too long (fd=%d)", fd);
+ log_printf(DEBUG, "string too long (fd=%d)", door_fd);
buffer->offset = 0;
return 0;
}
FD_SET(sig_fd, &readfds);
max_fd = (max_fd < sig_fd) ? sig_fd : max_fd;
+ struct timeval timeout;
int return_value = 0;
while(!return_value) {
memcpy(&tmpfds, &readfds, sizeof(tmpfds));
- int ret = select(max_fd+1, &tmpfds, NULL, NULL, NULL);
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 200000;
+ int ret = select(max_fd+1, &tmpfds, NULL, NULL, &timeout);
if(ret == -1 && errno != EINTR) {
log_printf(ERROR, "select returned with error: %s", strerror(errno));
return_value = -1;
break;
}
- if(!ret || ret == -1)
+ if(ret == -1)
continue;
+ if(!ret) {
+ if(cmd_q && cmd_has_expired(*cmd_q)) {
+ log_printf(ERROR, "last command expired");
+ cmd_pop(&cmd_q);
+ }
+ else
+ continue;
+ }
if(FD_ISSET(sig_fd, &tmpfds)) {
if(signal_handle()) {
}
if(FD_ISSET(door_fd, &tmpfds)) {
- return_value = nonblock_readline(&door_buffer, door_fd, &cmd_q, client_lst, process_door);
+ return_value = process_door(&door_buffer, door_fd, &cmd_q, client_lst);
if(return_value)
break;
}
client_t* lst = client_lst;
while(lst) {
if(FD_ISSET(lst->fd, &tmpfds)) {
- return_value = nonblock_readline(&(lst->buffer), lst->fd, &cmd_q, client_lst, process_cmd);
+ return_value = nonblock_recvline(&(lst->buffer), lst->fd, &cmd_q, client_lst);
if(return_value == 2) {
log_printf(DEBUG, "removing closed command connection (fd=%d)", lst->fd);
client_t* deletee = lst;
int door_fd = 0;
for(;;) {
- door_fd = open(opt.door_dev_, O_RDWR | O_NOCTTY | O_NONBLOCK);
+ door_fd = open(opt.door_dev_, O_RDWR | O_NOCTTY);
if(door_fd < 0)
ret = 2;
else {