diff --git a/Makefile b/Makefile index 37f59bb..039c680 100644 --- a/Makefile +++ b/Makefile @@ -15,11 +15,11 @@ VERSION = 24.00 all: dist/libmp.so $(PO_OUTS) -dist/libmp.so: $(OBJS) +dist/libmp.so: $(OBJS) mkdir -p dist $(CC) -shared -o $@ $^ $(LIBS) $(CFLAGS) -dist/%.o: src/%.c +dist/%.o: src/%.c mkdir -p dist $(CC) -c -Wall -fPIC -o $@ $^ $(LIBS) $(CFLAGS) -DVERSION=\"${VERSION}\" diff --git a/examples/pool/main.c b/examples/pool/main.c index 35025d6..69adfd6 100644 --- a/examples/pool/main.c +++ b/examples/pool/main.c @@ -20,6 +20,7 @@ int main(int argc, char *argv[]) { goto end; } + lm_ctx_pool_test(&ctx); ret = EXIT_SUCCESS; end: diff --git a/include/error.h b/include/error.h index 2a136b0..3463c90 100644 --- a/include/error.h +++ b/include/error.h @@ -1,18 +1,29 @@ #pragma once typedef enum lm_error { - LM_ERR_NoError = 0, - LM_ERR_URLBadChar = 1, - LM_ERR_URLBadProtocol = 2, - LM_ERR_URLTooLarge = 3, - 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_NoError = 0, + LM_ERR_URLBadChar = 1, + LM_ERR_URLBadProtocol = 2, + LM_ERR_URLTooLarge = 3, + 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_MPTPChunkFail = 29, + LM_ERR_MPTPSetsockopt = 30, + LM_ERR_MPTPTimeout = 31, } lm_error_t; typedef struct lm_error_desc { diff --git a/include/mptp.h b/include/mptp.h index 6f260fe..97216a1 100644 --- a/include/mptp.h +++ b/include/mptp.h @@ -1,5 +1,6 @@ #pragma once #include "types.h" +#include #include // clang-format off @@ -40,6 +41,7 @@ 4- WHAT: bad request --------------------------------------------------------- 1 bit used to specify if this the last request/response + --------------------------------------------------------- 0- no stay connected, im not done responsing/requesting yet 1- yes, im done, disconnect @@ -64,6 +66,11 @@ #define MPTP_VERSION_SUPPORTED 0 #define MPTP_VERSION_MAX 15 // 4 bits #define MPTP_CODE_MAX 4 // 2 bits +#define MPTP_CHUNK_MAX 4096 +#define MPTP_TIMEOUT 10 + +#define MPTP_REQUEST 0 +#define MPTP_RESPONSE 1 typedef enum lm_mptp_request { MPTP_C2S_PING = 0, @@ -85,13 +92,18 @@ typedef struct lm_mptp { char *data; } lm_mptp_t; -void lm_mptp_flags_set(lm_mptp_t *packet, uint8_t version, bool is_request, uint8_t code, bool is_last); -#define MPTP_FLAGS_VERSION(m) (m->flags >> 4) & 15 -#define MPTP_FLAGS_IS_REQUEST(m) ((m->flags >> 3) & 1) == 0 -#define MPTP_FLAGS_TYPE(m) (m->flags >> 1) & 3 -#define MPTP_FLAGS_IS_LAST(m) (m->flags & 1) == 1 +bool lm_mptp_init(lm_mptp_t *packet, bool is_request, uint8_t code, bool is_last); +#define MPTP_FLAGS_VERSION(m) ((m->flags >> 4) & 15) +#define MPTP_FLAGS_IS_REQUEST(m) (((m->flags >> 3) & 1) == 0) +#define MPTP_FLAGS_TYPE(m) ((m->flags >> 1) & 3) +#define MPTP_FLAGS_IS_LAST(m) ((m->flags & 1) == 1) -int lm_mptp_connect(lm_url_t *url); -bool lm_mptp_recv(int socket, lm_mptp_t *packet); -bool lm_mptp_send(int socket, lm_mptp_t *packet); -void lm_mptp_disconnect(int socket); +int lm_mptp_connect(lm_url_t *url); + +bool lm_mptp_recv(int sock, lm_mptp_t *packet); +bool lm_mptp_recv_data(int sock, char *data, size_t size); + +bool lm_mptp_send(int sock, lm_mptp_t *packet); +bool lm_mptp_send_data(int sock, char *data, size_t size); + +void lm_mptp_disconnect(int sock); diff --git a/locale/tr/LC_MESSAGES/libmp.po b/locale/tr/LC_MESSAGES/libmp.po index e69e884..88c5566 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-20 20:00+0300\n" +"POT-Creation-Date: 2024-06-21 04:42+0300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -65,3 +65,48 @@ msgstr "URL tamamlanmamış" #: src/error.c:24 msgid "pool does not support the specified protocol" msgstr "pool does not support the specified protocol" + +#: src/error.c:25 +msgid "unsupported MPTP version" +msgstr "" + +#: src/error.c:26 +msgid "invalid MPTP request/response code" +msgstr "" + +#: src/error.c:27 +msgid "invalid MPTP URL" +msgstr "" + +#: src/error.c:28 +msgid "failed to resolve hostname for MPTP communication" +msgstr "" + +#: src/error.c:29 +msgid "failed to create a MPTP socket" +msgstr "" + +#: src/error.c:30 +msgid "failed to connect to the MPTP host" +msgstr "" + +#: src/error.c:31 +msgid "failed receive MPTP data from host" +msgstr "" + +#: src/error.c:32 +msgid "failed send MPTP data to host" +msgstr "" + +#: src/error.c:33 +#, fuzzy +msgid "MPTP data chunk is too large" +msgstr "URL path is too large" + +#: src/error.c:34 +msgid "failed to set MPTP socket options" +msgstr "" + +#: src/error.c:35 +msgid "MPTP connection timed out" +msgstr "" diff --git a/src/error.c b/src/error.c index fd95e94..4c48247 100644 --- a/src/error.c +++ b/src/error.c @@ -10,18 +10,29 @@ void lm_error_set(lm_error_t code) { char *lm_strerror() { lm_error_desc_t errors[] = { - {.code = LM_ERR_NoError, .desc = _("no error") }, - {.code = LM_ERR_URLBadChar, .desc = _("URL contains an invalid character") }, - {.code = LM_ERR_URLBadProtocol, .desc = _("URL does not have a valid protocol field") }, - {.code = LM_ERR_URLTooLarge, .desc = _("URL is too large") }, - {.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_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_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") }, + {.code = LM_ERR_NoError, .desc = _("no error") }, + {.code = LM_ERR_URLBadChar, .desc = _("URL contains an invalid character") }, + {.code = LM_ERR_URLBadProtocol, .desc = _("URL does not have a valid protocol field") }, + {.code = LM_ERR_URLTooLarge, .desc = _("URL is too large") }, + {.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_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_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") }, + {.code = LM_ERR_MPTPBadVersion, .desc = _("unsupported MPTP version") }, + {.code = LM_ERR_MPTPBadCode, .desc = _("invalid MPTP request/response code") }, + {.code = LM_ERR_MPTPBadUrl, .desc = _("invalid MPTP URL") }, + {.code = LM_ERR_MPTPHostFail, .desc = _("failed to resolve hostname for MPTP communication") }, + {.code = LM_ERR_MPTPSocketFail, .desc = _("failed to create a MPTP socket") }, + {.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_MPTPChunkFail, .desc = _("MPTP data chunk is too large") }, + {.code = LM_ERR_MPTPSetsockopt, .desc = _("failed to set MPTP socket options") }, + {.code = LM_ERR_MPTPTimeout, .desc = _("MPTP connection timed out") }, }; for (int i = 0; i < sizeof(errors) / sizeof(lm_error_desc_t); i++) { diff --git a/src/mptp.c b/src/mptp.c index e69de29..ed7d0bd 100644 --- a/src/mptp.c +++ b/src/mptp.c @@ -0,0 +1,195 @@ +#include "../include/mptp.h" +#include "../include/error.h" +#include "../include/url.h" +#include +#include +#include +#include +#include +#include +#include + +bool lm_mptp_init(lm_mptp_t *packet, bool is_request, uint8_t code, bool is_last) { + packet->data = NULL; + packet->flags = 0; + packet->size = 0; + + if (code > MPTP_CODE_MAX) { + lm_error_set(LM_ERR_MPTPBadCode); + return false; + } + + // X-X-X-X-0-0-0-0 + packet->flags |= (MPTP_VERSION_SUPPORTED << 4); + + // 0-0-0-0-X-0-0-0 + if (is_request) + packet->flags |= (MPTP_REQUEST << 3); + else + packet->flags |= (MPTP_RESPONSE << 3); + + // 0-0-0-0-0-X-X-0 + packet->flags |= (code << 1); + + // 0-0-0-0-0-0-0-X + if (is_last) + packet->flags |= 1; + else + packet->flags |= 0; + + return true; +} + +int lm_mptp_connect(lm_url_t *url) { + if (NULL == url || NULL == url->host) { + lm_error_set(LM_ERR_MPTPBadUrl); + return -1; + } + + int sock; + struct sockaddr_in addr; + struct hostent *ent = gethostbyname(url->host); + if (NULL == ent) { + lm_error_set(LM_ERR_MPTPHostFail); + return -1; + } + + if (ent->h_addrtype != AF_INET && ent->h_addrtype != AF_INET6) { + lm_error_set(LM_ERR_MPTPHostFail); + return -1; + } + + if (NULL == ent->h_addr_list[0]) { + lm_error_set(LM_ERR_MPTPHostFail); + return -1; + } + + addr.sin_addr.s_addr = *(long *)(ent->h_addr_list[0]); + addr.sin_family = ent->h_addrtype; + addr.sin_port = htons(url->port); + + if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { + lm_error_set(LM_ERR_MPTPSocketFail); + return -1; + } + + struct timeval timeout; + bzero(&timeout, sizeof(timeout)); + + timeout.tv_sec = MPTP_TIMEOUT; + timeout.tv_usec = 0; + + if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout)) < 0) { + lm_mptp_disconnect(sock); + lm_error_set(LM_ERR_MPTPSetsockopt); + return -1; + } + + if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + lm_mptp_disconnect(sock); + lm_error_set(LM_ERR_MPTPConnectFail); + return -1; + } + + return sock; +} + +bool lm_mptp_send(int sock, lm_mptp_t *packet) { + if (MPTP_FLAGS_VERSION(packet) != MPTP_VERSION_SUPPORTED) { + lm_error_set(LM_ERR_MPTPBadVersion); + return false; + } + + size_t size = sizeof(packet->flags) + sizeof(packet->size); + + if (NULL == packet->data || packet->size <= 0) { + if (send(sock, packet, size, 0) < 0) { + lm_error_set(LM_ERR_MPTPSendFail); + return false; + } + return true; + } + + if (send(sock, packet, size, 0) < 0) { + lm_error_set(LM_ERR_MPTPSendFail); + return false; + } + + if (send(sock, packet->data, packet->size, 0) < 0) { + lm_error_set(LM_ERR_MPTPSendFail); + return false; + } + + return true; +} + +bool lm_mptp_send_data(int sock, char *data, size_t size) { + if (size > MPTP_CHUNK_MAX) { + lm_error_set(LM_ERR_MPTPChunkFail); + return false; + } + + if (send(sock, data, size, 0) < 0) { + lm_error_set(LM_ERR_MPTPSendFail); + return false; + } + + return true; +} + +bool lm_mptp_recv(int sock, lm_mptp_t *packet) { + if (recv(sock, &packet->flags, sizeof(packet->flags), 0) < 0) + goto recvfail; + + if (recv(sock, &packet->size, sizeof(packet->size), 0) < 0) + goto recvfail; + + if (MPTP_FLAGS_VERSION(packet) != MPTP_VERSION_SUPPORTED) { + lm_error_set(LM_ERR_MPTPBadVersion); + return false; + } + + if (NULL == packet->data) + return true; + + if (packet->size <= 0) + return true; + + if (packet->size > MPTP_CHUNK_MAX) { + lm_error_set(LM_ERR_MPTPChunkFail); + return false; + } + + if (recv(sock, &packet->data, packet->size, 0) < 0) + goto recvfail; + + return true; + +recvfail: + if (errno == ETIMEDOUT || errno == EAGAIN) + lm_error_set(LM_ERR_MPTPTimeout); + else + lm_error_set(LM_ERR_MPTPRecvFail); + return false; +} + +bool lm_mptp_recv_data(int sock, char *data, size_t size) { + if (size > MPTP_CHUNK_MAX) { + lm_error_set(LM_ERR_MPTPChunkFail); + return false; + } + + if (recv(sock, data, size, 0) < 0) { + if (errno == ETIMEDOUT) + lm_error_set(LM_ERR_MPTPTimeout); + else + lm_error_set(LM_ERR_MPTPRecvFail); + return false; + } + + return true; +} + +void lm_mptp_disconnect(int sock) { + close(sock); +} diff --git a/src/pool.c b/src/pool.c index b8d3a95..3660295 100644 --- a/src/pool.c +++ b/src/pool.c @@ -1,5 +1,6 @@ #include "../include/pool.h" #include "../include/error.h" +#include "../include/mptp.h" #include "../include/util.h" #include #include @@ -22,10 +23,37 @@ lm_pool_t *lm_pool_new(char *name, char *url) { return NULL; } - pool->name = name; + pool->available = true; + pool->name = name; return pool; } +void lm_pool_test(lm_pool_t *pool) { + lm_mptp_t packet; + lm_mptp_init(&packet, true, MPTP_C2S_PING, true); + + int sock = lm_mptp_connect(&pool->url); + if (sock == -1) { + pool->available = false; + return; + } + + if (!lm_mptp_send(sock, &packet)) { + pool->available = false; + goto end; + } + + if (!lm_mptp_recv(sock, &packet)) { + pool->available = false; + goto end; + } + + pool->available = true; +end: + lm_mptp_disconnect(sock); + return; +} + bool lm_ctx_pool_add(lm_ctx_t *ctx, char *name, char *url) { lm_pool_t *pool = lm_pool_new(name, url); if (NULL == pool) @@ -85,5 +113,11 @@ void lm_ctx_pool_clear(lm_ctx_t *ctx) { } void lm_ctx_pool_test(lm_ctx_t *ctx) { - return; + lm_pool_t *cur = ctx->pools; + while (NULL != cur) { + lm_pool_test(cur); + if (!cur->available) + pdebug(ctx, __func__, "%s is not avaliable: %s", cur->name, lm_strerror()); + cur = cur->next; + } }