From 532c4b5dc77740477c6d5b9deb5b66dc3a985993 Mon Sep 17 00:00:00 2001 From: lohhiiccc <96543753+lohhiiccc@users.noreply.github.com> Date: Sat, 24 Jan 2026 22:33:36 +0100 Subject: [PATCH] feat(error): add ICMP error utilities with tests - Added `icmp_set_error`. - Added `icmp_strerror`. - Added unit tests. --- includes/icmp.h | 47 +++++++++++++++++++++++++ includes/internal/icmp_internal.h | 23 ++++++++++++ src/error/.gitkeep | 0 src/error/set_error.c | 13 +++++++ src/error/strerror.c | 19 ++++++++++ tests/error/.gitkeep | 0 tests/error/test_error.c | 58 +++++++++++++++++++++++++++++++ 7 files changed, 160 insertions(+) create mode 100644 includes/icmp.h create mode 100644 includes/internal/icmp_internal.h delete mode 100644 src/error/.gitkeep create mode 100644 src/error/set_error.c create mode 100644 src/error/strerror.c delete mode 100644 tests/error/.gitkeep create mode 100644 tests/error/test_error.c diff --git a/includes/icmp.h b/includes/icmp.h new file mode 100644 index 0000000..edacd73 --- /dev/null +++ b/includes/icmp.h @@ -0,0 +1,47 @@ +#ifndef ICMP_H +#define ICMP_H + +#include +#include +#include +#include + +/* Opaque handle type */ +typedef struct icmp_handle icmp_handle_t; + +/* Reply structure passed to callback */ +typedef struct icmp_reply { + uint8_t type; + uint8_t code; + struct in_addr from; + uint8_t ttl; + struct timespec timestamp; + void *payload; + size_t payload_len; + void *ip_payload; + size_t ip_payload_len; +} icmp_reply_t; + +/* Callback type for received packets */ +typedef void (*icmp_callback_t)(const icmp_reply_t *reply, void *userdata); + +/* Handle lifecycle */ +icmp_handle_t *icmp_create(void); +void icmp_destroy(icmp_handle_t *h); +int icmp_get_fd(const icmp_handle_t *h); + +/* Send functions */ +int icmp_send_raw(icmp_handle_t *h, uint8_t type, uint8_t code, + const void *payload, size_t len, struct in_addr dest, + uint8_t ttl); + +int icmp_send_echo(icmp_handle_t *h, struct in_addr dest, uint16_t id, + uint16_t seq, uint8_t ttl); + +/* Receive function */ +int icmp_process(icmp_handle_t *h, icmp_callback_t cb, void *userdata); + +/* Error handling */ +const char *icmp_strerror(const icmp_handle_t *h); + +#endif /* ICMP_H */ diff --git a/includes/internal/icmp_internal.h b/includes/internal/icmp_internal.h new file mode 100644 index 0000000..7e389b8 --- /dev/null +++ b/includes/internal/icmp_internal.h @@ -0,0 +1,23 @@ +#ifndef ICMP_INTERNAL_H +#define ICMP_INTERNAL_H + +/* Internal handle structure */ +struct icmp_handle { + int fd; + int last_error; + char error_msg[256]; +}; + +/* Error codes */ +#define ICMP_OK 0 +#define ICMP_ERR_PERMISSION -1 +#define ICMP_ERR_SOCKET -2 +#define ICMP_ERR_SEND -3 +#define ICMP_ERR_RECV -4 +#define ICMP_ERR_INVALID -5 +#define ICMP_ERR_ENOMEM -6 + +/* Internal error handling functions */ +void icmp_set_error(struct icmp_handle *h, int code, const char *msg); + +#endif diff --git a/src/error/.gitkeep b/src/error/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/src/error/set_error.c b/src/error/set_error.c new file mode 100644 index 0000000..d40931c --- /dev/null +++ b/src/error/set_error.c @@ -0,0 +1,13 @@ +#include "internal/icmp_internal.h" +#include + +void +icmp_set_error(struct icmp_handle *h, int code, const char *msg) +{ + h->last_error = code; + + if (NULL != msg) + snprintf(h->error_msg, sizeof(h->error_msg), "%s", msg); + else + h->error_msg[0] = '\0'; +} diff --git a/src/error/strerror.c b/src/error/strerror.c new file mode 100644 index 0000000..5bf3b12 --- /dev/null +++ b/src/error/strerror.c @@ -0,0 +1,19 @@ +#include "icmp.h" +#include "internal/icmp_internal.h" + +const char * +icmp_strerror(const icmp_handle_t *h) +{ + const struct icmp_handle *handle = (const struct icmp_handle *)h; + + if (NULL == handle) + return "Invalid handle"; + + if (ICMP_OK == handle->last_error) + return "No error"; + + if ('\0' == handle->error_msg[0]) + return "Unknown error"; + + return handle->error_msg; +} diff --git a/tests/error/.gitkeep b/tests/error/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/tests/error/test_error.c b/tests/error/test_error.c new file mode 100644 index 0000000..85f3511 --- /dev/null +++ b/tests/error/test_error.c @@ -0,0 +1,58 @@ +#include +#include +#include "internal/icmp_internal.h" +#include "icmp.h" + +/* Test 1: set_error sets code and message */ +Test(error, set_error_basic) +{ + struct icmp_handle h = {0}; + + icmp_set_error(&h, ICMP_ERR_SOCKET, "Test error message"); + + cr_assert_eq(h.last_error, ICMP_ERR_SOCKET); + cr_assert_str_eq(h.error_msg, "Test error message"); +} + +/* Test 3: set_error with NULL message clears error_msg */ +Test(error, set_error_null_message) +{ + struct icmp_handle h = {0}; + strcpy(h.error_msg, "Old error"); + + icmp_set_error(&h, ICMP_ERR_SEND, NULL); + + cr_assert_eq(h.last_error, ICMP_ERR_SEND); + cr_assert_eq(h.error_msg[0], '\0'); +} + +/* Test 4: strerror returns message from handle */ +Test(error, strerror_returns_message) +{ + struct icmp_handle h = {0}; + h.last_error = ICMP_ERR_PERMISSION; + strcpy(h.error_msg, "Permission denied"); + + const char *msg = icmp_strerror((icmp_handle_t *)&h); + + cr_assert_str_eq(msg, "Permission denied"); +} + +/* Test 5: strerror with NULL handle */ +Test(error, strerror_null_handle) +{ + const char *msg = icmp_strerror(NULL); + + cr_assert_str_eq(msg, "Invalid handle"); +} + +/* Test 6: strerror with ICMP_OK */ +Test(error, strerror_no_error) +{ + struct icmp_handle h = {0}; + h.last_error = ICMP_OK; + + const char *msg = icmp_strerror((icmp_handle_t *)&h); + + cr_assert_str_eq(msg, "No error"); +}