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 <dimitri.staessens@intec.ugent.be> + *    Sander Vrijders   <sander.vrijders@intec.ugent.be> + * + * 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 <dimitri.staessens@intec.ugent.be> + *    Sander Vrijders   <sander.vrijders@intec.ugent.be> + * + * 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 <dimitri.staessens@intec.ugent.be> + *    Sander Vrijders   <sander.vrijders@intec.ugent.be> + * + * 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;                  }  | 
