feat(error): add ICMP error utilities with tests
- Added `icmp_set_error`. - Added `icmp_strerror`. - Added unit tests.
This commit is contained in:
parent
2e509336c7
commit
532c4b5dc7
7 changed files with 160 additions and 0 deletions
47
includes/icmp.h
Normal file
47
includes/icmp.h
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
#ifndef ICMP_H
|
||||
#define ICMP_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <netinet/in.h>
|
||||
#include <time.h>
|
||||
|
||||
/* 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 */
|
||||
23
includes/internal/icmp_internal.h
Normal file
23
includes/internal/icmp_internal.h
Normal file
|
|
@ -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
|
||||
13
src/error/set_error.c
Normal file
13
src/error/set_error.c
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
#include "internal/icmp_internal.h"
|
||||
#include <stdio.h>
|
||||
|
||||
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';
|
||||
}
|
||||
19
src/error/strerror.c
Normal file
19
src/error/strerror.c
Normal file
|
|
@ -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;
|
||||
}
|
||||
58
tests/error/test_error.c
Normal file
58
tests/error/test_error.c
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
#include <criterion/criterion.h>
|
||||
#include <string.h>
|
||||
#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");
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue