diff options
-rw-r--r-- | include/ouroboros/np1_flow.h | 3 | ||||
-rw-r--r-- | src/ipcpd/ipcp.c | 22 | ||||
-rw-r--r-- | src/ipcpd/local/main.c | 40 | ||||
-rw-r--r-- | src/ipcpd/shim-eth-llc/main.c | 55 | ||||
-rw-r--r-- | src/ipcpd/shim-udp/main.c | 85 | ||||
-rw-r--r-- | src/irmd/main.c | 2 | ||||
-rw-r--r-- | src/lib/dev.c | 205 | ||||
-rw-r--r-- | src/lib/shm_flow_set.c | 18 | ||||
-rw-r--r-- | src/tools/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/tools/irm/irm_ipcp_bootstrap.c | 4 | ||||
-rw-r--r-- | src/tools/operf/CMakeLists.txt | 21 | ||||
-rw-r--r-- | src/tools/operf/operf.c | 179 | ||||
-rw-r--r-- | src/tools/operf/operf_client.c | 248 | ||||
-rw-r--r-- | src/tools/operf/operf_server.c | 179 | ||||
-rw-r--r-- | src/tools/oping/oping.c | 9 |
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(ð_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(ð_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(ð_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(ð_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; } |