diff --git a/examples/server/main.c b/examples/server/main.c index c5800ae..c3298db 100644 --- a/examples/server/main.c +++ b/examples/server/main.c @@ -1,5 +1,4 @@ -#include "../../include/error.h" -#include "../../include/mptp.h" +#include "../../include/all.h" #include #include #include @@ -7,46 +6,28 @@ int main(int argc, char *argv[]) { int ret = EXIT_FAILURE; - if (argc != 3) { - printf("usage: %s \n", argv[0]); + if (argc != 2) { + printf("usage: %s \n", argv[0]); return ret; } - int porti = atoi(argv[2]); - if (porti <= 0 || porti > UINT16_MAX) { - printf("bad port number\n"); - return ret; + lm_ctx_t ctx; + lm_ctx_init(&ctx); + + ctx.debug = true; + + if (!lm_ctx_pool_add(&ctx, "test", NULL)) { + printf("failed to add pool: %s (%d)\n", lm_strerror(), lm_error()); + goto end; } - int sock = lm_mptp_server_listen(argv[1], porti); - if (sock < 0) { - printf("failed to start the server: %s\n", lm_strerror()); - return ret; - } - - lm_mptp_t packet; - struct sockaddr addr; - - while (lm_mptp_server_recv(sock, &packet, &addr)) { - switch (MPTP_FLAGS_TYPE(&packet)) { - case MPTP_C2S_PING: - bzero(&packet, sizeof(packet)); - lm_mptp_packet_init(&packet, false, MPTP_S2C_PONG, true); - - lm_mptp_server_send(sock, &packet, &addr); - break; - - default: - bzero(&packet, sizeof(packet)); - lm_mptp_packet_init(&packet, false, MPTP_S2C_WHAT, true); - - lm_mptp_server_send(sock, &packet, &addr); - break; - } + if(!lm_ctx_pool_serve(&ctx, argv[1])) { + printf("failed to serve the pools: %s (%d)\n", lm_strerror(), lm_error()); + goto end; } ret = EXIT_SUCCESS; end: - lm_mptp_close(sock); + lm_ctx_free(&ctx); return ret; } diff --git a/include/error.h b/include/error.h index 38b1fbb..218f5d3 100644 --- a/include/error.h +++ b/include/error.h @@ -8,24 +8,30 @@ typedef enum lm_error { LM_ERR_URLHostLarge = 4, LM_ERR_URLPathLarge = 5, LM_ERR_URLBadHost = 6, - LM_ERR_URLBadPath = 7, - LM_ERR_URLPortUnknown = 8, - LM_ERR_URLBadPort = 9, - LM_ERR_PoolNoSupport = 10, - LM_ERR_URLEnd = 11, - LM_ERR_MPTPBadVersion = 12, - LM_ERR_MPTPBadCode = 13, - LM_ERR_MPTPBadUrl = 14, - LM_ERR_MPTPHostFail = 15, - LM_ERR_MPTPSocketFail = 16, - LM_ERR_MPTPConnectFail = 17, - LM_ERR_MPTPRecvFail = 18, - LM_ERR_MPTPSendFail = 19, - LM_ERR_MPTPBadChunk = 29, - LM_ERR_MPTPSetsockopt = 30, - LM_ERR_MPTPTimeout = 31, - LM_ERR_MPTPBindFail = 32, - LM_ERR_ArgNULL = 33, + LM_ERR_URLBadPort = 7, + LM_ERR_URLBadPath = 8, + LM_ERR_URLPortUnknown = 9, + LM_ERR_BadPort = 10, + LM_ERR_BadHost = 11, + LM_ERR_PoolNoSupport = 12, + LM_ERR_URLEnd = 13, + LM_ERR_MPTPBadVersion = 14, + LM_ERR_MPTPBadCode = 15, + LM_ERR_MPTPBadUrl = 16, + LM_ERR_MPTPHostFail = 17, + LM_ERR_MPTPSocketFail = 18, + LM_ERR_MPTPConnectFail = 19, + LM_ERR_MPTPRecvFail = 20, + LM_ERR_MPTPSendFail = 21, + LM_ERR_MPTPBadChunk = 22, + LM_ERR_MPTPSetsockopt = 23, + LM_ERR_MPTPTimeout = 24, + LM_ERR_MPTPBindFail = 25, + LM_ERR_ArgNULL = 26, + LM_ERR_MPTPNotResponse = 27, + LM_ERR_MPTPNotRequest = 28, + LM_ERR_MPTPNotLast = 29, + LM_ERR_NoPort = 30, } lm_error_t; typedef struct lm_error_desc { diff --git a/include/mptp.h b/include/mptp.h index 0068c7e..647e794 100644 --- a/include/mptp.h +++ b/include/mptp.h @@ -69,8 +69,7 @@ // clang-format on #define MPTP_VERSION_SUPPORTED 0 -#define MPTP_VERSION_MAX 15 // 4 bits -#define MPTP_CODE_MAX 4 // 2 bits +#define MPTP_CODE_MAX 3 // 2 bits #define MPTP_CHUNK_MAX 256 #define MPTP_TIMEOUT 10 @@ -101,24 +100,25 @@ typedef struct lm_mptp { char data[MPTP_CHUNK_MAX]; } lm_mptp_t; -#define MPTP_FLAGS_VERSION(m) ((m)->header.flags & 0xFF00) >> 8 -#define MPTP_FLAGS_REQUEST(m) ((m)->header.flags & 0x0080) >> 1 -#define MPTP_FLAGS_TYPE(m) ((m)->header.flags & 0x0070) >> 4 -#define MPTP_FLAGS_LAST(m) ((m)->header.flags & 0x0008) >> 3 +#define MPTP_FLAGS_VERSION(m) (((m)->header.flags & 0xFF00) >> 8) +#define MPTP_FLAGS_TYPE(m) (((m)->header.flags & 0x0080) >> 1) +#define MPTP_FLAGS_CODE(m) (((m)->header.flags & 0x0070) >> 4) +#define MPTP_FLAGS_LAST(m) (((m)->header.flags & 0x0008) >> 3) -#define MPTP_IS_REQUEST(m) MPTP_FLAGS_REQUEST(m) == 0 -#define MPTP_IS_LAST(m) MPTP_FLAGS_LAST(m) == 1 +#define MPTP_IS_REQUEST(m) (MPTP_FLAGS_TYPE(m) == 0) +#define MPTP_IS_LAST(m) (MPTP_FLAGS_LAST(m) == 1) bool lm_mptp_packet_init(lm_mptp_t *packet, bool is_request, uint8_t code, bool is_last); int lm_mptp_socket(char *addr, uint16_t port, struct sockaddr *saddr); +bool lm_mptp_verify(lm_mptp_t *packet); void lm_mptp_close(int sock); int lm_mptp_client_connect(char *addr, uint16_t port); -bool lm_mptp_client_verify(int sock, lm_mptp_t *packet); // not implemented +bool lm_mptp_client_verify(lm_mptp_t *packet); bool lm_mptp_client_send(int sock, lm_mptp_t *packet); bool lm_mptp_client_recv(int sock, lm_mptp_t *packet); int lm_mptp_server_listen(char *addr, uint16_t port); -bool lm_mptp_server_verify(int sock, lm_mptp_t *packet, struct sockaddr *addr); // not implemented +bool lm_mptp_server_verify(lm_mptp_t *packet); bool lm_mptp_server_recv(int sock, lm_mptp_t *packet, struct sockaddr *addr); bool lm_mptp_server_send(int sock, lm_mptp_t *packet, struct sockaddr *adrr); diff --git a/include/pool.h b/include/pool.h index 6f8db60..12a945c 100644 --- a/include/pool.h +++ b/include/pool.h @@ -6,3 +6,4 @@ bool lm_ctx_pool_add(lm_ctx_t *ctx, char *name, char *url); bool lm_ctx_pool_del(lm_ctx_t *ctx, char *name); void lm_ctx_pool_clear(lm_ctx_t *ctx); void lm_ctx_pool_test(lm_ctx_t *ctx); +bool lm_ctx_pool_serve(lm_ctx_t *ctx, char *addr); diff --git a/include/url.h b/include/url.h index 8d954db..fd09ea8 100644 --- a/include/url.h +++ b/include/url.h @@ -11,7 +11,8 @@ typedef struct lm_url { char protocol[URL_PROTOCOL_MAX + 1]; char *host; char *path; + bool empty; } lm_url_t; -bool lm_url_parse(lm_url_t *url, char *str); +bool lm_url_init(lm_url_t *url, char *str); void lm_url_free(lm_url_t *url); diff --git a/include/util.h b/include/util.h index 1a8f045..1991209 100644 --- a/include/util.h +++ b/include/util.h @@ -6,6 +6,7 @@ #define _(x) gettext(x) void pdebug(lm_ctx_t *ctx, const char *func, const char *fmt, ...); +bool parse_host(char *addr, char *host, uint16_t *port); bool contains(char *str, char s); bool eq(char *s1, char *s2); bool is_letter(char c); diff --git a/locale/tr/LC_MESSAGES/libmp.po b/locale/tr/LC_MESSAGES/libmp.po index 0fed559..3cbdf0b 100644 --- a/locale/tr/LC_MESSAGES/libmp.po +++ b/locale/tr/LC_MESSAGES/libmp.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-06-22 04:17+0300\n" +"POT-Creation-Date: 2024-06-22 07:00+0300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -47,74 +47,101 @@ msgid "URL does not have a valid hostname" msgstr "URL does not have a valid hostname" #: src/error.c:20 +#, fuzzy +msgid "URL does not have a valid port number" +msgstr "URL does not have a valid hostname" + +#: src/error.c:21 msgid "URL does not have a valid path" msgstr "URL does not have a valid path" -#: src/error.c:21 -msgid "URL does not contain a hostname with a valid port number" +#: src/error.c:22 +#, fuzzy +msgid "hostname does not contain a valid port number" msgstr "URL does not contain a hostname with a valid port number" -#: src/error.c:22 +#: src/error.c:23 +#, fuzzy +msgid "hostname is not valid" +msgstr "URL hostname is too large" + +#: src/error.c:24 msgid "URL protocol port number is unknown" msgstr "URL protocol port number is unknown" -#: src/error.c:23 +#: src/error.c:25 msgid "URL is incomplete" msgstr "URL tamamlanmamış" -#: src/error.c:24 +#: src/error.c:26 msgid "pool does not support the specified protocol" msgstr "pool does not support the specified protocol" -#: src/error.c:25 +#: src/error.c:27 msgid "unsupported MPTP version" msgstr "" -#: src/error.c:26 +#: src/error.c:28 msgid "invalid MPTP request/response code" msgstr "" -#: src/error.c:27 +#: src/error.c:29 msgid "invalid MPTP URL" msgstr "" -#: src/error.c:28 +#: src/error.c:30 msgid "failed to resolve hostname for MPTP connection" msgstr "" -#: src/error.c:29 +#: src/error.c:31 msgid "failed to create a MPTP socket" msgstr "" -#: src/error.c:30 +#: src/error.c:32 msgid "failed to connect to the MPTP host" msgstr "" -#: src/error.c:31 +#: src/error.c:33 msgid "failed receive MPTP data from host" msgstr "" -#: src/error.c:32 +#: src/error.c:34 msgid "failed send MPTP data to host" msgstr "" -#: src/error.c:33 +#: src/error.c:35 #, fuzzy -msgid "MPTP data chunk is too large" +msgid "MPTP data chunk size is invalid" msgstr "URL path is too large" -#: src/error.c:34 +#: src/error.c:36 msgid "failed to set MPTP socket options" msgstr "" -#: src/error.c:35 +#: src/error.c:37 msgid "MPTP connection timed out" msgstr "" -#: src/error.c:36 +#: src/error.c:38 msgid "failed to bind MPTP socket" msgstr "" -#: src/error.c:37 +#: src/error.c:39 msgid "required argument is a NULL pointer" msgstr "" + +#: src/error.c:40 +msgid "not a MPTP request" +msgstr "" + +#: src/error.c:41 +msgid "not a MPTP response" +msgstr "" + +#: src/error.c:42 +msgid "MPTP request last flag is not set" +msgstr "" + +#: src/error.c:43 +msgid "host port not specified" +msgstr "" diff --git a/src/error.c b/src/error.c index 5f90e03..a4c214c 100644 --- a/src/error.c +++ b/src/error.c @@ -17,8 +17,10 @@ char *lm_strerror() { {.code = LM_ERR_URLHostLarge, .desc = _("URL hostname is too large") }, {.code = LM_ERR_URLPathLarge, .desc = _("URL path is too large") }, {.code = LM_ERR_URLBadHost, .desc = _("URL does not have a valid hostname") }, + {.code = LM_ERR_URLBadPort, .desc = _("URL does not have a valid port number") }, {.code = LM_ERR_URLBadPath, .desc = _("URL does not have a valid path") }, - {.code = LM_ERR_URLBadPort, .desc = _("URL does not contain a hostname with a valid port number")}, + {.code = LM_ERR_BadPort, .desc = _("hostname does not contain a valid port number")}, + {.code = LM_ERR_BadHost, .desc = _("hostname is not valid")}, {.code = LM_ERR_URLPortUnknown, .desc = _("URL protocol port number is unknown") }, {.code = LM_ERR_URLEnd, .desc = _("URL is incomplete") }, {.code = LM_ERR_PoolNoSupport, .desc = _("pool does not support the specified protocol") }, @@ -30,11 +32,15 @@ char *lm_strerror() { {.code = LM_ERR_MPTPConnectFail, .desc = _("failed to connect to the MPTP host") }, {.code = LM_ERR_MPTPRecvFail, .desc = _("failed receive MPTP data from host") }, {.code = LM_ERR_MPTPSendFail, .desc = _("failed send MPTP data to host") }, - {.code = LM_ERR_MPTPBadChunk, .desc = _("MPTP data chunk is too large") }, + {.code = LM_ERR_MPTPBadChunk, .desc = _("MPTP data chunk size is invalid") }, {.code = LM_ERR_MPTPSetsockopt, .desc = _("failed to set MPTP socket options") }, {.code = LM_ERR_MPTPTimeout, .desc = _("MPTP connection timed out") }, {.code = LM_ERR_MPTPBindFail, .desc = _("failed to bind MPTP socket") }, {.code = LM_ERR_ArgNULL, .desc = _("required argument is a NULL pointer") }, + {.code = LM_ERR_MPTPNotRequest, .desc = _("not a MPTP request") }, + {.code = LM_ERR_MPTPNotResponse, .desc = _("not a MPTP response") }, + {.code = LM_ERR_MPTPNotLast, .desc = _("MPTP request last flag is not set") }, + {.code = LM_ERR_NoPort, .desc = _("host port not specified") }, }; for (int i = 0; i < sizeof(errors) / sizeof(lm_error_desc_t); i++) { diff --git a/src/mptp.c b/src/mptp.c index 2c1b0b6..a6705ee 100644 --- a/src/mptp.c +++ b/src/mptp.c @@ -27,7 +27,7 @@ bool lm_mptp_packet_init(lm_mptp_t *packet, bool is_request, uint8_t code, bool if (is_request) packet->header.flags |= (MPTP_REQUEST << 7); else - packet->header.flags |= (MPTP_REQUEST << 7); + packet->header.flags |= (MPTP_RESPONSE << 7); packet->header.flags |= (code << 4); @@ -39,6 +39,30 @@ bool lm_mptp_packet_init(lm_mptp_t *packet, bool is_request, uint8_t code, bool return true; } +bool lm_mptp_verify(lm_mptp_t *packet){ + if (NULL == packet) { + lm_error_set(LM_ERR_ArgNULL); + return false; + } + + if (MPTP_FLAGS_VERSION(packet) != MPTP_VERSION_SUPPORTED) { + lm_error_set(LM_ERR_MPTPBadVersion); + return false; + } + + if (packet->header.size > MPTP_CHUNK_MAX || packet->header.size < 0) { + lm_error_set(LM_ERR_MPTPBadChunk); + return false; + } + + if (MPTP_FLAGS_CODE(packet) > MPTP_CODE_MAX || MPTP_FLAGS_CODE(packet) < 0) { + lm_error_set(LM_ERR_MPTPBadCode); + return false; + } + + return true; +} + int lm_mptp_socket(char *addr, uint16_t port, struct sockaddr *saddr) { if (NULL == addr || NULL == saddr) { lm_error_set(LM_ERR_ArgNULL); @@ -129,6 +153,18 @@ int lm_mptp_client_connect(char *addr, uint16_t port) { return sock; } +bool lm_mptp_client_verify(lm_mptp_t *packet) { + if (!lm_mptp_verify(packet)) + return false; + + if (MPTP_IS_REQUEST(packet)) { + lm_error_set(LM_ERR_MPTPNotResponse); + return false; + } + + return true; +} + bool lm_mptp_client_send(int sock, lm_mptp_t *packet) { if (NULL == packet) { lm_error_set(LM_ERR_ArgNULL); @@ -210,6 +246,23 @@ int lm_mptp_server_listen(char *addr, uint16_t port) { return sock; } +bool lm_mptp_server_verify(lm_mptp_t *packet) { + if (!lm_mptp_verify(packet)) + return false; + + if (!MPTP_IS_REQUEST(packet)) { + lm_error_set(LM_ERR_MPTPNotRequest); + return false; + } + + if(!MPTP_IS_LAST(packet)){ + lm_error_set(LM_ERR_MPTPNotLast); + return false; + } + + return true; +} + bool lm_mptp_server_recv(int sock, lm_mptp_t *packet, struct sockaddr *addr) { if (NULL == packet || NULL == addr) { lm_error_set(LM_ERR_ArgNULL); diff --git a/src/pool.c b/src/pool.c index 9316475..e6330be 100644 --- a/src/pool.c +++ b/src/pool.c @@ -2,8 +2,9 @@ #include "../include/error.h" #include "../include/mptp.h" #include "../include/util.h" -#include +#include #include +#include void lm_pool_free(lm_pool_t *pool) { lm_url_free(&pool->url); @@ -12,23 +13,32 @@ void lm_pool_free(lm_pool_t *pool) { lm_pool_t *lm_pool_new(char *name, char *url) { lm_pool_t *pool = malloc(sizeof(lm_pool_t)); - if (!lm_url_parse(&pool->url, url)) { + pool->available = true; + pool->name = name; + + if (!lm_url_init(&pool->url, url)) { free(pool); return NULL; } + if(pool->url.empty) + return pool; + if (!eq(pool->url.protocol, "mptp")) { lm_error_set(LM_ERR_PoolNoSupport); lm_pool_free(pool); return NULL; } - pool->available = true; - pool->name = name; return pool; } void lm_pool_test(lm_pool_t *pool) { + if(pool->url.empty){ + pool->available = false; + return; + } + lm_mptp_t packet; lm_mptp_packet_init(&packet, true, MPTP_C2S_PING, true); @@ -48,7 +58,12 @@ void lm_pool_test(lm_pool_t *pool) { goto end; } - pool->available = MPTP_FLAGS_TYPE(&packet) == MPTP_S2C_PONG; + if (!lm_mptp_client_verify(&packet)){ + pool->available = false; + goto end; + } + + pool->available = MPTP_FLAGS_CODE(&packet) == MPTP_S2C_PONG; end: lm_mptp_close(sock); return; @@ -60,7 +75,8 @@ bool lm_ctx_pool_add(lm_ctx_t *ctx, char *name, char *url) { return false; pdebug(ctx, __func__, "pool name is %s", pool->name); - pdebug(ctx, __func__, "pool URL is %s://%s:%d%s", pool->url.protocol, pool->url.host, pool->url.port, pool->url.path); + if(!pool->url.empty) + pdebug(ctx, __func__, "pool URL is %s://%s:%d%s", pool->url.protocol, pool->url.host, pool->url.port, pool->url.path); if (NULL == ctx->pools) { ctx->pools = pool; @@ -121,3 +137,38 @@ void lm_ctx_pool_test(lm_ctx_t *ctx) { cur = cur->next; } } + +bool lm_ctx_pool_serve(lm_ctx_t *ctx, char *addr) { + struct sockaddr saddr; + char *host = NULL; + lm_mptp_t packet; + uint16_t port; + int sock; + + if(!parse_host(addr, host, &port)) + return false; + + if(port == 0){ + lm_error_set(LM_ERR_NoPort); + return false; + } + + if((sock = lm_mptp_server_listen(addr, port)) < 0) + return false; + + while(lm_mptp_server_recv(sock, &packet, &saddr)){ + if(!lm_mptp_verify(&packet)){ + pdebug(ctx, __func__, "skipping invalid packet: %s", lm_strerror()); + continue; + } + + switch (MPTP_FLAGS_CODE(&packet)) { + case MPTP_C2S_PING: + lm_mptp_packet_init(&packet, false, MPTP_S2C_PONG, true); + lm_mptp_server_send(sock, &packet, &saddr); + break; + } + } + + return true; +} diff --git a/src/url.c b/src/url.c index 05a2109..3f83c2b 100644 --- a/src/url.c +++ b/src/url.c @@ -2,6 +2,7 @@ #include "../include/error.h" #include "../include/util.h" #include +#include #include #include @@ -14,7 +15,7 @@ typedef enum lm_state { URL_PATH_3 = 3, } lm_state_t; -uint16_t lm_url_default(char *protocol) { +uint16_t lm_url_default_port(char *protocol) { if (eq(protocol, "ftp")) return 21; else if (eq(protocol, "ftps")) @@ -28,13 +29,20 @@ uint16_t lm_url_default(char *protocol) { return 0; } -bool lm_url_parse(lm_url_t *url, char *str) { +bool lm_url_init(lm_url_t *url, char *str) { // clear out every variable bzero(url->protocol, sizeof(url->protocol)); + url->empty = true; url->host = NULL; url->path = NULL; url->port = 0; + if(NULL == str) + return true; + + // str is not NULL + url->empty = false; + // stores the string size size_t strl = 0, index = 0, pos = 0; @@ -46,7 +54,7 @@ bool lm_url_parse(lm_url_t *url, char *str) { } lm_state_t state = URL_PROTOCOL_0; - char buffer[strl + 1], *save; // temporary buffer, strok_r save pointer + char buffer[strl + 1]; // temporary buffer, strok_r save pointer bool ret = false; // return value // clear out the temporary buffer @@ -182,30 +190,34 @@ bool lm_url_parse(lm_url_t *url, char *str) { goto end; } - if (strtok_r(url->host, ":", &save) == NULL) { - lm_error_set(LM_ERR_URLBadHost); - goto end; - } - - char *portc = strtok_r(NULL, ":", &save); - if (NULL == portc) { - url->port = lm_url_default(url->protocol); - if (url->port == 0) { + if(parse_host(url->host, url->host, &url->port)){ + if(url->port != 0){ + ret = true; + goto end; + } + + url->port = lm_url_default_port(url->protocol); + if(url->port == 0){ lm_error_set(LM_ERR_URLPortUnknown); goto end; } + ret = true; goto end; } - int port = atoi(portc); - if (port <= 0 || port > UINT16_MAX) { + switch (lm_error()) { + case LM_ERR_BadHost: + lm_error_set(LM_ERR_URLBadHost); + break; + + case LM_ERR_BadPort: lm_error_set(LM_ERR_URLBadPort); - goto end; - } + break; - url->port = port; - ret = true; + default: + break; + } end: if (!ret && NULL != url->host) diff --git a/src/util.c b/src/util.c index be99cd5..1d47a0d 100644 --- a/src/util.c +++ b/src/util.c @@ -1,5 +1,7 @@ #include "../include/util.h" #include "../include/types.h" +#include "../include/error.h" +#include #include #include #include @@ -43,3 +45,27 @@ bool contains(char *str, char s) { return true; return false; } + +bool parse_host(char *addr, char *host, uint16_t *port){ + char *save = NULL, *portc = NULL; + int portint = 0; + + if((host = strtok_r(addr, ":", &save)) == NULL){ + lm_error_set(LM_ERR_BadHost); + return false; + } + + if((portc = strtok_r(NULL, ":", &save)) == NULL){ + *port = 0; + return true; + } + + portint = atoi(portc); + if(portint <= 0 || portint > UINT16_MAX){ + lm_error_set(LM_ERR_BadPort); + return false; + } + + *port = portint; + return true; +}