Commit b8444b37 authored by Manuel Stoeckl's avatar Manuel Stoeckl
Browse files

Relay messages between client and server, but without fds

parent 4b0e9dcf
......@@ -5,8 +5,8 @@ way_cflags := $(shell pkg-config --cflags wayland-client wayland-server)
all: waypipe
waypipe: waypipe.c server.c client.c Makefile
gcc -ggdb3 $(way_libs) $(way_cflags) -o waypipe waypipe.c server.c client.c
waypipe: waypipe.c server.c client.c util.c util.h Makefile
gcc -std=c11 -ggdb3 $(way_libs) $(way_cflags) -o waypipe waypipe.c server.c client.c util.h util.c
clean:
rm -f waypipe
......
......@@ -23,12 +23,18 @@
* SOFTWARE.
*/
#define _XOPEN_SOURCE 700
#include "util.h"
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <time.h>
#include <unistd.h>
#include <wayland-client-core.h>
......@@ -39,6 +45,7 @@ int run_client(const char *socket_path)
fprintf(stderr, "Failed to connect to a wayland server.\n");
return EXIT_FAILURE;
}
int displayfd = wl_display_get_fd(display);
struct sockaddr_un saddr;
int fd;
......@@ -70,9 +77,13 @@ int run_client(const char *socket_path)
return EXIT_FAILURE;
}
int maxmsg = 4096;
char *buffer = calloc(1, maxmsg + 1);
fprintf(stderr, "I'm a client on %s!\n", socket_path);
for (int i = 0; i < 1; i++) {
// Q: multiple parallel client support?
// Q: multiple parallel remote client support? then multiplex
// over all accepted clients?
int client = accept(fd, NULL, NULL);
if (client == -1) {
......@@ -83,18 +94,86 @@ int run_client(const char *socket_path)
int bufsize = 4096;
char *buf = calloc(bufsize + 1, 1);
while (1) {
int nb = read(client, buf, bufsize);
if (nb <= 0) {
fprintf(stderr, "Read failed, stopping\n");
// pselect multiple.
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(client, &readfds);
FD_SET(displayfd, &readfds);
struct timespec timeout = {
.tv_sec = 0, .tv_nsec = 700000000L};
int maxfd = client > displayfd ? client : displayfd;
int r = pselect(maxfd + 1, &readfds, NULL, NULL,
&timeout, NULL);
if (r == -1) {
fprintf(stderr, "Select failed, stopping\n");
break;
} else {
fprintf(stderr, "Read with %d bytes of data |%s|\n",
nb, buf);
}
fprintf(stderr, "Post select %d %d %d\n", r,
FD_ISSET(client, &readfds),
FD_ISSET(displayfd, &readfds));
if (r == 0) {
const char *msg = "magic";
ssize_t nb = write(
client, msg, strlen(msg) + 1);
if (nb == -1) {
fprintf(stderr, "Write failed, retrying anyway\n");
}
continue;
}
if (FD_ISSET(client, &readfds)) {
fprintf(stderr, "client isset\n");
int rc = iovec_read(client, buffer, maxmsg,
NULL, NULL);
if (rc == -1) {
fprintf(stderr, "FD Read failure %ld: %s\n",
rc, strerror(errno));
break;
}
fprintf(stderr, "read bytes: %d\n", rc);
if (rc > 0) {
int wc = iovec_write(displayfd, buffer,
rc, NULL, NULL);
if (wc == -1) {
fprintf(stderr, "FD Write failure %ld: %s\n",
wc,
strerror(errno));
break;
}
} else {
fprintf(stderr, "the other side shut down\n");
break;
}
}
if (FD_ISSET(displayfd, &readfds)) {
fprintf(stderr, "displayfd isset\n");
int rc = iovec_read(displayfd, buffer, maxmsg,
NULL, NULL);
if (rc == -1) {
fprintf(stderr, "CS Read failure %ld: %s\n",
rc, strerror(errno));
break;
}
if (rc > 0) {
int wc = iovec_write(client, buffer, rc,
NULL, NULL);
if (wc == -1) {
fprintf(stderr, "CS Write failure %ld: %s\n",
wc,
strerror(errno));
break;
}
} else {
fprintf(stderr, "the display shut down\n");
break;
}
}
}
fprintf(stderr, "...\n");
}
fprintf(stderr, "Closing\n");
close(displayfd);
close(fd);
unlink(socket_path);
......
......@@ -23,14 +23,22 @@
* SOFTWARE.
*/
#define _POSIX_C_SOURCE 200112L
#define _XOPEN_SOURCE 700
#include "util.h"
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/un.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
#include <wayland-server-core.h>
......@@ -43,20 +51,15 @@ int run_server(const char *socket_path, int app_argc, char *const app_argv[])
}
fprintf(stderr, "\n");
struct wl_display *display = wl_display_create();
// create another socketpair; one goes to display; one goes to child
int csockpair[2];
socketpair(AF_UNIX, SOCK_STREAM, 0, csockpair);
if (wl_display_add_socket_fd(display, csockpair[0]) == -1) {
fprintf(stderr, "Failed to add socket to display object\n");
wl_display_destroy(display);
return EXIT_FAILURE;
}
int flags = fcntl(csockpair[0], F_GETFD);
fcntl(csockpair[0], F_SETFD, flags | FD_CLOEXEC);
pid_t pid = fork();
if (pid == -1) {
fprintf(stderr, "Fork failed\n");
wl_display_destroy(display);
return EXIT_FAILURE;
} else if (pid == 0) {
char bufs2[16];
......@@ -70,6 +73,14 @@ int run_server(const char *socket_path, int app_argc, char *const app_argv[])
fprintf(stderr, "Failed to execv: %s\n", strerror(errno));
return EXIT_FAILURE;
}
struct wl_display *display = wl_display_create();
if (wl_display_add_socket_fd(display, csockpair[0]) == -1) {
fprintf(stderr, "Failed to add socket to display object\n");
wl_display_destroy(display);
return EXIT_FAILURE;
}
int status;
struct sockaddr_un saddr;
......@@ -95,11 +106,90 @@ int run_server(const char *socket_path, int app_argc, char *const app_argv[])
return EXIT_FAILURE;
}
for (int i = 0; i < 10; i++) {
sleep(1);
char msg[256];
sprintf(msg, "Message #%d", i);
write(fd, msg, strlen(msg) + 1);
// A connection has already been established
int client_socket = csockpair[0];
/** Main select loop:
* fd -> csockpair[0]
* csockpair[0] -> fd
* 1 second timer (poll waitpid) */
struct timespec timeout = {.tv_sec = 0, .tv_nsec = 500000000L};
fd_set readfds;
int iter = 0;
int maxmsg = 4096;
char *buffer = calloc(1, maxmsg + 1);
while (true) {
iter++;
if (iter > 10) {
break;
}
FD_ZERO(&readfds);
FD_SET(fd, &readfds);
FD_SET(client_socket, &readfds);
int maxfd = fd > client_socket ? fd : client_socket;
int r = pselect(maxfd + 1, &readfds, NULL, NULL, &timeout,
NULL);
if (r < 0) {
fprintf(stderr, "Error selecting fds: %s\n",
strerror(errno));
return EXIT_FAILURE;
}
if (r == 0) {
// timeout!
fprintf(stderr, "timeout,?? \n");
} else {
fprintf(stderr, "%d are set\n", r);
}
if (FD_ISSET(fd, &readfds)) {
fprintf(stderr, "Readfd isset\n");
int rc = iovec_read(fd, buffer, maxmsg, NULL, NULL);
if (rc == -1) {
fprintf(stderr, "FD Read failure %ld: %s\n", rc,
strerror(errno));
break;
}
fprintf(stderr, "Read from conn %d bytes\n", rc);
if (rc > 0) {
int wc = iovec_write(client_socket, buffer, rc,
NULL, NULL);
if (wc == -1) {
fprintf(stderr, "FD Write failure %ld: %s\n",
wc, strerror(errno));
break;
}
} else {
fprintf(stderr, "the other side shut down\n");
break;
}
}
if (FD_ISSET(client_socket, &readfds)) {
fprintf(stderr, "client socket isset\n");
int rc = iovec_read(client_socket, buffer, maxmsg, NULL,
NULL);
if (rc == -1) {
fprintf(stderr, "CS Read failure %ld: %s\n", rc,
strerror(errno));
break;
}
if (rc > 0) {
int wc = iovec_write(
fd, buffer, rc, NULL, NULL);
if (wc == -1) {
fprintf(stderr, "CS Write failure %ld: %s\n",
wc, strerror(errno));
break;
}
} else {
fprintf(stderr, "the client shut down\n");
break;
}
}
if (waitpid(pid, &status, WNOHANG) > 0) {
break;
}
}
close(fd);
......
......@@ -2,8 +2,9 @@
root=`pwd`
# program=`which bash`
program=`which weston-flower`
#program=`which bash`
# program=`which weston-flower`
program=`which demo.py`
($root/waypipe client /tmp/socket-client 2>&1 | sed 's/.*/\x1b[33m&\x1b[0m/') &
# ssh-to-self; should have a local keypair set up
......
/*
* Copyright © 2019 Manuel Stoeckl
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/un.h>
#include <unistd.h>
int iovec_read(int conn, char* buf, size_t buflen, int* fds, int* numfds) {
char cmsgdata[ (CMSG_LEN(28 * sizeof(int32_t))) ];
struct iovec the_iovec;
the_iovec.iov_len = buflen;
the_iovec.iov_base = buf;
struct msghdr msg;
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = &the_iovec;
msg.msg_iovlen = 1;
msg.msg_control = &cmsgdata;
msg.msg_controllen = sizeof(cmsgdata);
msg.msg_flags = 0;
ssize_t ret = recvmsg(conn, &msg, MSG_DONTWAIT);
// parse FDS
return ret;
}
int iovec_write(int conn, char* buf, size_t buflen, int* fds, int* numfds) {
// char cmsgdata[ (CMSG_LEN(28 * sizeof(int32_t))) ];
struct iovec the_iovec;
the_iovec.iov_len = buflen;
the_iovec.iov_base = buf;
struct msghdr msg;
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = &the_iovec;
msg.msg_iovlen = 1;
msg.msg_control = NULL;
msg.msg_controllen = 0;
msg.msg_flags = 0;
ssize_t ret = sendmsg(conn, &msg, 0);
// parse FDS
return ret;
}
/*
* Copyright © 2019 Manuel Stoeckl
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef WAYPIPE_UTIL_H
#define WAYPIPE_UTIL_H
#include <stdint.h>
#include <stddef.h>
int iovec_read(int socket, char* buf, size_t buflen, int* fds, int* numfds);
int iovec_write(int conn, char* buf, size_t buflen, int* fds, int* numfds);
#endif // WAYPIPE_UTIL_H
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment