mp_flush(worker->pkt_pool.ctx);
}
-int udp_bind(struct endpoint *ep, struct sockaddr *addr)
+int udp_bind(uv_udp_t *handle, struct sockaddr *addr)
{
- uv_udp_t *handle = &ep->udp;
unsigned flags = UV_UDP_REUSEADDR;
if (addr->sa_family == AF_INET6) {
flags |= UV_UDP_IPV6ONLY;
return io_start_read((uv_handle_t *)handle);
}
-void udp_unbind(struct endpoint *ep)
-{
- uv_udp_t *handle = &ep->udp;
- uv_close((uv_handle_t *)handle, NULL);
-}
-
static void tcp_recv(uv_stream_t *handle, ssize_t nread, const uv_buf_t *buf)
{
uv_loop_t *loop = handle->loop;
io_start_read((uv_handle_t *)client);
}
-int tcp_bind(struct endpoint *ep, struct sockaddr *addr)
+int tcp_bind(uv_tcp_t *handle, struct sockaddr *addr)
{
- uv_tcp_t *handle = &ep->tcp;
unsigned flags = UV_UDP_REUSEADDR;
if (addr->sa_family == AF_INET6) {
flags |= UV_UDP_IPV6ONLY;
ret = uv_listen((uv_stream_t *)handle, 16, tcp_accept);
if (ret != 0) {
- tcp_unbind(ep);
return ret;
}
return 0;
}
-void tcp_unbind(struct endpoint *ep)
-{
- uv_close((uv_handle_t *)&ep->tcp, NULL);
-}
-
void io_create(uv_loop_t *loop, uv_handle_t *handle, int type)
{
if (type == SOCK_DGRAM) {
#include <uv.h>
#include <libknot/packet/pkt.h>
-struct endpoint;
-int udp_bind(struct endpoint *ep, struct sockaddr *addr);
-void udp_unbind(struct endpoint *ep);
-int tcp_bind(struct endpoint *ep, struct sockaddr *addr);
-void tcp_unbind(struct endpoint *ep);
+int udp_bind(uv_udp_t *handle, struct sockaddr *addr);
+int tcp_bind(uv_tcp_t *handle, struct sockaddr *addr);
void io_create(uv_loop_t *loop, uv_handle_t *handle, int type);
int io_start_read(uv_handle_t *handle);
int io_stop_read(uv_handle_t *handle);
\ No newline at end of file
void network_init(struct network *net, uv_loop_t *loop)
{
if (net != NULL) {
- /* No multiplexing now, I/O in single thread. */
net->loop = loop;
net->endpoints = map_make();
}
}
-/** Close endpoint protocols. */
-static int close_endpoint(struct endpoint *ep)
+static void free_handle(uv_handle_t *handle)
{
- if (ep->flags & NET_UDP) {
- udp_unbind(ep);
+ free(handle);
+}
+
+static void close_handle(uv_handle_t *handle, bool force)
+{
+ if (force) { /* Force close if event loop isn't running. */
+ uv_os_fd_t fd = 0;
+ if (uv_fileno(handle, &fd) == 0) {
+ close(fd);
+ }
+ free_handle(handle);
+ } else { /* Asynchronous close */
+ uv_close(handle, free_handle);
+ }
+}
+
+static int close_endpoint(struct endpoint *ep, bool force)
+{
+ if (ep->udp) {
+ close_handle((uv_handle_t *)ep->udp, force);
}
- if (ep->flags & NET_TCP) {
- tcp_unbind(ep);
+ if (ep->tcp) {
+ close_handle((uv_handle_t *)ep->tcp, force);
}
free(ep);
}
/** Endpoint visitor (see @file map.h) */
-static int visit_key(const char *key, void *val, void *ext)
+static int close_key(const char *key, void *val, void *ext)
{
- int (*callback)(struct endpoint *) = ext;
endpoint_array_t *ep_array = val;
for (size_t i = ep_array->len; i--;) {
- callback(ep_array->at[i]);
+ close_endpoint(ep_array->at[i], true);
}
return 0;
}
void network_deinit(struct network *net)
{
if (net != NULL) {
- map_walk(&net->endpoints, visit_key, close_endpoint);
+ map_walk(&net->endpoints, close_key, 0);
map_walk(&net->endpoints, free_key, 0);
map_clear(&net->endpoints);
}
static int open_endpoint(struct network *net, struct endpoint *ep, struct sockaddr *sa, uint32_t flags)
{
if (flags & NET_UDP) {
- handle_init(udp, net->loop, &ep->udp, sa->sa_family);
- int ret = udp_bind(ep, sa);
+ ep->udp = malloc(sizeof(*ep->udp));
+ if (!ep->udp) {
+ return kr_error(ENOMEM);
+ }
+ handle_init(udp, net->loop, ep->udp, sa->sa_family);
+ int ret = udp_bind(ep->udp, sa);
if (ret != 0) {
return ret;
}
ep->flags |= NET_UDP;
}
if (flags & NET_TCP) {
- handle_init(tcp, net->loop, &ep->tcp, sa->sa_family);
- int ret = tcp_bind(ep, sa);
+ ep->tcp = malloc(sizeof(*ep->tcp));
+ if (!ep->tcp) {
+ return kr_error(ENOMEM);
+ }
+ handle_init(tcp, net->loop, ep->tcp, sa->sa_family);
+ int ret = tcp_bind(ep->tcp, sa);
if (ret != 0) {
return ret;
}
return kr_error(EINVAL);
}
+ /* Already listening */
+ if (map_get(&net->endpoints, addr)) {
+ return kr_ok();
+ }
+
/* Parse address. */
int ret = 0;
struct sockaddr_storage sa;
ret = insert_endpoint(net, addr, ep);
}
if (ret != 0) {
- close_endpoint(ep);
+ close_endpoint(ep, false);
}
return ret;
for (size_t i = ep_array->len; i--;) {
struct endpoint *ep = ep_array->at[i];
if (ep->port == port) {
- close_endpoint(ep);
+ close_endpoint(ep, false);
array_del(*ep_array, i);
break;
}