Skip to content

Instantly share code, notes, and snippets.

@x42
Created March 30, 2021 14:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save x42/11603acd12d84485df4a13a0d3afb2a3 to your computer and use it in GitHub Desktop.
Save x42/11603acd12d84485df4a13a0d3afb2a3 to your computer and use it in GitHub Desktop.
#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