aboutsummaryrefslogtreecommitdiff
path: root/src/client.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/client.c')
-rw-r--r--src/client.c216
1 files changed, 134 insertions, 82 deletions
diff --git a/src/client.c b/src/client.c
index 0a131d1..fff08a6 100644
--- a/src/client.c
+++ b/src/client.c
@@ -36,9 +36,13 @@ static volatile sig_atomic_t output_locked = 0;
char *current_user = NULL;
-void out_raw(const unsigned char *buf, size_t len)
+void out_raw(const void *buf, size_t len)
{
+ if(!len)
+ return;
+
try_again:
+
while(output_locked);
/* something weird happened and the value changed between the loop and here */
@@ -52,19 +56,58 @@ try_again:
goto try_again;
}
+#define WRAP_COLS 80
+
void __attribute__((format(printf,1,2))) out(const char *fmt, ...)
{
- char buf[128];
+ char buf[1024];
memset(buf, 0, sizeof(buf));
va_list ap;
va_start(ap, fmt);
- int len = vsnprintf(buf, sizeof(buf), fmt, ap);
+ vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
- out_raw((unsigned char*)buf, len);
+
+ /* do some line wrapping */
+
+ int x = 0;
+
+ char word_buf[sizeof(buf)], *ptr = buf;
+
+ char newline = '\n';
+
+ int word_idx = 0;
+ while(1)
+ {
+ char c = *ptr++;
+ if(!c)
+ break;
+ word_buf[word_idx++] = c;
+ x++;
+ if(c == ' ' || c == '\n')
+ {
+ if(x >= WRAP_COLS - 1)
+ {
+ sig_debugf("Wrapping...\n");
+ out_raw(&newline, 1);
+ x = 0;
+ }
+ out_raw(word_buf, word_idx);
+ word_idx = 0;
+ }
+ }
+
+ if(x >= WRAP_COLS - 1)
+ {
+ sig_debugf("Wrapping...\n");
+ out_raw(&newline, 1);
+ x = 0;
+ }
+ out_raw(word_buf, word_idx);
}
static volatile sig_atomic_t request_complete;
+/* for rate-limiting */
static int reqs_since_ts;
static time_t ts = 0;
@@ -93,20 +136,22 @@ void send_master(unsigned char cmd, const void *data, size_t sz)
sigprocmask(SIG_BLOCK, &block, &old);
pid_t our_pid = getpid();
- size_t total_len = (data?sz:0) + 1;
if(!data)
sz = 0;
+ /* format of child->parent packets:
+ * | PID | CMD | DATA |
+ */
+
/* pack it all into one write so it's atomic */
- char *req = malloc(1 + sizeof(pid_t) + sizeof(size_t) + sz);
+ char *req = malloc(sizeof(pid_t) + 1 + sz);
memcpy(req, &our_pid, sizeof(pid_t));
- memcpy(req + sizeof(pid_t), &total_len, sizeof(size_t));
- memcpy(req + sizeof(pid_t) + sizeof(size_t), &cmd, 1);
- memcpy(req + sizeof(pid_t) + sizeof(size_t) + 1, data, sz);
+ memcpy(req + sizeof(pid_t), &cmd, 1);
+ memcpy(req + sizeof(pid_t) + 1, data, sz);
- write(to_parent, req, 1 + sizeof(pid_t) + sizeof(size_t) + sz);
+ write(to_parent, req, 1 + sizeof(pid_t) + sz);
sigsuspend(&old);
sigprocmask(SIG_SETMASK, &old, NULL);
@@ -154,18 +199,6 @@ char *client_read_password(void)
return ret;
}
-static void print_all(int fd)
-{
- unsigned char buf[MSG_MAX + 1];
- do {
- ssize_t len = read(fd, &buf, MSG_MAX);
- if(len <= 0)
- break;
- buf[MSG_MAX] = '\0';
- out_raw(buf, len);
- } while(1);
-}
-
enum reqdata_typespec reqdata_type = TYPE_NONE;
union reqdata_t returned_reqdata;
@@ -189,6 +222,8 @@ void sig_rt_0_handler(int s, siginfo_t *info, void *v)
if(!are_child)
return;
+ sig_debugf("Master process sends SIG\n");
+
/* we only listen to requests from our parent */
if(info->si_pid != getppid())
{
@@ -196,74 +231,91 @@ void sig_rt_0_handler(int s, siginfo_t *info, void *v)
return;
}
+
reqdata_type = TYPE_NONE;
- unsigned char cmd;
- read(from_parent, &cmd, 1);
- switch(cmd)
- {
- case REQ_BCASTMSG:
- {
- print_all(from_parent);
- break;
- }
- case REQ_KICK:
- {
- print_all(from_parent);
- union sigval junk = { 0 };
- /* the master still expects an ACK */
- sigqueue(getppid(), SIGRTMIN+1, junk);
- exit(EXIT_SUCCESS);
- }
- case REQ_MOVE:
- {
- bool status;
- read(from_parent, &status, sizeof(status));
- reqdata_type = TYPE_BOOLEAN;
- returned_reqdata.boolean = status;
- if(!status)
- out("Cannot go that way.\n");
- break;
- }
- case REQ_GETUSERDATA:
+ while(1)
{
- sig_debugf("got user data\n");
- bool success;
- read(from_parent, &success, sizeof(success));
- if(success)
- reqdata_type = TYPE_USERDATA;
- else
+ unsigned char packet[MSG_MAX + 1];
+ memset(packet, 0, sizeof(packet));
+ ssize_t packetlen = read(from_parent, packet, MSG_MAX);
+ sig_debugf("done reading data\n");
+ unsigned char *data = packet + 1;
+ size_t datalen = packetlen - 1;
+ packet[MSG_MAX] = '\0';
+
+ if(packetlen <= 0)
+ goto fail;
+
+ unsigned char cmd = packet[0];
+
+ sig_debugf("child got code %d\n", cmd);
+
+ switch(cmd)
{
- sig_debugf("failure\n");
+ case REQ_BCASTMSG:
+ {
+ out((char*)data, datalen);
break;
}
+ case REQ_KICK:
+ {
+ out((char*)data, datalen);
+ union sigval junk = { 0 };
+ /* the master still expects an ACK */
+ sigqueue(getppid(), SIGRTMIN+1, junk);
+ exit(EXIT_SUCCESS);
+ }
+ case REQ_MOVE:
+ {
+ bool status = *((bool*)data);
- struct userdata_t *user = &returned_reqdata.userdata;
- if(read(from_parent, user, sizeof(*user)) != sizeof(*user))
- error("user data too short");
- break;
- }
- case REQ_DELUSERDATA:
- {
- reqdata_type = TYPE_BOOLEAN;
- if(read(from_parent, &returned_reqdata.boolean, sizeof(bool)) != sizeof(bool))
- error("error reading bool");
- break;
- }
- case REQ_ADDUSERDATA:
- {
- reqdata_type = TYPE_BOOLEAN;
- if(read(from_parent, &returned_reqdata.boolean, sizeof(bool)) != sizeof(bool))
- error("error reading bool");
- break;
- }
- case REQ_NOP:
- break;
- default:
- sig_debugf("WARNING: client process received unknown code %d\n", cmd);
- break;
- }
+ reqdata_type = TYPE_BOOLEAN;
+ returned_reqdata.boolean = status;
+ if(!status)
+ out("Cannot go that way.\n");
+ break;
+ }
+ case REQ_GETUSERDATA:
+ {
+ sig_debugf("got user data\n");
+ if(datalen == sizeof(struct userdata_t))
+ reqdata_type = TYPE_USERDATA;
+ else
+ {
+ sig_debugf("failure %d %d\n", datalen, sizeof(struct userdata_t));
+ break;
+ }
+ struct userdata_t *user = &returned_reqdata.userdata;
+ *user = *((struct userdata_t*)data);
+ break;
+ }
+ case REQ_DELUSERDATA:
+ {
+ reqdata_type = TYPE_BOOLEAN;
+ returned_reqdata.boolean = *((bool*)data);
+ break;
+ }
+ case REQ_ADDUSERDATA:
+ {
+ reqdata_type = TYPE_BOOLEAN;
+ returned_reqdata.boolean = *((bool*)data);
+ break;
+ }
+ case REQ_NOP:
+ break;
+ case REQ_PRINT_NL:
+ {
+ out("\n");
+ break;
+ }
+ default:
+ sig_debugf("WARNING: client process received unknown code %d\n", cmd);
+ break;
+ }
+ }
+fail:
sig_debugf("Client finishes handling request.\n");
request_complete = 1;