diff options
| -rw-r--r-- | src/loop.c | 2 | ||||
| -rw-r--r-- | src/multiplex.c | 63 | ||||
| -rw-r--r-- | src/multiplex.h | 11 | ||||
| -rw-r--r-- | src/packet_cache.c | 28 | ||||
| -rw-r--r-- | src/packet_cache.h | 4 | ||||
| -rw-r--r-- | src/packet_pool.c | 48 | ||||
| -rw-r--r-- | src/packet_pool.h | 6 | ||||
| -rw-r--r-- | src/packet_stream.c | 89 | ||||
| -rw-r--r-- | src/packet_stream.h | 4 | ||||
| -rw-r--r-- | src/rpc.c | 6 | ||||
| -rw-r--r-- | src/socket/socket.h | 3 | ||||
| -rw-r--r-- | src/util/packet.h | 7 | ||||
| -rw-r--r-- | subprojects/libalabaster.wrap | 4 |
13 files changed, 178 insertions, 97 deletions
@@ -25,11 +25,9 @@ s32 nn_event_loop_run_once(struct nn_event_loop *loop) void nn_event_loop_sleep(struct nn_event_loop *loop, nn_os_tstamp delay) { - al_assert(delay >= NNWT_TS_FROM_USEC(1000)); u64 prev = nn_get_timestamp(), now; while (delay >= 0.0) { nn_event_loop_run_once(loop); - nn_thread_sleep(NNWT_TS_FROM_USEC(1000)); now = nn_get_timestamp(); delay -= NNWT_TS_FROM_USEC(now - prev); prev = now; diff --git a/src/multiplex.c b/src/multiplex.c index 0911540..b1db007 100644 --- a/src/multiplex.c +++ b/src/multiplex.c @@ -1,6 +1,7 @@ #define AL_LOG_SECTION "multiplex" //#define AL_LOG_ENABLE_TRACE #include <al/log.h> +#include <al/atomic.h> #include "multiplex.h" @@ -92,25 +93,53 @@ void nn_multiplex_socket_close(struct nn_multiplex_socket *multi) nn_socket_cleanup(&multi->sock); } -static struct nn_multiplex_direct multiplex_direct_global = { 0 }; +static struct nn_multiplex_direct direct_global = { 0 }; void nn_multiplex_direct_init(bool (*connection_callback)(void *, u8, struct nn_packet_stream *), void *userdata) { - multiplex_direct_global.closing_bridge = al_alloc_object(struct nn_packet_stream); - multiplex_direct_global.connection_callback = connection_callback; - multiplex_direct_global.userdata = userdata; + direct_global.connection_callback = connection_callback; + direct_global.userdata = userdata; +} + +static void queue_packet_callback(void *userdata, struct nn_packet_stream *stream, struct nn_packet *packet) +{ + struct nn_multiplex_bridge *bridge = (struct nn_multiplex_bridge *)userdata; + (void)stream; + al_array_push(bridge->queue, packet); } static void direct_connect(struct nn_packet_stream *client, u8 id) { - struct nn_packet_stream *server = al_alloc_object(struct nn_packet_stream); - nn_packet_stream_init(server, NULL, NULL, NULL); - multiplex_direct_global.connection_callback(multiplex_direct_global.userdata, id, server); - server->direct = client; - client->direct = server; - // Explicitly signal connected on the server first. - nn_packet_stream_set_connected(server); + struct nn_multiplex_bridge *bridge = al_alloc_object(struct nn_multiplex_bridge); + bridge->broken = false; + al_array_init(bridge->queue); + bridge->bridge = al_alloc_object(struct nn_packet_stream); + nn_packet_stream_init(bridge->bridge, NULL, NULL, NULL); + // Server-side client, emulates the result of socket_accept(). + struct nn_packet_stream *cl = al_alloc_object(struct nn_packet_stream); + nn_packet_stream_init(cl, NULL, NULL, NULL); + cl->is_direct = true; + client->is_direct = true; + atomic_store(void)(&cl->direct, client, AL_ATOMIC_RELAXED); + atomic_store(void)(&client->direct, cl, AL_ATOMIC_RELAXED); + cl->bridge = bridge; + cl->packet_callback = queue_packet_callback; + cl->userdata = bridge; + // The order of connect client -> global callback -> connect server-side client cannot change. nn_packet_stream_set_connected(client); + direct_global.connection_callback(direct_global.userdata, id, cl); + nn_packet_stream_set_connected(cl); + // Resend any packets that might have been sent in client->connection_callback(). + struct nn_packet *packet; + al_array_foreach(bridge->queue, i, packet) { + al_assert(cl->packet_callback != queue_packet_callback); + cl->packet_callback(cl->userdata, cl, packet); + if (bridge->broken) break; + } + bridge->queue.count = 0; + if (bridge->broken) { + nn_multiplex_bridge_free(bridge); + } } void nn_multiplex_direct_connect(struct nn_packet_stream *client, u8 id) @@ -124,12 +153,10 @@ void nn_multiplex_direct_reconnect(struct nn_packet_stream *client) direct_connect(client, client->id); } -struct nn_packet_stream *nn_multiplex_direct_get_bridge(void) -{ - return multiplex_direct_global.closing_bridge; -} - -void nn_multiplex_direct_close(void) +void nn_multiplex_bridge_free(struct nn_multiplex_bridge *bridge) { - al_free(multiplex_direct_global.closing_bridge); + nn_packet_stream_free(bridge->bridge); + al_free(bridge->bridge); + al_array_free(bridge->queue); + al_free(bridge); } diff --git a/src/multiplex.h b/src/multiplex.h index 946e570..255591a 100644 --- a/src/multiplex.h +++ b/src/multiplex.h @@ -8,11 +8,16 @@ #include "packet_stream.h" struct nn_multiplex_direct { - struct nn_packet_stream *closing_bridge; bool (*connection_callback)(void *, u8 id, struct nn_packet_stream *stream); void *userdata; }; +struct nn_multiplex_bridge { + bool broken; + struct nn_packet_stream *bridge; + array(struct nn_packet *) queue; +}; + struct nn_multiplex_socket; struct nn_multiplex_connection { struct nn_socket sock; @@ -36,5 +41,5 @@ void nn_multiplex_socket_close(struct nn_multiplex_socket *multi); void nn_multiplex_direct_init(bool (*connection_callback)(void *, u8, struct nn_packet_stream *), void *userdata); void nn_multiplex_direct_connect(struct nn_packet_stream *client, u8 id); void nn_multiplex_direct_reconnect(struct nn_packet_stream *client); -struct nn_packet_stream *nn_multiplex_direct_get_bridge(void); -void nn_multiplex_direct_close(void); + +void nn_multiplex_bridge_free(struct nn_multiplex_bridge *bridge); diff --git a/src/packet_cache.c b/src/packet_cache.c index 2e907b3..8398d6c 100644 --- a/src/packet_cache.c +++ b/src/packet_cache.c @@ -10,12 +10,6 @@ void nn_packet_cache_init(struct nn_packet_cache *cache, u32 size) nn_mutex_init(&cache->mutex); } -bool nn_packet_cache_available(struct nn_packet_cache *cache) -{ - nn_mutex_lock(&cache->mutex); - return !cache->disabled; -} - void nn_packet_cache_send_packet(struct nn_packet_cache *cache, struct nn_packet *packet) { al_assert(!cache->disabled); @@ -57,16 +51,6 @@ struct nn_packet *nn_packet_cache_at(struct nn_packet_cache *cache, u32 index) return al_array_at(cache->cache, index); } -void nn_packet_cache_lock(struct nn_packet_cache *cache) -{ - nn_mutex_lock(&cache->mutex); -} - -void nn_packet_cache_unlock(struct nn_packet_cache *cache) -{ - nn_mutex_unlock(&cache->mutex); -} - void nn_packet_cache_disable(struct nn_packet_cache *cache) { nn_mutex_lock(&cache->mutex); @@ -77,6 +61,12 @@ void nn_packet_cache_disable(struct nn_packet_cache *cache) nn_mutex_unlock(&cache->mutex); } +bool nn_packet_cache_disabled(struct nn_packet_cache *cache) +{ + nn_mutex_lock(&cache->mutex); + return cache->disabled; +} + void nn_packet_cache_enable(struct nn_packet_cache *cache) { nn_mutex_lock(&cache->mutex); @@ -84,8 +74,14 @@ void nn_packet_cache_enable(struct nn_packet_cache *cache) nn_mutex_unlock(&cache->mutex); } +void nn_packet_cache_unlock(struct nn_packet_cache *cache) +{ + nn_mutex_unlock(&cache->mutex); +} + void nn_packet_cache_free(struct nn_packet_cache *cache) { + al_assert(!cache->cache.count); al_array_free(cache->cache); nn_mutex_destroy(&cache->mutex); nn_cond_destroy(&cache->cond); diff --git a/src/packet_cache.h b/src/packet_cache.h index 5d2535c..833ca23 100644 --- a/src/packet_cache.h +++ b/src/packet_cache.h @@ -14,12 +14,12 @@ struct nn_packet_cache { }; void nn_packet_cache_init(struct nn_packet_cache *cache, u32 size); -bool nn_packet_cache_available(struct nn_packet_cache *cache); void nn_packet_cache_send_packet(struct nn_packet_cache *cache, struct nn_packet *packet); void nn_packet_cache_flush(struct nn_packet_cache *cache); bool nn_packet_cache_wait(struct nn_packet_cache *cache, u32 *count); struct nn_packet *nn_packet_cache_at(struct nn_packet_cache *cache, u32 index); -void nn_packet_cache_unlock(struct nn_packet_cache *cache); void nn_packet_cache_disable(struct nn_packet_cache *cache); +bool nn_packet_cache_disabled(struct nn_packet_cache *cache); void nn_packet_cache_enable(struct nn_packet_cache *cache); +void nn_packet_cache_unlock(struct nn_packet_cache *cache); void nn_packet_cache_free(struct nn_packet_cache *cache); diff --git a/src/packet_pool.c b/src/packet_pool.c index 7d9ac4d..9fcbf18 100644 --- a/src/packet_pool.c +++ b/src/packet_pool.c @@ -2,6 +2,7 @@ static void return_internal(struct nn_packet_pool *pool, struct nn_packet *packet) { + al_assert(!packet->opaque); nn_packet_reset(packet); al_array_push(pool->empty, packet); } @@ -30,21 +31,22 @@ static void signal_callback(struct ev_loop *loop, ev_async *w, s32 revents) pool->sending.count = 0; } -void nn_packet_pool_init(struct nn_packet_pool *pool, u32 size, +void nn_packet_pool_init(struct nn_packet_pool *pool, u32 size, u32 init, struct nn_event_loop *loop, void (*callback)(void *, struct nn_packet *), void *userdata) { pool->loop = loop; - pool->size = size; + pool->size = init; + pool->allowed = size; pool->grow = false; pool->flushing = false; pool->disabled = false; nn_cond_init(&pool->cond); nn_mutex_init(&pool->mutex); al_array_init(pool->ready); - al_array_reserve(pool->ready, size); + al_array_reserve(pool->ready, pool->size); al_array_init(pool->empty); - al_array_reserve(pool->empty, size); - for (u32 i = 0; i < size; i++) { + al_array_reserve(pool->empty, pool->size); + for (u32 i = 0; i < pool->size; i++) { al_array_push(pool->empty, nn_packet_create()); } al_array_init(pool->sending); @@ -59,28 +61,28 @@ struct nn_packet *nn_packet_pool_get(struct nn_packet_pool *pool) { nn_mutex_lock(&pool->mutex); if (!pool->disabled && !pool->empty.count) { - if (pool->grow) { + if (pool->grow || pool->size < pool->allowed) { al_array_push(pool->empty, nn_packet_create()); + pool->size++; } else { nn_cond_wait(&pool->cond, &pool->mutex); } } - if (pool->disabled) { + if (pool->disabled) { // Check disabled after wait(). nn_mutex_unlock(&pool->mutex); return NULL; } + al_assert(pool->empty.count > 0); struct nn_packet *packet = al_array_pop(pool->empty); nn_mutex_unlock(&pool->mutex); return packet; } -void nn_packet_pool_submit(struct nn_packet_pool *pool, struct nn_packet *packet) +bool nn_packet_pool_submit(struct nn_packet_pool *pool, struct nn_packet *packet) { nn_mutex_lock(&pool->mutex); if (pool->disabled) { - return_internal(pool, packet); - nn_mutex_unlock(&pool->mutex); - return; + return false; } al_array_push(pool->ready, packet); bool flush = pool->ready.count >= pool->size / 2; @@ -89,6 +91,7 @@ void nn_packet_pool_submit(struct nn_packet_pool *pool, struct nn_packet *packet ev_async_send(pool->loop->ev, &pool->signal); } nn_mutex_unlock(&pool->mutex); + return true; } void nn_packet_pool_flush(struct nn_packet_pool *pool) @@ -127,22 +130,26 @@ void nn_packet_pool_disable(struct nn_packet_pool *pool) // This makes disable()/enable() required to be called from the loop thread. ev_async_stop(pool->loop->ev, &pool->signal); pool->flushing = false; - struct nn_packet *packet; - al_array_foreach(pool->ready, i, packet) { - nn_packet_reset(packet); - al_array_push(pool->empty, packet); - } - pool->ready.count = 0; if (nn_cond_is_waiting(&pool->cond)) { nn_cond_signal(&pool->cond); } nn_mutex_unlock(&pool->mutex); } +struct nn_packet *nn_packet_pool_pop(struct nn_packet_pool *pool) +{ + al_assert(pool->disabled); + struct nn_packet *packet = NULL; + if (pool->ready.count > 0) { + al_array_pop_at(pool->ready, 0, packet); + } + return packet; +} + void nn_packet_pool_enable(struct nn_packet_pool *pool) { nn_mutex_lock(&pool->mutex); - al_assert(pool->disabled); + al_assert(pool->disabled && !pool->ready.count); pool->disabled = false; ev_async_start(pool->loop->ev, &pool->signal); nn_mutex_unlock(&pool->mutex); @@ -163,12 +170,11 @@ void nn_packet_pool_free(struct nn_packet_pool *pool) } al_array_free(pool->empty); al_array_foreach(pool->ready, i, packet) { + al_assert(!packet->opaque); nn_packet_free(packet); } al_array_free(pool->ready); - al_array_foreach(pool->sending, i, packet) { - nn_packet_free(packet); - } + al_assert(!pool->sending.count); al_array_free(pool->sending); nn_mutex_destroy(&pool->mutex); nn_cond_destroy(&pool->cond); diff --git a/src/packet_pool.h b/src/packet_pool.h index 8e21c12..27e6254 100644 --- a/src/packet_pool.h +++ b/src/packet_pool.h @@ -25,6 +25,7 @@ enum { struct nn_packet_pool { struct nn_event_loop *loop; u32 size; + u32 allowed; bool grow; bool flushing; bool disabled; @@ -38,14 +39,15 @@ struct nn_packet_pool { void *userdata; }; -void nn_packet_pool_init(struct nn_packet_pool *pool, u32 size, +void nn_packet_pool_init(struct nn_packet_pool *pool, u32 size, u32 init, struct nn_event_loop *loop, void (*callback)(void *, struct nn_packet *), void *userdata); struct nn_packet *nn_packet_pool_get(struct nn_packet_pool *pool); -void nn_packet_pool_submit(struct nn_packet_pool *pool, struct nn_packet *packet); +bool nn_packet_pool_submit(struct nn_packet_pool *pool, struct nn_packet *packet); void nn_packet_pool_flush(struct nn_packet_pool *pool); void nn_packet_pool_lock(struct nn_packet_pool *pool); void nn_packet_pool_return(struct nn_packet_pool *pool, struct nn_packet *packet); void nn_packet_pool_unlock(struct nn_packet_pool *pool); void nn_packet_pool_disable(struct nn_packet_pool *pool); +struct nn_packet *nn_packet_pool_pop(struct nn_packet_pool *pool); void nn_packet_pool_enable(struct nn_packet_pool *pool); void nn_packet_pool_free(struct nn_packet_pool *pool); diff --git a/src/packet_stream.c b/src/packet_stream.c index ef53daf..93ce0d2 100644 --- a/src/packet_stream.c +++ b/src/packet_stream.c @@ -1,3 +1,5 @@ +#include <al/atomic.h> + #include "multiplex.h" #include "packet_stream.h" @@ -199,11 +201,13 @@ void nn_packet_stream_init(struct nn_packet_stream *stream, void (*connection_closed_callback)(void *, struct nn_packet_stream *), void *userdata) { init_io_state(stream); + stream->sock.type = NNWT_SOCKET_INVALID; stream->revent.data = stream; stream->wevent.data = stream; ev_init_n(&stream->revent, stream_read_callback); ev_init_n(&stream->wevent, stream_write_callback); - stream->direct = NULL; + stream->is_direct = false; + stream->bridge = NULL; stream->connection_callback = connection_callback; stream->connection_closed_callback = connection_closed_callback; stream->packet_callback = NULL; @@ -252,7 +256,6 @@ static bool do_connect_internal(struct nn_packet_stream *stream, str *addr, u16 s32 fd = nn_socket_get_fd(&stream->sock); ev_io_set(&stream->revent, fd, EV_READ); ev_io_set(&stream->wevent, fd, EV_WRITE); - // Start non-blocking connection. stream->connect = PACKET_STREAM_CONNECTING; start_write_internal(stream); return true; @@ -285,7 +288,7 @@ bool nn_packet_stream_set_connected(struct nn_packet_stream *stream) void nn_packet_stream_cork(struct nn_packet_stream *stream, bool cork) { - if (stream->direct) return; + if (stream->is_direct) return; if (stream->connect == PACKET_STREAM_CONNECTED) { if (cork && !stream->corked) { ev_io_stop(stream->loop->ev, &stream->revent); @@ -298,15 +301,16 @@ void nn_packet_stream_cork(struct nn_packet_stream *stream, bool cork) bool nn_packet_stream_send_packet(struct nn_packet_stream *stream, struct nn_packet *packet) { + if (stream->is_direct) { + stream->packet_dequeued_callback(stream->userdata, packet); + struct nn_packet_stream *direct = atomic_load(void)(&stream->direct, AL_ATOMIC_RELAXED); + direct->packet_callback(direct->userdata, direct, packet); + return true; + } if (stream->connect == PACKET_STREAM_DISCONNECTING) { return false; } al_assert(stream->connect == PACKET_STREAM_CONNECTED); - if (stream->direct) { - struct nn_packet_stream *direct = stream->direct; - direct->packet_callback(direct->userdata, direct, packet); - return true; - } al_array_push(stream->out.queue, packet); if (!stream->out.running) { start_write_internal(stream); @@ -321,8 +325,8 @@ void nn_packet_stream_discard_queue(struct nn_packet_stream *stream) void nn_packet_stream_return_packet(struct nn_packet_stream *stream, struct nn_packet *packet) { - if (stream->direct) { - struct nn_packet_stream *direct = stream->direct; + if (stream->is_direct) { + struct nn_packet_stream *direct = atomic_load(void)(&stream->direct, AL_ATOMIC_RELAXED); direct->packet_sent_callback(direct->userdata, packet); } else { nn_packet_free(packet); @@ -331,44 +335,77 @@ void nn_packet_stream_return_packet(struct nn_packet_stream *stream, struct nn_p void nn_packet_stream_return_packets(struct nn_packet_stream *stream, struct nn_packet **packets, u32 count) { - if (stream->direct) { - struct nn_packet_stream *direct = stream->direct; + if (stream->is_direct) { + struct nn_packet_stream *direct = atomic_load(void)(&stream->direct, AL_ATOMIC_RELAXED); if (direct->packets_sent_callback) { direct->packets_sent_callback(direct->userdata, packets, count); } else { for (u32 i = 0; i < count; i++) { - if (packets[i]) { - direct->packet_sent_callback(direct->userdata, packets[i]); - } + direct->packet_sent_callback(direct->userdata, packets[i]); } } } else { for (u32 i = 0; i < count; i++) { - if (packets[i]) nn_packet_free(packets[i]); + nn_packet_free(packets[i]); } } } +static void bridge_packet_callback(void *userdata, struct nn_packet_stream *stream, struct nn_packet *packet) +{ + (void)userdata; + al_assert(stream->is_direct); + struct nn_packet_stream *direct = stream->direct; + direct->packet_sent_callback(direct->userdata, packet); +} + +static inline void install_bridge(struct nn_packet_stream *stream, struct nn_packet_stream *direct, struct nn_packet_stream *bridge) +{ + bridge->is_direct = true; + bridge->direct = stream; + // Update all callbacks that could happen post-connection because + // direct->connection_closed_callback() could run the event loop after + // we update stream->direct to bridge. + bridge->packet_callback = bridge_packet_callback; + bridge->packet_dequeued_callback = direct->packet_dequeued_callback; + bridge->packet_sent_callback = direct->packet_sent_callback; + bridge->packets_sent_callback = direct->packets_sent_callback; + bridge->userdata = direct->userdata; + // nn_packet_stream_return_packet() needs to be thread-safe. Non-atomically updating + // the value of stream->direct here would break that. + atomic_store(void)(&stream->direct, bridge, AL_ATOMIC_RELEASE); +} + void nn_packet_stream_disconnect(struct nn_packet_stream *stream) { al_assert(stream->connect != PACKET_STREAM_DISCONNECTED); al_assert(stream->connect != PACKET_STREAM_DISCONNECTING); - if (stream->direct) { - struct nn_packet_stream *direct = stream->direct; + if (stream->is_direct) { + struct nn_packet_stream *direct = atomic_load(void)(&stream->direct, AL_ATOMIC_ACQUIRE); + // After direct->connection_closed_callback(), direct could be freed. + // So use the bridge to finish the disconnect() on this side of the stream. + struct nn_multiplex_bridge *bridge = NULL; + if (stream->bridge) { + bridge = stream->bridge; + stream->bridge = NULL; + } else if (direct->bridge) { + bridge = direct->bridge; + direct->bridge = NULL; + } + if (!bridge) { + return; // Disconnect already in progress. + } direct->connect = PACKET_STREAM_DISCONNECTED; stream->connect = PACKET_STREAM_DISCONNECTED; direct->corked = true; stream->corked = true; - struct nn_packet_stream *bridge = nn_multiplex_direct_get_bridge(); - bridge->connection_callback = NULL; - bridge->connection_closed_callback = NULL; - bridge->packet_dequeued_callback = direct->packet_dequeued_callback; - bridge->packet_sent_callback = direct->packet_sent_callback; - bridge->packets_sent_callback = direct->packets_sent_callback; - bridge->userdata = direct->userdata; + install_bridge(stream, direct, bridge->bridge); direct->connection_closed_callback(direct->userdata, direct); - stream->direct = bridge; stream->connection_closed_callback(stream->userdata, stream); + bridge->broken = true; // See multiplex.c:direct_connect(). + if (!bridge->queue.count) { + nn_multiplex_bridge_free(bridge); + } return; } if (stream->connect == PACKET_STREAM_CONNECTING) { diff --git a/src/packet_stream.h b/src/packet_stream.h index 623f61f..aa9b1a7 100644 --- a/src/packet_stream.h +++ b/src/packet_stream.h @@ -12,7 +12,7 @@ struct nn_packet_stream { struct nn_socket sock; ev_io revent; ev_io wevent; - u8 id; // multiplex + u8 id; u8 connect; bool corked; struct { @@ -26,7 +26,9 @@ struct nn_packet_stream { size_t index; bool running; } out; + bool is_direct; struct nn_packet_stream *direct; + void *bridge; bool (*connection_callback)(void *, struct nn_packet_stream *); void (*connection_closed_callback)(void *, struct nn_packet_stream *); void (*packet_callback)(void *, struct nn_packet_stream *, struct nn_packet *); @@ -320,9 +320,9 @@ void nn_rpc_add_stream(struct nn_rpc *rpc, struct nn_packet_stream *stream) struct nn_rpc_connection *conn = al_alloc_object(struct nn_rpc_connection); init_rpc_connection(rpc, conn); conn->stream = stream; - conn->stream->connection_callback = stream_connection_callback; - conn->stream->connection_closed_callback = stream_connection_closed_callback; - conn->stream->userdata = conn; + stream->connection_callback = stream_connection_callback; + stream->connection_closed_callback = stream_connection_closed_callback; + stream->userdata = conn; } void nn_rpc_prepare_client(struct nn_rpc *rpc) diff --git a/src/socket/socket.h b/src/socket/socket.h index 31f23f3..b3f2d98 100644 --- a/src/socket/socket.h +++ b/src/socket/socket.h @@ -13,7 +13,8 @@ #endif enum { - NNWT_SOCKET_TCP = 0, + NNWT_SOCKET_INVALID = 0, + NNWT_SOCKET_TCP, NNWT_SOCKET_UDP, NNWT_SOCKET_UNIX }; diff --git a/src/util/packet.h b/src/util/packet.h index c8d9400..a649ff2 100644 --- a/src/util/packet.h +++ b/src/util/packet.h @@ -39,6 +39,13 @@ static inline u32 nn_packet_get_u32(struct nn_packet *packet, u32 index) return value; } +static inline u8 nn_packet_get_u8(struct nn_packet *packet, u32 index) +{ + u8 value; + NNWT_BUFFER_READ_TYPE(&packet->buffer, index, u8, value); + return value; +} + struct nn_packet *nn_packet_create(void); struct nn_packet *nn_packet_clone(struct nn_packet *packet); void nn_packet_reset(struct nn_packet *packet); diff --git a/subprojects/libalabaster.wrap b/subprojects/libalabaster.wrap index 7b8a7bf..432a813 100644 --- a/subprojects/libalabaster.wrap +++ b/subprojects/libalabaster.wrap @@ -1,5 +1,5 @@ [wrap-git] -directory = libalabaster-81a7b4b +directory = libalabaster-8386718 url = https://git.akon.city/libalabaster.git -revision = 81a7b4ba322aeddf52207fdcd2213e5f5a493471 +revision = 8386718d2b7e5af4e74544922197df678a761c5f depth = 1 |