Created
March 30, 2021 14:49
-
-
Save x42/11603acd12d84485df4a13a0d3afb2a3 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define _POSIX_C_SOURCE 200809L | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <pthread.h> | |
#include <signal.h> | |
#include <fcntl.h> | |
#include <sys/socket.h> | |
#include <sys/ioctl.h> | |
#include <arpa/inet.h> | |
#include <unistd.h> | |
#include <errno.h> | |
#include <pty.h> | |
#include <sys/types.h> | |
#include <sys/wait.h> | |
#include "lv2/lv2plug.in/ns/lv2core/lv2.h" | |
typedef struct { | |
float* ports[2]; | |
int sockfd; | |
pthread_t thread_id; | |
} ModShell; | |
static void doit (int client_sock) | |
{ | |
pid_t f = fork (); | |
if (f < 0) { | |
return; | |
} | |
if (f > 0) { | |
return; | |
} | |
#if 1 | |
fcntl (client_sock, F_SETFD, FD_CLOEXEC); | |
for (int i = 0; i < 3; i++) { | |
close (i); | |
} | |
for (int i = 0; i < 3; i++) { | |
if (dup2 (client_sock, i) < 0) { | |
perror ("error duplicating socket for stdin/stdout/stderr"); | |
exit (1); | |
} | |
} | |
close (client_sock); | |
char* args[] = {"/bin/sh", "-l", "-i", NULL}; | |
exit (execve (args[0], args, NULL)); | |
#else | |
for (int i = 0; i < 3; i++) { | |
close (i); | |
} | |
for (int i = 0; i < 3; i++) { | |
dup2 (client_sock, i); | |
} | |
close (client_sock); | |
char buf[8192]; | |
int terminalfd; | |
pid_t r = forkpty (&terminalfd, NULL, NULL, NULL); | |
if (r < 0) { | |
fprintf(stderr, "PTY FAIL\n"); | |
return; | |
} | |
if (r == 0) { | |
char* args[] = {"/bin/sh", "-l", "-i", NULL}; | |
exit (execve (args[0], args, NULL)); | |
} | |
// forward I/O | |
pid_t forkpid = fork(); | |
if (forkpid < 0) { | |
kill (r, SIGINT); | |
for (int i = 0; i < 3; i++) { close (i); } | |
return; | |
} | |
if (forkpid == 0) { | |
while (1) { | |
int numbytes = read (terminalfd, buf, 8191); | |
if (numbytes <= 0){ | |
break; | |
} | |
if (write (1, buf, numbytes) <= 0) { | |
break; | |
} | |
} | |
kill (r, SIGINT); | |
for (int i = 0; i < 3; i++) { close (i); } | |
close (terminalfd); | |
exit (0); | |
} else { | |
int wstatus; | |
pid_t w; | |
struct termios old, new; | |
tcgetattr (0, &old); | |
new = old; | |
new.c_lflag &= ~ICANON; | |
new.c_lflag &= ~ECHO; | |
tcsetattr (0, TCSANOW, &new); | |
while (1) { | |
int numbytes = read (0, buf, 8191); | |
if (numbytes <= 0){ | |
break; | |
} | |
if (write (terminalfd, buf, numbytes) <= 0) { | |
break; | |
} | |
usleep (20000); | |
w = waitpid (r, &wstatus, WNOHANG); | |
if (w < 0 || (w > 0 && WIFEXITED(wstatus))) { | |
break; | |
} | |
} | |
kill (forkpid, SIGINT); | |
waitpid (forkpid, &wstatus, 0); | |
tcsetattr(0, TCSANOW, &old); | |
close (terminalfd); | |
for (int i = 0; i < 3; i++) { close (i); } | |
} | |
#endif | |
} | |
static void* io_thread (void *arg) | |
{ | |
ModShell* self = (ModShell*)arg; | |
listen (self->sockfd, 2); | |
while (1) { | |
int client_sock, c; | |
struct sockaddr_in client; | |
client_sock = accept (self->sockfd, (struct sockaddr *)&client, (socklen_t*)&c); | |
if (client_sock < 0) { | |
break; | |
} | |
doit (client_sock); | |
close (client_sock); | |
} | |
return NULL; | |
} | |
static LV2_Handle | |
instantiate (const LV2_Descriptor* descriptor, | |
double rate, | |
const char* bundle_path, | |
const LV2_Feature* const* features) | |
{ | |
ModShell* self = (ModShell*)calloc (1, sizeof (ModShell)); | |
int sockfd; | |
sockfd = socket (AF_INET , SOCK_STREAM , 0); | |
struct sockaddr_in server; | |
server.sin_family = AF_INET; | |
server.sin_addr.s_addr = INADDR_ANY; | |
server.sin_port = htons (6666); | |
int enable = 1; | |
setsockopt (sockfd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof (int)); | |
if (bind (sockfd, (struct sockaddr*)&server, sizeof (server)) < 0) { | |
free (self); | |
return 0; | |
} | |
self->sockfd = sockfd; | |
pthread_create (&self->thread_id, NULL, io_thread, self); | |
return (LV2_Handle)self; | |
} | |
static void | |
connect_port (LV2_Handle instance, | |
uint32_t port, | |
void* data) | |
{ | |
ModShell* self = (ModShell*)instance; | |
if (port < 2) { | |
self->ports[port] = (float*)data; | |
} | |
} | |
static void | |
run (LV2_Handle instance, uint32_t n_samples) | |
{ | |
ModShell* self = (ModShell*)instance; | |
if (self->ports[0] != self->ports[1]) { | |
memcpy (self->ports[1], self->ports[0], sizeof (float) * n_samples); | |
} | |
} | |
static void | |
cleanup (LV2_Handle instance) | |
{ | |
ModShell* self = (ModShell*)instance; | |
if (shutdown (self->sockfd, SHUT_RDWR) ) { | |
pthread_kill (self->thread_id, 9); | |
} else { | |
close (self->sockfd); | |
} | |
pthread_join (self->thread_id, NULL); | |
free (instance); | |
} | |
static const LV2_Descriptor descriptor = { | |
"http://moddevices.com/hack/modlv2shell", | |
instantiate, | |
connect_port, | |
NULL, | |
run, | |
NULL, | |
cleanup, | |
NULL | |
}; | |
#undef LV2_SYMBOL_EXPORT | |
#ifdef _WIN32 | |
# define LV2_SYMBOL_EXPORT __declspec(dllexport) | |
#else | |
# define LV2_SYMBOL_EXPORT __attribute__ ((visibility ("default"))) | |
#endif | |
LV2_SYMBOL_EXPORT | |
const LV2_Descriptor* | |
lv2_descriptor (uint32_t index) | |
{ | |
switch (index) { | |
case 0: | |
return &descriptor; | |
default: | |
return NULL; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment