implement mptp send/receive

This commit is contained in:
ngn 2024-06-21 04:42:51 +03:00
parent e773ff7f09
commit cb66106e50
8 changed files with 347 additions and 38 deletions

View File

@ -20,6 +20,7 @@ int main(int argc, char *argv[]) {
goto end; goto end;
} }
lm_ctx_pool_test(&ctx);
ret = EXIT_SUCCESS; ret = EXIT_SUCCESS;
end: end:

View File

@ -1,18 +1,29 @@
#pragma once #pragma once
typedef enum lm_error { typedef enum lm_error {
LM_ERR_NoError = 0, LM_ERR_NoError = 0,
LM_ERR_URLBadChar = 1, LM_ERR_URLBadChar = 1,
LM_ERR_URLBadProtocol = 2, LM_ERR_URLBadProtocol = 2,
LM_ERR_URLTooLarge = 3, LM_ERR_URLTooLarge = 3,
LM_ERR_URLHostLarge = 4, LM_ERR_URLHostLarge = 4,
LM_ERR_URLPathLarge = 5, LM_ERR_URLPathLarge = 5,
LM_ERR_URLBadHost = 6, LM_ERR_URLBadHost = 6,
LM_ERR_URLBadPath = 7, LM_ERR_URLBadPath = 7,
LM_ERR_URLPortUnknown = 8, LM_ERR_URLPortUnknown = 8,
LM_ERR_URLBadPort = 9, LM_ERR_URLBadPort = 9,
LM_ERR_PoolNoSupport = 10, LM_ERR_PoolNoSupport = 10,
LM_ERR_URLEnd = 11, 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; } lm_error_t;
typedef struct lm_error_desc { typedef struct lm_error_desc {

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include "types.h" #include "types.h"
#include <stddef.h>
#include <stdint.h> #include <stdint.h>
// clang-format off // clang-format off
@ -40,6 +41,7 @@
4- WHAT: bad request 4- WHAT: bad request
--------------------------------------------------------- ---------------------------------------------------------
1 bit used to specify if this the last request/response 1 bit used to specify if this the last request/response
---------------------------------------------------------
0- no stay connected, im not done responsing/requesting yet 0- no stay connected, im not done responsing/requesting yet
1- yes, im done, disconnect 1- yes, im done, disconnect
@ -64,6 +66,11 @@
#define MPTP_VERSION_SUPPORTED 0 #define MPTP_VERSION_SUPPORTED 0
#define MPTP_VERSION_MAX 15 // 4 bits #define MPTP_VERSION_MAX 15 // 4 bits
#define MPTP_CODE_MAX 4 // 2 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 { typedef enum lm_mptp_request {
MPTP_C2S_PING = 0, MPTP_C2S_PING = 0,
@ -85,13 +92,18 @@ typedef struct lm_mptp {
char *data; char *data;
} lm_mptp_t; } lm_mptp_t;
void lm_mptp_flags_set(lm_mptp_t *packet, uint8_t version, bool is_request, uint8_t code, bool is_last); 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_VERSION(m) ((m->flags >> 4) & 15)
#define MPTP_FLAGS_IS_REQUEST(m) ((m->flags >> 3) & 1) == 0 #define MPTP_FLAGS_IS_REQUEST(m) (((m->flags >> 3) & 1) == 0)
#define MPTP_FLAGS_TYPE(m) (m->flags >> 1) & 3 #define MPTP_FLAGS_TYPE(m) ((m->flags >> 1) & 3)
#define MPTP_FLAGS_IS_LAST(m) (m->flags & 1) == 1 #define MPTP_FLAGS_IS_LAST(m) ((m->flags & 1) == 1)
int lm_mptp_connect(lm_url_t *url); 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); bool lm_mptp_recv(int sock, lm_mptp_t *packet);
void lm_mptp_disconnect(int socket); 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);

View File

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \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" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -65,3 +65,48 @@ msgstr "URL tamamlanmamış"
#: src/error.c:24 #: src/error.c:24
msgid "pool does not support the specified protocol" msgid "pool does not support the specified protocol"
msgstr "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 ""

View File

@ -10,18 +10,29 @@ void lm_error_set(lm_error_t code) {
char *lm_strerror() { char *lm_strerror() {
lm_error_desc_t errors[] = { lm_error_desc_t errors[] = {
{.code = LM_ERR_NoError, .desc = _("no error") }, {.code = LM_ERR_NoError, .desc = _("no error") },
{.code = LM_ERR_URLBadChar, .desc = _("URL contains an invalid character") }, {.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_URLBadProtocol, .desc = _("URL does not have a valid protocol field") },
{.code = LM_ERR_URLTooLarge, .desc = _("URL is too large") }, {.code = LM_ERR_URLTooLarge, .desc = _("URL is too large") },
{.code = LM_ERR_URLHostLarge, .desc = _("URL hostname 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_URLPathLarge, .desc = _("URL path is too large") },
{.code = LM_ERR_URLBadHost, .desc = _("URL does not have a valid hostname") }, {.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_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_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_URLPortUnknown, .desc = _("URL protocol port number is unknown") },
{.code = LM_ERR_URLEnd, .desc = _("URL is incomplete") }, {.code = LM_ERR_URLEnd, .desc = _("URL is incomplete") },
{.code = LM_ERR_PoolNoSupport, .desc = _("pool does not support the specified protocol") }, {.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++) { for (int i = 0; i < sizeof(errors) / sizeof(lm_error_desc_t); i++) {

View File

@ -0,0 +1,195 @@
#include "../include/mptp.h"
#include "../include/error.h"
#include "../include/url.h"
#include <errno.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/socket.h>
#include <unistd.h>
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);
}

View File

@ -1,5 +1,6 @@
#include "../include/pool.h" #include "../include/pool.h"
#include "../include/error.h" #include "../include/error.h"
#include "../include/mptp.h"
#include "../include/util.h" #include "../include/util.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -22,10 +23,37 @@ lm_pool_t *lm_pool_new(char *name, char *url) {
return NULL; return NULL;
} }
pool->name = name; pool->available = true;
pool->name = name;
return pool; 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) { bool lm_ctx_pool_add(lm_ctx_t *ctx, char *name, char *url) {
lm_pool_t *pool = lm_pool_new(name, url); lm_pool_t *pool = lm_pool_new(name, url);
if (NULL == pool) 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) { 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;
}
} }