diff options
| author | Sander Vrijders <sander.vrijders@intec.ugent.be> | 2016-08-03 13:25:12 +0200 | 
|---|---|---|
| committer | Sander Vrijders <sander.vrijders@intec.ugent.be> | 2016-08-03 13:25:12 +0200 | 
| commit | 44b55f0b03ffc6aff4f1c290b5687d5ac95ddbf9 (patch) | |
| tree | 6e80ca15368a75908ba4053ceb07c25269ae786c /src | |
| parent | d409fd569683d8f0e8c8f65d4820087dbf7c0786 (diff) | |
| parent | ca494922f3815077efbcd28da3748df38c8a6961 (diff) | |
| download | ouroboros-44b55f0b03ffc6aff4f1c290b5687d5ac95ddbf9.tar.gz ouroboros-44b55f0b03ffc6aff4f1c290b5687d5ac95ddbf9.zip | |
Merged in dstaesse/ouroboros/be-select (pull request #184)
select() like call
Diffstat (limited to 'src')
| -rw-r--r-- | src/lib/dev.c | 13 | ||||
| -rw-r--r-- | src/lib/shm_ap_rbuff.c | 172 | ||||
| -rw-r--r-- | src/lib/shm_du_map.c | 6 | ||||
| -rw-r--r-- | src/tools/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | src/tools/oping/CMakeLists.txt | 21 | ||||
| -rw-r--r-- | src/tools/oping/oping.c | 176 | ||||
| -rw-r--r-- | src/tools/oping/oping_client.c | 234 | ||||
| -rw-r--r-- | src/tools/oping/oping_server.c | 162 | 
8 files changed, 719 insertions, 66 deletions
| diff --git a/src/lib/dev.c b/src/lib/dev.c index f13c8423..22e77169 100644 --- a/src/lib/dev.c +++ b/src/lib/dev.c @@ -130,17 +130,14 @@ void ap_fini(void)          free(_ap_instance);  } -#if 0  static int port_id_to_fd(int port_id)  {          int i;          for (i = 0; i < AP_MAX_FLOWS; ++i) -                if (_ap_instance->flows[i].port_id == port_id -                        && _ap_instance->flows[i].state != FLOW_NULL) +                if (_ap_instance->flows[i].port_id == port_id)                          return i;          return -1;  } -#endif  int flow_accept(char ** ae_name)  { @@ -523,6 +520,14 @@ ssize_t flow_write(int fd, void * buf, size_t count)          return 0;  } +int flow_select(const struct timespec * timeout) +{ +        int port_id = shm_ap_rbuff_peek(_ap_instance->rb, timeout); +        if (port_id < 0) +                return port_id; +        return port_id_to_fd(port_id); +} +  ssize_t flow_read(int fd, void * buf, size_t count)  {          int idx = -1; diff --git a/src/lib/shm_ap_rbuff.c b/src/lib/shm_ap_rbuff.c index 84f7617a..be4cd0c2 100644 --- a/src/lib/shm_ap_rbuff.c +++ b/src/lib/shm_ap_rbuff.c @@ -28,6 +28,7 @@  #include <ouroboros/logs.h>  #include <ouroboros/shm_ap_rbuff.h>  #include <ouroboros/lockfile.h> +#include <ouroboros/time_utils.h>  #include <pthread.h>  #include <sys/mman.h> @@ -39,6 +40,8 @@  #include <signal.h>  #include <sys/stat.h> +#define PTHREAD_COND_CLOCK CLOCK_MONOTONIC +  #define SHM_RBUFF_FILE_SIZE (SHM_RBUFF_SIZE * sizeof(struct rb_entry)          \                               + 2 * sizeof(size_t) + sizeof(pthread_mutex_t)    \                               + sizeof (pthread_cond_t)) @@ -54,7 +57,7 @@ struct shm_ap_rbuff {          struct rb_entry * shm_base;    /* start of entry */          size_t *          ptr_head;    /* start of ringbuffer head */          size_t *          ptr_tail;    /* start of ringbuffer tail */ -        pthread_mutex_t * shm_mutex;   /* lock all free space in shm */ +        pthread_mutex_t * lock;        /* lock all free space in shm */          pthread_cond_t *  work;        /* threads will wait for a signal */          pid_t             api;         /* api to which this rb belongs */          int               fd; @@ -73,31 +76,31 @@ struct shm_ap_rbuff * shm_ap_rbuff_create()          rb = malloc(sizeof(*rb));          if (rb == NULL) { -                LOG_DBGF("Could not allocate struct."); +                LOG_DBG("Could not allocate struct.");                  return NULL;          }          shm_fd = shm_open(fn, O_CREAT | O_EXCL | O_RDWR, 0666);          if (shm_fd == -1) { -                LOG_DBGF("Failed creating ring buffer."); +                LOG_DBG("Failed creating ring buffer.");                  free(rb);                  return NULL;          }          if (fchmod(shm_fd, 0666)) { -                LOG_DBGF("Failed to chmod shared memory."); +                LOG_DBG("Failed to chmod shared memory.");                  free(rb);                  return NULL;          }          if (ftruncate(shm_fd, SHM_RBUFF_FILE_SIZE - 1) < 0) { -                LOG_DBGF("Failed to extend ringbuffer."); +                LOG_DBG("Failed to extend ringbuffer.");                  free(rb);                  return NULL;          }          if (write(shm_fd, "", 1) != 1) { -                LOG_DBGF("Failed to finalise extension of ringbuffer."); +                LOG_DBG("Failed to finalise extension of ringbuffer.");                  free(rb);                  return NULL;          } @@ -110,30 +113,31 @@ struct shm_ap_rbuff * shm_ap_rbuff_create()                          0);          if (shm_base == MAP_FAILED) { -                LOG_DBGF("Failed to map shared memory."); +                LOG_DBG("Failed to map shared memory.");                  if (close(shm_fd) == -1) -                        LOG_DBGF("Failed to close invalid shm."); +                        LOG_DBG("Failed to close invalid shm.");                  if (shm_unlink(fn) == -1) -                        LOG_DBGF("Failed to remove invalid shm."); +                        LOG_DBG("Failed to remove invalid shm.");                  free(rb);                  return NULL;          } -        rb->shm_base  = shm_base; -        rb->ptr_head  = (size_t *) (rb->shm_base + SHM_RBUFF_SIZE); -        rb->ptr_tail  = rb->ptr_head + 1; -        rb->shm_mutex = (pthread_mutex_t *) (rb->ptr_tail + 1); -        rb->work      = (pthread_cond_t *) (rb->shm_mutex + 1); +        rb->shm_base = shm_base; +        rb->ptr_head = (size_t *) (rb->shm_base + SHM_RBUFF_SIZE); +        rb->ptr_tail = rb->ptr_head + 1; +        rb->lock     = (pthread_mutex_t *) (rb->ptr_tail + 1); +        rb->work     = (pthread_cond_t *) (rb->lock + 1);          pthread_mutexattr_init(&mattr);          pthread_mutexattr_setrobust(&mattr, PTHREAD_MUTEX_ROBUST);          pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED); -        pthread_mutex_init(rb->shm_mutex, &mattr); +        pthread_mutex_init(rb->lock, &mattr);          pthread_condattr_init(&cattr);          pthread_condattr_setpshared(&cattr, PTHREAD_PROCESS_SHARED); +        pthread_condattr_setclock(&cattr, PTHREAD_COND_CLOCK);          pthread_cond_init(rb->work, &cattr);          *rb->ptr_head = 0; @@ -156,13 +160,13 @@ struct shm_ap_rbuff * shm_ap_rbuff_open(pid_t api)          rb = malloc(sizeof(*rb));          if (rb == NULL) { -                LOG_DBGF("Could not allocate struct."); +                LOG_DBG("Could not allocate struct.");                  return NULL;          }          shm_fd = shm_open(fn, O_RDWR, 0666);          if (shm_fd == -1) { -                LOG_DBGF("%d failed opening shared memory %s.", getpid(), fn); +                LOG_DBG("%d failed opening shared memory %s.", getpid(), fn);                  return NULL;          } @@ -174,22 +178,22 @@ struct shm_ap_rbuff * shm_ap_rbuff_open(pid_t api)                          0);          if (shm_base == MAP_FAILED) { -                LOG_DBGF("Failed to map shared memory."); +                LOG_DBG("Failed to map shared memory.");                  if (close(shm_fd) == -1) -                        LOG_DBGF("Failed to close invalid shm."); +                        LOG_DBG("Failed to close invalid shm.");                  if (shm_unlink(fn) == -1) -                        LOG_DBGF("Failed to remove invalid shm."); +                        LOG_DBG("Failed to remove invalid shm.");                  free(rb);                  return NULL;          } -        rb->shm_base  = shm_base; -        rb->ptr_head  = (size_t *) (rb->shm_base + SHM_RBUFF_SIZE); -        rb->ptr_tail  = rb->ptr_head + 1; -        rb->shm_mutex = (pthread_mutex_t *) (rb->ptr_tail + 1); -        rb->work      = (pthread_cond_t *) (rb->shm_mutex + 1); +        rb->shm_base = shm_base; +        rb->ptr_head = (size_t *) (rb->shm_base + SHM_RBUFF_SIZE); +        rb->ptr_tail = rb->ptr_head + 1; +        rb->lock     = (pthread_mutex_t *) (rb->ptr_tail + 1); +        rb->work     = (pthread_cond_t *) (rb->lock + 1);          rb->fd = shm_fd;          rb->api = api; @@ -199,15 +203,15 @@ struct shm_ap_rbuff * shm_ap_rbuff_open(pid_t api)  void shm_ap_rbuff_close(struct shm_ap_rbuff * rb)  {          if (rb == NULL) { -                LOG_DBGF("Bogus input. Bugging out."); +                LOG_DBG("Bogus input. Bugging out.");                  return;          }          if (close(rb->fd) < 0) -                LOG_DBGF("Couldn't close shared memory."); +                LOG_DBG("Couldn't close shared memory.");          if (munmap(rb->shm_base, SHM_RBUFF_FILE_SIZE) == -1) -                LOG_DBGF("Couldn't unmap shared memory."); +                LOG_DBG("Couldn't unmap shared memory.");          free(rb);  } @@ -218,7 +222,7 @@ void shm_ap_rbuff_destroy(struct shm_ap_rbuff * rb)          struct lockfile * lf = NULL;          if (rb == NULL) { -                LOG_DBGF("Bogus input. Bugging out."); +                LOG_DBG("Bogus input. Bugging out.");                  return;          } @@ -227,7 +231,7 @@ void shm_ap_rbuff_destroy(struct shm_ap_rbuff * rb)                  if (lf == NULL)                          return;                  if (lockfile_owner(lf) == getpid()) { -                        LOG_DBGF("Ringbuffer %d destroyed by IRMd %d.", +                        LOG_DBG("Ringbuffer %d destroyed by IRMd %d.",                                   rb->api, getpid());                          lockfile_close(lf);                  } else { @@ -238,16 +242,19 @@ void shm_ap_rbuff_destroy(struct shm_ap_rbuff * rb)                  }          } +        pthread_mutex_destroy(rb->lock); +        pthread_cond_destroy(rb->work); +          if (close(rb->fd) < 0) -                LOG_DBGF("Couldn't close shared memory."); +                LOG_DBG("Couldn't close shared memory.");          sprintf(fn, SHM_AP_RBUFF_PREFIX "%d", rb->api);          if (munmap(rb->shm_base, SHM_RBUFF_FILE_SIZE) == -1) -                LOG_DBGF("Couldn't unmap shared memory."); +                LOG_DBG("Couldn't unmap shared memory.");          if (shm_unlink(fn) == -1) -                LOG_DBGF("Failed to unlink shm."); +                LOG_DBG("Failed to unlink shm.");          free(rb);  } @@ -257,13 +264,13 @@ int shm_ap_rbuff_write(struct shm_ap_rbuff * rb, struct rb_entry * e)          if (rb == NULL || e == NULL)                  return -1; -        if (pthread_mutex_lock(rb->shm_mutex) == EOWNERDEAD) { -                LOG_DBGF("Recovering dead mutex."); -                pthread_mutex_consistent(rb->shm_mutex); +        if (pthread_mutex_lock(rb->lock) == EOWNERDEAD) { +                LOG_DBG("Recovering dead mutex."); +                pthread_mutex_consistent(rb->lock);          }          if (!shm_rbuff_free(rb)) { -                pthread_mutex_unlock(rb->shm_mutex); +                pthread_mutex_unlock(rb->lock);                  return -1;          } @@ -273,11 +280,59 @@ int shm_ap_rbuff_write(struct shm_ap_rbuff * rb, struct rb_entry * e)          *head_el_ptr = *e;          *rb->ptr_head = (*rb->ptr_head + 1) & (SHM_RBUFF_SIZE -1); -        pthread_mutex_unlock(rb->shm_mutex); +        pthread_mutex_unlock(rb->lock);          return 0;  } +int shm_ap_rbuff_peek(struct shm_ap_rbuff * rb, +                      const struct timespec * timeout) +{ +        struct timespec abstime; +        int ret = 0; + +        if (rb == NULL) +                return -EINVAL; + +        if (timeout != NULL) { +                clock_gettime(PTHREAD_COND_CLOCK, &abstime); +                ts_add(&abstime, timeout, &abstime); +        } + +        pthread_cleanup_push((void(*)(void *))pthread_mutex_unlock, +                             (void *) rb->lock); + +        if (pthread_mutex_lock(rb->lock) == EOWNERDEAD) { +                LOG_DBG("Recovering dead mutex."); +                pthread_mutex_consistent(rb->lock); +        } + +        while (shm_rbuff_empty(rb)) { +                if (timeout != NULL) +                        ret = pthread_cond_timedwait(rb->work, +                                                     rb->lock, +                                                     &abstime); +                else +                        ret = pthread_cond_wait(rb->work, rb->lock); + +                if (ret == EOWNERDEAD) { +                        LOG_DBG("Recovering dead mutex."); +                        pthread_mutex_consistent(rb->lock); +                } + +                if (ret == ETIMEDOUT) { +                        pthread_mutex_unlock(rb->lock); +                        return -ret; +                } +        } + +        ret = (rb->shm_base + *rb->ptr_tail)->port_id; + +        pthread_cleanup_pop(true); + +        return ret; +} +  struct rb_entry * shm_ap_rbuff_read(struct shm_ap_rbuff * rb)  {          struct rb_entry * e = NULL; @@ -286,26 +341,25 @@ struct rb_entry * shm_ap_rbuff_read(struct shm_ap_rbuff * rb)                  return NULL;          pthread_cleanup_push((void(*)(void *))pthread_mutex_unlock, -                             (void *) rb->shm_mutex); +                             (void *) rb->lock); -        if (pthread_mutex_lock(rb->shm_mutex) == EOWNERDEAD) { -                LOG_DBGF("Recovering dead mutex."); -                pthread_mutex_consistent(rb->shm_mutex); +        if (pthread_mutex_lock(rb->lock) == EOWNERDEAD) { +                LOG_DBG("Recovering dead mutex."); +                pthread_mutex_consistent(rb->lock);          } -        while (tail_el_ptr->port_id < 0) +        while (!shm_rbuff_empty(rb) && tail_el_ptr->port_id < 0)                  *rb->ptr_tail = (*rb->ptr_tail + 1) & (SHM_RBUFF_SIZE -1);          while (shm_rbuff_empty(rb)) -                if (pthread_cond_wait(rb->work, rb->shm_mutex) -                    == EOWNERDEAD) { -                LOG_DBGF("Recovering dead mutex."); -                pthread_mutex_consistent(rb->shm_mutex); +                if (pthread_cond_wait(rb->work, rb->lock) == EOWNERDEAD) { +                LOG_DBG("Recovering dead mutex."); +                pthread_mutex_consistent(rb->lock);          }          e = malloc(sizeof(*e));          if (e == NULL) { -                pthread_mutex_unlock(rb->shm_mutex); +                pthread_mutex_unlock(rb->lock);                  return NULL;          } @@ -313,7 +367,7 @@ struct rb_entry * shm_ap_rbuff_read(struct shm_ap_rbuff * rb)          *rb->ptr_tail = (*rb->ptr_tail + 1) & (SHM_RBUFF_SIZE -1); -        pthread_cleanup_pop(1); +        pthread_cleanup_pop(true);          return e;  } @@ -322,13 +376,13 @@ ssize_t shm_ap_rbuff_read_port(struct shm_ap_rbuff * rb, int port_id)  {          ssize_t idx = -1; -        if (pthread_mutex_lock(rb->shm_mutex) == EOWNERDEAD) { -                LOG_DBGF("Recovering dead mutex."); -                pthread_mutex_consistent(rb->shm_mutex); +        if (pthread_mutex_lock(rb->lock) == EOWNERDEAD) { +                LOG_DBG("Recovering dead mutex."); +                pthread_mutex_consistent(rb->lock);          }          if (shm_rbuff_empty(rb)) { -                pthread_mutex_unlock(rb->shm_mutex); +                pthread_mutex_unlock(rb->lock);                  return -1;          } @@ -336,7 +390,7 @@ ssize_t shm_ap_rbuff_read_port(struct shm_ap_rbuff * rb, int port_id)                  *rb->ptr_tail = (*rb->ptr_tail + 1) & (SHM_RBUFF_SIZE -1);          if (tail_el_ptr->port_id != port_id) { -                pthread_mutex_unlock(rb->shm_mutex); +                pthread_mutex_unlock(rb->lock);                  return -1;          } @@ -344,7 +398,7 @@ ssize_t shm_ap_rbuff_read_port(struct shm_ap_rbuff * rb, int port_id)          *rb->ptr_tail = (*rb->ptr_tail + 1) & (SHM_RBUFF_SIZE -1); -        pthread_mutex_unlock(rb->shm_mutex); +        pthread_mutex_unlock(rb->lock);          return idx;  } @@ -355,9 +409,9 @@ pid_t shm_ap_rbuff_get_api(struct shm_ap_rbuff *rb)          if (rb == NULL)                  return -1; -        pthread_mutex_lock(rb->shm_mutex); +        pthread_mutex_lock(rb->lock);          api = rb->api; -        pthread_mutex_unlock(rb->shm_mutex); +        pthread_mutex_unlock(rb->lock);          return api;  } @@ -367,8 +421,8 @@ void shm_ap_rbuff_reset(struct shm_ap_rbuff * rb)          if (rb == NULL)                  return; -        pthread_mutex_lock(rb->shm_mutex); +        pthread_mutex_lock(rb->lock);          *rb->ptr_tail = 0;          *rb->ptr_head = 0; -        pthread_mutex_unlock(rb->shm_mutex); +        pthread_mutex_unlock(rb->lock);  } diff --git a/src/lib/shm_du_map.c b/src/lib/shm_du_map.c index 6dc4a1bd..b090bb74 100644 --- a/src/lib/shm_du_map.c +++ b/src/lib/shm_du_map.c @@ -416,7 +416,7 @@ ssize_t shm_du_map_write(struct shm_du_map * dum,          int                  sz = size + sizeof *sdb;  #endif          uint8_t *            write_pos; -        ssize_t              index = -1; +        ssize_t              idx = -1;          if (dum == NULL || data == NULL) {                  LOG_DBGF("Bogus input, bugging out."); @@ -475,7 +475,7 @@ ssize_t shm_du_map_write(struct shm_du_map * dum,          memcpy(write_pos, data, len); -        index = *dum->ptr_head; +        idx = *dum->ptr_head;  #ifdef SHM_DU_MAP_MULTI_BLOCK          *dum->ptr_head = (*dum->ptr_head + blocks) & (SHM_BLOCKS_IN_MAP - 1);  #else @@ -483,7 +483,7 @@ ssize_t shm_du_map_write(struct shm_du_map * dum,  #endif          pthread_mutex_unlock(dum->shm_mutex); -        return index; +        return idx;  }  int shm_du_map_read(uint8_t **          dst, diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt index 9f5e6fbe..e8c24557 100644 --- a/src/tools/CMakeLists.txt +++ b/src/tools/CMakeLists.txt @@ -1,3 +1,4 @@  add_subdirectory(irm)  add_subdirectory(echo)  add_subdirectory(cbr) +add_subdirectory(oping) diff --git a/src/tools/oping/CMakeLists.txt b/src/tools/oping/CMakeLists.txt new file mode 100644 index 00000000..a8fc7d86 --- /dev/null +++ b/src/tools/oping/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 +        oping.c +) + +add_executable(oping ${SOURCE_FILES}) + +target_link_libraries(oping LINK_PUBLIC ${LIBM_LIBRARIES} ouroboros) + +install(TARGETS oping RUNTIME DESTINATION usr/bin) diff --git a/src/tools/oping/oping.c b/src/tools/oping/oping.c new file mode 100644 index 00000000..cf8dc485 --- /dev/null +++ b/src/tools/oping/oping.c @@ -0,0 +1,176 @@ +/* + * 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. + */ + +#define _POSIX_C_SOURCE 199506L + +#include <stdio.h> +#include <string.h> +#include <pthread.h> +#include <stdint.h> +#include <stdbool.h> + +#define OPING_BUF_SIZE 1500 + +#define ECHO_REQUEST 0 +#define ECHO_REPLY 1 + +#define OPING_MAX_FLOWS 256 + +struct c { +        char * s_apn; +        int    interval; +        int    count; +        int    size; + +        /* stats */ +        int    sent; +        int    rcvd; +        float  rtt_min; +        float  rtt_max; +        float  rtt_avg; +        float  rtt_m2; + +        /* needs locking */ +        struct timespec * times; +        pthread_mutex_t lock; + +        pthread_t reader_pt; +        pthread_t writer_pt; +} client; + +struct s { +        struct timespec times[OPING_MAX_FLOWS]; +        pthread_mutex_t lock; + +        pthread_t cleaner_pt; +        pthread_t accept_pt; +        pthread_t server_pt; +} server; + +struct oping_msg { +        uint32_t type; +        uint32_t id; +}; + + +#include "oping_client.c" +#include "oping_server.c" + +static void usage() +{ +        printf("Usage: oping [OPTION]...\n" +               "Checks liveness between a client and a server\n" +               "and reports the Round Trip Time (RTT)\n\n" +               "  -l, --listen              Run in server mode\n" +               "\n" +               "  -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" +               "      --help                Display this help text and exit\n"); +} + +int main(int argc, char ** argv) +{ +        int ret = -1; +        char * rem = NULL; +        bool serv = false; + +        if (ap_init(argv[0])) { +                printf("Failed to init AP.\n"); +                exit(EXIT_FAILURE); +        } + +        argc--; +        argv++; + +        client.s_apn = NULL; +        client.interval = 1000; +        client.size = 64; +        client.count = 1000; + +        while (argc > 0) { +                if (strcmp(*argv, "-i") == 0 || +                    strcmp(*argv, "--interval") == 0) { +                        client.interval = strtol(*(++argv), &rem, 10); +                        --argc; +                } else if (strcmp(*argv, "-n") == 0 || +                           strcmp(*argv, "--server_apn") == 0) { +                        client.s_apn = *(++argv); +                        --argc; +                } else if (strcmp(*argv, "-c") == 0 || +                           strcmp(*argv, "--count") == 0) { +                        client.count = strtol(*(++argv), &rem, 10); +                        --argc; +                } else if (strcmp(*argv, "-s") == 0 || +                           strcmp(*argv, "--size") == 0) { +                        client.size = strtol(*(++argv), &rem, 10); +                        --argc; +                } else if (strcmp(*argv, "-l") == 0 || +                           strcmp(*argv, "--listen") == 0) { +                        serv = true; +                } else { +                        usage(); +                        exit(EXIT_SUCCESS); +                } +                argc--; +                argv++; +        } + +        if (serv) { +                ret = server_main(); +        } else { +                if (client.s_apn == NULL) { +                        printf("No server specified.\n"); +                        usage(); +                        exit(EXIT_SUCCESS); +                } +                if (client.interval > 10000) { +                        printf("Ping interval truncated to 10s.\n"); +                        client.interval = 10000; +                } +                if (client.size > OPING_BUF_SIZE) { +                        printf("Packet size truncated to 1500 bytes.\n"); +                        client.size = 1500; +                } + +                if (client.size < 2) { +                        printf("Packet size set to 64 bytes.\n"); +                        client.size = 64; +                } + +                if (client.count > 1000000) { +                        printf("Count truncated to 1 million SDUs.\n"); +                        client.count = 1000000; +                } + +                ret = client_main(); +        } + +        ap_fini(); + +        if (ret < 0) +                exit(EXIT_FAILURE); + +        exit(EXIT_SUCCESS); +} diff --git a/src/tools/oping/oping_client.c b/src/tools/oping/oping_client.c new file mode 100644 index 00000000..23a57549 --- /dev/null +++ b/src/tools/oping/oping_client.c @@ -0,0 +1,234 @@ +/* + * 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/errno.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 <float.h> + +void shutdown_client(int signo, siginfo_t * 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}; +        struct timespec now = {0, 0}; + +        struct oping_msg * msg; +        char buf[OPING_BUF_SIZE]; +        int fd = 0; +        int msg_len = 0; +        float ms = 0; +        float d = 0; + +        msg = (struct oping_msg *) buf; + +        /* FIXME: use flow timeout option once we have it */ +        while(client.rcvd != client.count && +              (fd = flow_select(&timeout)) != -ETIMEDOUT) { +                flow_cntl(fd, FLOW_F_SETFL, FLOW_O_NONBLOCK); +                while (!((msg_len = flow_read(fd, buf, OPING_BUF_SIZE)) < 0)) { +                        if (msg_len < 0) +                                continue; + +                        if (ntohl(msg->type) != ECHO_REPLY) { +                                printf("Invalid message received (%d).\n", +                                       msg->type); +                                continue; +                        } + +                        if (ntohl(msg->id) >= client.count) { +                                printf("Invalid id.\n"); +                                continue; +                        } + +                        ++client.rcvd; + +                        clock_gettime(CLOCK_REALTIME, &now); + +                        pthread_mutex_lock(&client.lock); +                        ms = ts_diff_us(&client.times[ntohl(msg->id)], &now) +                                /1000.0; +                        pthread_mutex_unlock(&client.lock); + +                        printf("%d bytes from %s: seq=%d time=%.3f ms\n", +                               msg_len, +                               client.s_apn, +                               ntohl(msg->id), +                               ms); + +                        if (ms < client.rtt_min) +                                client.rtt_min = ms; +                        if (ms > client.rtt_max) +                                client.rtt_max = ms; + +                        d = (ms - client.rtt_avg); +                        client.rtt_avg += d  / (float) client.rcvd; +                        client.rtt_m2 += d * (ms - client.rtt_avg); +                } +        } + +        return (void *) 0; +} + +void * writer(void * o) +{ +        int * fdp = (int *) o; +        struct timespec now; +        struct timespec wait = {client.interval / 1000, client.interval % 1000}; +        struct oping_msg * msg; +        char * buf = malloc(client.size); + +        if (buf == NULL) +                return (void *) -ENOMEM; + +        if (fdp == NULL) +                return (void *) -EINVAL; + +        memset(buf, 0, client.size); + +        msg = (struct oping_msg *) buf; + +        printf("Pinging %s with %d bytes of data:\n\n", +               client.s_apn, client.size); + +        while (client.sent < client.count) { +                nanosleep(&wait, NULL); +                msg->id = htonl(client.sent); +                if (flow_write(*fdp, buf, client.size) == -1) { +                        printf("Failed to send SDU.\n"); +                        flow_dealloc(*fdp); +                        return (void *) -1; +                } + +                clock_gettime(CLOCK_REALTIME, &now); + +                pthread_mutex_lock(&client.lock); +                client.times[client.sent++] = now; +                pthread_mutex_unlock(&client.lock); +        } + +        return (void *) 0; +} + +int client_main() +{ +        struct sigaction sig_act; + +        struct timespec tic; +        struct timespec toc; + +        int fd = flow_alloc(client.s_apn, NULL, NULL); +        if (fd < 0) { +                printf("Failed to allocate flow.\n"); +                return -1; +        } + +        if (flow_alloc_res(fd)) { +                printf("Flow allocation refused.\n"); +                flow_dealloc(fd); +                return -1; +        } + +        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; +        } + +        pthread_mutex_init(&client.lock, NULL); +        pthread_mutex_lock(&client.lock); +        client.sent = 0; +        client.rcvd = 0; +        client.rtt_min = FLT_MAX; +        client.rtt_max = 0; +        client.rtt_avg = 0; +        client.rtt_m2 = 0; +        client.times = malloc(sizeof(struct timespec) * client.count); +        if (client.times == NULL) { +                pthread_mutex_unlock(&client.lock); +                return -ENOMEM; +        } + +        pthread_mutex_unlock(&client.lock); + +        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); +        pthread_join(client.reader_pt, NULL); + +        clock_gettime(CLOCK_REALTIME, &toc); + +        printf("\n"); +        printf("--- %s ping statistics ---\n", client.s_apn); +        printf("%d SDU's transmitted, ", client.sent); +        printf("%d received, ", client.rcvd); +        printf("%d%% packet loss, ", 100 - ((100 * client.rcvd) / client.sent)); +        printf("time: %.3f ms\n", ts_diff_us(&tic, &toc) / 1000.0); +        printf("rtt min/avg/max/mdev = %.3f/%.3f/%.3f/", +               client.rtt_min, +               client.rtt_avg, +               client.rtt_max); +        client.rcvd > 1 ? +                printf("%.3f ms\n", +                       sqrt(client.rtt_m2 / (float) (client.rcvd - 1))) : +                printf("Nan ms\n"); + +        pthread_mutex_lock(&client.lock); +        free(client.times); +        pthread_mutex_unlock(&client.lock); +        pthread_mutex_destroy(&client.lock); + +        flow_dealloc(fd); + +        return 0; +} diff --git a/src/tools/oping/oping_server.c b/src/tools/oping/oping_server.c new file mode 100644 index 00000000..eb0b511b --- /dev/null +++ b/src/tools/oping/oping_server.c @@ -0,0 +1,162 @@ +/* + * 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> + +#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) +{ +        switch(signo) { +        case SIGINT: +        case SIGTERM: +        case SIGHUP: +                pthread_cancel(server.server_pt); +                pthread_cancel(server.accept_pt); +                pthread_cancel(server.cleaner_pt); +        default: +                return; +        } +} + +void * cleaner_thread(void * o) +{ +        int i = 0; +        struct timespec now = {0, 0}; +        int deadline_ms = 10000; + +        while (true) { +                clock_gettime(CLOCK_REALTIME, &now); +                pthread_mutex_lock(&server.lock); +                for (i = 0; i < OPING_MAX_FLOWS; ++i) +                        if (ts_diff_ms(&server.times[i], &now) > deadline_ms) +                                flow_dealloc(i); + +                pthread_mutex_unlock(&server.lock); +                sleep(1); +        } +} + +void * server_thread(void *o) +{ +        char buf[OPING_BUF_SIZE]; +        int msg_len = 0; +        struct oping_msg * msg = (struct oping_msg *) buf; +        struct timespec now = {0, 0}; + +        while (true) { + +                int fd = flow_select(NULL); +                while (!((msg_len = flow_read(fd, buf, OPING_BUF_SIZE)) < 0)) { +                        if (msg_len < 0) +                                continue; + +                        if (ntohl(msg->type) != ECHO_REQUEST) { +                                printf("Invalid message received.\n"); +                                continue; +                        } + +                        clock_gettime(CLOCK_REALTIME, &now); + +                        pthread_mutex_lock(&server.lock); +                        server.times[fd] = now; +                        pthread_mutex_unlock(&server.lock); + +                        msg->type = htonl((uint32_t) ECHO_REPLY); + +                        if (flow_write(fd, buf, 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}; + +        printf("Ouroboros ping server started.\n"); + +        while (true) { +                fd = flow_accept(NULL); +                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); +                server.times[fd] = now; +                pthread_mutex_unlock(&server.lock); + +                flow_cntl(fd, FLOW_F_SETFL, FLOW_O_NONBLOCK); +        } + +        return (void *) 0; +} + +int server_main() +{ +        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; +        } + +        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.server_pt, NULL); +        pthread_join(server.accept_pt, NULL); +        pthread_join(server.cleaner_pt, NULL); + +        return 0; +} | 
