mirror of
https://cagebreak.project-repo.co/cagebreak.git
synced 2026-08-09 15:19:11 +02:00
Add ipc capability
This commit is contained in:
parent
989438a1cb
commit
0017ad48c5
6 changed files with 307 additions and 6 deletions
14
cagebreak.c
14
cagebreak.c
|
|
@ -55,6 +55,7 @@
|
|||
#include "server.h"
|
||||
#include "view.h"
|
||||
#include "xdg_shell.h"
|
||||
#include "ipc_server.h"
|
||||
#if CG_HAS_XWAYLAND
|
||||
#include "xwayland.h"
|
||||
#endif
|
||||
|
|
@ -189,10 +190,9 @@ 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) {
|
||||
|
|
@ -286,9 +286,9 @@ main(int argc, char *argv[]) {
|
|||
server.modes[1] = strdup("root");
|
||||
server.modes[2] = strdup("resize");
|
||||
server.modes[3] = NULL;
|
||||
if(!server.modes[0] || !server.modes[1] || server.modes[2]) {
|
||||
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;
|
||||
|
|
@ -533,7 +533,9 @@ main(int argc, char *argv[]) {
|
|||
}
|
||||
}
|
||||
|
||||
/* Place the cursor to the topl left of the output layout. */
|
||||
ipc_init(&server);
|
||||
|
||||
/* 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);
|
||||
|
|
|
|||
248
ipc_server.c
Normal file
248
ipc_server.c
Normal file
|
|
@ -0,0 +1,248 @@
|
|||
/*
|
||||
* 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 "server.h"
|
||||
#include "parse.h"
|
||||
#include "message.h"
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include <stdlib.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");
|
||||
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");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (listen(ipc->socket, 3) == -1) {
|
||||
wlr_log(WLR_ERROR, "Unable to listen on IPC socket");
|
||||
}
|
||||
|
||||
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) == -1) {
|
||||
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;
|
||||
int 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);
|
||||
if(parse_rc_line(client->server, line) != 0) {
|
||||
wlr_log(WLR_ERROR, "Error parsing input from IPC socket.");
|
||||
}
|
||||
}
|
||||
}
|
||||
offset+=(nl_pos-client->read_buffer)+1;
|
||||
}
|
||||
if(client->read_buf_len-offset == MAX_LINE_SIZE+1) {
|
||||
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;
|
||||
}
|
||||
44
ipc_server.h
Normal file
44
ipc_server.h
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
#ifndef CG_IPC_SERVER_H
|
||||
#define CG_IPC_SERVER_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <inttypes.h>
|
||||
#include <wayland-server-core.h>
|
||||
|
||||
struct cg_server;
|
||||
|
||||
struct cg_ipc_client {
|
||||
struct wl_event_source *event_source;
|
||||
struct wl_event_source *writable_event_source;
|
||||
struct cg_server *server;
|
||||
struct wl_list link;
|
||||
int fd;
|
||||
uint32_t security_policy;
|
||||
size_t write_buffer_len;
|
||||
size_t write_buffer_size;
|
||||
char *write_buffer;
|
||||
// The following is for storing data between event_loop calls
|
||||
uint8_t read_buf_len;
|
||||
uint8_t read_discard;// 1 if the current line is to be discarded
|
||||
char *read_buffer;
|
||||
};
|
||||
|
||||
struct cg_ipc_handle {
|
||||
int socket;
|
||||
struct wl_event_source *event_source;
|
||||
struct wl_list client_list;
|
||||
struct wl_listener display_destroy;
|
||||
struct sockaddr_un *sockaddr;
|
||||
};
|
||||
|
||||
int ipc_init(struct cg_server *server);
|
||||
int ipc_handle_connection(int fd, uint32_t mask, void *data);
|
||||
int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data);
|
||||
//int ipc_client_handle_writable(int client_fd, uint32_t mask, void *data);
|
||||
void ipc_client_disconnect(struct cg_ipc_client *client);
|
||||
void ipc_client_handle_command(struct cg_ipc_client *client);
|
||||
//bool ipc_send_reply(struct ipc_client *client, const char *payload, uint32_t payload_length);
|
||||
|
||||
#endif
|
||||
|
|
@ -121,6 +121,7 @@ conf_data.set_quoted('CG_VERSION', version)
|
|||
cagebreak_main_file = [ 'cagebreak.c', ]
|
||||
cagebreak_source_strings = [
|
||||
'idle_inhibit_v1.c',
|
||||
'ipc_server.c',
|
||||
'keybinding.c',
|
||||
'workspace.c',
|
||||
'output.c',
|
||||
|
|
@ -137,6 +138,7 @@ cagebreak_source_strings = [
|
|||
|
||||
cagebreak_header_strings = [
|
||||
'idle_inhibit_v1.h',
|
||||
'ipc_server.h',
|
||||
'keybinding.h',
|
||||
'workspace.h',
|
||||
'output.h',
|
||||
|
|
|
|||
2
parse.h
2
parse.h
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
#define PARSE_H
|
||||
|
||||
# define MAX_LINE_SIZE 256
|
||||
|
||||
struct cg_server;
|
||||
|
||||
int
|
||||
|
|
|
|||
3
server.h
3
server.h
|
|
@ -2,6 +2,7 @@
|
|||
#define CG_SERVER_H
|
||||
|
||||
#include "config.h"
|
||||
#include "ipc_server.h"
|
||||
|
||||
#include <wayland-server-core.h>
|
||||
#include <wlr/types/wlr_xdg_decoration_v1.h>
|
||||
|
|
@ -40,6 +41,8 @@ struct cg_server {
|
|||
|
||||
enum wl_output_transform output_transform;
|
||||
|
||||
struct cg_ipc_handle ipc;
|
||||
|
||||
bool running;
|
||||
char **modes;
|
||||
uint16_t nws;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue