/* * secde -- experimental lightweight Wayland/X11 server * Copyright (C) 2019 Samuel Lidén Borell * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include "evdev.h" #include "fbdev.h" #include "misc.h" #include "protohnd.h" struct FdInfo { struct FdInfo *next; int fd; FdFlags flags; FdProtocol protocol; /* For readable/writeable fds (flags & FDF_READABLE) */ int write_rdy; unsigned char *buffer, *largebuffer; int bufflen, lbufflen; /* For client sockets (flags & FDF_SOCKET) */ struct FdInfo *server; }; /*#define INITIAL_FDINFO_HASHBITS 4*/ static struct { int hashbits; /* num buckets = 1<<(hashbits-1) */ int count; struct FdInfo **buckets; } fdinfomap; struct ProtoInfo { int bufflen; int maxlbuff; }; #define BUFFERMIN static const struct ProtoInfo protoinfo[] = { /* UNSPEC */ { 0, 0 }, /* X11 */ { BUFFERMIN+1024, 128*1024 }, /* TODO what is the max packet size? */ /* PULSE */ { 0, 0 }, /* TODO max packet size for the other protocols */ /* WAYLAND */ { 0, 0 }, /* KMS */ { 0, 0 }, /* EVDEV */ { BUFFERMIN+48, 0 }, /* TODO size? seems to be either 32 or 48 bytes per packet... what about 64-bit platforms? */ /* ALSA */ { 0, 0 }, /* V4L2 */ { 0, 0 }, /* INOTIFY */ { BUFFERMIN+512, 0 } /* TODO max size? something+NAME_MAX... what about 64-bit platforms? */ }; void protohnd_initing(void) { map_init(fdinfomap); } struct FdInfo *protohnd_getfdinfo(int fd) { FdInfo *ret; map_get(fdinfomap, fd, struct FdInfo, ret); return ret; } int protohnd_getfd(struct FdInfo *info) { return info->fd; } FdFlags protohnd_getfdflags(struct FdInfo *info) { return info->flags; } struct FdInfo *protohnd_fdadded(struct FdInfo *server, int fd, FdFlags flags, FdProtocol protocol /*, cliantaddr, clientaddrsize*/) { struct FdInfo *info; int serverfd = server ? server->fd : -1; printf("fd added %d (server: %d)\n", fd, serverfd); if (protocol == FDP_UNSPEC && server != NULL) { protocol = server->protocol; } map_add(fdinfomap, fd, struct FdInfo, info); if (!info) { fprintf(stderr, "out of memory [map_add] (protocol #%d, " "server %d, client %d)\n", protocol, serverfd, fd); return NULL; } info->flags = flags; info->protocol = protocol; info->write_rdy = 0; info->server = server; info->buffer = NULL; /* lazy allocated */ info->bufflen = 0; info->largebuffer = NULL; info->lbufflen = 0; switch (protocol) { case FDP_EVDEV: if (!input_evdev_init(info)) { protohnd_closed(info); return NULL; } break; case FDP_FBDEV: if (!display_fbdev_init(info)) { protohnd_closed(info); return NULL; } printf("testing display\n"); display_fbdev_test(info); break; case FDP_X11: case FDP_PULSE: case FDP_WAYLAND: case FDP_KMS: case FDP_ALSA: case FDP_V4L2: case FDP_INOTIFY: case FDP_UNSPEC: /* Do nothing */ break; } return info; } #if 0 /* TODO should inotify be implemented here in protohnd instead? */ int protohnd_fdexists(FdProtocol protocol, int devnum) { /* TODO */ } #endif void protohnd_inited(void) { } void protohnd_willclose(struct FdInfo *info) { (void) info; } void protohnd_closed(struct FdInfo *info) { free(info->buffer); map_remove(fdinfomap, info->fd, struct FdInfo); /* TODO do something more? */ } /** * Allocates the packet buffer for an FdInfo * \return 1 if successful, 0 if not. */ static int allocate_buffer(struct FdInfo *info) { const int protocol = info->protocol; if (!protoinfo[protocol].bufflen) { fprintf(stderr, "internal error - protocol #%d is not supposed to use buffering\n", protocol); return 0; } info->buffer = malloc(protoinfo[protocol].bufflen); if (!info->buffer) { fprintf(stderr, "out of memory [buffer] (protocol #%d, " "client %d)\n", protocol, info->fd); return 0; } return 1; } static int process_received(struct FdInfo *info, const unsigned char *buff, int len) { switch (info->protocol) { case FDP_EVDEV: return input_evdev_handler(info, buff, len); case FDP_X11: /* for X11, /usr/include/X11/Xproto.h contains defs for the different packets. for example, xConnClientPrefix which is what the client sends upon connection */ case FDP_PULSE: case FDP_WAYLAND: case FDP_KMS: case FDP_ALSA: case FDP_V4L2: fprintf(stderr, "received data for unimplemented " "protocol #%d\n", info->protocol); return len; case FDP_INOTIFY: fprintf(stderr, "received data for protocol #%d was not " "handled correctly.\n", info->protocol); return len; case FDP_UNSPEC: case FDP_FBDEV: ; /* Fall through */ } fprintf(stderr, "Corrupted FdInfo. Unknown protocol #%d\n", info->protocol); return len; } void protohnd_received(struct FdInfo *info, const unsigned char *buff, int numrecv) { if (!info->bufflen) { /* Avoid copying to the buffer if there is no need */ int processed = process_received(info, buff, numrecv); numrecv -= processed; if (!numrecv) return; buff += processed; if (!info->buffer) { if (!allocate_buffer(info)) return; } memcpy(info->buffer, buff, numrecv); info->bufflen = numrecv; } else { int buffcap = protoinfo[info->protocol].bufflen; int newlen, processed; if (!info->buffer) { if (!allocate_buffer(info)) return; } newlen = info->bufflen + numrecv; if (newlen > buffcap) { fprintf(stderr, "BUG: protocol #%d buffer would overflow, throwing away data\n", info->protocol); info->bufflen = 0; return; } memcpy(&info->buffer[info->bufflen], buff, numrecv); processed = process_received(info, buff, numrecv); info->bufflen -= processed; memmove(info->buffer, &info->buffer[processed], processed); } } void protohnd_writeready(struct FdInfo *info, int state) { info->write_rdy = state; } struct FdInfo *protohnd_getwrite(unsigned char **buff, int *length, int *clientmore) { (void) buff; (void) length; (void) clientmore; return NULL; } void protohnd_written(struct FdInfo *info, int numwritten, int remaining, int result) { (void) info; (void) numwritten; (void) remaining; (void) result; }