From 76a8b864156274a4da8662dec3dbcdf0919c283b Mon Sep 17 00:00:00 2001 From: Shuanglei Tao Date: Sat, 17 Sep 2016 11:58:40 +0800 Subject: [PATCH] Re organize and format code --- CMakeLists.txt | 2 +- README.md | 2 +- http.c | 2 +- protocol.c | 38 +++-------- server.c | 177 +++++++++++++++++-------------------------------- server.h | 9 +-- utils.c | 102 ++++++++++++++++++++++++++++ utils.h | 32 +++++++++ 8 files changed, 210 insertions(+), 154 deletions(-) create mode 100644 utils.c create mode 100644 utils.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 3a3485e..0499f95 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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) diff --git a/README.md b/README.md index 0cf8001..862e709 100644 --- a/README.md +++ b/README.md @@ -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 .. diff --git a/http.c b/http.c index 7c167a6..c7d1681 100644 --- a/http.c +++ b/http.c @@ -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)) diff --git a/protocol.c b/protocol.c index 7bce529..b581e27 100644 --- a/protocol.c +++ b/protocol.c @@ -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: diff --git a/server.c b/server.c index 153b7b6..aba0406 100644 --- a/server.c +++ b/server.c @@ -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] []\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] []\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; } diff --git a/server.h b/server.h index 4f94173..dd29ed4 100644 --- a/server.h +++ b/server.h @@ -1,12 +1,8 @@ #include "lws_config.h" -// warning: implicit declaration of function -#define _GNU_SOURCE - #include #include #include -#include #include #include #include @@ -18,9 +14,12 @@ #include #include #include +#include #ifdef __APPLE__ + #include + #else #include #endif @@ -28,6 +27,8 @@ #include #include +#include "utils.h" + extern volatile bool force_exit; extern struct lws_context *context; extern struct tty_server *server; diff --git a/utils.c b/utils.c new file mode 100644 index 0000000..f32564e --- /dev/null +++ b/utils.c @@ -0,0 +1,102 @@ +#define _GNU_SOURCE + +#include +#include +#include +#include + +#include +#include +#include + +// 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; +} \ No newline at end of file diff --git a/utils.h b/utils.h new file mode 100644 index 0000000..c8ffade --- /dev/null +++ b/utils.h @@ -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 -- 2.43.4