summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/ouroboros/np1_flow.h3
-rw-r--r--src/ipcpd/ipcp.c22
-rw-r--r--src/ipcpd/local/main.c40
-rw-r--r--src/ipcpd/shim-eth-llc/main.c55
-rw-r--r--src/ipcpd/shim-udp/main.c85
-rw-r--r--src/irmd/main.c2
-rw-r--r--src/lib/dev.c205
-rw-r--r--src/lib/shm_flow_set.c18
-rw-r--r--src/tools/CMakeLists.txt1
-rw-r--r--src/tools/irm/irm_ipcp_bootstrap.c4
-rw-r--r--src/tools/operf/CMakeLists.txt21
-rw-r--r--src/tools/operf/operf.c179
-rw-r--r--src/tools/operf/operf_client.c248
-rw-r--r--src/tools/operf/operf_server.c179
-rw-r--r--src/tools/oping/oping.c9
15 files changed, 878 insertions, 193 deletions
diff --git a/include/ouroboros/np1_flow.h b/include/ouroboros/np1_flow.h
index 5b063213..4e7e6070 100644
--- a/include/ouroboros/np1_flow.h
+++ b/include/ouroboros/np1_flow.h
@@ -28,8 +28,7 @@
int np1_flow_alloc(pid_t n_api,
int port_id);
-int np1_flow_resp(pid_t n_api,
- int port_id);
+int np1_flow_resp(int port_id);
int np1_flow_dealloc(int port_id);
diff --git a/src/ipcpd/ipcp.c b/src/ipcpd/ipcp.c
index 89033c26..00dd69cb 100644
--- a/src/ipcpd/ipcp.c
+++ b/src/ipcpd/ipcp.c
@@ -114,7 +114,6 @@ void ipcp_fini()
ipcp_data_destroy(ipcpi.data);
pthread_cond_destroy(&ipcpi.state_cond);
- pthread_mutex_destroy(&ipcpi.state_mtx);
pthread_rwlock_destroy(&ipcpi.state_lock);
}
@@ -234,7 +233,8 @@ void * ipcp_main_loop(void * o)
int fd = -1;
pthread_rwlock_rdlock(&ipcpi.state_lock);
- if (ipcp_get_state() == IPCP_SHUTDOWN) {
+ if (ipcp_get_state() == IPCP_SHUTDOWN
+ || ipcp_get_state() == IPCP_NULL) {
pthread_rwlock_unlock(&ipcpi.state_lock);
break;
}
@@ -281,7 +281,8 @@ void * ipcp_main_loop(void * o)
if (conf_msg->ipcp_type == IPCP_NORMAL) {
conf.addr_size = conf_msg->addr_size;
conf.cep_id_size = conf_msg->cep_id_size;
- conf.pdu_length_size = conf_msg->pdu_length_size;
+ conf.pdu_length_size =
+ conf_msg->pdu_length_size;
conf.qos_id_size = conf_msg->qos_id_size;
conf.seqno_size = conf_msg->seqno_size;
conf.has_ttl = conf_msg->has_ttl;
@@ -348,7 +349,7 @@ void * ipcp_main_loop(void * o)
}
fd = np1_flow_alloc(msg->api, msg->port_id);
if (fd < 0) {
- LOG_ERR("Could not get fd for port_id. %d",
+ LOG_ERR("Failed allocating fd on port_id %d.",
msg->port_id);
ret_msg.has_result = true;
ret_msg.result = -1;
@@ -361,11 +362,6 @@ void * ipcp_main_loop(void * o)
msg->dst_name,
msg->src_ae_name,
msg->qos_cube);
- if (ret_msg.result < 0) {
- LOG_DBG("Deallocate failed on port_id %d.",
- msg->port_id);
- flow_dealloc(fd);
- }
break;
case IPCP_MSG_CODE__IPCP_FLOW_ALLOC_RESP:
if (ipcpi.ops->ipcp_flow_alloc_resp == NULL) {
@@ -374,10 +370,10 @@ void * ipcp_main_loop(void * o)
}
if (!msg->response) {
- fd = np1_flow_resp(msg->api, msg->port_id);
+ fd = np1_flow_resp(msg->port_id);
if (fd < 0) {
- LOG_ERR("Could not get fd for port_id %d.",
- msg->port_id);
+ LOG_WARN("Port_id %d is not known.",
+ msg->port_id);
ret_msg.has_result = true;
ret_msg.result = -1;
break;
@@ -396,7 +392,7 @@ void * ipcp_main_loop(void * o)
fd = np1_flow_dealloc(msg->port_id);
if (fd < 0) {
- LOG_ERR("Could not deallocate port_id %d.",
+ LOG_WARN("Could not deallocate port_id %d.",
msg->port_id);
ret_msg.has_result = true;
ret_msg.result = -1;
diff --git a/src/ipcpd/local/main.c b/src/ipcpd/local/main.c
index 412795ec..f0c85084 100644
--- a/src/ipcpd/local/main.c
+++ b/src/ipcpd/local/main.c
@@ -26,7 +26,6 @@
#include <ouroboros/logs.h>
#include <ouroboros/errno.h>
#include <ouroboros/dev.h>
-#include <ouroboros/fcntl.h>
#include <ouroboros/fqueue.h>
#include <ouroboros/ipcp-dev.h>
#include <ouroboros/local-dev.h>
@@ -38,7 +37,6 @@
#include <stdlib.h>
#include <pthread.h>
#include <sys/wait.h>
-#include <fcntl.h>
#include <assert.h>
#define EVENT_WAIT_TIMEOUT 100 /* us */
@@ -90,14 +88,10 @@ static void * ipcp_local_sdu_loop(void * o)
(void) o;
- while (true) {
+ while (flow_event_wait(local_data.flows, local_data.fq, &timeout)) {
int fd;
ssize_t idx;
- if (flow_event_wait(local_data.flows, local_data.fq, &timeout)
- == -ETIMEDOUT)
- continue;
-
pthread_rwlock_rdlock(&ipcpi.state_lock);
if (ipcp_get_state() != IPCP_ENROLLED) {
@@ -140,7 +134,11 @@ void ipcp_sig_handler(int sig, siginfo_t * info, void * c)
pthread_rwlock_wrlock(&ipcpi.state_lock);
- ipcp_set_state(IPCP_SHUTDOWN);
+ if (ipcp_get_state() == IPCP_INIT)
+ ipcp_set_state(IPCP_NULL);
+
+ if (ipcp_get_state() == IPCP_ENROLLED)
+ ipcp_set_state(IPCP_SHUTDOWN);
pthread_rwlock_unlock(&ipcpi.state_lock);
}
@@ -154,9 +152,6 @@ static int ipcp_local_bootstrap(struct dif_config * conf)
assert(conf);
assert(conf->type == THIS_TYPE);
- /* this IPCP doesn't need to maintain its dif_name */
- free(conf->dif_name);
-
pthread_rwlock_wrlock(&ipcpi.state_lock);
if (ipcp_get_state() != IPCP_INIT) {
@@ -165,6 +160,9 @@ static int ipcp_local_bootstrap(struct dif_config * conf)
return -1;
}
+ /* this IPCP doesn't need to maintain its dif_name */
+ free(conf->dif_name);
+
ipcp_set_state(IPCP_ENROLLED);
pthread_create(&local_data.sduloop, NULL, ipcp_local_sdu_loop, NULL);
@@ -231,7 +229,8 @@ static int ipcp_local_flow_alloc(int fd,
LOG_DBG("Allocating flow to %s on fd %d.", dst_name, fd);
- assert(dst_name || src_ae_name);
+ assert(dst_name);
+ assert(src_ae_name);
pthread_rwlock_rdlock(&ipcpi.state_lock);
@@ -296,17 +295,24 @@ static int ipcp_local_flow_dealloc(int fd)
ipcp_flow_fini(fd);
pthread_rwlock_rdlock(&ipcpi.state_lock);
+
+ if (ipcp_get_state() != IPCP_ENROLLED) {
+ pthread_rwlock_unlock(&ipcpi.state_lock);
+ LOG_DBG("Won't register with non-enrolled IPCP.");
+ return -1; /* -ENOTENROLLED */
+ }
+
pthread_rwlock_wrlock(&local_data.lock);
flow_set_del(local_data.flows, fd);
local_data.in_out[fd] = -1;
+ flow_dealloc(fd);
+
pthread_rwlock_unlock(&local_data.lock);
pthread_rwlock_unlock(&ipcpi.state_lock);
- flow_dealloc(fd);
-
LOG_INFO("Flow with fd %d deallocated.", fd);
return 0;
@@ -382,8 +388,10 @@ int main(int argc, char * argv[])
ipcp_fini();
- pthread_cancel(local_data.sduloop);
- pthread_join(local_data.sduloop, NULL);
+ if (ipcp_get_state() == IPCP_SHUTDOWN) {
+ pthread_cancel(local_data.sduloop);
+ pthread_join(local_data.sduloop, NULL);
+ }
local_data_fini();
diff --git a/src/ipcpd/shim-eth-llc/main.c b/src/ipcpd/shim-eth-llc/main.c
index b7b9f783..3f3c0e1e 100644
--- a/src/ipcpd/shim-eth-llc/main.c
+++ b/src/ipcpd/shim-eth-llc/main.c
@@ -31,7 +31,6 @@
#include <ouroboros/bitmap.h>
#include <ouroboros/dev.h>
#include <ouroboros/ipcp-dev.h>
-#include <ouroboros/fcntl.h>
#include <ouroboros/fqueue.h>
#include <ouroboros/logs.h>
@@ -625,18 +624,22 @@ static void * eth_llc_ipcp_sdu_writer(void * o)
(void) o;
- while (true) {
- if (flow_event_wait(eth_llc_data.np1_flows,
- eth_llc_data.fq,
- &timeout) == -ETIMEDOUT)
- continue;
+ while (flow_event_wait(eth_llc_data.np1_flows,
+ eth_llc_data.fq,
+ &timeout)) {
+ pthread_rwlock_rdlock(&ipcpi.state_lock);
+
+ if (ipcp_get_state() != IPCP_ENROLLED) {
+ pthread_rwlock_unlock(&ipcpi.state_lock);
+ return (void *) -1; /* -ENOTENROLLED */
+ }
while ((fd = fqueue_next(eth_llc_data.fq)) >= 0) {
if (ipcp_flow_read(fd, &sdb)) {
LOG_ERR("Bad read from fd %d.", fd);
continue;
}
- pthread_rwlock_rdlock(&ipcpi.state_lock);
+
pthread_rwlock_rdlock(&eth_llc_data.flows_lock);
ssap = reverse_bits(eth_llc_data.fd_to_ef[fd].sap);
@@ -646,7 +649,6 @@ static void * eth_llc_ipcp_sdu_writer(void * o)
MAC_SIZE);
pthread_rwlock_unlock(&eth_llc_data.flows_lock);
- pthread_rwlock_unlock(&ipcpi.state_lock);
eth_llc_ipcp_send_frame(r_addr, dsap, ssap,
shm_du_buff_head(sdb),
@@ -654,6 +656,8 @@ static void * eth_llc_ipcp_sdu_writer(void * o)
- shm_du_buff_head(sdb));
ipcp_flow_del(sdb);
}
+
+ pthread_rwlock_unlock(&ipcpi.state_lock);
}
return (void *) 1;
@@ -673,7 +677,11 @@ void ipcp_sig_handler(int sig, siginfo_t * info, void * c)
pthread_rwlock_wrlock(&ipcpi.state_lock);
- ipcp_set_state(IPCP_SHUTDOWN);
+ if (ipcp_get_state() == IPCP_INIT)
+ ipcp_set_state(IPCP_NULL);
+
+ if (ipcp_get_state() == IPCP_ENROLLED)
+ ipcp_set_state(IPCP_SHUTDOWN);
pthread_rwlock_unlock(&ipcpi.state_lock);
}
@@ -702,9 +710,6 @@ static int eth_llc_ipcp_bootstrap(struct dif_config * conf)
assert(conf);
assert(conf->type == THIS_TYPE);
- /* this IPCP doesn't need to maintain its dif_name */
- free(conf->dif_name);
-
if (conf->if_name == NULL) {
LOG_ERR("Interface name is NULL.");
return -1;
@@ -831,7 +836,6 @@ static int eth_llc_ipcp_bootstrap(struct dif_config * conf)
if (ipcp_get_state() != IPCP_INIT) {
pthread_rwlock_unlock(&ipcpi.state_lock);
LOG_ERR("IPCP in wrong state.");
- close(skfd);
return -1;
}
@@ -855,6 +859,9 @@ static int eth_llc_ipcp_bootstrap(struct dif_config * conf)
pthread_rwlock_unlock(&ipcpi.state_lock);
+ /* this IPCP doesn't need to maintain its dif_name */
+ free(conf->dif_name);
+
LOG_DBG("Bootstrapped shim IPCP over Ethernet with LLC with api %d.",
getpid());
@@ -1043,6 +1050,13 @@ static int eth_llc_ipcp_flow_dealloc(int fd)
ipcp_flow_fini(fd);
pthread_rwlock_rdlock(&ipcpi.state_lock);
+
+ if (ipcp_get_state() != IPCP_ENROLLED) {
+ pthread_rwlock_unlock(&ipcpi.state_lock);
+ LOG_DBG("Won't register with non-enrolled IPCP.");
+ return -1; /* -ENOTENROLLED */
+ }
+
pthread_rwlock_wrlock(&eth_llc_data.flows_lock);
flow_set_del(eth_llc_data.np1_flows, fd);
@@ -1056,11 +1070,11 @@ static int eth_llc_ipcp_flow_dealloc(int fd)
eth_llc_data.ef_to_fd[sap] = -1;
+ flow_dealloc(fd);
+
pthread_rwlock_unlock(&eth_llc_data.flows_lock);
pthread_rwlock_unlock(&ipcpi.state_lock);
- flow_dealloc(fd);
-
LOG_DBG("Flow with fd %d deallocated.", fd);
return 0;
@@ -1135,11 +1149,12 @@ int main(int argc, char * argv[])
ipcp_fini();
- pthread_cancel(eth_llc_data.sdu_reader);
- pthread_cancel(eth_llc_data.sdu_writer);
-
- pthread_join(eth_llc_data.sdu_writer, NULL);
- pthread_join(eth_llc_data.sdu_reader, NULL);
+ if (ipcp_get_state() == IPCP_SHUTDOWN) {
+ pthread_cancel(eth_llc_data.sdu_reader);
+ pthread_cancel(eth_llc_data.sdu_writer);
+ pthread_join(eth_llc_data.sdu_writer, NULL);
+ pthread_join(eth_llc_data.sdu_reader, NULL);
+ }
eth_llc_data_fini();
diff --git a/src/ipcpd/shim-udp/main.c b/src/ipcpd/shim-udp/main.c
index c90b47a2..eff0bd94 100644
--- a/src/ipcpd/shim-udp/main.c
+++ b/src/ipcpd/shim-udp/main.c
@@ -28,7 +28,6 @@
#include <ouroboros/dev.h>
#include <ouroboros/ipcp-dev.h>
#include <ouroboros/fqueue.h>
-#include <ouroboros/fcntl.h>
#include <ouroboros/errno.h>
#include <ouroboros/logs.h>
@@ -453,7 +452,6 @@ static void * ipcp_udp_sdu_reader(void * o)
continue;
flags = fcntl(skfd, F_GETFL, 0);
fcntl(skfd, F_SETFL, flags | O_NONBLOCK);
- fd = udp_data.uf_to_fd[skfd];
n = sizeof(r_saddr);
if ((n = recvfrom(skfd,
&buf,
@@ -463,7 +461,14 @@ static void * ipcp_udp_sdu_reader(void * o)
(unsigned *) &n)) <= 0)
continue;
+ pthread_rwlock_rdlock(&ipcpi.state_lock);
+ pthread_rwlock_rdlock(&udp_data.flows_lock);
+
+ fd = udp_data.uf_to_fd[skfd];
flow_write(fd, buf, n);
+
+ pthread_rwlock_unlock(&udp_data.flows_lock);
+ pthread_rwlock_unlock(&ipcpi.state_lock);
}
}
@@ -478,11 +483,16 @@ static void * ipcp_udp_sdu_loop(void * o)
(void) o;
- while (true) {
- if (flow_event_wait(udp_data.np1_flows,
- udp_data.fq,
- &timeout) == -ETIMEDOUT)
- continue;
+ while (flow_event_wait(udp_data.np1_flows, udp_data.fq, &timeout)) {
+ pthread_rwlock_rdlock(&ipcpi.state_lock);
+
+ if (ipcp_get_state() != IPCP_ENROLLED) {
+ pthread_rwlock_unlock(&ipcpi.state_lock);
+ return (void *) -1; /* -ENOTENROLLED */
+ }
+
+
+ pthread_rwlock_rdlock(&udp_data.flows_lock);
while ((fd = fqueue_next(udp_data.fq)) >= 0) {
if (ipcp_flow_read(fd, &sdb)) {
@@ -490,19 +500,18 @@ static void * ipcp_udp_sdu_loop(void * o)
continue;
}
- pthread_rwlock_rdlock(&ipcpi.state_lock);
- pthread_rwlock_rdlock(&udp_data.flows_lock);
-
if (send(udp_data.fd_to_uf[fd].skfd,
shm_du_buff_head(sdb),
shm_du_buff_tail(sdb) - shm_du_buff_head(sdb),
0) < 0)
LOG_ERR("Failed to send SDU.");
- pthread_rwlock_unlock(&udp_data.flows_lock);
- pthread_rwlock_unlock(&ipcpi.state_lock);
+ ipcp_flow_del(sdb);
+ }
+
- ipcp_flow_del(sdb); }
+ pthread_rwlock_unlock(&udp_data.flows_lock);
+ pthread_rwlock_unlock(&ipcpi.state_lock);
}
return (void *) 1;
@@ -519,7 +528,11 @@ void ipcp_sig_handler(int sig, siginfo_t * info, void * c)
if (info->si_pid == irmd_api) {
pthread_rwlock_wrlock(&ipcpi.state_lock);
- ipcp_set_state(IPCP_SHUTDOWN);
+ if (ipcp_get_state() == IPCP_INIT)
+ ipcp_set_state(IPCP_NULL);
+
+ if (ipcp_get_state() == IPCP_ENROLLED)
+ ipcp_set_state(IPCP_SHUTDOWN);
pthread_rwlock_unlock(&ipcpi.state_lock);
}
@@ -539,9 +552,6 @@ static int ipcp_udp_bootstrap(struct dif_config * conf)
assert(conf);
assert(conf->type == THIS_TYPE);
- /* this IPCP doesn't need to maintain its dif_name */
- free(conf->dif_name);
-
if (inet_ntop(AF_INET,
&conf->ip_addr,
ipstr,
@@ -624,6 +634,9 @@ static int ipcp_udp_bootstrap(struct dif_config * conf)
pthread_rwlock_unlock(&ipcpi.state_lock);
+ /* this IPCP doesn't need to maintain its dif_name */
+ free(conf->dif_name);
+
LOG_DBG("Bootstrapped shim IPCP over UDP with api %d.", getpid());
LOG_DBG("Bound to IP address %s.", ipstr);
LOG_DBG("DNS server address is %s.", dnsstr);
@@ -945,8 +958,8 @@ static int ipcp_udp_flow_alloc(int fd,
LOG_DBG("Allocating flow to %s.", dst_name);
- if (dst_name == NULL || src_ae_name == NULL)
- return -1;
+ assert(dst_name);
+ assert(src_ae_name);
if (strlen(dst_name) > 255
|| strlen(src_ae_name) > 255) {
@@ -1098,32 +1111,36 @@ static int ipcp_udp_flow_dealloc(int fd)
ipcp_flow_fini(fd);
- flow_set_del(udp_data.np1_flows, fd);
-
pthread_rwlock_rdlock(&ipcpi.state_lock);
+
+ if (ipcp_get_state() != IPCP_ENROLLED) {
+ pthread_rwlock_unlock(&ipcpi.state_lock);
+ LOG_DBG("Won't register with non-enrolled IPCP.");
+ return -1; /* -ENOTENROLLED */
+ }
+
pthread_rwlock_wrlock(&udp_data.flows_lock);
+ flow_set_del(udp_data.np1_flows, fd);
+
skfd = udp_data.fd_to_uf[fd].skfd;
udp_data.uf_to_fd[skfd] = -1;
udp_data.fd_to_uf[fd].udp = -1;
udp_data.fd_to_uf[fd].skfd = -1;
+ close(skfd);
+
pthread_rwlock_unlock(&udp_data.flows_lock);
pthread_rwlock_rdlock(&udp_data.flows_lock);
clr_fd(skfd);
- pthread_rwlock_unlock(&udp_data.flows_lock);
- pthread_rwlock_wrlock(&udp_data.flows_lock);
-
- close(skfd);
+ flow_dealloc(fd);
pthread_rwlock_unlock(&udp_data.flows_lock);
pthread_rwlock_unlock(&ipcpi.state_lock);
- flow_dealloc(fd);
-
LOG_DBG("Flow with fd %d deallocated.", fd);
return 0;
@@ -1197,13 +1214,15 @@ int main(int argc, char * argv[])
ipcp_fini();
- pthread_cancel(udp_data.handler);
- pthread_cancel(udp_data.sdu_reader);
- pthread_cancel(udp_data.sduloop);
- pthread_join(udp_data.sduloop, NULL);
- pthread_join(udp_data.handler, NULL);
- pthread_join(udp_data.sdu_reader, NULL);
+ if (ipcp_get_state() == IPCP_SHUTDOWN) {
+ pthread_cancel(udp_data.handler);
+ pthread_cancel(udp_data.sdu_reader);
+ pthread_cancel(udp_data.sduloop);
+ pthread_join(udp_data.sduloop, NULL);
+ pthread_join(udp_data.handler, NULL);
+ pthread_join(udp_data.sdu_reader, NULL);
+ }
udp_data_fini();
diff --git a/src/irmd/main.c b/src/irmd/main.c
index 2bb933c4..6e3f952f 100644
--- a/src/irmd/main.c
+++ b/src/irmd/main.c
@@ -974,7 +974,7 @@ static struct irm_flow * flow_accept(pid_t api, char ** dst_ae_name)
pthread_rwlock_rdlock(&irmd->state_lock);
if (irmd->state != IRMD_RUNNING) {
pthread_rwlock_unlock(&irmd->state_lock);
- break;
+ return NULL;
}
pthread_rwlock_unlock(&irmd->state_lock);
}
diff --git a/src/lib/dev.c b/src/lib/dev.c
index ec1cd696..fc8739a2 100644
--- a/src/lib/dev.c
+++ b/src/lib/dev.c
@@ -388,6 +388,14 @@ int flow_accept(char ** ae_name, struct qos_spec * qos)
return -1;
}
+ ai.flows[fd].tx_rb = shm_rbuff_open(recv_msg->api, recv_msg->port_id);
+ if (ai.flows[fd].tx_rb == NULL) {
+ reset_flow(fd);
+ pthread_rwlock_unlock(&ai.flows_lock);
+ pthread_rwlock_unlock(&ai.data_lock);
+ return -1;
+ }
+
ai.flows[fd].set = shm_flow_set_open(recv_msg->api);
if (ai.flows[fd].set == NULL) {
reset_flow(fd);
@@ -398,7 +406,6 @@ int flow_accept(char ** ae_name, struct qos_spec * qos)
return -1;
}
-
if (ae_name != NULL) {
*ae_name = strdup(recv_msg->ae_name);
if (*ae_name == NULL) {
@@ -452,40 +459,34 @@ int flow_alloc_resp(int fd, int response)
msg.port_id = ai.flows[fd].port_id;
pthread_rwlock_unlock(&ai.flows_lock);
+ pthread_rwlock_unlock(&ai.data_lock);
msg.has_response = true;
msg.response = response;
recv_msg = send_recv_irm_msg(&msg);
- if (recv_msg == NULL) {
- pthread_rwlock_unlock(&ai.data_lock);
+ if (recv_msg == NULL)
return -1;
- }
if (!recv_msg->has_result) {
- pthread_rwlock_unlock(&ai.data_lock);
irm_msg__free_unpacked(recv_msg, NULL);
return -1;
}
ret = recv_msg->result;
- pthread_rwlock_wrlock(&ai.flows_lock);
+ irm_msg__free_unpacked(recv_msg, NULL);
+
+ if (response) {
+ pthread_rwlock_rdlock(&ai.data_lock);
+ pthread_rwlock_wrlock(&ai.flows_lock);
- ai.flows[fd].tx_rb = shm_rbuff_open(ai.flows[fd].api,
- ai.flows[fd].port_id);
- if (ai.flows[fd].tx_rb == NULL) {
reset_flow(fd);
+
pthread_rwlock_unlock(&ai.flows_lock);
pthread_rwlock_unlock(&ai.data_lock);
- return -1;
}
- pthread_rwlock_unlock(&ai.flows_lock);
- pthread_rwlock_unlock(&ai.data_lock);
-
- irm_msg__free_unpacked(recv_msg, NULL);
-
return ret;
}
@@ -535,9 +536,6 @@ int flow_alloc(char * dst_name, char * src_ae_name, struct qos_spec * qos)
return -1;
}
- ai.flows[fd].port_id = recv_msg->port_id;
- ai.flows[fd].oflags = FLOW_O_DEFAULT;
- ai.flows[fd].api = recv_msg->api;
ai.flows[fd].rx_rb = shm_rbuff_open(ai.api, recv_msg->port_id);
if (ai.flows[fd].rx_rb == NULL) {
reset_flow(fd);
@@ -548,6 +546,25 @@ int flow_alloc(char * dst_name, char * src_ae_name, struct qos_spec * qos)
return -1;
}
+ ai.flows[fd].tx_rb = shm_rbuff_open(recv_msg->api, recv_msg->port_id);
+ if (ai.flows[fd].tx_rb == NULL) {
+ pthread_rwlock_unlock(&ai.flows_lock);
+ pthread_rwlock_unlock(&ai.data_lock);
+ return -1;
+ }
+
+ ai.flows[fd].set = shm_flow_set_open(recv_msg->api);
+ if (ai.flows[fd].set == NULL) {
+ reset_flow(fd);
+ pthread_rwlock_unlock(&ai.flows_lock);
+ pthread_rwlock_unlock(&ai.data_lock);
+ return -1;
+ }
+
+ ai.flows[fd].port_id = recv_msg->port_id;
+ ai.flows[fd].oflags = FLOW_O_DEFAULT;
+ ai.flows[fd].api = recv_msg->api;
+
ai.ports[recv_msg->port_id].fd = fd;
ai.ports[recv_msg->port_id].state = PORT_ID_ASSIGNED;
@@ -582,22 +599,6 @@ int flow_alloc_res(int fd)
msg.port_id = ai.flows[fd].port_id;
- ai.flows[fd].tx_rb = shm_rbuff_open(ai.flows[fd].api,
- ai.flows[fd].port_id);
- if (ai.flows[fd].tx_rb == NULL) {
- pthread_rwlock_unlock(&ai.flows_lock);
- pthread_rwlock_unlock(&ai.data_lock);
- return -1;
- }
-
- ai.flows[fd].set = shm_flow_set_open(ai.flows[fd].api);
- if (ai.flows[fd].set == NULL) {
- reset_flow(fd);
- pthread_rwlock_unlock(&ai.flows_lock);
- pthread_rwlock_unlock(&ai.data_lock);
- return -1;
- }
-
pthread_rwlock_unlock(&ai.flows_lock);
pthread_rwlock_unlock(&ai.data_lock);
@@ -764,10 +765,14 @@ ssize_t flow_write(int fd, void * buf, size_t count)
}
} else { /* blocking */
struct shm_rdrbuff * rdrb = ai.rdrb;
- pid_t api = ai.flows[fd].api;
+ struct shm_rbuff * tx_rb = ai.flows[fd].tx_rb;
+ pid_t api = ai.flows[fd].api;
+
pthread_rwlock_unlock(&ai.flows_lock);
pthread_rwlock_unlock(&ai.data_lock);
+ assert(tx_rb);
+
idx = shm_rdrbuff_write_b(rdrb,
api,
DU_BUFF_HEADSPACE,
@@ -775,15 +780,13 @@ ssize_t flow_write(int fd, void * buf, size_t count)
buf,
count);
- pthread_rwlock_rdlock(&ai.data_lock);
- pthread_rwlock_rdlock(&ai.flows_lock);
-
- if (shm_rbuff_write(ai.flows[fd].tx_rb, idx) < 0) {
- shm_rdrbuff_remove(ai.rdrb, idx);
- pthread_rwlock_unlock(&ai.flows_lock);
- pthread_rwlock_unlock(&ai.data_lock);
+ if (shm_rbuff_write(tx_rb, idx) < 0) {
+ shm_rdrbuff_remove(rdrb, idx);
return -ENOTALLOC;
}
+
+ pthread_rwlock_rdlock(&ai.data_lock);
+ pthread_rwlock_rdlock(&ai.flows_lock);
}
shm_flow_set_notify(ai.flows[fd].set, ai.flows[fd].port_id);
@@ -993,7 +996,7 @@ int flow_event_wait(struct flow_set * set,
{
ssize_t ret;
- if (set == NULL)
+ if (set == NULL || fq == NULL)
return -EINVAL;
if (fq->fqsize > 0)
@@ -1002,12 +1005,16 @@ int flow_event_wait(struct flow_set * set,
assert(!fq->next);
ret = shm_flow_set_wait(ai.fqset, set->idx, fq->fqueue, timeout);
- if (ret == -ETIMEDOUT)
+ if (ret == -ETIMEDOUT) {
+ fq->fqsize = 0;
return -ETIMEDOUT;
+ }
fq->fqsize = ret;
- return 0;
+ assert(ret);
+
+ return ret;
}
/* ipcp-dev functions */
@@ -1034,6 +1041,22 @@ int np1_flow_alloc(pid_t n_api, int port_id)
return -1;
}
+ ai.flows[fd].tx_rb = shm_rbuff_open(n_api, port_id);
+ if (ai.flows[fd].tx_rb == NULL) {
+ reset_flow(fd);
+ pthread_rwlock_unlock(&ai.flows_lock);
+ pthread_rwlock_unlock(&ai.data_lock);
+ return -1;
+ }
+
+ ai.flows[fd].set = shm_flow_set_open(n_api);
+ if (ai.flows[fd].set == NULL) {
+ reset_flow(fd);
+ pthread_rwlock_unlock(&ai.flows_lock);
+ pthread_rwlock_unlock(&ai.data_lock);
+ return -1;
+ }
+
ai.flows[fd].port_id = port_id;
ai.flows[fd].oflags = FLOW_O_DEFAULT;
ai.flows[fd].api = n_api;
@@ -1062,8 +1085,7 @@ int np1_flow_dealloc(int port_id)
return fd;
}
-
-int np1_flow_resp(pid_t n_api, int port_id)
+int np1_flow_resp(int port_id)
{
int fd;
@@ -1073,28 +1095,6 @@ int np1_flow_resp(pid_t n_api, int port_id)
pthread_rwlock_wrlock(&ai.flows_lock);
fd = ai.ports[port_id].fd;
- if (fd < 0) {
- pthread_rwlock_unlock(&ai.flows_lock);
- pthread_rwlock_unlock(&ai.data_lock);
- return fd;
- }
-
- ai.flows[fd].tx_rb = shm_rbuff_open(n_api, port_id);
- if (ai.flows[fd].tx_rb == NULL) {
- reset_flow(fd);
- port_destroy(&ai.ports[port_id]);
- pthread_rwlock_unlock(&ai.flows_lock);
- pthread_rwlock_unlock(&ai.data_lock);
- return -1;
- }
-
- ai.flows[fd].set = shm_flow_set_open(n_api);
- if (ai.flows[fd].set == NULL) {
- reset_flow(fd);
- pthread_rwlock_unlock(&ai.flows_lock);
- pthread_rwlock_unlock(&ai.data_lock);
- return -1;
- }
pthread_rwlock_unlock(&ai.flows_lock);
pthread_rwlock_unlock(&ai.data_lock);
@@ -1162,21 +1162,47 @@ int ipcp_flow_req_arr(pid_t api, char * dst_name, char * src_ae_name)
if (recv_msg == NULL)
return -1;
- if (!recv_msg->has_port_id) {
+ if (!recv_msg->has_port_id || !recv_msg->has_api) {
irm_msg__free_unpacked(recv_msg, NULL);
return -1;
}
+ if (recv_msg->has_result && recv_msg->result) {
+ irm_msg__free_unpacked(recv_msg, NULL);
+ return -1;
+ }
+
port_id = recv_msg->port_id;
- irm_msg__free_unpacked(recv_msg, NULL);
- if (port_id < 0)
+ if (port_id < 0) {
+ irm_msg__free_unpacked(recv_msg, NULL);
return -1;
+ }
pthread_rwlock_rdlock(&ai.data_lock);
pthread_rwlock_wrlock(&ai.flows_lock);
ai.flows[fd].rx_rb = shm_rbuff_open(ai.api, port_id);
if (ai.flows[fd].rx_rb == NULL) {
+ irm_msg__free_unpacked(recv_msg, NULL);
+ reset_flow(fd);
+ pthread_rwlock_unlock(&ai.flows_lock);
+ pthread_rwlock_unlock(&ai.data_lock);
+ return -1;
+ }
+
+ ai.flows[fd].tx_rb = shm_rbuff_open(recv_msg->api, port_id);
+ if (ai.flows[fd].tx_rb == NULL) {
+ irm_msg__free_unpacked(recv_msg, NULL);
+ reset_flow(fd);
+ port_destroy(&ai.ports[port_id]);
+ pthread_rwlock_unlock(&ai.flows_lock);
+ pthread_rwlock_unlock(&ai.data_lock);
+ return -1;
+ }
+
+ ai.flows[fd].set = shm_flow_set_open(recv_msg->api);
+ if (ai.flows[fd].set == NULL) {
+ irm_msg__free_unpacked(recv_msg, NULL);
reset_flow(fd);
pthread_rwlock_unlock(&ai.flows_lock);
pthread_rwlock_unlock(&ai.data_lock);
@@ -1192,6 +1218,8 @@ int ipcp_flow_req_arr(pid_t api, char * dst_name, char * src_ae_name)
pthread_rwlock_unlock(&ai.flows_lock);
pthread_rwlock_unlock(&ai.data_lock);
+ irm_msg__free_unpacked(recv_msg, NULL);
+
return fd;
}
@@ -1224,27 +1252,6 @@ int ipcp_flow_alloc_reply(int fd, int response)
ret = recv_msg->result;
- pthread_rwlock_wrlock(&ai.flows_lock);
-
- ai.flows[fd].tx_rb = shm_rbuff_open(ai.flows[fd].api,
- ai.flows[fd].port_id);
- if (ai.flows[fd].tx_rb == NULL) {
- reset_flow(fd);
- pthread_rwlock_unlock(&ai.flows_lock);
- pthread_rwlock_unlock(&ai.data_lock);
- return -1;
- }
-
- ai.flows[fd].set = shm_flow_set_open(ai.flows[fd].api);
- if (ai.flows[fd].set == NULL) {
- reset_flow(fd);
- pthread_rwlock_unlock(&ai.flows_lock);
- pthread_rwlock_unlock(&ai.data_lock);
- return -1;
- }
-
- pthread_rwlock_unlock(&ai.flows_lock);
-
irm_msg__free_unpacked(recv_msg, NULL);
return ret;
@@ -1295,6 +1302,12 @@ int ipcp_flow_write(int fd, struct shm_du_buff * sdb)
pthread_rwlock_rdlock(&ai.data_lock);
pthread_rwlock_rdlock(&ai.flows_lock);
+ if (ai.flows[fd].port_id < 0) {
+ pthread_rwlock_unlock(&ai.flows_lock);
+ pthread_rwlock_unlock(&ai.data_lock);
+ return -ENOTALLOC;
+ }
+
if ((ai.flows[fd].oflags & FLOW_O_ACCMODE) == FLOW_O_RDONLY) {
pthread_rwlock_unlock(&ai.flows_lock);
pthread_rwlock_unlock(&ai.data_lock);
@@ -1356,7 +1369,11 @@ int local_flow_write(int fd, size_t idx)
pthread_rwlock_rdlock(&ai.data_lock);
pthread_rwlock_rdlock(&ai.flows_lock);
- assert(ai.flows[fd].tx_rb);
+ if (ai.flows[fd].port_id < 0) {
+ pthread_rwlock_unlock(&ai.flows_lock);
+ pthread_rwlock_unlock(&ai.data_lock);
+ return -ENOTALLOC;
+ }
shm_rbuff_write(ai.flows[fd].tx_rb, idx);
diff --git a/src/lib/shm_flow_set.c b/src/lib/shm_flow_set.c
index 3b1af83f..6cc94573 100644
--- a/src/lib/shm_flow_set.c
+++ b/src/lib/shm_flow_set.c
@@ -376,22 +376,20 @@ ssize_t shm_flow_set_wait(const struct shm_flow_set * shm_set,
while (shm_set->heads[idx] == 0 && ret != -ETIMEDOUT) {
if (timeout != NULL)
- ret = pthread_cond_timedwait(shm_set->conds + idx,
- shm_set->lock,
- &abstime);
+ ret = -pthread_cond_timedwait(shm_set->conds + idx,
+ shm_set->lock,
+ &abstime);
else
- ret = pthread_cond_wait(shm_set->conds + idx,
- shm_set->lock);
+ ret = -pthread_cond_wait(shm_set->conds + idx,
+ shm_set->lock);
#ifndef __APPLE__
- if (ret == EOWNERDEAD) {
+ if (ret == -EOWNERDEAD) {
LOG_DBG("Recovering dead mutex.");
pthread_mutex_consistent(shm_set->lock);
}
#endif
- if (ret == ETIMEDOUT) {
- ret = -ETIMEDOUT;
+ if (ret == -ETIMEDOUT)
break;
- }
}
if (ret != -ETIMEDOUT) {
@@ -404,5 +402,7 @@ ssize_t shm_flow_set_wait(const struct shm_flow_set * shm_set,
pthread_cleanup_pop(true);
+ assert(ret);
+
return ret;
}
diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt
index e8c24557..e8181d5f 100644
--- a/src/tools/CMakeLists.txt
+++ b/src/tools/CMakeLists.txt
@@ -2,3 +2,4 @@ add_subdirectory(irm)
add_subdirectory(echo)
add_subdirectory(cbr)
add_subdirectory(oping)
+add_subdirectory(operf)
diff --git a/src/tools/irm/irm_ipcp_bootstrap.c b/src/tools/irm/irm_ipcp_bootstrap.c
index 65e99765..2508ffa3 100644
--- a/src/tools/irm/irm_ipcp_bootstrap.c
+++ b/src/tools/irm/irm_ipcp_bootstrap.c
@@ -206,8 +206,10 @@ int do_bootstrap_ipcp(int argc, char ** argv)
}
for (i = 0; i < len; i++)
- if (irm_bootstrap_ipcp(apis[i], &conf))
+ if (irm_bootstrap_ipcp(apis[i], &conf)) {
+ free(apis);
return -1;
+ }
if (apis != NULL)
free(apis);
diff --git a/src/tools/operf/CMakeLists.txt b/src/tools/operf/CMakeLists.txt
new file mode 100644
index 00000000..b63d24ee
--- /dev/null
+++ b/src/tools/operf/CMakeLists.txt
@@ -0,0 +1,21 @@
+include_directories(${CMAKE_CURRENT_SOURCE_DIR})
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+
+include_directories(${CMAKE_SOURCE_DIR}/include)
+include_directories(${CMAKE_BINARY_DIR}/include)
+
+find_library(LIBM_LIBRARIES m)
+if(NOT LIBM_LIBRARIES)
+ message(FATAL_ERROR "libm not found")
+endif()
+
+set(SOURCE_FILES
+ # Add source files here
+ operf.c
+)
+
+add_executable(operf ${SOURCE_FILES})
+
+target_link_libraries(operf LINK_PUBLIC ${LIBM_LIBRARIES} ouroboros)
+
+install(TARGETS operf RUNTIME DESTINATION usr/bin)
diff --git a/src/tools/operf/operf.c b/src/tools/operf/operf.c
new file mode 100644
index 00000000..b52109cf
--- /dev/null
+++ b/src/tools/operf/operf.c
@@ -0,0 +1,179 @@
+/*
+ * Ouroboros - Copyright (C) 2016
+ *
+ * Ouroboros perf application
+ *
+ * Dimitri Staessens <[email protected]>
+ * Sander Vrijders <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#define _POSIX_C_SOURCE 199506L
+
+#include <ouroboros/fqueue.h>
+#include <ouroboros/dev.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#define OPERF_BUF_SIZE (1024 * 1024)
+
+#define OPERF_MAX_FLOWS 256
+
+struct c {
+ char * s_apn;
+ int size;
+ long rate;
+ bool flood;
+ int duration;
+
+ size_t sent;
+ size_t rcvd;
+
+ flow_set_t * flows;
+ fqueue_t * fq;
+
+ pthread_t reader_pt;
+ pthread_t writer_pt;
+} client;
+
+struct s {
+ struct timespec times[OPERF_MAX_FLOWS];
+ flow_set_t * flows;
+ fqueue_t * fq;
+ pthread_mutex_t lock;
+
+ uint8_t buffer[OPERF_BUF_SIZE];
+ ssize_t timeout;
+
+ pthread_t cleaner_pt;
+ pthread_t accept_pt;
+ pthread_t server_pt;
+} server;
+
+#include "operf_client.c"
+#include "operf_server.c"
+
+static void usage(void)
+{
+ printf("Usage: operf [OPTION]...\n"
+ "Measures bandwidth between a client and a server\n"
+ " -l, --listen Run in server mode\n"
+ "\n"
+ " -n, --server-apn Name of the operf server\n"
+ " -d, --duration Test duration (s, default 60)\n"
+ " -r, --rate Rate (b/s)\n"
+ " -s, --size Payload size (B, default 1500)\n"
+ " -f, --flood Send SDUs as fast as possible\n"
+ " --help Display this help text and exit\n");
+}
+
+int main(int argc, char ** argv)
+{
+ int ret = -1;
+ char * rem = NULL;
+ bool serv = false;
+ char ** argv_dup = argv;
+
+ argc--;
+ argv++;
+
+ client.s_apn = NULL;
+ client.size = 1500;
+ client.duration = 60000;
+ server.timeout = 1000; /* ms */
+ client.rate = 1000000;
+ client.flood = false;
+
+ while (argc > 0) {
+ if (strcmp(*argv, "-n") == 0 ||
+ strcmp(*argv, "--server_apn") == 0) {
+ client.s_apn = *(++argv);
+ --argc;
+ } else if (strcmp(*argv, "-s") == 0 ||
+ strcmp(*argv, "--size") == 0) {
+ client.size = strtol(*(++argv), &rem, 10);
+ --argc;
+ } else if (strcmp(*argv, "-d") == 0 ||
+ strcmp(*argv, "--duration") == 0) {
+ client.duration = strtol(*(++argv), &rem, 10) * 1000;
+ --argc;
+ } else if (strcmp(*argv, "-r") == 0 ||
+ strcmp(*argv, "--rate") == 0) {
+ client.rate = strtol(*(++argv), &rem, 10);
+ if (*rem == 'k')
+ client.rate *= 1000;
+ if (*rem == 'M')
+ client.rate *= MILLION;
+ if (*rem == 'G')
+ client.rate *= BILLION;
+ --argc;
+ } else if (strcmp(*argv, "-f") == 0 ||
+ strcmp(*argv, "--flood") == 0) {
+ client.flood = true;
+ } else if (strcmp(*argv, "-l") == 0 ||
+ strcmp(*argv, "--listen") == 0) {
+ serv = true;
+ } else {
+ usage();
+ exit(EXIT_SUCCESS);
+ }
+ argc--;
+ argv++;
+ }
+
+ if (serv) {
+ if (ap_init(argv_dup[0])) {
+ printf("Failed to init AP.\n");
+ exit(EXIT_FAILURE);
+ }
+
+ ret = server_main();
+ } else {
+ if (ap_init(NULL)) {
+ printf("Failed to init AP.\n");
+ exit(EXIT_FAILURE);
+ }
+
+ if (client.s_apn == NULL) {
+ printf("No server specified.\n");
+ usage();
+ exit(EXIT_SUCCESS);
+ }
+ if (client.size > OPERF_BUF_SIZE) {
+ printf("Packet size truncated to %d bytes.\n",
+ OPERF_BUF_SIZE);
+ client.size = OPERF_BUF_SIZE;
+ }
+
+ if (client.size < 64) {
+ printf("Packet size set to 64 bytes.\n");
+ client.size = 64;
+ }
+
+ ret = client_main();
+ }
+
+ ap_fini();
+
+ if (ret < 0)
+ exit(EXIT_FAILURE);
+
+ exit(EXIT_SUCCESS);
+}
diff --git a/src/tools/operf/operf_client.c b/src/tools/operf/operf_client.c
new file mode 100644
index 00000000..1f6226d4
--- /dev/null
+++ b/src/tools/operf/operf_client.c
@@ -0,0 +1,248 @@
+/*
+ * Ouroboros - Copyright (C) 2016
+ *
+ * Ouroboros ping application
+ *
+ * Dimitri Staessens <[email protected]>
+ * Sander Vrijders <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <ouroboros/dev.h>
+#include <ouroboros/time_utils.h>
+
+#ifdef __FreeBSD__
+#define __XSI_VISIBLE 500
+#endif
+
+#include <signal.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <arpa/inet.h>
+#include <math.h>
+#include <errno.h>
+#include <float.h>
+
+void shutdown_client(int signo, siginfo_t * info, void * c)
+{
+ (void) info;
+ (void) c;
+
+ switch(signo) {
+ case SIGINT:
+ case SIGTERM:
+ case SIGHUP:
+ pthread_cancel(client.reader_pt);
+ pthread_cancel(client.writer_pt);
+ default:
+ return;
+ }
+}
+
+void * reader(void * o)
+{
+ struct timespec timeout = {2, 0};
+
+ char buf[OPERF_BUF_SIZE];
+ int fd = 0;
+ int msg_len = 0;
+
+ (void) o;
+
+ /* FIXME: use flow timeout option once we have it */
+ while (flow_event_wait(client.flows, client.fq, &timeout) != -ETIMEDOUT)
+ while ((fd = fqueue_next(client.fq)) >= 0) {
+ msg_len = flow_read(fd, buf, OPERF_BUF_SIZE);
+ if (msg_len != client.size) {
+ printf("Invalid message on fd %d.\n", fd);
+ continue;
+ }
+
+ ++client.rcvd;
+ }
+
+ return (void *) 0;
+}
+
+void * writer(void * o)
+{
+ int * fdp = (int *) o;
+ long gap = client.size * 8.0 * (BILLION / (double) client.rate);
+
+ struct timespec now;
+ struct timespec start;
+ struct timespec intv = {(gap / BILLION), gap % BILLION};
+
+ char * buf = malloc(client.size);
+ if (buf == NULL)
+ return (void *) -ENOMEM;
+
+ if (fdp == NULL)
+ return (void *) -EINVAL;
+
+ memset(buf, 0, client.size);
+
+ if (client.flood)
+ printf("Flooding %s with %d byte SDUs for %d seconds.\n\n",
+ client.s_apn, client.size, client.duration / 1000);
+ else
+ printf("Sending %d byte SDUs for %d s to %s at %.3lf Mb/s.\n\n",
+ client.size, client.duration / 1000, client.s_apn,
+ client.rate / (double) MILLION);
+
+ clock_gettime(CLOCK_REALTIME, &start);
+ clock_gettime(CLOCK_REALTIME, &now);
+
+ pthread_cleanup_push((void (*) (void *)) free, buf);
+
+ if (client.flood) {
+ while (ts_diff_ms(&start, &now) < client.duration) {
+ if (flow_write(*fdp, buf, client.size) == -1) {
+ printf("Failed to send SDU.\n");
+ flow_dealloc(*fdp);
+ free(buf);
+ return (void *) -1;
+ }
+
+ ++client.sent;
+
+ clock_gettime(CLOCK_REALTIME, &now);
+ }
+ } else {
+ while (ts_diff_ms(&start, &now) < client.duration) {
+ if (flow_write(*fdp, buf, client.size) == -1) {
+ printf("Failed to send SDU.\n");
+ flow_dealloc(*fdp);
+ free(buf);
+ return (void *) -1;
+ }
+
+ ++client.sent;
+
+ nanosleep(&intv, NULL);
+
+ clock_gettime(CLOCK_REALTIME, &now);
+ }
+ }
+
+ pthread_cleanup_pop(true);
+
+ printf("Test finished.\n");
+
+ return (void *) 0;
+}
+
+static int client_init(void)
+{
+ client.flows = flow_set_create();
+ if (client.flows == NULL)
+ return -ENOMEM;
+
+ client.fq = fqueue_create();
+ if (client.fq == NULL) {
+ flow_set_destroy(client.flows);
+ return -ENOMEM;
+ }
+
+ client.sent = 0;
+ client.rcvd = 0;
+
+ return 0;
+}
+
+void client_fini(void)
+{
+ if (client.flows != NULL)
+ flow_set_destroy(client.flows);
+
+ if (client.fq != NULL)
+ fqueue_destroy(client.fq);
+}
+
+int client_main(void)
+{
+ struct sigaction sig_act;
+
+ struct timespec tic;
+ struct timespec toc;
+
+ int fd;
+
+ memset(&sig_act, 0, sizeof sig_act);
+ sig_act.sa_sigaction = &shutdown_client;
+ sig_act.sa_flags = 0;
+
+ if (sigaction(SIGINT, &sig_act, NULL) ||
+ sigaction(SIGTERM, &sig_act, NULL) ||
+ sigaction(SIGHUP, &sig_act, NULL) ||
+ sigaction(SIGPIPE, &sig_act, NULL)) {
+ printf("Failed to install sighandler.\n");
+ return -1;
+ }
+
+ if (client_init()) {
+ printf("Failed to initialize client.\n");
+ return -1;
+ }
+
+ fd = flow_alloc(client.s_apn, NULL, NULL);
+ if (fd < 0) {
+ flow_set_destroy(client.flows);
+ fqueue_destroy(client.fq);
+ printf("Failed to allocate flow.\n");
+ return -1;
+ }
+
+ flow_set_add(client.flows, fd);
+
+ if (flow_alloc_res(fd)) {
+ printf("Flow allocation refused.\n");
+ flow_set_del(client.flows, fd);
+ flow_dealloc(fd);
+ client_fini();
+ return -1;
+ }
+
+ clock_gettime(CLOCK_REALTIME, &tic);
+
+ pthread_create(&client.reader_pt, NULL, reader, NULL);
+ pthread_create(&client.writer_pt, NULL, writer, &fd);
+
+ pthread_join(client.writer_pt, NULL);
+
+ clock_gettime(CLOCK_REALTIME, &toc);
+
+ pthread_join(client.reader_pt, NULL);
+
+ printf("\n");
+ printf("--- %s perf statistics ---\n", client.s_apn);
+ printf("%ld SDUs transmitted, ", client.sent);
+ printf("%ld received, ", client.rcvd);
+ printf("%ld%% packet loss, ", client.sent == 0 ? 0 :
+ 100 - ((100 * client.rcvd) / client.sent));
+ printf("time: %.3f ms, ", ts_diff_us(&tic, &toc) / 1000.0);
+ printf("bandwidth: %.3lf Mb/s.\n",
+ (client.rcvd * client.size * 8)
+ / (double) ts_diff_us(&tic, &toc));
+
+ flow_set_del(client.flows, fd);
+
+ flow_dealloc(fd);
+
+ client_fini();
+
+ return 0;
+}
diff --git a/src/tools/operf/operf_server.c b/src/tools/operf/operf_server.c
new file mode 100644
index 00000000..4eb93879
--- /dev/null
+++ b/src/tools/operf/operf_server.c
@@ -0,0 +1,179 @@
+/*
+ * Ouroboros - Copyright (C) 2016
+ *
+ * Ouroboros perf application
+ *
+ * Dimitri Staessens <[email protected]>
+ * Sander Vrijders <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifdef __FreeBSD__
+#define __XSI_VISIBLE 500
+#endif
+
+#include <stdlib.h>
+#include <signal.h>
+#include <arpa/inet.h>
+
+void shutdown_server(int signo, siginfo_t * info, void * c)
+{
+ (void) info;
+ (void) c;
+
+ switch(signo) {
+ case SIGINT:
+ case SIGTERM:
+ case SIGHUP:
+ pthread_cancel(server.accept_pt);
+ default:
+ return;
+ }
+}
+
+void * cleaner_thread(void * o)
+{
+ int i = 0;
+ struct timespec now = {0, 0};
+
+ (void) o;
+
+ while (true) {
+ clock_gettime(CLOCK_REALTIME, &now);
+ pthread_mutex_lock(&server.lock);
+ for (i = 0; i < OPERF_MAX_FLOWS; ++i)
+ if (flow_set_has(server.flows, i) &&
+ ts_diff_ms(&server.times[i], &now)
+ > server.timeout) {
+ printf("Flow %d timed out.\n", i);
+ flow_set_del(server.flows, i);
+ flow_dealloc(i);
+ }
+
+ pthread_mutex_unlock(&server.lock);
+ sleep(1);
+ }
+}
+
+void * server_thread(void *o)
+{
+ int msg_len = 0;
+ struct timespec timeout = {0, 100 * MILLION};
+ struct timespec now = {0, 0};
+ int fd;
+
+ (void) o;
+
+ while (flow_event_wait(server.flows, server.fq, &timeout))
+ while ((fd = fqueue_next(server.fq)) >= 0) {
+ msg_len = flow_read(fd, server.buffer, OPERF_BUF_SIZE);
+ if (msg_len < 0)
+ continue;
+
+ clock_gettime(CLOCK_REALTIME, &now);
+
+ pthread_mutex_lock(&server.lock);
+ server.times[fd] = now;
+ pthread_mutex_unlock(&server.lock);
+
+ if (flow_write(fd, server.buffer, msg_len) < 0) {
+ printf("Error writing to flow (fd %d).\n", fd);
+ flow_dealloc(fd);
+ }
+ }
+
+ return (void *) 0;
+}
+
+void * accept_thread(void * o)
+{
+ int fd = 0;
+ struct timespec now = {0, 0};
+ struct qos_spec qs;
+
+ (void) o;
+
+ printf("Ouroboros perf server started.\n");
+
+ while (true) {
+ fd = flow_accept(NULL, &qs);
+ if (fd < 0) {
+ printf("Failed to accept flow.\n");
+ break;
+ }
+
+ printf("New flow %d.\n", fd);
+
+ if (flow_alloc_resp(fd, 0)) {
+ printf("Failed to give an allocate response.\n");
+ flow_dealloc(fd);
+ continue;
+ }
+
+ clock_gettime(CLOCK_REALTIME, &now);
+
+ pthread_mutex_lock(&server.lock);
+ flow_set_add(server.flows, fd);
+ server.times[fd] = now;
+ pthread_mutex_unlock(&server.lock);
+ }
+
+ return (void *) 0;
+}
+
+int server_main(void)
+{
+ struct sigaction sig_act;
+
+ memset(&sig_act, 0, sizeof sig_act);
+ sig_act.sa_sigaction = &shutdown_server;
+ sig_act.sa_flags = 0;
+
+ if (sigaction(SIGINT, &sig_act, NULL) ||
+ sigaction(SIGTERM, &sig_act, NULL) ||
+ sigaction(SIGHUP, &sig_act, NULL) ||
+ sigaction(SIGPIPE, &sig_act, NULL)) {
+ printf("Failed to install sighandler.\n");
+ return -1;
+ }
+
+ server.flows = flow_set_create();
+ if (server.flows == NULL)
+ return 0;
+
+ server.fq = fqueue_create();
+ if (server.fq == NULL) {
+ flow_set_destroy(server.flows);
+ return -1;
+ }
+
+ pthread_create(&server.cleaner_pt, NULL, cleaner_thread, NULL);
+ pthread_create(&server.accept_pt, NULL, accept_thread, NULL);
+ pthread_create(&server.server_pt, NULL, server_thread, NULL);
+
+ pthread_join(server.accept_pt, NULL);
+
+ pthread_cancel(server.server_pt);
+ pthread_cancel(server.cleaner_pt);
+
+ flow_set_destroy(server.flows);
+ fqueue_destroy(server.fq);
+
+ pthread_join(server.server_pt, NULL);
+ pthread_join(server.cleaner_pt, NULL);
+
+ return 0;
+}
diff --git a/src/tools/oping/oping.c b/src/tools/oping/oping.c
index 801f79b5..8bb01daf 100644
--- a/src/tools/oping/oping.c
+++ b/src/tools/oping/oping.c
@@ -94,7 +94,7 @@ static void usage(void)
" -c, --count Number of packets (default 1000)\n"
" -i, --interval Interval (ms, default 1000)\n"
" -n, --server-apn Name of the oping server\n"
- " -s, --size Payload size (b, default 64)\n"
+ " -s, --size Payload size (B, default 64)\n"
" --help Display this help text and exit\n");
}
@@ -164,11 +164,12 @@ int main(int argc, char ** argv)
client.interval = 10000;
}
if (client.size > OPING_BUF_SIZE) {
- printf("Packet size truncated to 1500 bytes.\n");
- client.size = 1500;
+ printf("Packet size truncated to %d bytes.\n",
+ OPING_BUF_SIZE);
+ client.size = OPING_BUF_SIZE;
}
- if (client.size < 2) {
+ if (client.size < 64) {
printf("Packet size set to 64 bytes.\n");
client.size = 64;
}