From f917cbe29b5a9589c5019ae40b0339e721d285f9 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Thu, 10 May 2012 08:23:23 -0500 Subject: [PATCH] add server side to scgi --- libs/libscgi/Makefile | 7 +- libs/libscgi/src/include/scgi.h | 7 +- libs/libscgi/src/scgi.c | 184 ++++++++++++++++++++++++++++++++ libs/libscgi/testclient.c | 3 +- libs/libscgi/testserver.c | 42 ++++++++ 5 files changed, 238 insertions(+), 5 deletions(-) create mode 100644 libs/libscgi/testserver.c diff --git a/libs/libscgi/Makefile b/libs/libscgi/Makefile index fb59cb7848..88b5b4e73c 100644 --- a/libs/libscgi/Makefile +++ b/libs/libscgi/Makefile @@ -14,7 +14,7 @@ HEADERS=src/include/scgi.h SOLINK=-shared -Xlinker -x -all: $(MYLIB) testclient +all: $(MYLIB) testclient testserver $(MYLIB): $(OBJS) $(HEADERS) $(SRC) ar rcs $(MYLIB) $(OBJS) @@ -26,7 +26,10 @@ $(MYLIB): $(OBJS) $(HEADERS) $(SRC) testclient: $(MYLIB) testclient.c $(CC) $(CC_CFLAGS) $(CFLAGS) testclient.c -o testclient -lscgi $(LDFLAGS) $(LIBS) +testserver: $(MYLIB) testserver.c + $(CC) $(CC_CFLAGS) $(CFLAGS) testserver.c -o testserver -lscgi $(LDFLAGS) $(LIBS) + clean: - rm -f *.o src/*.o libscgi.a *~ src/*~ src/include/*~ testclient + rm -f *.o src/*.o libscgi.a *~ src/*~ src/include/*~ testclient testserver diff --git a/libs/libscgi/src/include/scgi.h b/libs/libscgi/src/include/scgi.h index ea8d30ade4..29abcf0271 100644 --- a/libs/libscgi/src/include/scgi.h +++ b/libs/libscgi/src/include/scgi.h @@ -138,7 +138,7 @@ typedef int scgi_filehandle_t; #define scgi_strlen_zero(s) (!s || *(s) == '\0') #define scgi_strlen_zero_buf(s) (*(s) == '\0') #define end_of(_s) *(*_s == '\0' ? _s : _s + strlen(_s) - 1) - +#define end_of_p(_s) (*_s == '\0' ? _s : _s + strlen(_s) - 1) typedef enum { SCGI_POLL_READ = (1 << 0), @@ -179,7 +179,7 @@ typedef enum { SCGI_GENERR } scgi_status_t; - +typedef void (*scgi_listen_callback_t)(scgi_socket_t server_sock, scgi_socket_t client_sock, struct sockaddr_in *addr); SCGI_DECLARE(scgi_status_t) scgi_connect(scgi_handle_t *handle, const char *host, scgi_port_t port, uint32_t timeout); SCGI_DECLARE(scgi_status_t) scgi_disconnect(scgi_handle_t *handle); @@ -190,6 +190,9 @@ SCGI_DECLARE(scgi_status_t) scgi_add_param(scgi_handle_t *handle, const char *na SCGI_DECLARE(scgi_status_t) scgi_add_body(scgi_handle_t *handle, const char *value); SCGI_DECLARE(size_t) scgi_build_message(scgi_handle_t *handle, char **buffer); SCGI_DECLARE(scgi_status_t) scgi_destroy_params(scgi_handle_t *handle); +SCGI_DECLARE(scgi_status_t) scgi_listen(const char *host, scgi_port_t port, scgi_listen_callback_t callback); +SCGI_DECLARE(const char *) scgi_get_body(scgi_handle_t *handle); +SCGI_DECLARE(const char *) scgi_get_param(scgi_handle_t *handle, const char *name); #ifdef __cplusplus } diff --git a/libs/libscgi/src/scgi.c b/libs/libscgi/src/scgi.c index eeec39a07b..74cd5cae38 100644 --- a/libs/libscgi/src/scgi.c +++ b/libs/libscgi/src/scgi.c @@ -165,6 +165,11 @@ SCGI_DECLARE(scgi_status_t) scgi_add_body(scgi_handle_t *handle, const char *val return SCGI_SUCCESS; } +SCGI_DECLARE(const char *) scgi_get_body(scgi_handle_t *handle) +{ + return handle->body; +} + SCGI_DECLARE(scgi_status_t) scgi_add_param(scgi_handle_t *handle, const char *name, const char *value) { scgi_param_t *param, *pp; @@ -190,6 +195,19 @@ SCGI_DECLARE(scgi_status_t) scgi_add_param(scgi_handle_t *handle, const char *na return SCGI_SUCCESS; } +SCGI_DECLARE(const char *) scgi_get_param(scgi_handle_t *handle, const char *name) +{ + scgi_param_t *pp; + + for(pp = handle->params; pp; pp = pp->next) { + if (!strcasecmp(pp->name, name)) { + return pp->value; + } + } + + return NULL; +} + static scgi_status_t scgi_push_param(scgi_handle_t *handle, const char *name, const char *value) { scgi_param_t *param; @@ -518,3 +536,169 @@ SCGI_DECLARE(int) scgi_wait_sock(scgi_socket_t sock, uint32_t ms, scgi_poll_t fl } #endif + +static int scgi_socket_reuseaddr(scgi_socket_t socket) +{ +#ifdef WIN32 + BOOL reuse_addr = TRUE; + return setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse_addr, sizeof(reuse_addr)); +#else + int reuse_addr = 1; + return setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, &reuse_addr, sizeof(reuse_addr)); +#endif +} + +SCGI_DECLARE(scgi_status_t) scgi_listen(const char *host, scgi_port_t port, scgi_listen_callback_t callback) +{ + scgi_socket_t server_sock = SCGI_SOCK_INVALID; + struct sockaddr_in addr; + scgi_status_t status = SCGI_SUCCESS; + + if ((server_sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { + return SCGI_FAIL; + } + + scgi_socket_reuseaddr(server_sock); + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(INADDR_ANY); + addr.sin_port = htons(port); + + if (bind(server_sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + status = SCGI_FAIL; + goto end; + } + + if (listen(server_sock, 10000) < 0) { + status = SCGI_FAIL; + goto end; + } + + for (;;) { + int client_sock; + struct sockaddr_in echoClntAddr; +#ifdef WIN32 + int clntLen; +#else + unsigned int clntLen; +#endif + + clntLen = sizeof(echoClntAddr); + + if ((client_sock = accept(server_sock, (struct sockaddr *) &echoClntAddr, &clntLen)) == SCGI_SOCK_INVALID) { + status = SCGI_FAIL; + goto end; + } + + callback(server_sock, client_sock, &echoClntAddr); + } + + end: + + if (server_sock != SCGI_SOCK_INVALID) { + closesocket(server_sock); + server_sock = SCGI_SOCK_INVALID; + } + + return status; + +} + +#define next_str(_e, _s) _s = _e; while(*_s) _s++; _s++ + +SCGI_DECLARE(scgi_status_t) scgi_parse(scgi_socket_t sock, scgi_handle_t *handle) +{ + char sbuf[128] = ""; + char *p = sbuf, *e, *end; + ssize_t r = 0; + scgi_status_t status = SCGI_FAIL; + ssize_t bytes = 0; + char *headers = NULL; + int loops = 0; + ssize_t clen = 0; + char *body = NULL; + char comma = 0; + + handle->sock = sock; + handle->connected = 1; + sock_setup(handle); + + + for(;;) { + + if ((r = recv(sock, p, 1, 0)) < 1) { + break; + } + + if (*p == ':') { + *p = '\0'; + break; + } + p++; + } + + if (r <= 0) goto end; + + bytes = atoi(sbuf); + + if (bytes <= 0) goto end; + + headers = malloc(bytes); + r = recv(sock, headers, bytes, 0); + if (r <= 0) goto end; + + r = recv(sock, &comma, 1, 0); + if (r <= 0 || comma != ',') goto end; + + + p = headers; + end = p + bytes; + e = NULL; + + while(p < end) { + next_str(p, e); + + if (!e) break; + + if (!loops++) { + if (!strcasecmp(p, "CONTENT_LENGTH") && e) { + clen = atoi(e); + if (clen) { + body = malloc(clen+1); + r = recv(sock, body, clen, 0); + *(body + clen) = '\0'; + if (r <= 0) goto end; + scgi_add_body(handle, body); + scgi_safe_free(body); + } + + status = SCGI_SUCCESS; + + } else { + goto end; + } + } + + scgi_add_param(handle, p, e); + next_str(e, p); + } + + end: + + scgi_safe_free(headers); + + return status; +} + + +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4: + */ diff --git a/libs/libscgi/testclient.c b/libs/libscgi/testclient.c index c43fe237c4..9b9078691c 100644 --- a/libs/libscgi/testclient.c +++ b/libs/libscgi/testclient.c @@ -10,7 +10,8 @@ int main(int argc, char *argv[]) int port = 0; if (argc < 2) { - fprintf(stderr, "usage: testclient "); + fprintf(stderr, "usage: testclient \n"); + exit(-1); } ip = argv[1]; diff --git a/libs/libscgi/testserver.c b/libs/libscgi/testserver.c new file mode 100644 index 0000000000..7cb6e32a03 --- /dev/null +++ b/libs/libscgi/testserver.c @@ -0,0 +1,42 @@ +#include + +static void callback(scgi_socket_t server_sock, scgi_socket_t client_sock, struct sockaddr_in *addr) +{ + scgi_handle_t handle = { 0 }; + + if (scgi_parse(client_sock, &handle) == SCGI_SUCCESS) { + scgi_param_t *pp; + + for(pp = handle.params; pp; pp = pp->next) { + printf("HEADER: [%s] VALUE: [%s]\n", pp->name, pp->value); + } + + if (handle.body) { + printf("\n\nBODY:\n%s\n\n", handle.body); + } + + } + + scgi_disconnect(&handle); + +} + +int main(int argc, char *argv[]) +{ + char *ip; + int port = 0; + + if (argc < 2) { + fprintf(stderr, "usage: testserver \n"); + exit(-1); + } + + ip = argv[1]; + port = atoi(argv[2]); + + + scgi_listen(ip, port, callback); + + + +}