simpler socket api. Now the blocking of functions and error codes aren't function parameters but attributes of the socket object with their respective getters and setters

This commit is contained in:
cozis
2023-11-01 21:33:49 +01:00
parent e6dbeafcd7
commit c3f4a52b6d
6 changed files with 322 additions and 304 deletions
+10 -8
View File
@@ -3,7 +3,6 @@
int main(void)
{
microtcp_errcode_t err;
microtcp_t *mtcp = microtcp_create("10.0.0.5", "10.0.0.4", NULL, NULL);
if (mtcp == NULL) {
fprintf(stderr, "Error: Couldn't create MicroTCP instance\n");
@@ -11,24 +10,27 @@ int main(void)
}
uint16_t port = 8081;
microtcp_socket_t *server = microtcp_open(mtcp, port, &err);
microtcp_socket_t *server = microtcp_open(mtcp, port);
if (server == NULL) {
fprintf(stderr, "Error: %s\n", microtcp_strerror(err));
fprintf(stderr, "Error: %s\n", microtcp_strerror(microtcp_get_error(mtcp)));
microtcp_destroy(mtcp);
return -1;
}
while (1) {
microtcp_socket_t *client = microtcp_accept(server, false, &err);
microtcp_socket_t *client = microtcp_accept(server);
if (client == NULL) {
fprintf(stderr, "Error: %s\n", microtcp_strerror(err));
fprintf(stderr, "Error: %s\n", microtcp_strerror(microtcp_get_socket_error(server)));
break;
}
char buffer[1024];
size_t num = microtcp_recv(client, buffer, sizeof(buffer), false, NULL);
microtcp_send(client, "echo: ", 6, false, NULL);
microtcp_send(client, buffer, num, false, NULL);
int num = microtcp_recv(client, buffer, sizeof(buffer));
if (num > 0) {
microtcp_send(client, "echo: ", 6);
microtcp_send(client, buffer, num);
}
microtcp_close(client);
}
+2 -57
View File
@@ -5,8 +5,6 @@
#include <tuntap.h>
#include "xhttp.h"
static xh_handle handle;
static void callback(xh_request *req, xh_response *res, void *userp)
{
(void) req;
@@ -16,63 +14,10 @@ static void callback(xh_request *req, xh_response *res, void *userp)
res->body.str = "Hello, world!";
xh_header_add(res, "Content-Type", "text/plain");
}
/*
static void handle_sigterm(int signum)
{
(void) signum;
xh_quit(handle);
}
*/
int main(void)
{
/*
signal(SIGTERM, handle_sigterm);
signal(SIGINT, handle_sigterm);
#ifndef _WIN32
signal(SIGQUIT, handle_sigterm);
#endif
*/
char ip[] = "10.0.0.4";
char mac[] = "00:01:00:01:00:00";
struct device *dev = tuntap_init();
if (!dev) {
fprintf(stderr, "Error: Couldn't initialize the TAP library\n");
return -1;
}
// This must be set AFTER tuntap_init because
// it sets the callback function to the default
// callback which writes to stderr.
//tuntap_log_set_cb(NULL);
int netmask = 24; // TODO: Make this configurable
if (tuntap_start(dev, TUNTAP_MODE_ETHERNET, TUNTAP_ID_ANY)) {
fprintf(stderr, "Error: Couldn't set up the TAP device\n");
tuntap_release(dev);
return -1;
}
tuntap_set_ip(dev, "10.0.0.5", netmask);
tuntap_set_hwaddr(dev, mac);
if (tuntap_up(dev)) {
fprintf(stderr, "Error: Couldn't activate the TAP device\n");
tuntap_release(dev);
}
microhttp_config_t config = {
.userp = dev,
.ip = ip,
.mac = mac,
.recv_frame = (int(*)(void*, void*, size_t)) tuntap_read,
.send_frame = (int(*)(void*, const void*, size_t)) tuntap_write,
};
const char *error = xhttp(80, callback, NULL, &handle, config);
tuntap_release(dev);
const char *error = xhttp(80, callback, NULL);
if(error != NULL) {
fprintf(stderr, "Error: %s\n", error);
return 1;
+31 -46
View File
@@ -512,11 +512,9 @@ static void req_deinit(xh_request *req)
static conn_t *accept_connection(context_t *ctx)
{
microtcp_errcode_t errcode;
microtcp_socket_t *accepted_sock = microtcp_accept(ctx->sock, true, &errcode);
if(accepted_sock == NULL)
return NULL; // Failed to accept.
microtcp_socket_t *accepted_sock = microtcp_accept(ctx->sock);
if(accepted_sock == NULL) return NULL;
microtcp_set_blocking(accepted_sock, false);
if(ctx->freelist == NULL)
{
@@ -953,11 +951,12 @@ static bool upload(conn_t *conn)
while(sent < total)
{
microtcp_errcode_t errcode;
size_t n = microtcp_send(conn->sock, conn->out.data + sent, total - sent, true, &errcode);
if(n == 0)
int n = microtcp_send(conn->sock, conn->out.data + sent, total - sent);
if(n <= 0)
{
microtcp_errcode_t errcode = microtcp_get_socket_error(conn->sock);
microtcp_clear_socket_error(conn->sock);
if (errcode == MICROTCP_ERRCODE_WOULDBLOCK)
break;
@@ -1254,26 +1253,24 @@ static void when_data_is_ready_to_be_read(context_t *ctx, conn_t *conn)
assert(b->size > b->used);
microtcp_errcode_t errcode;
size_t n = microtcp_recv(conn->sock, b->data + b->used, b->size - b->used, true, &errcode);
if(n == 0)
{
// Peer disconnected or an error occurred
if(errcode == MICROTCP_ERRCODE_WOULDBLOCK)
break; // Done downloading.
if (errcode != MICROTCP_ERRCODE_NONE)
{
#ifdef DEBUG
fprintf(stderr, "XHTTP :: %s\n", microtcp_strerror(errcode));
#endif
// An error occurred.
int n = microtcp_recv(conn->sock, b->data + b->used, b->size - b->used);
if (n == 0) {
// Peer disconnected.
close_connection(ctx, conn);
return;
}
// Peer disconnected.
if(n < 0)
{
microtcp_errcode_t errcode = microtcp_get_socket_error(conn->sock);
microtcp_clear_socket_error(conn->sock);
if(errcode == MICROTCP_ERRCODE_WOULDBLOCK)
break; // Done downloading.
#ifdef DEBUG
fprintf(stderr, "XHTTP :: %s\n", microtcp_strerror(errcode));
#endif
// An error occurred.
close_connection(ctx, conn);
return;
}
@@ -1407,31 +1404,23 @@ void xh_quit(xh_handle handle)
ctx->exiting = 1;
}
static const char *init(context_t *context, unsigned short port,
microhttp_config_t config)
static const char *init(context_t *context, unsigned short port)
{
microtcp_callbacks_t callbacks = {
.data = config.userp,
.free = NULL,
.recv = config.recv_frame,
.send = config.send_frame,
};
microtcp_t *mtcp = microtcp_create_using_callbacks(config.ip, config.mac, callbacks);
microtcp_t *mtcp = microtcp_create("10.0.0.5", "10.0.0.4", NULL, NULL);
if (!mtcp)
return "Failed to initialize TCP";
context->mtcp = mtcp;
microtcp_errcode_t errcode;
context->sock = microtcp_open(mtcp, port, &errcode);
context->sock = microtcp_open(mtcp, port);
if (!context->sock)
return microtcp_strerror(errcode);
return microtcp_strerror(microtcp_get_error(mtcp));
microtcp_set_blocking(context->sock, false);
context->mux = microtcp_mux_create(mtcp);
if (!context->mux)
{
microtcp_close(context->sock);
return microtcp_strerror(errcode);
return "Couldn't craete mux";
}
if (!microtcp_mux_register(context->mux, context->sock, MICROTCP_MUX_ACCEPT, NULL))
@@ -1454,27 +1443,23 @@ static const char *init(context_t *context, unsigned short port,
return NULL;
}
const char *xhttp(unsigned short port, xh_callback callback,
void *userp, xh_handle *handle,
microhttp_config_t config)
const char *xhttp(unsigned short port, xh_callback callback, xh_handle *handle)
{
context_t context;
const char *error = init(&context, port, config);
const char *error = init(&context, port);
if(error != NULL)
return error;
context.callback = callback;
context.userp = userp;
context.userp = NULL;
if(handle)
*handle = &context;
while(!context.exiting)
{
microtcp_step(context.mtcp);
microtcp_muxevent_t ev;
if (!microtcp_mux_wait(context.mux, &ev))
continue;
+1 -4
View File
@@ -58,9 +58,7 @@ typedef struct {
typedef void (*xh_callback)(xh_request*, xh_response*, void*);
const char *xhttp(unsigned short port, xh_callback callback,
void *userp, xh_handle *handle,
microhttp_config_t config);
const char *xhttp(unsigned short port, xh_callback callback, xh_handle *handle);
void xh_quit(xh_handle handle);
void xh_header_add(xh_response *res, const char *name, const char *valfmt, ...);
@@ -71,7 +69,6 @@ _Bool xh_header_cmp(const char *a, const char *b);
int xh_urlcmp(const char *URL, const char *fmt, ...);
int xh_vurlcmp(const char *URL, const char *fmt, va_list va);
#define xh_string_new(s, l) \
((xh_string) { (s), ((int) (l)) < 0 ? (int) strlen(s) : (int) (l) })
+228 -149
View File
@@ -1,6 +1,7 @@
#include <time.h> // time()
#include <time.h>
#include <errno.h>
#include <string.h> // strerror()
#include <limits.h>
#include <string.h>
#include <stdint.h>
#include <stdlib.h>
#include <tuntap.h>
@@ -19,7 +20,6 @@
#define MICROTCP_DEBUG_LOG(...) do {} while (0);
#endif
typedef struct mux_entry_t mux_entry_t;
struct mux_entry_t {
mux_entry_t **mux_prev;
@@ -63,10 +63,12 @@ struct microtcp_socket_t {
microtcp_t *mtcp;
microtcp_socket_t *prev;
microtcp_socket_t *next;
microtcp_errcode_t errcode;
socket_type_t type;
bool block; // If true, operations on this socket will block execution, else they wont
union {
tcp_listener_t *listener;
tcp_connection_t *connection;
tcp_connection_t *conn;
};
union {
@@ -84,6 +86,8 @@ struct microtcp_t {
uint64_t last_update_time_ms;
microtcp_errcode_t errcode;
bool thread_should_stop;
thrd_t thread_id;
mtx_t lock;
@@ -107,10 +111,31 @@ struct microtcp_t {
microtcp_socket_t socket_pool[MICROTCP_MAX_SOCKETS];
};
microtcp_errcode_t microtcp_get_error(microtcp_t *mtcp)
{
return mtcp->errcode;
}
void microtcp_clear_error(microtcp_t *mtcp)
{
mtcp->errcode = MICROTCP_ERRCODE_NONE;
}
microtcp_errcode_t microtcp_get_socket_error(microtcp_socket_t *sock)
{
return sock->errcode;
}
void microtcp_clear_socket_error(microtcp_socket_t *sock)
{
sock->errcode = MICROTCP_ERRCODE_NONE;
}
const char *microtcp_strerror(microtcp_errcode_t errcode)
{
switch (errcode) {
case MICROTCP_ERRCODE_NONE: return "No error occurred";
case MICROTCP_ERRCODE_NOCLEAR: return "Uncleared error";
case MICROTCP_ERRCODE_SOCKETLIMIT: return "Can't create a socket because the socket limit per microtcp instance was reached";
case MICROTCP_ERRCODE_TCPERROR: return "An error occurred at the TCP layer";
case MICROTCP_ERRCODE_BADCONDVAR: return "Condition variable error";
@@ -366,11 +391,17 @@ process_packet(microtcp_t *mtcp, const void *packet, size_t len)
}
}
void microtcp_process_packet(microtcp_t *mtcp, const void *packet, size_t len)
bool microtcp_process_packet(microtcp_t *mtcp, const void *packet, size_t len)
{
if (mtcp->errcode != MICROTCP_ERRCODE_NONE) {
mtcp->errcode = MICROTCP_ERRCODE_NOCLEAR;
return false;
}
mtx_lock(&mtcp->lock);
process_packet(mtcp, packet, len);
mtx_unlock(&mtcp->lock);
return true;
}
static uint64_t get_time_in_ms(void)
@@ -380,8 +411,13 @@ static uint64_t get_time_in_ms(void)
return t.tv_sec * 1000 + t.tv_nsec / 1000000;
}
void microtcp_step(microtcp_t *mtcp)
bool microtcp_step(microtcp_t *mtcp)
{
if (mtcp->errcode != MICROTCP_ERRCODE_NONE) {
mtcp->errcode = MICROTCP_ERRCODE_NOCLEAR;
return false;
}
char packet[1024]; // This buffer is the bottleneck for the
// maximum packet size that can be processed.
@@ -390,7 +426,7 @@ void microtcp_step(microtcp_t *mtcp)
// threads the ability to progress in the mean time.
int size = mtcp->callbacks.recv(mtcp->callbacks.data, packet, sizeof(packet));
if (size < 0)
return;
return true;
uint64_t current_time_ms = get_time_in_ms();
@@ -408,6 +444,7 @@ void microtcp_step(microtcp_t *mtcp)
}
}
mtx_unlock(&mtcp->lock);
return true;
}
static int loop(void *data)
@@ -438,6 +475,7 @@ microtcp_t *microtcp_create_using_callbacks(const char *ip, const char *mac,
if (mtcp == NULL)
return NULL;
mtcp->errcode = MICROTCP_ERRCODE_NONE;
mtcp->ip = parsed_ip;
mtcp->mac = parsed_mac;
mtcp->callbacks = callbacks;
@@ -665,16 +703,19 @@ static void listener_event_callback(void *data, tcp_listenevent_t event)
signal_events_to_muxes_associated_to_socket(socket, flags);
}
microtcp_socket_t *microtcp_open(microtcp_t *mtcp, uint16_t port,
microtcp_errcode_t *errcode)
microtcp_socket_t *microtcp_open(microtcp_t *mtcp, uint16_t port)
{
microtcp_errcode_t errcode2 = MICROTCP_ERRCODE_NONE;
if (mtcp->errcode != MICROTCP_ERRCODE_NONE) {
mtcp->errcode = MICROTCP_ERRCODE_NOCLEAR;
return NULL;
}
microtcp_socket_t *socket = NULL;
mtx_lock(&mtcp->lock);
{
socket = pop_socket_struct_from_free_list(mtcp);
if (!socket) {
errcode2 = MICROTCP_ERRCODE_SOCKETLIMIT;
mtcp->errcode = MICROTCP_ERRCODE_SOCKETLIMIT;
goto unlock_and_exit; // Socket limit reached
}
@@ -682,7 +723,7 @@ microtcp_socket_t *microtcp_open(microtcp_t *mtcp, uint16_t port,
if (listener == NULL) {
// FIXME: This error code should be more specific,
// but the TCP module isn't stable yet
errcode2 = MICROTCP_ERRCODE_TCPERROR;
mtcp->errcode = MICROTCP_ERRCODE_TCPERROR;
push_unlinked_socket_into_free_list(mtcp, socket);
goto unlock_and_exit;
}
@@ -691,22 +732,22 @@ microtcp_socket_t *microtcp_open(microtcp_t *mtcp, uint16_t port,
socket->prev = NULL;
socket->next = NULL;
socket->type = SOCKET_LISTENER;
socket->block = true;
socket->errcode = MICROTCP_ERRCODE_NONE;
socket->listener = listener;
socket->mux_list = NULL;
if (cnd_init(&socket->something_to_accept) != thrd_success) {
errcode2 = MICROTCP_ERRCODE_BADCONDVAR;
mtcp->errcode = MICROTCP_ERRCODE_BADCONDVAR;
push_unlinked_socket_into_free_list(mtcp, socket);
tcp_listener_destroy(listener);
goto unlock_and_exit;
}
push_unlinked_socket_into_used_list(socket);
}
unlock_and_exit:
mtx_unlock(&mtcp->lock);
if (errcode)
*errcode = errcode2;
return socket;
}
@@ -738,9 +779,9 @@ void microtcp_close(microtcp_socket_t *socket)
break;
case SOCKET_CONNECTION:
if (socket->connection) // Only need to close the connection
if (socket->conn) // Only need to close the connection
// if the peer didn't already.
tcp_connection_destroy(socket->connection);
tcp_connection_destroy(socket->conn);
break;
}
@@ -771,7 +812,7 @@ static void conn_event_callback(void *data, tcp_connevent_t event)
case TCP_CONNEVENT_RESET:
case TCP_CONNEVENT_CLOSE:
socket->connection = NULL;
socket->conn = NULL;
flags = 0; // TODO: Maybe signal closing and reset events to muxes?
break;
}
@@ -779,167 +820,205 @@ static void conn_event_callback(void *data, tcp_connevent_t event)
signal_events_to_muxes_associated_to_socket(socket, flags);
}
microtcp_socket_t *microtcp_accept(microtcp_socket_t *socket,
bool no_block,
microtcp_errcode_t *errcode)
void microtcp_set_blocking(microtcp_socket_t *socket, bool block)
{
microtcp_errcode_t errcode2 = MICROTCP_ERRCODE_NONE;
microtcp_t *mtcp = socket->mtcp;
microtcp_socket_t *socket2 = NULL;
socket->block = block;
}
mtx_lock(&mtcp->lock);
static bool init_conn_socket(microtcp_socket_t *socket,
microtcp_socket_t *parent,
tcp_connection_t *conn)
{
socket->mtcp = parent->mtcp;
socket->prev = NULL;
socket->next = NULL;
socket->type = SOCKET_CONNECTION;
socket->block = true;
socket->conn = conn;
socket->errcode = MICROTCP_ERRCODE_NONE;
socket->mux_list = NULL;
if (cnd_init(&socket->something_to_recv) != thrd_success) {
socket->errcode = MICROTCP_ERRCODE_BADCONDVAR;
return false;
}
if (cnd_init(&socket->something_to_send) != thrd_success) {
socket->errcode = MICROTCP_ERRCODE_BADCONDVAR;
cnd_destroy(&socket->something_to_recv);
return false;
}
return true;
}
static microtcp_socket_t *accept_inner(microtcp_socket_t *socket)
{
microtcp_t *mtcp = socket->mtcp;
if (socket->errcode != MICROTCP_ERRCODE_NONE) {
socket->errcode = MICROTCP_ERRCODE_NOCLEAR;
return NULL;
}
if (socket->type != SOCKET_LISTENER) {
errcode2 = MICROTCP_ERRCODE_NOTLISTENER;
goto unlock_and_exit; // Can't accept from a non-listening socket
socket->errcode = MICROTCP_ERRCODE_NOTLISTENER;
return NULL; // Can't accept from a non-listening socket
}
socket2 = pop_socket_struct_from_free_list(mtcp);
if (!socket2) {
errcode2 = MICROTCP_ERRCODE_SOCKETLIMIT;
goto unlock_and_exit; // Socket limit reached
microtcp_socket_t *accepted = pop_socket_struct_from_free_list(mtcp);
if (!accepted) {
socket->errcode = MICROTCP_ERRCODE_SOCKETLIMIT;
return NULL; // Socket limit reached
}
tcp_connection_t *connection = tcp_listener_accept(socket->listener, socket2, conn_event_callback);
tcp_connection_t *conn = tcp_listener_accept(socket->listener, accepted, conn_event_callback);
if (conn == NULL) {
while (!connection && !no_block) {
if (!socket->block) {
socket->errcode = MICROTCP_ERRCODE_WOULDBLOCK;
return NULL;
}
do {
if (cnd_wait(&socket->something_to_accept, &mtcp->lock) != thrd_success) {
errcode2 = MICROTCP_ERRCODE_BADCONDVAR;
push_unlinked_socket_into_free_list(mtcp, socket2);
goto unlock_and_exit;
socket->errcode = MICROTCP_ERRCODE_BADCONDVAR;
push_unlinked_socket_into_free_list(mtcp, accepted);
return NULL;
}
connection = tcp_listener_accept(socket->listener, socket2, conn_event_callback);
conn = tcp_listener_accept(socket->listener, accepted, conn_event_callback);
} while (!conn);
}
socket2->mtcp = mtcp;
socket2->prev = NULL;
socket2->next = NULL;
socket2->type = SOCKET_CONNECTION;
socket2->connection = connection;
socket2->mux_list = NULL;
if (cnd_init(&socket2->something_to_recv) != thrd_success) {
errcode2 = MICROTCP_ERRCODE_BADCONDVAR;
push_unlinked_socket_into_free_list(mtcp, socket2);
goto unlock_and_exit;
}
if (cnd_init(&socket2->something_to_send) != thrd_success) {
errcode2 = MICROTCP_ERRCODE_BADCONDVAR;
cnd_destroy(&socket2->something_to_recv);
push_unlinked_socket_into_free_list(mtcp, socket2);
goto unlock_and_exit;
if (!init_conn_socket(accepted, socket, conn)) {
push_unlinked_socket_into_free_list(mtcp, accepted);
return NULL;
}
push_unlinked_socket_into_used_list(socket2);
push_unlinked_socket_into_used_list(accepted);
return accepted;
}
unlock_and_exit:
mtx_unlock(&mtcp->lock);
if (errcode)
*errcode = errcode2;
return socket2;
}
size_t microtcp_recv(microtcp_socket_t *socket,
void *dst, size_t len,
bool no_block,
microtcp_errcode_t *errcode)
microtcp_socket_t *microtcp_accept(microtcp_socket_t *socket)
{
if (!socket || socket->type != SOCKET_CONNECTION) {
if (errcode)
*errcode = MICROTCP_ERRCODE_NOTCONNECTION;
return 0;
}
if (socket->connection == NULL) {
if (errcode)
*errcode = MICROTCP_ERRCODE_PEERCLOSED;
return 0;
}
size_t num;
if (!socket)
return NULL;
microtcp_socket_t *accepted;
microtcp_t *mtcp = socket->mtcp;
microtcp_errcode_t errcode2 = MICROTCP_ERRCODE_NONE;
mtx_lock(&mtcp->lock);
{
num = tcp_connection_recv(socket->connection, dst, len);
accepted = accept_inner(socket);
mtx_unlock(&mtcp->lock);
return accepted;
}
while (num == 0 && !no_block) {
static int recv_inner(microtcp_socket_t *socket,
void *dst, size_t len)
{
microtcp_t *mtcp = socket->mtcp;
if (socket->errcode != MICROTCP_ERRCODE_NONE) {
socket->errcode = MICROTCP_ERRCODE_NOCLEAR;
return -1;
}
if (socket->type != SOCKET_CONNECTION) {
socket->errcode = MICROTCP_ERRCODE_NOTCONNECTION;
return -1;
}
if (socket->conn == NULL)
return 0;
// Don't read more bytes than the maximum number
// representable by an "int" to not overflow the
// return value.
if (len > (size_t) INT_MAX) len = INT_MAX;
size_t num = tcp_connection_recv(socket->conn, dst, len);
if (num == 0) {
if (!socket->block) {
socket->errcode = MICROTCP_ERRCODE_WOULDBLOCK;
return -1;
}
do {
if (cnd_wait(&socket->something_to_recv, &mtcp->lock) != thrd_success) {
errcode2 = MICROTCP_ERRCODE_BADCONDVAR;
goto unlock_and_exit;
socket->errcode = MICROTCP_ERRCODE_BADCONDVAR;
return -1;
}
num = tcp_connection_recv(socket->connection, dst, len);
num = tcp_connection_recv(socket->conn, dst, len);
} while (num == 0);
}
if (num == 0) {
if (no_block)
errcode2 = MICROTCP_ERRCODE_WOULDBLOCK;
else
errcode2 = MICROTCP_ERRCODE_CANTBLOCK;
}
assert(num <= INT_MAX);
return (int) num;
}
goto unlock_and_exit; // Warning
unlock_and_exit:
mtx_unlock(&mtcp->lock);
if (errcode)
*errcode = errcode2;
return num;
}
size_t microtcp_send(microtcp_socket_t *socket,
const void *src, size_t len,
bool no_block,
microtcp_errcode_t *errcode)
int microtcp_recv(microtcp_socket_t *socket,
void *dst, size_t len)
{
if (!socket || socket->type != SOCKET_CONNECTION) {
if (errcode)
*errcode = MICROTCP_ERRCODE_NOTCONNECTION;
return 0;
}
if (socket->connection == NULL) {
if (errcode)
*errcode = MICROTCP_ERRCODE_PEERCLOSED;
return 0;
}
size_t num;
if (!socket)
return -1;
int res;
microtcp_t *mtcp = socket->mtcp;
microtcp_errcode_t errcode2 = MICROTCP_ERRCODE_NONE;
mtx_lock(&mtcp->lock);
{
num = tcp_connection_send(socket->connection, src, len);
while (num == 0 && !no_block) {
if (cnd_wait(&socket->something_to_send, &mtcp->lock) != thrd_success) {
errcode2 = MICROTCP_ERRCODE_BADCONDVAR;
goto unlock_and_exit;
}
num = tcp_connection_send(socket->connection, src, len);
}
if (num == 0) {
if (no_block)
errcode2 = MICROTCP_ERRCODE_WOULDBLOCK;
else
errcode2 = MICROTCP_ERRCODE_CANTBLOCK;
}
}
goto unlock_and_exit; // Warning
unlock_and_exit:
res = recv_inner(socket, dst, len);
mtx_unlock(&mtcp->lock);
return res;
}
if (errcode)
*errcode = errcode2;
return num;
static int send_inner(microtcp_socket_t *socket,
const void *src, size_t len)
{
microtcp_t *mtcp = socket->mtcp;
if (socket->type != SOCKET_CONNECTION) {
socket->errcode = MICROTCP_ERRCODE_NOTCONNECTION;
return -1;
}
if (socket->conn == NULL)
return 0;
// As for "recv", never send a number of bytes
// bigger than what can be represented by the
// return value.
if (len > INT_MAX) len = INT_MAX;
size_t num = tcp_connection_send(socket->conn, src, len);
if (num == 0) {
if (!socket->block) {
socket->errcode = MICROTCP_ERRCODE_WOULDBLOCK;
return -1;
}
do {
if (cnd_wait(&socket->something_to_send, &mtcp->lock) != thrd_success) {
socket->errcode = MICROTCP_ERRCODE_BADCONDVAR;
return -1;
}
num = tcp_connection_send(socket->conn, src, len);
} while (num == 0);
}
assert(num <= INT_MAX);
return (int) num;
}
int microtcp_send(microtcp_socket_t *socket,
const void *src, size_t len)
{
if (!socket)
return -1;
int res;
microtcp_t *mtcp = socket->mtcp;
mtx_lock(&mtcp->lock);
res = send_inner(socket, src, len);
mtx_unlock(&mtcp->lock);
return res;
}
microtcp_mux_t *microtcp_mux_create(microtcp_t *mtcp)
+20 -10
View File
@@ -17,6 +17,8 @@ typedef enum {
MICROTCP_ERRCODE_NONE = 0,
MICROTCP_ERRCODE_NOCLEAR,
// Returned by microtcp_open and microtcp_accept
MICROTCP_ERRCODE_SOCKETLIMIT,
@@ -48,22 +50,30 @@ typedef struct {
bool microtcp_callbacks_create_for_tap(const char *ip, const char *mac, microtcp_callbacks_t *callbacks);
microtcp_t *microtcp_create(const char *tap_ip, const char *stack_ip, const char *tap_mac, const char *stack_mac);
microtcp_t *microtcp_create_using_callbacks(const char *ip, const char *mac, microtcp_callbacks_t callbacks);
void microtcp_destroy(microtcp_t *mtcp);
microtcp_errcode_t microtcp_get_error(microtcp_t *mtcp);
void microtcp_clear_error(microtcp_t *mtcp);
microtcp_errcode_t microtcp_get_socket_error(microtcp_socket_t *sock);
void microtcp_clear_socket_error(microtcp_socket_t *sock);
const char *microtcp_strerror(microtcp_errcode_t errcode);
microtcp_socket_t *microtcp_open(microtcp_t *mtcp, uint16_t port, microtcp_errcode_t *errcode);
microtcp_socket_t *microtcp_accept(microtcp_socket_t *socket, bool no_block, microtcp_errcode_t *errcode);
microtcp_socket_t *microtcp_open(microtcp_t *mtcp, uint16_t port);
microtcp_socket_t *microtcp_accept(microtcp_socket_t *socket);
void microtcp_close(microtcp_socket_t *socket);
size_t microtcp_send(microtcp_socket_t *socket, const void *src, size_t len, bool no_block, microtcp_errcode_t *errcode);
size_t microtcp_recv(microtcp_socket_t *socket, void *dst, size_t len, bool no_block, microtcp_errcode_t *errcode);
void microtcp_step(microtcp_t *mtcp);
void microtcp_process_packet(microtcp_t *mtcp, const void *packet, size_t len);
int microtcp_send(microtcp_socket_t *socket, const void *src, size_t len);
int microtcp_recv(microtcp_socket_t *socket, void *dst, size_t len);
bool microtcp_step(microtcp_t *mtcp);
void microtcp_set_blocking(microtcp_socket_t *socket, bool block);
bool microtcp_process_packet(microtcp_t *mtcp, const void *packet, size_t len);
typedef enum {
MICROTCP_MUX_ACCEPT = 1,
MICROTCP_MUX_RECV = 2,
MICROTCP_MUX_SEND = 4,
MICROTCP_MUX_ACCEPT = 1 << 0,
MICROTCP_MUX_RECV = 1 << 1,
MICROTCP_MUX_SEND = 1 << 2,
} microtcp_muxeventid_t;
typedef struct {