Skip to content

Commit

Permalink
Release 1.3.0
Browse files Browse the repository at this point in the history
- Add IPC
  • Loading branch information
Cagebreak Signing Key 1 committed May 25, 2020
1 parent e35da69 commit 0c185ee
Show file tree
Hide file tree
Showing 14 changed files with 503 additions and 116 deletions.
2 changes: 1 addition & 1 deletion Bugs.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,6 @@ difficult to reproduce.
* github issue number : N/A
* Fixed: 1.2.1

Our fuzzing framework up to and including release 1.2.0 does not the limit line
Our fuzzing framework up to and including release 1.2.0 does not limit line
lengths. This can crash the fuzzing framework with a segfault due to running
out of memory.
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,9 @@ Release checklist
* [ ] Update signature of the binary
* [ ] Signature
* [ ] Branching Strategy
* [ ] git archive --prefix=cagebreak/ -o release_version.tar.gz tags/version .
* [ ] gpg --detach-sign -u keyid release_version.tar.gz
* [ ] upload build assets

### Signing Key

Expand Down Expand Up @@ -180,6 +183,11 @@ ninja -C build

For every release after 1.0.5, hashes will be provided.

1.3.0

* sha 256: aecc5292f56f7250d777110cee1f11a92018a9eb2117d7d37cd51d7d3a5cbae0
* sha 512: 1d2d220f44787a97359a32f305e33185f0369551e61a9d7066023bfa43de50849eba5bcbb0083d2dc563ac993b8d51dd733afa0adb2a823ef50ecfee5624bbc0

1.2.1

* sha 256: 803f7667dc4997062f9ec95afcdca0cac68c82a7cf057cef83fe1ccfee33b8bc
Expand Down Expand Up @@ -256,6 +264,10 @@ Unifies commands and actions. See Issue 4 in Bugs.md.

Adds output configuration as described in the man pages.

### Release 1.3.0

Adds IPC as described in the man pages.

## License

Please see [LICENSE](https://github.com/project-repo/cagebreak/blob/master/LICENSE)
22 changes: 16 additions & 6 deletions cagebreak.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
#endif

#include "idle_inhibit_v1.h"
#include "ipc_server.h"
#include "keybinding.h"
#include "message.h"
#include "output.h"
Expand Down Expand Up @@ -189,16 +190,19 @@ set_configuration(struct cg_server *server,
config_file_path);
return -1;
}
size_t max_line_size = 256;
char line[max_line_size * sizeof(char)];
char line[MAX_LINE_SIZE * sizeof(char)];
for(unsigned int line_num = 1;
fgets(line, max_line_size, config_file) != NULL; ++line_num) {
fgets(line, MAX_LINE_SIZE, config_file) != NULL; ++line_num) {
line[strcspn(line, "\n")] = '\0';
if(*line != '\0' && *line != '#') {
if(parse_rc_line(server, line) != 0) {
char *errstr;
if(parse_rc_line(server, line, &errstr) != 0) {
wlr_log(WLR_ERROR, "Error in config file \"%s\", line %d\n",
config_file_path, line_num);
fclose(config_file);
if(errstr != NULL) {
free(errstr);
}
return -1;
}
}
Expand Down Expand Up @@ -289,7 +293,7 @@ main(int argc, char *argv[]) {
if(server.modes[0] == NULL || server.modes[1] == NULL ||
server.modes[2] == NULL) {
wlr_log(WLR_ERROR, "Error allocating default modes");
goto end;
return 1;
}

server.nws = 1;
Expand Down Expand Up @@ -512,6 +516,12 @@ main(int argc, char *argv[]) {
wlr_xwayland_set_seat(xwayland, server.seat->seat);
#endif

if(ipc_init(&server) != 0) {
wlr_log(WLR_ERROR, "Failed to initialize IPC");
ret = 1;
goto end;
}

{ // config_file should only be visible as long as it is valid
char *config_file = get_config_file();
if(config_file == NULL) {
Expand All @@ -534,7 +544,7 @@ main(int argc, char *argv[]) {
}
}

/* Place the cursor to the topl left of the output layout. */
/* Place the cursor to the top left of the output layout. */
wlr_cursor_warp(server.seat->cursor, NULL, 0, 0);

wl_display_run(server.wl_display);
Expand Down
6 changes: 5 additions & 1 deletion fuzz/fuzz-parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,11 @@ set_configuration(struct cg_server *server, char *content) {
(line = strtok_r(NULL, "\n", &content)) != NULL; ++line_num) {
line[strcspn(line, "\n")] = '\0';
if(*line != '\0' && *line != '#') {
if(parse_rc_line(server, line) != 0) {
char *errstr;
if(parse_rc_line(server, line, &errstr) != 0) {
if(errstr != NULL) {
free(errstr);
}
return -1;
}
}
Expand Down
277 changes: 277 additions & 0 deletions ipc_server.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,277 @@
/*
* Cagebreak: A Wayland tiling compositor.
*
* Copyright (C) 2020 The Cagebreak Authors
* Copyright (C) 2018-2020 Jente Hidskes
*
* See the LICENSE file accompanying this file.
*/

#define _POSIX_C_SOURCE 200112L

#include "ipc_server.h"
#include "message.h"
#include "parse.h"
#include "server.h"

#include <fcntl.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <wlr/util/log.h>

static void
handle_display_destroy(struct wl_listener *listener, void *data) {
struct cg_ipc_handle *ipc = wl_container_of(listener, ipc, display_destroy);
if(ipc->event_source != NULL) {
wl_event_source_remove(ipc->event_source);
}
close(ipc->socket);
unlink(ipc->sockaddr->sun_path);

struct cg_ipc_client *tmp_client, *client;
wl_list_for_each_safe(client, tmp_client, &ipc->client_list, link) {
ipc_client_disconnect(client);
}

free(ipc->sockaddr);

wl_list_remove(&ipc->display_destroy.link);
}

int
ipc_init(struct cg_server *server) {
struct cg_ipc_handle *ipc = &server->ipc;
ipc->socket = socket(AF_UNIX, SOCK_STREAM, 0);
if(ipc->socket == -1) {
wlr_log(WLR_ERROR, "Unable to create IPC socket");
return -1;
}
if(fcntl(ipc->socket, F_SETFD, FD_CLOEXEC) == -1) {
wlr_log(WLR_ERROR, "Unable to set CLOEXEC on IPC socket");
return -1;
}
if(fcntl(ipc->socket, F_SETFL, O_NONBLOCK) == -1) {
wlr_log(WLR_ERROR, "Unable to set NONBLOCK on IPC socket");
return -1;
}

ipc->sockaddr = malloc(sizeof(struct sockaddr_un));

if(ipc->sockaddr == NULL) {
wlr_log(WLR_ERROR, "Unable to allocate socket address");
return -1;
}

ipc->sockaddr->sun_family = AF_UNIX;
int max_path_size = sizeof(ipc->sockaddr->sun_path);
const char *sockdir = getenv("XDG_RUNTIME_DIR");
if(sockdir == NULL) {
sockdir = "/tmp";
}

if(max_path_size <= snprintf(ipc->sockaddr->sun_path, max_path_size,
"%s/cagebreak-ipc.%i.%i.sock", sockdir,
getuid(), getpid())) {
wlr_log(WLR_ERROR, "Unable to write socket path to "
"ipc->sockaddr->sun_path. Path too long");
free(ipc->sockaddr);
return -1;
}

unlink(ipc->sockaddr->sun_path);

if(bind(ipc->socket, (struct sockaddr *)ipc->sockaddr,
sizeof(*ipc->sockaddr)) == -1) {
wlr_log(WLR_ERROR, "Unable to bind IPC socket");
free(ipc->sockaddr);
return -1;
}

if(listen(ipc->socket, 3) == -1) {
wlr_log(WLR_ERROR, "Unable to listen on IPC socket");
free(ipc->sockaddr);
return -1;
}

setenv("CAGEBREAK_SOCKET", ipc->sockaddr->sun_path, 1);

wl_list_init(&ipc->client_list);

ipc->display_destroy.notify = handle_display_destroy;
wl_display_add_destroy_listener(server->wl_display, &ipc->display_destroy);

ipc->event_source =
wl_event_loop_add_fd(server->event_loop, ipc->socket, WL_EVENT_READABLE,
ipc_handle_connection, server);
return 0;
}

int
ipc_handle_connection(int fd, uint32_t mask, void *data) {
(void)fd;
struct cg_server *server = data;
struct cg_ipc_handle *ipc = &server->ipc;
if(mask != WL_EVENT_READABLE) {
wlr_log(WLR_ERROR, "Expected to receive a WL_EVENT_READABLE");
return 0;
}

int client_fd = accept(ipc->socket, NULL, NULL);
if(client_fd == -1) {
wlr_log(WLR_ERROR, "Unable to accept IPC client connection");
return 0;
}

int flags;
if((flags = fcntl(client_fd, F_GETFD)) == -1 ||
fcntl(client_fd, F_SETFD, flags | FD_CLOEXEC) == -1) {
wlr_log(WLR_ERROR, "Unable to set CLOEXEC on IPC client socket");
close(client_fd);
return 0;
}
if((flags = fcntl(client_fd, F_GETFL)) == -1 ||
fcntl(client_fd, F_SETFL, flags | O_NONBLOCK) == -1) {
wlr_log(WLR_ERROR, "Unable to set NONBLOCK on IPC client socket");
close(client_fd);
return 0;
}

struct cg_ipc_client *client = malloc(sizeof(struct cg_ipc_client));
if(!client) {
wlr_log(WLR_ERROR, "Unable to allocate ipc client");
close(client_fd);
return 0;
}
// +1 for \n and +1 for \0
client->read_buffer = malloc(sizeof(char) * (MAX_LINE_SIZE + 2));
client->read_buf_len = 0;
client->read_discard = 0;
client->server = server;
client->fd = client_fd;
client->event_source =
wl_event_loop_add_fd(server->event_loop, client_fd, WL_EVENT_READABLE,
ipc_client_handle_readable, client);
client->writable_event_source = NULL;

client->write_buffer_size = 128;
client->write_buffer_len = 0;
client->write_buffer = malloc(client->write_buffer_size);
if(!client->write_buffer) {
wlr_log(WLR_ERROR, "Unable to allocate ipc client write buffer");
close(client_fd);
return 0;
}

wl_list_insert(&ipc->client_list, &client->link);
return 0;
}

int
ipc_client_handle_readable(int client_fd, uint32_t mask, void *data) {
struct cg_ipc_client *client = data;

if(mask & WL_EVENT_ERROR) {
wlr_log(WLR_ERROR, "IPC Client socket error, removing client");
ipc_client_disconnect(client);
return 0;
}

if(mask & WL_EVENT_HANGUP) {
ipc_client_disconnect(client);
return 0;
}

int read_available;
if(ioctl(client_fd, FIONREAD, &read_available) < 0) {
wlr_log(WLR_ERROR, "Unable to read IPC socket buffer size");
ipc_client_disconnect(client);
return 0;
}

int read_size = read_available < MAX_LINE_SIZE + 1 - client->read_buf_len
? read_available
: MAX_LINE_SIZE + 1 - client->read_buf_len;
// Append to buffer
ssize_t received = recv(
client_fd, client->read_buffer + client->read_buf_len, read_size, 0);
if(received == -1) {
wlr_log(WLR_ERROR, "Unable to receive data from IPC client");
ipc_client_disconnect(client);
return 0;
}
client->read_buf_len += received;

ipc_client_handle_command(client);

return 0;
}

void
ipc_client_disconnect(struct cg_ipc_client *client) {
if(client == NULL) {
wlr_log(WLR_ERROR,
"Client \"NULL\" was passed to ipc_client_disconnect");
return;
}

shutdown(client->fd, SHUT_RDWR);

wl_event_source_remove(client->event_source);
if(client->writable_event_source) {
wl_event_source_remove(client->writable_event_source);
}
wl_list_remove(&client->link);
free(client->write_buffer);
free(client->read_buffer);
close(client->fd);
free(client);
}

void
ipc_client_handle_command(struct cg_ipc_client *client) {
if(client == NULL) {
wlr_log(WLR_ERROR,
"Client \"NULL\" was passed to ipc_client_handle_command");
return;
}
client->read_buffer[client->read_buf_len] = '\0';
char *nl_pos;
uint32_t offset = 0;
while((nl_pos = strchr(client->read_buffer + offset, '\n')) != NULL) {
if(client->read_discard) {
client->read_discard = 0;
} else {
*nl_pos = '\0';
char *line = client->read_buffer + offset;
if(*line != '\0' && *line != '#') {
message_clear(client->server->curr_output);
char *errstr;
if(parse_rc_line(client->server, line, &errstr) != 0) {
if(errstr != NULL) {
message_printf(client->server->curr_output, "%s",
errstr);
wlr_log(WLR_ERROR, "%s", errstr);
free(errstr);
}
wlr_log(WLR_ERROR, "Error parsing input from IPC socket");
}
}
}
offset = (nl_pos - client->read_buffer) + 1;
}
if(offset == 0) {
wlr_log(WLR_ERROR, "Line received was longer that %d, discarding it",
MAX_LINE_SIZE);
client->read_buf_len = 0;
client->read_discard = 1;
return;
}
if(offset < client->read_buf_len) {
memmove(client->read_buffer, client->read_buffer + offset,
client->read_buf_len - offset);
}
client->read_buf_len -= offset;
}
Loading

0 comments on commit 0c185ee

Please sign in to comment.