summaryrefslogtreecommitdiff
path: root/src/ipcpd/udp/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ipcpd/udp/main.c')
-rw-r--r--src/ipcpd/udp/main.c611
1 files changed, 266 insertions, 345 deletions
diff --git a/src/ipcpd/udp/main.c b/src/ipcpd/udp/main.c
index 04c21a8b..2e8d84ce 100644
--- a/src/ipcpd/udp/main.c
+++ b/src/ipcpd/udp/main.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2020
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* IPC process over UDP
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -31,6 +31,7 @@
#define OUROBOROS_PREFIX "ipcpd/udp"
#include <ouroboros/bitmap.h>
+#include <ouroboros/endian.h>
#include <ouroboros/hash.h>
#include <ouroboros/list.h>
#include <ouroboros/utils.h>
@@ -39,6 +40,7 @@
#include <ouroboros/fqueue.h>
#include <ouroboros/errno.h>
#include <ouroboros/logs.h>
+#include <ouroboros/pthread.h>
#include "ipcp.h"
#include "shim-data.h"
@@ -51,7 +53,6 @@
#include <netinet/in.h>
#include <signal.h>
#include <stdlib.h>
-#include <pthread.h>
#include <sys/wait.h>
#include <fcntl.h>
@@ -65,18 +66,23 @@
#define IPCP_UDP_BUF_SIZE 8980
#define IPCP_UDP_MSG_SIZE 8980
#define DNS_TTL 86400
-#define FD_UPDATE_TIMEOUT 100 /* microseconds */
-#define SERV_PORT udp_data.s_saddr.sin_port;
-#define SERV_SADDR ((struct sockaddr *) &udp_data.s_saddr)
-#define CLNT_SADDR ((struct sockaddr *) &udp_data.c_saddr)
-#define SERV_SADDR_SIZE (sizeof(udp_data.s_saddr))
+#define SADDR ((struct sockaddr *) &udp_data.s_saddr)
+#define SADDR_SIZE (sizeof(udp_data.s_saddr))
#define LOCAL_IP (udp_data.s_saddr.sin_addr.s_addr)
#define MGMT_EID 0
#define MGMT_FRAME_SIZE (sizeof(struct mgmt_msg))
#define MGMT_FRAME_BUF_SIZE 2048
+#ifdef __linux__
+#define SENDTO_FLAGS MSG_CONFIRM
+#else
+#define SENDTO_FLAGS 0
+#endif
+
+struct ipcp ipcpi;
+
/* Keep order for alignment. */
struct mgmt_msg {
uint32_t eid;
@@ -92,7 +98,9 @@ struct mgmt_msg {
uint32_t loss;
uint32_t ber;
uint32_t max_gap;
+ uint32_t timeout;
uint16_t cypher_s;
+
} __attribute__((packed));
struct mgmt_frame {
@@ -104,20 +112,17 @@ struct mgmt_frame {
/* UDP flow */
struct uf {
- int d_eid;
- /* IP details are stored through connect(). */
- int skfd;
+ int d_eid;
+ struct sockaddr_in r_saddr;
};
struct {
struct shim_data * shim_data;
uint32_t dns_addr;
- /* server socket */
+
struct sockaddr_in s_saddr;
int s_fd;
- /* client port */
- int clt_port;
fset_t * np1_flows;
struct uf fd_to_uf[SYS_MAX_FLOWS];
@@ -135,21 +140,25 @@ struct {
static int udp_data_init(void)
{
- int i;
+ int i;
+ pthread_condattr_t cattr;
if (pthread_rwlock_init(&udp_data.flows_lock, NULL))
goto fail_rwlock_init;
- if (pthread_cond_init(&udp_data.mgmt_cond, NULL))
+ if (pthread_condattr_init(&cattr))
+ goto fail_condattr;
+#ifndef __APPLE__
+ pthread_condattr_setclock(&cattr, PTHREAD_COND_CLOCK);
+#endif
+ if (pthread_cond_init(&udp_data.mgmt_cond, &cattr))
goto fail_mgmt_cond;
if (pthread_mutex_init(&udp_data.mgmt_lock, NULL))
goto fail_mgmt_lock;
- for (i = 0; i < SYS_MAX_FLOWS; ++i) {
- udp_data.fd_to_uf[i].skfd = -1;
+ for (i = 0; i < SYS_MAX_FLOWS; ++i)
udp_data.fd_to_uf[i].d_eid = -1;
- }
udp_data.np1_flows = fset_create();
if (udp_data.np1_flows == NULL)
@@ -159,9 +168,12 @@ static int udp_data_init(void)
if (udp_data.shim_data == NULL)
goto fail_data;
+ pthread_condattr_destroy(&cattr);
+
list_head_init(&udp_data.mgmt_frames);
return 0;
+
fail_data:
fset_destroy(udp_data.np1_flows);
fail_fset:
@@ -169,6 +181,8 @@ static int udp_data_init(void)
fail_mgmt_lock:
pthread_cond_destroy(&udp_data.mgmt_cond);
fail_mgmt_cond:
+ pthread_condattr_destroy(&cattr);
+ fail_condattr:
pthread_rwlock_destroy(&udp_data.flows_lock);
fail_rwlock_init:
return -1;
@@ -185,22 +199,21 @@ static void udp_data_fini(void)
pthread_mutex_destroy(&udp_data.mgmt_lock);
}
-static int ipcp_udp_port_alloc(int skfd,
- uint32_t s_eid,
- const uint8_t * dst,
- qosspec_t qs,
- const void * data,
- size_t dlen)
+static int udp_ipcp_port_alloc(const struct sockaddr_in * r_saddr,
+ uint32_t s_eid,
+ const uint8_t * dst,
+ qosspec_t qs,
+ const buffer_t * data)
{
uint8_t * buf;
struct mgmt_msg * msg;
size_t len;
- assert(dlen > 0 ? data != NULL : data == NULL);
+ assert(data->len > 0 ? data->data != NULL : data->data == NULL);
len = sizeof(*msg) + ipcp_dir_hash_len();
- buf = malloc(len + dlen);
+ buf = malloc(len + data->len);
if (buf == NULL)
return -1;
@@ -216,11 +229,15 @@ static int ipcp_udp_port_alloc(int skfd,
msg->in_order = qs.in_order;
msg->max_gap = hton32(qs.max_gap);
msg->cypher_s = hton16(qs.cypher_s);
+ msg->timeout = hton32(qs.timeout);
memcpy(msg + 1, dst, ipcp_dir_hash_len());
- memcpy(buf + len, data, dlen);
+ if (data->len > 0)
+ memcpy(buf + len, data->data, data->len);
- if (write(skfd, msg, len + dlen) < 0) {
+ if (sendto(udp_data.s_fd, msg, len + data->len,
+ SENDTO_FLAGS,
+ (const struct sockaddr *) r_saddr, sizeof(*r_saddr)) < 0) {
free(buf);
return -1;
}
@@ -230,16 +247,15 @@ static int ipcp_udp_port_alloc(int skfd,
return 0;
}
-static int ipcp_udp_port_alloc_resp(int skfd,
- uint32_t s_eid,
- uint32_t d_eid,
- int8_t response,
- const void * data,
- size_t len)
+static int udp_ipcp_port_alloc_resp(const struct sockaddr_in * r_saddr,
+ uint32_t s_eid,
+ uint32_t d_eid,
+ int8_t response,
+ const buffer_t * data)
{
- struct mgmt_msg * msg;
+ struct mgmt_msg * msg;
- msg = malloc(sizeof(*msg) + len);
+ msg = malloc(sizeof(*msg) + data->len);
if (msg == NULL)
return -1;
@@ -249,9 +265,12 @@ static int ipcp_udp_port_alloc_resp(int skfd,
msg->d_eid = hton32(d_eid);
msg->response = response;
- memcpy(msg + 1, data, len);
+ if (data->len > 0)
+ memcpy(msg + 1, data->data, data->len);
- if (write(skfd, msg, sizeof(*msg) + len) < 0) {
+ if (sendto(udp_data.s_fd, msg, sizeof(*msg) + data->len,
+ SENDTO_FLAGS,
+ (const struct sockaddr *) r_saddr, sizeof(*r_saddr)) < 0 ) {
free(msg);
return -1;
}
@@ -261,134 +280,74 @@ static int ipcp_udp_port_alloc_resp(int skfd,
return 0;
}
-static int ipcp_udp_port_req(struct sockaddr_in * c_saddr,
+static int udp_ipcp_port_req(struct sockaddr_in * c_saddr,
int d_eid,
const uint8_t * dst,
qosspec_t qs,
- const void * data,
- size_t len)
+ const buffer_t * data)
{
- struct timespec ts = {0, FD_UPDATE_TIMEOUT * 1000};
- struct timespec abstime;
- int skfd;
- int fd;
-
- skfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
- if (skfd < 0) {
- log_err("Could not create UDP socket.");
- return -1;
- }
-
- /* Remote listens on server port. Mod of c_saddr allowed. */
- c_saddr->sin_port = udp_data.s_saddr.sin_port;
+ int fd;
- /* Connect stores the remote address in the file descriptor. */
- if (connect(skfd, (struct sockaddr *) c_saddr, sizeof(*c_saddr)) < 0) {
- log_err("Could not connect to remote UDP client.");
- close(skfd);
- return -1;
- }
-
- clock_gettime(PTHREAD_COND_CLOCK, &abstime);
-
- pthread_mutex_lock(&ipcpi.alloc_lock);
-
- while (ipcpi.alloc_id != -1 && ipcp_get_state() == IPCP_OPERATIONAL) {
- ts_add(&abstime, &ts, &abstime);
- pthread_cond_timedwait(&ipcpi.alloc_cond, &ipcpi.alloc_lock,
- &abstime);
- }
-
- if (ipcp_get_state() != IPCP_OPERATIONAL) {
- log_dbg("Won't allocate over non-operational IPCP.");
- pthread_mutex_unlock(&ipcpi.alloc_lock);
- close(skfd);
- return -1;
- }
-
- /* reply to IRM */
- fd = ipcp_flow_req_arr(dst, ipcp_dir_hash_len(), qs, data, len);
+ fd = ipcp_wait_flow_req_arr(dst, qs, IPCP_UDP_MPL, data);
if (fd < 0) {
- pthread_mutex_unlock(&ipcpi.alloc_lock);
log_err("Could not get new flow from IRMd.");
- close(skfd);
return -1;
}
pthread_rwlock_wrlock(&udp_data.flows_lock);
- udp_data.fd_to_uf[fd].skfd = skfd;
- udp_data.fd_to_uf[fd].d_eid = d_eid;
+ udp_data.fd_to_uf[fd].r_saddr = *c_saddr;
+ udp_data.fd_to_uf[fd].d_eid = d_eid;
pthread_rwlock_unlock(&udp_data.flows_lock);
- ipcpi.alloc_id = fd;
- pthread_cond_broadcast(&ipcpi.alloc_cond);
-
- pthread_mutex_unlock(&ipcpi.alloc_lock);
-
log_dbg("Pending allocation request, fd %d, remote eid %d.",
fd, d_eid);
return 0;
}
-static int ipcp_udp_port_alloc_reply(uint32_t s_eid,
- uint32_t d_eid,
- int8_t response,
- const void * data,
- size_t len)
+static int udp_ipcp_port_alloc_reply(const struct sockaddr_in * saddr,
+ uint32_t s_eid,
+ uint32_t d_eid,
+ int8_t response,
+ const buffer_t * data)
{
- struct sockaddr_in t_saddr;
- socklen_t t_saddr_len;
- int ret = 0;
- int skfd = -1;
-
- t_saddr_len = sizeof(t_saddr);
+ time_t mpl = IPCP_UDP_MPL;
pthread_rwlock_wrlock(&udp_data.flows_lock);
- skfd = udp_data.fd_to_uf[s_eid].skfd;
- if (skfd < 0) {
+ if (memcmp(&udp_data.fd_to_uf[s_eid].r_saddr, saddr, sizeof(*saddr))) {
pthread_rwlock_unlock(&udp_data.flows_lock);
- log_err("Got reply for unknown UDP eid: %u.", s_eid);
+ log_err("Flow allocation reply for %u from wrong source.",
+ s_eid);
return -1;
}
- udp_data.fd_to_uf[s_eid].d_eid = d_eid;
+ if (response == 0)
+ udp_data.fd_to_uf[s_eid].d_eid = d_eid;
pthread_rwlock_unlock(&udp_data.flows_lock);
- if (getpeername(skfd, (struct sockaddr *) &t_saddr, &t_saddr_len) < 0) {
- log_dbg("Flow with fd %d has no peer.", s_eid);
- close(skfd);
- return -1;
- }
-
- if (connect(skfd, (struct sockaddr *) &t_saddr, sizeof(t_saddr)) < 0) {
- log_dbg("Could not connect flow to remote.");
- close(skfd);
- return -1;
- }
-
- if (ipcp_flow_alloc_reply(s_eid, response, data, len) < 0) {
- log_dbg("Failed to reply to flow allocation.");
+ if (ipcp_flow_alloc_reply(s_eid, response, mpl, data) < 0) {
+ log_err("Failed to reply to flow allocation.");
return -1;
}
log_dbg("Flow allocation completed on eids (%d, %d).",
s_eid, d_eid);
- return ret;
+ return 0;
}
-static int ipcp_udp_mgmt_frame(const uint8_t * buf,
+static int udp_ipcp_mgmt_frame(const uint8_t * buf,
size_t len,
struct sockaddr_in c_saddr)
{
struct mgmt_msg * msg;
size_t msg_len;
qosspec_t qs;
+ buffer_t data;
msg = (struct mgmt_msg *) buf;
@@ -398,6 +357,10 @@ static int ipcp_udp_mgmt_frame(const uint8_t * buf,
assert(len >= msg_len);
+ data.len = len - msg_len;
+ data.data = (uint8_t *) buf + msg_len;
+
+
qs.delay = ntoh32(msg->delay);
qs.bandwidth = ntoh64(msg->bandwidth);
qs.availability = msg->availability;
@@ -406,31 +369,33 @@ static int ipcp_udp_mgmt_frame(const uint8_t * buf,
qs.in_order = msg->in_order;
qs.max_gap = ntoh32(msg->max_gap);
qs.cypher_s = ntoh16(msg->cypher_s);
+ qs.timeout = ntoh32(msg->timeout);
- return ipcp_udp_port_req(&c_saddr, ntoh32(msg->s_eid),
+ return udp_ipcp_port_req(&c_saddr, ntoh32(msg->s_eid),
(uint8_t *) (msg + 1), qs,
- buf + msg_len,
- len - msg_len);
+ &data);
case FLOW_REPLY:
assert(len >= sizeof(*msg));
- return ipcp_udp_port_alloc_reply(ntoh32(msg->s_eid),
+ data.len = len - sizeof(*msg);
+ data.data = (uint8_t *) buf + sizeof(*msg);
+
+ return udp_ipcp_port_alloc_reply(&c_saddr,
+ ntoh32(msg->s_eid),
ntoh32(msg->d_eid),
msg->response,
- buf + sizeof(*msg),
- len - sizeof(*msg));
+ &data);
default:
log_err("Unknown message received %d.", msg->code);
return -1;
}
}
-static void * ipcp_udp_mgmt_handler(void * o)
+static void * udp_ipcp_mgmt_handler(void * o)
{
(void) o;
- pthread_cleanup_push((void (*)(void *)) pthread_mutex_unlock,
- (void *) &udp_data.mgmt_lock);
+ pthread_cleanup_push(__cleanup_mutex_unlock, &udp_data.mgmt_lock);
while (true) {
struct mgmt_frame * frame;
@@ -448,7 +413,7 @@ static void * ipcp_udp_mgmt_handler(void * o)
pthread_mutex_unlock(&udp_data.mgmt_lock);
- ipcp_udp_mgmt_frame(frame->buf, frame->len, frame->r_saddr);
+ udp_ipcp_mgmt_frame(frame->buf, frame->len, frame->r_saddr);
free(frame);
}
@@ -458,7 +423,7 @@ static void * ipcp_udp_mgmt_handler(void * o)
return (void *) 0;
}
-static void * ipcp_udp_packet_reader(void * o)
+static void * udp_ipcp_packet_reader(void * o)
{
uint8_t buf[IPCP_UDP_MAX_PACKET_SIZE];
uint8_t * data;
@@ -468,13 +433,17 @@ static void * ipcp_udp_packet_reader(void * o)
(void) o;
+ ipcp_lock_to_core();
+
data = buf + sizeof(uint32_t);
eid_p = (uint32_t *) buf;
while (true) {
- struct mgmt_frame * frame;
- struct sockaddr_in r_saddr;
- socklen_t len;
+ struct mgmt_frame * frame;
+ struct sockaddr_in r_saddr;
+ socklen_t len;
+ struct shm_du_buff * sdb;
+ uint8_t * head;
len = sizeof(r_saddr);
@@ -515,18 +484,31 @@ static void * ipcp_udp_packet_reader(void * o)
continue;
}
- flow_write(eid, data, n - sizeof(eid));
+ n-= sizeof(eid);
+
+ if (ipcp_sdb_reserve(&sdb, n))
+ continue;
+
+ head = shm_du_buff_head(sdb);
+ memcpy(head, data, n);
+ if (np1_flow_write(eid, sdb) < 0)
+ ipcp_sdb_release(sdb);
}
- return 0;
+ return (void *) 0;
}
-static void cleanup_writer(void * o)
+static void cleanup_fqueue(void * fq)
{
- fqueue_destroy((fqueue_t *) o);
+ fqueue_destroy((fqueue_t *) fq);
}
-static void * ipcp_udp_packet_writer(void * o)
+static void cleanup_sdb(void * sdb)
+{
+ ipcp_sdb_release((struct shm_du_buff *) sdb);
+}
+
+static void * udp_ipcp_packet_writer(void * o)
{
fqueue_t * fq;
@@ -538,11 +520,12 @@ static void * ipcp_udp_packet_writer(void * o)
ipcp_lock_to_core();
- pthread_cleanup_push(cleanup_writer, fq);
+ pthread_cleanup_push(cleanup_fqueue, fq);
while (true) {
- int fd;
- int eid;
+ struct sockaddr_in saddr;
+ int eid;
+ int fd;
fevent(udp_data.np1_flows, fq, NULL);
while ((fd = fqueue_next(fq)) >= 0) {
struct shm_du_buff * sdb;
@@ -552,12 +535,12 @@ static void * ipcp_udp_packet_writer(void * o)
if (fqueue_type(fq) != FLOW_PKT)
continue;
- if (ipcp_flow_read(fd, &sdb)) {
+ if (np1_flow_read(fd, &sdb)) {
log_dbg("Bad read from fd %d.", fd);
continue;
}
- len = shm_du_buff_tail(sdb) - shm_du_buff_head(sdb);
+ len = shm_du_buff_len(sdb);
if (len > IPCP_UDP_MAX_PACKET_SIZE) {
log_dbg("Packet length exceeds MTU.");
ipcp_sdb_release(sdb);
@@ -574,16 +557,18 @@ static void * ipcp_udp_packet_writer(void * o)
pthread_rwlock_rdlock(&udp_data.flows_lock);
eid = hton32(udp_data.fd_to_uf[fd].d_eid);
- fd = udp_data.fd_to_uf[fd].skfd;
+ saddr = udp_data.fd_to_uf[fd].r_saddr;
pthread_rwlock_unlock(&udp_data.flows_lock);
memcpy(buf, &eid, sizeof(eid));
- pthread_cleanup_push((void (*)(void *))
- ipcp_sdb_release, (void *) sdb);
+ pthread_cleanup_push(cleanup_sdb, sdb);
- if (write(fd, buf, len + OUR_HEADER_LEN) < 0)
+ if (sendto(udp_data.s_fd, buf, len + OUR_HEADER_LEN,
+ SENDTO_FLAGS,
+ (const struct sockaddr *) &saddr,
+ sizeof(saddr)) < 0)
log_err("Failed to send packet.");
pthread_cleanup_pop(true);
@@ -595,30 +580,36 @@ static void * ipcp_udp_packet_writer(void * o)
return (void *) 1;
}
-static int ipcp_udp_bootstrap(const struct ipcp_config * conf)
+static const char * inet4_ntop(const void * addr,
+ char * buf)
+{
+ return inet_ntop(AF_INET, addr, buf, INET_ADDRSTRLEN);
+}
+
+static int udp_ipcp_bootstrap(const struct ipcp_config * conf)
{
char ipstr[INET_ADDRSTRLEN];
char dnsstr[INET_ADDRSTRLEN];
- char portstr[128]; /* port is max 64535 = 5 chars */
int i = 1;
assert(conf);
assert(conf->type == THIS_TYPE);
- if (inet_ntop(AF_INET, &conf->ip_addr, ipstr, INET_ADDRSTRLEN)
- == NULL) {
- log_err("Failed to convert IP address");
+ ipcpi.dir_hash_algo = HASH_MD5;
+ strcpy(ipcpi.layer_name, conf->layer_info.name);
+
+ if (inet4_ntop(&conf->udp.ip_addr, ipstr) == NULL) {
+ log_err("Failed to convert IP address.");
return -1;
}
- if (conf->dns_addr != 0) {
- if (inet_ntop(AF_INET, &conf->dns_addr, dnsstr, INET_ADDRSTRLEN)
- == NULL) {
- log_err("Failed to convert DNS address");
+ if (conf->udp.dns_addr != 0) {
+ if (inet4_ntop(&conf->udp.dns_addr, dnsstr) == NULL) {
+ log_err("Failed to convert DNS address.");
return -1;
}
#ifndef HAVE_DDNS
- log_warn("DNS disabled at compile time, address ignored");
+ log_warn("DNS disabled at compile time, address ignored.");
#endif
} else {
strcpy(dnsstr, "not set");
@@ -631,54 +622,48 @@ static int ipcp_udp_bootstrap(const struct ipcp_config * conf)
goto fail_socket;
}
- if (setsockopt(udp_data.s_fd, SOL_SOCKET, SO_REUSEADDR,
- &i, sizeof(i)) < 0)
- log_warn("Failed to set SO_REUSEADDR.");
-
memset((char *) &udp_data.s_saddr, 0, sizeof(udp_data.s_saddr));
udp_data.s_saddr.sin_family = AF_INET;
- udp_data.s_saddr.sin_addr.s_addr = conf->ip_addr;
- udp_data.s_saddr.sin_port = htons(conf->srv_port);
+ udp_data.s_saddr.sin_addr.s_addr = conf->udp.ip_addr;
+ udp_data.s_saddr.sin_port = htons(conf->udp.port);
- if (bind(udp_data.s_fd, SERV_SADDR, SERV_SADDR_SIZE) < 0) {
- log_err("Couldn't bind to %s.", ipstr);
+ if (bind(udp_data.s_fd, SADDR, SADDR_SIZE) < 0) {
+ log_err("Couldn't bind to %s:%d. %s.",
+ ipstr, conf->udp.port, strerror(errno));
goto fail_bind;
}
- udp_data.dns_addr = conf->dns_addr;
- udp_data.clt_port = htons(conf->clt_port);
-
- ipcp_set_state(IPCP_OPERATIONAL);
+ udp_data.dns_addr = conf->udp.dns_addr;
if (pthread_create(&udp_data.mgmt_handler, NULL,
- ipcp_udp_mgmt_handler, NULL)) {
- ipcp_set_state(IPCP_INIT);
+ udp_ipcp_mgmt_handler, NULL)) {
+ log_err("Failed to create management thread.");
goto fail_bind;
}
for (i = 0; i < IPCP_UDP_RD_THR; ++i) {
if (pthread_create(&udp_data.packet_reader[i], NULL,
- ipcp_udp_packet_reader, NULL)) {
- ipcp_set_state(IPCP_INIT);
+ udp_ipcp_packet_reader, NULL)) {
+ log_err("Failed to create reader thread.");
goto fail_packet_reader;
}
}
for (i = 0; i < IPCP_UDP_WR_THR; ++i) {
if (pthread_create(&udp_data.packet_writer[i], NULL,
- ipcp_udp_packet_writer, NULL)) {
- ipcp_set_state(IPCP_INIT);
+ udp_ipcp_packet_writer, NULL)) {
+ log_err("Failed to create writer thread.");
goto fail_packet_writer;
}
}
- sprintf(portstr, "%d", conf->clt_port);
-
log_dbg("Bootstrapped IPCP over UDP with pid %d.", getpid());
log_dbg("Bound to IP address %s.", ipstr);
- log_dbg("Client port is %s.", conf->clt_port == 0 ? "random" : portstr);
- log_dbg("Server port is %u.", conf->srv_port);
- log_dbg("DNS server address is %s.", dnsstr);
+ log_dbg("Using port %u.", conf->udp.port);
+ if (conf->udp.dns_addr != 0)
+ log_dbg("DNS server address is %s.", dnsstr);
+ else
+ log_dbg("DNS server not in use.");
return 0;
@@ -706,20 +691,22 @@ static int ipcp_udp_bootstrap(const struct ipcp_config * conf)
/* NOTE: Disgusted with this crap */
static int ddns_send(char * cmd)
{
- pid_t pid = -1;
+ pid_t pid;
int wstatus;
int pipe_fd[2];
char * argv[] = {NSUPDATE_EXEC, 0};
char * envp[] = {0};
if (pipe(pipe_fd)) {
- log_err("Failed to create pipe.");
+ log_err("Failed to create pipe: %s.", strerror(errno));
return -1;
}
pid = fork();
if (pid == -1) {
- log_err("Failed to fork.");
+ log_err("Failed to fork: %s.", strerror(errno));
+ close(pipe_fd[0]);
+ close(pipe_fd[1]);
return -1;
}
@@ -727,12 +714,15 @@ static int ddns_send(char * cmd)
close(pipe_fd[1]);
dup2(pipe_fd[0], 0);
execve(argv[0], &argv[0], envp);
+ log_err("Failed to execute: %s", strerror(errno));
+ exit(1);
}
close(pipe_fd[0]);
if (write(pipe_fd[1], cmd, strlen(cmd)) == -1) {
- log_err("Failed to communicate with nsupdate.");
+ log_err("Failed to communicate with nsupdate: %s.",
+ strerror(errno));
close(pipe_fd[1]);
return -1;
}
@@ -762,18 +752,20 @@ static uint32_t ddns_resolve(char * name,
char * addr_str = "Address:";
uint32_t ip_addr = 0;
- if (inet_ntop(AF_INET, &dns_addr, dnsstr, INET_ADDRSTRLEN) == NULL)
+ if (inet4_ntop(&dns_addr, dnsstr) == NULL)
return 0;
if (pipe(pipe_fd)) {
- log_err("Failed to create pipe.");
+ log_err("Failed to create pipe: %s.", strerror(errno));
return 0;
}
pid = fork();
if (pid == -1) {
- log_err("Failed to fork.");
- return 0;
+ log_err("Failed to fork: %s.", strerror(errno));
+ close(pipe_fd[0]);
+ close(pipe_fd[1]);
+ return -1;
}
if (pid == 0) {
@@ -783,11 +775,13 @@ static uint32_t ddns_resolve(char * name,
close(pipe_fd[0]);
dup2(pipe_fd[1], 1);
execve(argv[0], &argv[0], envp);
+ log_err("Failed to execute: %s", strerror(errno));
+ exit(1);
}
close(pipe_fd[1]);
- count = read(pipe_fd[0], buf, IPCP_UDP_BUF_SIZE);
+ count = read(pipe_fd[0], buf, IPCP_UDP_BUF_SIZE - 1);
if (count <= 0) {
log_err("Failed to communicate with nslookup.");
close(pipe_fd[0]);
@@ -798,7 +792,7 @@ static uint32_t ddns_resolve(char * name,
waitpid(pid, &wstatus, 0);
if (WIFEXITED(wstatus) && WEXITSTATUS(wstatus) == 0 &&
- count != IPCP_UDP_BUF_SIZE)
+ count != IPCP_UDP_BUF_SIZE - 1)
log_dbg("Succesfully communicated with nslookup.");
else
log_err("Failed to resolve DNS address.");
@@ -824,7 +818,7 @@ static uint32_t ddns_resolve(char * name,
}
#endif
-static int ipcp_udp_reg(const uint8_t * hash)
+static int udp_ipcp_reg(const uint8_t * hash)
{
#ifdef HAVE_DDNS
char ipstr[INET_ADDRSTRLEN];
@@ -836,16 +830,18 @@ static int ipcp_udp_reg(const uint8_t * hash)
char * hashstr;
hashstr = malloc(ipcp_dir_hash_strlen() + 1);
- if (hashstr == NULL)
+ if (hashstr == NULL) {
+ log_err("Failed to malloc hashstr.");
return -1;
+ }
assert(hash);
ipcp_hash_str(hashstr, hash);
if (shim_data_reg_add_entry(udp_data.shim_data, hash)) {
- log_err("Failed to add " HASH_FMT " to local registry.",
- HASH_VAL(hash));
+ log_err("Failed to add " HASH_FMT32 " to local registry.",
+ HASH_VAL32(hash));
free(hashstr);
return -1;
}
@@ -858,14 +854,14 @@ static int ipcp_udp_reg(const uint8_t * hash)
if (dns_addr != 0) {
ip_addr = udp_data.s_saddr.sin_addr.s_addr;
- if (inet_ntop(AF_INET, &ip_addr,
- ipstr, INET_ADDRSTRLEN) == NULL) {
+ if (inet4_ntop(&ip_addr, ipstr) == NULL) {
+ log_err("Failed to convert IP address to string.");
free(hashstr);
return -1;
}
- if (inet_ntop(AF_INET, &dns_addr,
- dnsstr, INET_ADDRSTRLEN) == NULL) {
+ if (inet4_ntop(&dns_addr, dnsstr) == NULL) {
+ log_err("Failed to convert DNS address to string.");
free(hashstr);
return -1;
}
@@ -874,20 +870,19 @@ static int ipcp_udp_reg(const uint8_t * hash)
dnsstr, hashstr, DNS_TTL, ipstr);
if (ddns_send(cmd)) {
+ log_err("Failed to send DDNS message.");
shim_data_reg_del_entry(udp_data.shim_data, hash);
free(hashstr);
return -1;
}
}
#endif
- log_dbg("Registered " HASH_FMT ".", HASH_VAL(hash));
-
free(hashstr);
return 0;
}
-static int ipcp_udp_unreg(const uint8_t * hash)
+static int udp_ipcp_unreg(const uint8_t * hash)
{
#ifdef HAVE_DDNS
char dnsstr[INET_ADDRSTRLEN];
@@ -900,8 +895,10 @@ static int ipcp_udp_unreg(const uint8_t * hash)
assert(hash);
hashstr = malloc(ipcp_dir_hash_strlen() + 1);
- if (hashstr == NULL)
+ if (hashstr == NULL) {
+ log_err("Failed to malloc hashstr.");
return -1;
+ }
ipcp_hash_str(hashstr, hash);
@@ -911,8 +908,8 @@ static int ipcp_udp_unreg(const uint8_t * hash)
dns_addr = udp_data.dns_addr;
if (dns_addr != 0) {
- if (inet_ntop(AF_INET, &dns_addr, dnsstr, INET_ADDRSTRLEN)
- == NULL) {
+ if (inet4_ntop(&dns_addr, dnsstr) == NULL) {
+ log_err("Failed to convert DNS address to string.");
free(hashstr);
return -1;
}
@@ -925,14 +922,12 @@ static int ipcp_udp_unreg(const uint8_t * hash)
shim_data_reg_del_entry(udp_data.shim_data, hash);
- log_dbg("Unregistered " HASH_FMT ".", HASH_VAL(hash));
-
free(hashstr);
return 0;
}
-static int ipcp_udp_query(const uint8_t * hash)
+static int udp_ipcp_query(const uint8_t * hash)
{
uint32_t ip_addr = 0;
char * hashstr;
@@ -943,8 +938,10 @@ static int ipcp_udp_query(const uint8_t * hash)
assert(hash);
hashstr = malloc(ipcp_dir_hash_strlen() + 1);
- if (hashstr == NULL)
+ if (hashstr == NULL) {
+ log_err("Failed to malloc hashstr.");
return -ENOMEM;
+ }
ipcp_hash_str(hashstr, hash);
@@ -959,7 +956,7 @@ static int ipcp_udp_query(const uint8_t * hash)
if (dns_addr != 0) {
ip_addr = ddns_resolve(hashstr, dns_addr);
if (ip_addr == 0) {
- log_dbg("Could not resolve %s.", hashstr);
+ log_err("Could not resolve %s.", hashstr);
free(hashstr);
return -1;
}
@@ -967,7 +964,7 @@ static int ipcp_udp_query(const uint8_t * hash)
#endif
h = gethostbyname(hashstr);
if (h == NULL) {
- log_dbg("Could not resolve %s.", hashstr);
+ log_err("Could not resolve %s.", hashstr);
free(hashstr);
return -1;
}
@@ -988,190 +985,116 @@ static int ipcp_udp_query(const uint8_t * hash)
return 0;
}
-static int ipcp_udp_flow_alloc(int fd,
- const uint8_t * dst,
- qosspec_t qs,
- const void * data,
- size_t len)
+static int udp_ipcp_flow_alloc(int fd,
+ const uint8_t * dst,
+ qosspec_t qs,
+ const buffer_t * data)
{
struct sockaddr_in r_saddr; /* Server address */
- struct sockaddr_in c_saddr; /* Client address */
- socklen_t c_saddr_len;
- int skfd;
uint32_t ip_addr = 0;
- char ip_str[INET_ADDRSTRLEN];
-
- c_saddr_len = sizeof(c_saddr);
-
- log_dbg("Allocating flow to " HASH_FMT ".", HASH_VAL(dst));
+ char ipstr[INET_ADDRSTRLEN];
(void) qs;
assert(dst);
- skfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
- if (skfd < 0) {
- log_err("Could not create socket.");
- return -1;
- }
-
- /* This socket is for the flow. */
- memset((char *) &c_saddr, 0, sizeof(c_saddr));
- c_saddr.sin_family = AF_INET;
- c_saddr.sin_addr.s_addr = LOCAL_IP;
- c_saddr.sin_port = udp_data.clt_port;
-
- if (bind(skfd, (struct sockaddr *) &c_saddr, sizeof(c_saddr)) < 0) {
- log_dbg("Could not bind socket to client address.");
- close(skfd);
+ if (!shim_data_dir_has(udp_data.shim_data, dst)) {
+ log_err("Could not resolve destination.");
return -1;
}
- if (getsockname(skfd, (struct sockaddr *) &c_saddr, &c_saddr_len) < 0) {
- log_err("Could not get address from fd.");
- close(skfd);
- return -1;
- }
+ ip_addr = (uint32_t) shim_data_dir_get_addr(udp_data.shim_data, dst);
- if (!shim_data_dir_has(udp_data.shim_data, dst)) {
- log_dbg("Could not resolve destination.");
- close(skfd);
+ if (inet4_ntop(&ip_addr, ipstr) == NULL) {
+ log_err("Could not convert IP address.");
return -1;
}
- ip_addr = (uint32_t) shim_data_dir_get_addr(udp_data.shim_data, dst);
-
- inet_ntop(AF_INET, &ip_addr, ip_str, INET_ADDRSTRLEN);
- log_dbg("Destination UDP ipcp resolved at %s.", ip_str);
+ log_dbg("Destination " HASH_FMT32 " resolved at IP %s.",
+ HASH_VAL32(dst), ipstr);
- /* Connect to server and store the remote IP address in the skfd. */
memset((char *) &r_saddr, 0, sizeof(r_saddr));
r_saddr.sin_family = AF_INET;
r_saddr.sin_addr.s_addr = ip_addr;
r_saddr.sin_port = udp_data.s_saddr.sin_port;
- if (connect(skfd, (struct sockaddr *) &r_saddr, sizeof(r_saddr)) < 0) {
- log_dbg("Could not connect socket to remote.");
- close(skfd);
- return -1;
- }
-
- if (ipcp_udp_port_alloc(skfd, fd, dst, qs, data, len) < 0) {
+ if (udp_ipcp_port_alloc(&r_saddr, fd, dst, qs, data) < 0) {
log_err("Could not allocate port.");
- close(skfd);
return -1;
}
pthread_rwlock_wrlock(&udp_data.flows_lock);
- udp_data.fd_to_uf[fd].d_eid = -1;
- udp_data.fd_to_uf[fd].skfd = skfd;
-
- fset_add(udp_data.np1_flows, fd);
+ udp_data.fd_to_uf[fd].d_eid = -1;
+ udp_data.fd_to_uf[fd].r_saddr = r_saddr;
pthread_rwlock_unlock(&udp_data.flows_lock);
- log_dbg("Flow pending on fd %d, UDP src port %d, dst port %d.",
- fd, ntohs(c_saddr.sin_port), ntohs(r_saddr.sin_port));
+ fset_add(udp_data.np1_flows, fd);
return 0;
}
-static int ipcp_udp_flow_alloc_resp(int fd,
- int resp,
- const void * data,
- size_t len)
+static int udp_ipcp_flow_alloc_resp(int fd,
+ int resp,
+ const buffer_t * data)
{
- struct timespec ts = {0, FD_UPDATE_TIMEOUT * 1000};
- struct timespec abstime;
- int skfd;
- int d_eid;
-
- if (resp)
- return 0;
-
- clock_gettime(PTHREAD_COND_CLOCK, &abstime);
-
- pthread_mutex_lock(&ipcpi.alloc_lock);
-
- while (ipcpi.alloc_id != fd && ipcp_get_state() == IPCP_OPERATIONAL) {
- ts_add(&abstime, &ts, &abstime);
- pthread_cond_timedwait(&ipcpi.alloc_cond,
- &ipcpi.alloc_lock,
- &abstime);
- }
+ struct sockaddr_in saddr;
+ int d_eid;
- if (ipcp_get_state() != IPCP_OPERATIONAL) {
- pthread_mutex_unlock(&ipcpi.alloc_lock);
+ if (ipcp_wait_flow_resp(fd) < 0) {
+ log_err("Failed to wait for flow response.");
return -1;
}
- ipcpi.alloc_id = -1;
- pthread_cond_broadcast(&ipcpi.alloc_cond);
-
- pthread_mutex_unlock(&ipcpi.alloc_lock);
-
pthread_rwlock_rdlock(&udp_data.flows_lock);
- skfd = udp_data.fd_to_uf[fd].skfd;
+ saddr = udp_data.fd_to_uf[fd].r_saddr;
d_eid = udp_data.fd_to_uf[fd].d_eid;
- fset_add(udp_data.np1_flows, fd);
-
pthread_rwlock_unlock(&udp_data.flows_lock);
- if (ipcp_udp_port_alloc_resp(skfd, d_eid, fd, resp, data, len) < 0) {
- pthread_rwlock_rdlock(&udp_data.flows_lock);
+ if (udp_ipcp_port_alloc_resp(&saddr, d_eid, fd, resp, data) < 0) {
fset_del(udp_data.np1_flows, fd);
- pthread_rwlock_unlock(&udp_data.flows_lock);
log_err("Failed to respond to flow request.");
return -1;
}
- log_dbg("Accepted flow, fd %d on eid %d.",
- fd, d_eid);
+ fset_add(udp_data.np1_flows, fd);
return 0;
}
-static int ipcp_udp_flow_dealloc(int fd)
+static int udp_ipcp_flow_dealloc(int fd)
{
- int skfd = -1;
-
ipcp_flow_fini(fd);
- pthread_rwlock_wrlock(&udp_data.flows_lock);
-
fset_del(udp_data.np1_flows, fd);
- skfd = udp_data.fd_to_uf[fd].skfd;
+ pthread_rwlock_wrlock(&udp_data.flows_lock);
udp_data.fd_to_uf[fd].d_eid = -1;
- udp_data.fd_to_uf[fd].skfd = -1;
-
- close(skfd);
+ memset(&udp_data.fd_to_uf[fd].r_saddr, 0, SADDR_SIZE);
pthread_rwlock_unlock(&udp_data.flows_lock);
- flow_dealloc(fd);
-
- log_dbg("Flow with fd %d deallocated.", fd);
+ ipcp_flow_dealloc(fd);
return 0;
}
static struct ipcp_ops udp_ops = {
- .ipcp_bootstrap = ipcp_udp_bootstrap,
+ .ipcp_bootstrap = udp_ipcp_bootstrap,
.ipcp_enroll = NULL,
.ipcp_connect = NULL,
.ipcp_disconnect = NULL,
- .ipcp_reg = ipcp_udp_reg,
- .ipcp_unreg = ipcp_udp_unreg,
- .ipcp_query = ipcp_udp_query,
- .ipcp_flow_alloc = ipcp_udp_flow_alloc,
+ .ipcp_reg = udp_ipcp_reg,
+ .ipcp_unreg = udp_ipcp_unreg,
+ .ipcp_query = udp_ipcp_query,
+ .ipcp_flow_alloc = udp_ipcp_flow_alloc,
.ipcp_flow_join = NULL,
- .ipcp_flow_alloc_resp = ipcp_udp_flow_alloc_resp,
- .ipcp_flow_dealloc = ipcp_udp_flow_dealloc
+ .ipcp_flow_alloc_resp = udp_ipcp_flow_alloc_resp,
+ .ipcp_flow_dealloc = udp_ipcp_flow_dealloc
};
int main(int argc,
@@ -1179,53 +1102,51 @@ int main(int argc,
{
int i;
- if (ipcp_init(argc, argv, &udp_ops) < 0)
- goto fail_init;
if (udp_data_init() < 0) {
log_err("Failed to init udp data.");
goto fail_data_init;
}
- if (ipcp_boot() < 0) {
- log_err("Failed to boot IPCP.");
- goto fail_boot;
+ if (ipcp_init(argc, argv, &udp_ops, THIS_TYPE) < 0) {
+ log_err("Failed to initialize IPCP.");
+ goto fail_init;
}
- if (ipcp_create_r(0)) {
- log_err("Failed to notify IRMd we are initialized.");
- goto fail_create_r;
+ if (ipcp_start() < 0) {
+ log_err("Failed to start IPCP.");
+ goto fail_start;
}
- ipcp_shutdown();
+ ipcp_sigwait();
if (ipcp_get_state() == IPCP_SHUTDOWN) {
- for (i = 0; i < IPCP_UDP_RD_THR; ++i)
- pthread_cancel(udp_data.packet_reader[i]);
for (i = 0; i < IPCP_UDP_WR_THR; ++i)
pthread_cancel(udp_data.packet_writer[i]);
+ for (i = 0; i < IPCP_UDP_RD_THR; ++i)
+ pthread_cancel(udp_data.packet_reader[i]);
pthread_cancel(udp_data.mgmt_handler);
- for (i = 0; i < IPCP_UDP_RD_THR; ++i)
- pthread_join(udp_data.packet_reader[i], NULL);
for (i = 0; i < IPCP_UDP_WR_THR; ++i)
pthread_join(udp_data.packet_writer[i], NULL);
+ for (i = 0; i < IPCP_UDP_RD_THR; ++i)
+ pthread_join(udp_data.packet_reader[i], NULL);
pthread_join(udp_data.mgmt_handler, NULL);
+ close(udp_data.s_fd);
}
- udp_data_fini();
+ ipcp_stop();
ipcp_fini();
- exit(EXIT_SUCCESS);
- fail_create_r:
- ipcp_set_state(IPCP_NULL);
- ipcp_shutdown();
- fail_boot:
udp_data_fini();
- fail_data_init:
+
+ exit(EXIT_SUCCESS);
+
+ fail_start:
ipcp_fini();
fail_init:
- ipcp_create_r(-1);
+ udp_data_fini();
+ fail_data_init:
exit(EXIT_FAILURE);
}