/* * Copyright (c) 2014 Cesanta Software Limited * All rights reserved * This software is dual-licensed: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. For the terms of this * license, see . * * You are free to use this software under the terms of the GNU General * Public License, but WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * Alternatively, you can license this software under a commercial * license, as set out in . */ #ifndef NS_SKELETON_HEADER_INCLUDED #define NS_SKELETON_HEADER_INCLUDED #define NS_SKELETON_VERSION "2.2.0" #undef UNICODE /* Use ANSI WinAPI functions */ #undef _UNICODE /* Use multibyte encoding on Windows */ #define _MBCS /* Use multibyte encoding on Windows */ #define _INTEGRAL_MAX_BITS 64 /* Enable _stati64() on Windows */ #define _CRT_SECURE_NO_WARNINGS /* Disable deprecation warning in VS2005+ */ #undef WIN32_LEAN_AND_MEAN /* Let windows.h always include winsock2.h */ #ifndef _XOPEN_SOURCE #define _XOPEN_SOURCE 600 /* For flockfile() on Linux */ #endif #define __STDC_FORMAT_MACROS /* wants this for C++ */ #define __STDC_LIMIT_MACROS /* C++ wants that for INT64_MAX */ #ifndef _LARGEFILE_SOURCE #define _LARGEFILE_SOURCE /* Enable fseeko() and ftello() functions */ #endif #define _FILE_OFFSET_BITS 64 /* Enable 64-bit file offsets */ #ifdef _MSC_VER #pragma warning (disable : 4127) /* FD_SET() emits warning, disable it */ #pragma warning (disable : 4204) /* missing c99 support */ #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef va_copy #ifdef __va_copy #define va_copy __va_copy #else #define va_copy(x,y) (x) = (y) #endif #endif #ifdef _WIN32 #ifdef _MSC_VER #pragma comment(lib, "ws2_32.lib") /* Linking with winsock library */ #endif #include #include #ifndef EINPROGRESS #define EINPROGRESS WSAEINPROGRESS #endif #ifndef EWOULDBLOCK #define EWOULDBLOCK WSAEWOULDBLOCK #endif #ifndef __func__ #define STRX(x) #x #define STR(x) STRX(x) #define __func__ __FILE__ ":" STR(__LINE__) #endif #define snprintf _snprintf #define vsnprintf _vsnprintf #define sleep(x) Sleep((x) * 1000) #define to64(x) _atoi64(x) typedef int socklen_t; typedef unsigned char uint8_t; typedef unsigned int uint32_t; typedef unsigned short uint16_t; typedef unsigned __int64 uint64_t; typedef __int64 int64_t; typedef SOCKET sock_t; #ifdef __MINGW32__ typedef struct stat ns_stat_t; #else typedef struct _stati64 ns_stat_t; #endif #ifndef S_ISDIR #define S_ISDIR(x) ((x) & _S_IFDIR) #endif #else /* not _WIN32 */ #include #include #include #include #include #include #include /* For inet_pton() when NS_ENABLE_IPV6 is defined */ #include #include #include #ifndef closesocket #define closesocket(x) close(x) #endif #define __cdecl #ifndef INVALID_SOCKET #define INVALID_SOCKET (-1) #endif #ifdef __APPLE__ int64_t strtoll(const char * str, char ** endptr, int base); #endif #define to64(x) strtoll(x, NULL, 10) typedef int sock_t; typedef struct stat ns_stat_t; #endif /* _WIN32 */ #ifdef NS_ENABLE_DEBUG #define DBG(x) do { printf("%-20s ", __func__); printf x; putchar('\n'); \ fflush(stdout); } while(0) #else #define DBG(x) #endif #ifndef ARRAY_SIZE #define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0])) #endif #ifdef NS_ENABLE_SSL #ifdef __APPLE__ #pragma GCC diagnostic ignored "-Wdeprecated-declarations" #endif #include #else typedef void *SSL; typedef void *SSL_CTX; #endif #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ union socket_address { struct sockaddr sa; struct sockaddr_in sin; #ifdef NS_ENABLE_IPV6 struct sockaddr_in6 sin6; #else struct sockaddr sin6; #endif }; /* Describes chunk of memory */ struct ns_str { const char *p; size_t len; }; /* IO buffers interface */ struct iobuf { char *buf; size_t len; size_t size; }; void iobuf_init(struct iobuf *, size_t initial_size); void iobuf_free(struct iobuf *); size_t iobuf_append(struct iobuf *, const void *data, size_t data_size); void iobuf_remove(struct iobuf *, size_t data_size); void iobuf_resize(struct iobuf *, size_t new_size); /* Callback function (event handler) prototype, must be defined by user. */ /* Net skeleton will call event handler, passing events defined above. */ struct ns_connection; typedef void (*ns_event_handler_t)(struct ns_connection *, int ev, void *); /* Events. Meaning of event parameter (evp) is given in the comment. */ #define NS_POLL 0 /* Sent to each connection on each call to ns_mgr_poll() */ #define NS_ACCEPT 1 /* New connection accept()-ed. union socket_address *addr */ #define NS_CONNECT 2 /* connect() succeeded or failed. int *success_status */ #define NS_RECV 3 /* Data has benn received. int *num_bytes */ #define NS_SEND 4 /* Data has been written to a socket. int *num_bytes */ #define NS_CLOSE 5 /* Connection is closed. NULL */ struct ns_mgr { struct ns_connection *active_connections; const char *hexdump_file; /* Debug hexdump file path */ sock_t ctl[2]; /* Socketpair for mg_wakeup() */ void *user_data; /* User data */ }; struct ns_connection { struct ns_connection *next, *prev; /* ns_mgr::active_connections linkage */ struct ns_connection *listener; /* Set only for accept()-ed connections */ struct ns_mgr *mgr; sock_t sock; /* Socket */ union socket_address sa; /* Peer address */ struct iobuf recv_iobuf; /* Received data */ struct iobuf send_iobuf; /* Data scheduled for sending */ SSL *ssl; SSL_CTX *ssl_ctx; time_t last_io_time; /* Timestamp of the last socket IO */ ns_event_handler_t proto_handler; /* Protocol-specific event handler */ void *proto_data; /* Protocol-specific data */ ns_event_handler_t handler; /* Event handler function */ void *user_data; /* User-specific data */ unsigned long flags; #define NSF_FINISHED_SENDING_DATA (1 << 0) #define NSF_BUFFER_BUT_DONT_SEND (1 << 1) #define NSF_SSL_HANDSHAKE_DONE (1 << 2) #define NSF_CONNECTING (1 << 3) #define NSF_CLOSE_IMMEDIATELY (1 << 4) #define NSF_WANT_READ (1 << 5) #define NSF_WANT_WRITE (1 << 6) /* NOTE(lsm): proto-specific */ #define NSF_LISTENING (1 << 7) /* NOTE(lsm): proto-specific */ #define NSF_UDP (1 << 8) #define NSF_IS_WEBSOCKET (1 << 9) /* NOTE(lsm): proto-specific */ #define NSF_WEBSOCKET_NO_DEFRAG (1 << 10) /* NOTE(lsm): proto-specific */ #define NSF_USER_1 (1 << 20) #define NSF_USER_2 (1 << 21) #define NSF_USER_3 (1 << 22) #define NSF_USER_4 (1 << 23) #define NSF_USER_5 (1 << 24) #define NSF_USER_6 (1 << 25) }; void ns_mgr_init(struct ns_mgr *, void *user_data); void ns_mgr_free(struct ns_mgr *); time_t ns_mgr_poll(struct ns_mgr *, int milli); void ns_broadcast(struct ns_mgr *, ns_event_handler_t, void *, size_t); struct ns_connection *ns_next(struct ns_mgr *, struct ns_connection *); struct ns_connection *ns_add_sock(struct ns_mgr *, sock_t, ns_event_handler_t); struct ns_connection *ns_bind(struct ns_mgr *, const char *, ns_event_handler_t); struct ns_connection *ns_connect(struct ns_mgr *, const char *, ns_event_handler_t); const char *ns_set_ssl(struct ns_connection *nc, const char *, const char *); int ns_send(struct ns_connection *, const void *buf, int len); int ns_printf(struct ns_connection *, const char *fmt, ...); int ns_vprintf(struct ns_connection *, const char *fmt, va_list ap); /* Utility functions */ void *ns_start_thread(void *(*f)(void *), void *p); int ns_socketpair(sock_t [2]); int ns_socketpair2(sock_t [2], int sock_type); /* SOCK_STREAM or SOCK_DGRAM */ void ns_set_close_on_exec(sock_t); void ns_sock_to_str(sock_t sock, char *buf, size_t len, int flags); int ns_hexdump(const void *buf, int len, char *dst, int dst_len); int ns_avprintf(char **buf, size_t size, const char *fmt, va_list ap); int ns_resolve(const char *domain_name, char *ip_addr_buf, size_t buf_len); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* NS_SKELETON_HEADER_INCLUDED */ /* * Copyright (c) 2004-2013 Sergey Lyubka * Copyright (c) 2013 Cesanta Software Limited * All rights reserved * * This library is dual-licensed: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. For the terms of this * license, see . * * You are free to use this library under the terms of the GNU General * Public License, but WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * Alternatively, you can license this library under a commercial * license, as set out in . */ #ifndef FROZEN_HEADER_INCLUDED #define FROZEN_HEADER_INCLUDED #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #include enum json_type { JSON_TYPE_EOF = 0, /* End of parsed tokens marker */ JSON_TYPE_STRING = 1, JSON_TYPE_NUMBER = 2, JSON_TYPE_OBJECT = 3, JSON_TYPE_TRUE = 4, JSON_TYPE_FALSE = 5, JSON_TYPE_NULL = 6, JSON_TYPE_ARRAY = 7 }; struct json_token { const char *ptr; /* Points to the beginning of the token */ int len; /* Token length */ int num_desc; /* For arrays and object, total number of descendants */ enum json_type type; /* Type of the token, possible values above */ }; /* Error codes */ #define JSON_STRING_INVALID -1 #define JSON_STRING_INCOMPLETE -2 #define JSON_TOKEN_ARRAY_TOO_SMALL -3 int parse_json(const char *json_string, int json_string_length, struct json_token *tokens_array, int size_of_tokens_array); struct json_token *parse_json2(const char *json_string, int string_length); struct json_token *find_json_token(struct json_token *toks, const char *path); int json_emit_long(char *buf, int buf_len, long value); int json_emit_double(char *buf, int buf_len, double value); int json_emit_quoted_str(char *buf, int buf_len, const char *str, int len); int json_emit_unquoted_str(char *buf, int buf_len, const char *str, int len); int json_emit(char *buf, int buf_len, const char *fmt, ...); int json_emit_va(char *buf, int buf_len, const char *fmt, va_list); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* FROZEN_HEADER_INCLUDED */ /* * Copyright (c) 2014 Cesanta Software Limited * All rights reserved */ #if !defined(NS_SHA1_HEADER_INCLUDED) && !defined(NS_DISABLE_SHA1) #define NS_SHA1_HEADER_INCLUDED #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ typedef struct { uint32_t state[5]; uint32_t count[2]; unsigned char buffer[64]; } SHA1_CTX; void SHA1Init(SHA1_CTX *); void SHA1Update(SHA1_CTX *, const unsigned char *data, uint32_t len); void SHA1Final(unsigned char digest[20], SHA1_CTX *); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* NS_SHA1_HEADER_INCLUDED */ /* * Copyright (c) 2014 Cesanta Software Limited * All rights reserved */ #ifndef NS_UTIL_HEADER_DEFINED #define NS_UTIL_HEADER_DEFINED #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #ifndef MAX_PATH_SIZE #define MAX_PATH_SIZE 500 #endif const char *ns_skip(const char *, const char *, const char *, struct ns_str *); int ns_ncasecmp(const char *s1, const char *s2, size_t len); int ns_vcmp(const struct ns_str *str2, const char *str1); int ns_vcasecmp(const struct ns_str *str2, const char *str1); void ns_base64_decode(const unsigned char *s, int len, char *dst); void ns_base64_encode(const unsigned char *src, int src_len, char *dst); int ns_stat(const char *path, ns_stat_t *st); FILE *ns_fopen(const char *path, const char *mode); int ns_open(const char *path, int flag, int mode); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* NS_UTIL_HEADER_DEFINED */ /* * Copyright (c) 2014 Cesanta Software Limited * All rights reserved */ #ifndef NS_HTTP_HEADER_DEFINED #define NS_HTTP_HEADER_DEFINED #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #define NS_MAX_HTTP_HEADERS 40 #define NS_MAX_HTTP_REQUEST_SIZE 8192 #define NS_MAX_PATH 1024 struct http_message { struct ns_str message; /* Whole message: request line + headers + body */ /* HTTP Request line (or HTTP response line) */ struct ns_str method; /* "GET" */ struct ns_str uri; /* "/my_file.html" */ struct ns_str proto; /* "HTTP/1.1" */ /* Headers */ struct ns_str header_names[NS_MAX_HTTP_HEADERS]; struct ns_str header_values[NS_MAX_HTTP_HEADERS]; /* Message body */ struct ns_str body; /* Zero-length for requests with no body */ }; struct websocket_message { unsigned char *data; size_t size; unsigned char flags; }; /* HTTP and websocket events. void *ev_data is described in a comment. */ #define NS_HTTP_REQUEST 100 /* struct http_message * */ #define NS_HTTP_REPLY 101 /* struct http_message * */ #define NS_WEBSOCKET_HANDSHAKE_REQUEST 111 /* NULL */ #define NS_WEBSOCKET_HANDSHAKE_DONE 112 /* NULL */ #define NS_WEBSOCKET_FRAME 113 /* struct websocket_message * */ void ns_set_protocol_http_websocket(struct ns_connection *); void ns_send_websocket_handshake(struct ns_connection *, const char *, const char *); void ns_send_websocket_frame(struct ns_connection *, int, const void *, size_t); void ns_send_websocket_framev(struct ns_connection *, int, const struct ns_str *, int); void ns_printf_websocket_frame(struct ns_connection *, int, const char *, ...); /* Websocket opcodes, from http://tools.ietf.org/html/rfc6455 */ #define WEBSOCKET_OP_CONTINUE 0 #define WEBSOCKET_OP_TEXT 1 #define WEBSOCKET_OP_BINARY 2 #define WEBSOCKET_OP_CLOSE 8 #define WEBSOCKET_OP_PING 9 #define WEBSOCKET_OP_PONG 10 /* Utility functions */ struct ns_str *ns_get_http_header(struct http_message *, const char *); int ns_parse_http(const char *s, int n, struct http_message *req); int ns_get_http_var(const struct ns_str *, const char *, char *dst, size_t); struct ns_serve_http_opts { const char *document_root; }; void ns_serve_http(struct ns_connection *, struct http_message *, struct ns_serve_http_opts); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* NS_HTTP_HEADER_DEFINED */ /* * Copyright (c) 2014 Cesanta Software Limited * All rights reserved */ #ifndef NS_JSON_RPC_HEADER_DEFINED #define NS_JSON_RPC_HEADER_DEFINED #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /* JSON-RPC standard error codes */ #define JSON_RPC_PARSE_ERROR (-32700) #define JSON_RPC_INVALID_REQUEST_ERROR (-32600) #define JSON_RPC_METHOD_NOT_FOUND_ERROR (-32601) #define JSON_RPC_INVALID_PARAMS_ERROR (-32602) #define JSON_RPC_INTERNAL_ERROR (-32603) #define JSON_RPC_SERVER_ERROR (-32000) struct ns_rpc_request { struct json_token *message; /* Whole RPC message */ struct json_token *id; /* Message ID */ struct json_token *method; /* Method name */ struct json_token *params; /* Method params */ }; struct ns_rpc_reply { struct json_token *message; /* Whole RPC message */ struct json_token *id; /* Message ID */ struct json_token *result; /* Remote call result */ }; struct ns_rpc_error { struct json_token *message; /* Whole RPC message */ struct json_token *id; /* Message ID */ struct json_token *error_code; /* error.code */ struct json_token *error_message; /* error.message */ struct json_token *error_data; /* error.data, can be NULL */ }; int ns_rpc_parse_request(const char *buf, int len, struct ns_rpc_request *req); int ns_rpc_parse_reply(const char *buf, int len, struct json_token *toks, int max_toks, struct ns_rpc_reply *, struct ns_rpc_error *); int ns_rpc_create_request(char *, int, const char *method, const char *id, const char *params_fmt, ...); int ns_rpc_create_reply(char *, int, const struct ns_rpc_request *req, const char *result_fmt, ...); int ns_rpc_create_error(char *, int, struct ns_rpc_request *req, int, const char *, const char *, ...); int ns_rpc_create_std_error(char *, int, struct ns_rpc_request *, int code); typedef int (*ns_rpc_handler_t)(char *buf, int len, struct ns_rpc_request *); int ns_rpc_dispatch(const char *buf, int, char *dst, int dst_len, const char **methods, ns_rpc_handler_t *handlers); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* NS_JSON_RPC_HEADER_DEFINED */