Re organize and format code

This commit is contained in:
Shuanglei Tao
2016-09-17 11:58:40 +08:00
parent ba88b042e2
commit 76a8b86415
8 changed files with 210 additions and 154 deletions

View File

@@ -3,7 +3,7 @@ set(CMAKE_C_STANDARD 99)
project(ttyd)
set(SOURCE_FILES server.c http.c protocol.c)
set(SOURCE_FILES server.c http.c protocol.c utils.c)
find_package(OpenSSL REQUIRED)
find_package(Libwebsockets QUIET)

View File

@@ -29,7 +29,7 @@ brew install ttyd --HEAD
Ubuntu as example:
```bash
sudo apt-get install cmake libwebsockets-dev libjson-c-dev libssl-dev
sudo apt-get install cmake g++ pkg-config git vim-common libwebsockets-dev libjson-c-dev libssl-dev
git clone https://github.com/tsl0922/ttyd.git
cd ttyd && mkdir build && cd build
cmake ..

2
http.c
View File

@@ -34,7 +34,7 @@ check_auth(struct lws *wsi) {
return 1;
if (lws_add_http_header_by_token(wsi,
WSI_TOKEN_HTTP_WWW_AUTHENTICATE,
(unsigned char *)"Basic realm=\"ttyd\"",
(unsigned char *) "Basic realm=\"ttyd\"",
18, &p, end))
return 1;
if (lws_add_http_header_content_length(wsi, 0, &p, end))

View File

@@ -14,28 +14,6 @@
#define BUF_SIZE 1024
char *
base64_encode(const unsigned char *buffer, size_t length) {
BIO *bio, *b64;
BUF_MEM *bptr;
b64 = BIO_new(BIO_f_base64());
bio = BIO_new(BIO_s_mem());
b64 = BIO_push(b64, bio);
BIO_write(b64, buffer, (int) length);
BIO_flush(b64);
BIO_get_mem_ptr(b64, &bptr);
char *data = (char *)malloc(bptr->length);
memcpy(data, bptr->data, bptr->length-1);
data[bptr->length-1] = 0;
BIO_free_all(b64);
return data;
}
int
send_initial_message(struct lws *wsi) {
unsigned char message[LWS_PRE + 256];
@@ -76,7 +54,7 @@ parse_window_size(const char *json) {
}
rows = json_object_get_int(o);
struct winsize *size = malloc(sizeof(struct winsize));
struct winsize *size = t_malloc(sizeof(struct winsize));
memset(size, 0, sizeof(struct winsize));
size->ws_col = (unsigned short) columns;
size->ws_row = (unsigned short) rows;
@@ -151,10 +129,10 @@ thread_run_command(void *args) {
if (FD_ISSET (pty, &des_set)) {
memset(buf, 0, BUF_SIZE);
bytes = (int) read(pty, buf, BUF_SIZE);
struct pty_data *frame = (struct pty_data *) malloc(sizeof(struct pty_data));
struct pty_data *frame = (struct pty_data *) t_malloc(sizeof(struct pty_data));
frame->len = bytes;
if (bytes > 0) {
frame->data = malloc((size_t) bytes);
frame->data = t_malloc((size_t) bytes);
memcpy(frame->data, buf, bytes);
}
pthread_mutex_lock(&client->lock);
@@ -212,7 +190,7 @@ callback_tty(struct lws *wsi, enum lws_callback_reasons reason,
// read error or client exited, close connection
if (frame->len <= 0) {
STAILQ_REMOVE_HEAD(&client->queue, list);
free(frame);
t_free(frame);
return -1;
}
@@ -222,7 +200,7 @@ callback_tty(struct lws *wsi, enum lws_callback_reasons reason,
unsigned char *p = &message[LWS_PRE];
size_t n = sprintf((char *) p, "%c%s", OUTPUT, b64_text);
free(b64_text);
t_free(b64_text);
if (lws_write(wsi, p, n, LWS_WRITE_TEXT) < n) {
lwsl_err("lws_write\n");
@@ -230,8 +208,8 @@ callback_tty(struct lws *wsi, enum lws_callback_reasons reason,
}
STAILQ_REMOVE_HEAD(&client->queue, list);
free(frame->data);
free(frame);
t_free(frame->data);
t_free(frame);
if(lws_partial_buffered(wsi)){
lws_callback_on_writable(wsi);
@@ -266,7 +244,7 @@ callback_tty(struct lws *wsi, enum lws_callback_reasons reason,
if (ioctl(client->pty, TIOCSWINSZ, size) == -1) {
lwsl_err("ioctl TIOCSWINSZ: %d (%s)\n", errno, strerror(errno));
}
free(size);
t_free(size);
}
break;
default:

177
server.c
View File

@@ -1,94 +1,75 @@
#include "server.h"
#ifdef __linux__
/*
* sys_signame -- an ordered list of signals.
* lifted from /usr/include/linux/signal.h
* this particular order is only correct for linux.
* this is _not_ portable.
*/
const char *sys_signame[NSIG] = {
"zero", "HUP", "INT", "QUIT", "ILL", "TRAP", "IOT", "UNUSED",
"FPE", "KILL", "USR1", "SEGV", "USR2", "PIPE", "ALRM", "TERM",
"STKFLT","CHLD", "CONT", "STOP", "TSTP", "TTIN", "TTOU", "IO",
"XCPU", "XFSZ", "VTALRM","PROF", "WINCH", NULL
};
#endif
volatile bool force_exit = false;
struct lws_context *context;
struct tty_server *server;
// websocket protocols
static const struct lws_protocols protocols[] = {
{"http-only", callback_http, 0, 0},
{"tty", callback_tty, sizeof(struct tty_client), 128},
{NULL, NULL, 0, 0}
{"http-only", callback_http, 0, 0},
{"tty", callback_tty, sizeof(struct tty_client), 128},
{NULL, NULL, 0, 0}
};
// websocket extensions
static const struct lws_extension extensions[] = {
{"permessage-deflate", lws_extension_callback_pm_deflate, "permessage-deflate"},
{"deflate-frame", lws_extension_callback_pm_deflate, "deflate_frame"},
{"deflate-frame", lws_extension_callback_pm_deflate, "deflate_frame"},
{NULL, NULL, NULL}
};
// command line options
static const struct option options[] = {
{"port", required_argument, NULL, 'p'},
{"interface", required_argument, NULL, 'i'},
{"credential", required_argument, NULL, 'c'},
{"uid", required_argument, NULL, 'u'},
{"gid", required_argument, NULL, 'g'},
{"signal", required_argument, NULL, 's'},
{"reconnect", required_argument, NULL, 'r'},
#ifdef LWS_OPENSSL_SUPPORT
{"ssl", no_argument, NULL, 'S'},
{"ssl-cert", required_argument, NULL, 'C'},
{"ssl-key", required_argument, NULL, 'K'},
{"ssl-ca", required_argument, NULL, 'A'},
#endif
{"debug", required_argument, NULL, 'd'},
{"help", no_argument, NULL, 'h'},
{NULL, 0, 0, 0}
{"port", required_argument, NULL, 'p'},
{"interface", required_argument, NULL, 'i'},
{"credential", required_argument, NULL, 'c'},
{"uid", required_argument, NULL, 'u'},
{"gid", required_argument, NULL, 'g'},
{"signal", required_argument, NULL, 's'},
{"reconnect", required_argument, NULL, 'r'},
{"ssl", no_argument, NULL, 'S'},
{"ssl-cert", required_argument, NULL, 'C'},
{"ssl-key", required_argument, NULL, 'K'},
{"ssl-ca", required_argument, NULL, 'A'},
{"debug", required_argument, NULL, 'd'},
{"help", no_argument, NULL, 'h'},
{NULL, 0, 0, 0}
};
static const char *opt_string = "p:i:c:u:g:s:r:aSC:K:A:d:vh";
void print_help() {
fprintf(stderr, "ttyd is a tool for sharing terminal over the web\n\n"
"USAGE: ttyd [options] <command> [<arguments...>]\n\n"
"OPTIONS:\n"
"\t--port, -p Port to listen (default: 7681)\n"
"\t--interface, -i Network interface to bind\n"
"\t--credential, -c Credential for Basic Authentication (format: username:password)\n"
"\t--uid, -u User id to run with\n"
"\t--gid, -g Group id to run with\n"
"\t--signal, -s Signal to send to the command when exit it (default: SIGHUP)\n"
"\t--reconnect, -r Time to reconnect for the client in seconds (default: 10)\n"
#ifdef LWS_OPENSSL_SUPPORT
"\t--ssl, -S Enable ssl\n"
"\t--ssl-cert, -C Ssl certificate file path\n"
"\t--ssl-key, -K Ssl key file path\n"
"\t--ssl-ca, -A Ssl ca file path\n"
#endif
"\t--debug, -d Set log level (0-9, default: 7)\n"
"\t--help, -h Print this text and exit\n"
"USAGE: ttyd [options] <command> [<arguments...>]\n\n"
"OPTIONS:\n"
"\t--port, -p Port to listen (default: 7681)\n"
"\t--interface, -i Network interface to bind\n"
"\t--credential, -c Credential for Basic Authentication (format: username:password)\n"
"\t--uid, -u User id to run with\n"
"\t--gid, -g Group id to run with\n"
"\t--signal, -s Signal to send to the command when exit it (default: SIGHUP)\n"
"\t--reconnect, -r Time to reconnect for the client in seconds (default: 10)\n"
"\t--ssl, -S Enable ssl\n"
"\t--ssl-cert, -C Ssl certificate file path\n"
"\t--ssl-key, -K Ssl key file path\n"
"\t--ssl-ca, -A Ssl ca file path\n"
"\t--debug, -d Set log level (0-9, default: 7)\n"
"\t--help, -h Print this text and exit\n"
);
}
struct tty_server*
struct tty_server *
tty_server_new(int argc, char **argv) {
struct tty_server *ts;
size_t cmd_len = 0;
ts = malloc(sizeof(struct tty_server));
ts = t_malloc(sizeof(struct tty_server));
LIST_INIT(&ts->clients);
ts->client_count = 0;
ts->credential = NULL;
ts->reconnect = 10;
ts->sig_code = SIGHUP;
ts->sig_name = strdup("SIGHUP");
ts->argv = malloc(sizeof(char *) * (argc + 1));
ts->argv = t_malloc(sizeof(char *) * (argc + 1));
for (int i = 0; i < argc; i++) {
ts->argv[i] = strdup(argv[i]);
cmd_len += strlen(ts->argv[i]);
@@ -98,11 +79,11 @@ tty_server_new(int argc, char **argv) {
}
ts->argv[argc] = NULL;
ts->command = malloc(cmd_len);
ts->command = t_malloc(cmd_len);
char *ptr = ts->command;
for (int i = 0; i < argc; i++) {
ptr = stpcpy(ptr, ts->argv[i]);
if (i != argc -1) {
if (i != argc - 1) {
sprintf(ptr++, "%c", ' ');
}
}
@@ -110,37 +91,6 @@ tty_server_new(int argc, char **argv) {
return ts;
}
char *
uppercase(char *str) {
int i = 0;
do {
str[i] = (char) toupper(str[i]);
} while (str[i++] != '\0');
return str;
}
// Get human readable signal string
int
get_sig_name(int sig, char *buf) {
int n = sprintf(buf, "SIG%s", sig < NSIG ? sys_signame[sig] : "unknown");
uppercase(buf);
return n;
}
// Get signal code from string like SIGHUP
int
get_sig(const char *sig_name) {
if (strcasestr(sig_name, "sig") != sig_name || strlen(sig_name) <= 3) {
return -1;
}
for (int sig = 1; sig < NSIG; sig++) {
const char *name = sys_signame[sig];
if (strcasecmp(name, sig_name + 3) == 0)
return sig;
}
return -1;
}
void
sig_handler(int sig) {
char sig_name[20];
@@ -154,16 +104,16 @@ int
calc_command_start(int argc, char **argv) {
// make a copy of argc and argv
int argc_copy = argc;
char **argv_copy = malloc(sizeof(char *) * argc);
char **argv_copy = t_malloc(sizeof(char *) * argc);
for (int i = 0; i < argc; i++) {
argv_copy[i] = strdup(argv[i]);
}
// do not print error message for invalid option
opterr = 0;
while(getopt_long(argc_copy, argv_copy, opt_string, options, NULL) != -1)
;;
int start= -1;
while (getopt_long(argc_copy, argv_copy, opt_string, options, NULL) != -1);
int start = -1;
if (optind < argc) {
char *command = argv_copy[optind];
for (int i = 0; i < argc; i++) {
@@ -176,9 +126,9 @@ calc_command_start(int argc, char **argv) {
// free argv copy
for (int i = 0; i < argc; i++) {
free(argv_copy[i]);
t_free(argv_copy[i]);
}
free(argv_copy);
t_free(argv_copy);
// reset for next use
opterr = 1;
@@ -217,12 +167,10 @@ main(int argc, char **argv) {
int debug_level = 7;
char iface[128] = "";
#ifdef LWS_OPENSSL_SUPPORT
bool ssl = false;
char cert_path[1024] = "";
char key_path[1024] = "";
char ca_path[1024] = "";
#endif
// parse command line options
int c;
@@ -239,7 +187,7 @@ main(int argc, char **argv) {
break;
case 'i':
strncpy(iface, optarg, sizeof(iface));
iface[sizeof(iface)-1] = '\0';
iface[sizeof(iface) - 1] = '\0';
break;
case 'c':
if (strchr(optarg, ':') == NULL) {
@@ -254,22 +202,20 @@ main(int argc, char **argv) {
case 'g':
info.gid = atoi(optarg);
break;
case 's':
{
int sig = get_sig(optarg);
if (sig > 0) {
server->sig_code = get_sig(optarg);
server->sig_name = uppercase(strdup(optarg));
} else {
fprintf(stderr, "ttyd: invalid signal: %s\n", optarg);
return -1;
}
case 's': {
int sig = get_sig(optarg);
if (sig > 0) {
server->sig_code = get_sig(optarg);
server->sig_name = uppercase(strdup(optarg));
} else {
fprintf(stderr, "ttyd: invalid signal: %s\n", optarg);
return -1;
}
}
break;
case 'r':
server->reconnect = atoi(optarg);
break;
#ifdef LWS_OPENSSL_SUPPORT
case 'S':
ssl = true;
break;
@@ -285,7 +231,6 @@ main(int argc, char **argv) {
strncpy(ca_path, optarg, sizeof(ca_path) - 1);
ca_path[sizeof(ca_path) - 1] = '\0';
break;
#endif
case '?':
break;
default:
@@ -298,7 +243,6 @@ main(int argc, char **argv) {
if (strlen(iface) > 0)
info.iface = iface;
#ifdef LWS_OPENSSL_SUPPORT
if (ssl) {
info.ssl_cert_filepath = cert_path;
info.ssl_private_key_filepath = key_path;
@@ -320,7 +264,6 @@ main(int argc, char **argv) {
info.options |= LWS_SERVER_OPTION_REDIRECT_HTTP_TO_HTTPS;
#endif
}
#endif
signal(SIGINT, sig_handler);
@@ -356,15 +299,15 @@ main(int argc, char **argv) {
// cleanup
if (server->credential != NULL)
free(server->credential);
free(server->command);
t_free(server->credential);
t_free(server->command);
int i = 0;
do {
free(server->argv[i++]);
t_free(server->argv[i++]);
} while (server->argv[i] != NULL);
free(server->argv);
free(server->sig_name);
free(server);
t_free(server->argv);
t_free(server->sig_name);
t_free(server);
return 0;
}

View File

@@ -1,12 +1,8 @@
#include "lws_config.h"
// warning: implicit declaration of function
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <ctype.h>
#include <signal.h>
#include <string.h>
#include <fcntl.h>
@@ -18,9 +14,12 @@
#include <sys/select.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <assert.h>
#ifdef __APPLE__
#include <util.h>
#else
#include <pty.h>
#endif
@@ -28,6 +27,8 @@
#include <libwebsockets.h>
#include <json.h>
#include "utils.h"
extern volatile bool force_exit;
extern struct lws_context *context;
extern struct tty_server *server;

102
utils.c Normal file
View File

@@ -0,0 +1,102 @@
#define _GNU_SOURCE
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <signal.h>
#include <openssl/bio.h>
#include <openssl/evp.h>
#include <openssl/buffer.h>
// http://web.mit.edu/~svalente/src/kill/kill.c
#ifdef __linux__
/*
* sys_signame -- an ordered list of signals.
* lifted from /usr/include/linux/signal.h
* this particular order is only correct for linux.
* this is _not_ portable.
*/
const char *sys_signame[NSIG] = {
"zero", "HUP", "INT", "QUIT", "ILL", "TRAP", "IOT", "UNUSED",
"FPE", "KILL", "USR1", "SEGV", "USR2", "PIPE", "ALRM", "TERM",
"STKFLT","CHLD", "CONT", "STOP", "TSTP", "TTIN", "TTOU", "IO",
"XCPU", "XFSZ", "VTALRM","PROF", "WINCH", NULL
};
#endif
void *
t_malloc(size_t size) {
if (size == 0)
return NULL;
void *p = malloc(size);
if (!p)
abort();
return p;
}
void t_free(void *p) {
if (p)
free(p);
}
void *
t_realloc(void *p, size_t size) {
if ((size == 0) && (p == NULL))
return NULL;
p = realloc(p, size);
if (!p)
abort();
return p;
}
char *
uppercase(char *str) {
int i = 0;
do {
str[i] = (char) toupper(str[i]);
} while (str[i++] != '\0');
return str;
}
int
get_sig_name(int sig, char *buf) {
int n = sprintf(buf, "SIG%s", sig < NSIG ? sys_signame[sig] : "unknown");
uppercase(buf);
return n;
}
int
get_sig(const char *sig_name) {
if (strcasestr(sig_name, "sig") != sig_name || strlen(sig_name) <= 3) {
return -1;
}
for (int sig = 1; sig < NSIG; sig++) {
const char *name = sys_signame[sig];
if (strcasecmp(name, sig_name + 3) == 0)
return sig;
}
return -1;
}
char *
base64_encode(const unsigned char *buffer, size_t length) {
BIO *bio, *b64;
BUF_MEM *bptr;
b64 = BIO_new(BIO_f_base64());
bio = BIO_new(BIO_s_mem());
b64 = BIO_push(b64, bio);
BIO_write(b64, buffer, (int) length);
BIO_flush(b64);
BIO_get_mem_ptr(b64, &bptr);
char *data = (char *) t_malloc(bptr->length);
memcpy(data, bptr->data, bptr->length - 1);
data[bptr->length - 1] = 0;
BIO_free_all(b64);
return data;
}

32
utils.h Normal file
View File

@@ -0,0 +1,32 @@
#ifndef TTYD_UTIL_H
#define TTYD_UTIL_H
// malloc with NULL check
void *
t_malloc(size_t size);
// free with NULL check
void
t_free(void *p);
// realloc with NULL check
void *
t_realloc(void *p, size_t size);
// Convert a string to upper case
char *
uppercase(char *str);
// Get human readable signal string
int
get_sig_name(int sig, char *buf);
// Get signal code from string like SIGHUP
int
get_sig(const char *sig_name);
// Encode text to base64, the caller should free the returned string
char *
base64_encode(const unsigned char *buffer, size_t length);
#endif //TTYD_UTIL_H