123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583 |
- /*
- * This file is part of the Sofia-SIP package
- *
- * Copyright (C) 2005 Nokia Corporation.
- *
- * Contact: Pekka Pessi <pekka.pessi@nokia.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This library 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
- /**@ingroup su_root_ex
- * @CFILE test_su.c
- *
- * @brief Test program for su wait objects, root, timers, clones, and messages.
- *
- * @internal
- *
- * @author Pekka Pessi <Pekka.Pessi@nokia.com>
- *
- * @date Created: Thu Mar 18 19:40:51 1999 pessi
- */
- #include "config.h"
- struct pinger;
- #define SU_ROOT_MAGIC_T struct pinger
- #define SU_INTERNAL_P su_root_t *
- #define SU_MSG_ARG_T su_sockaddr_t
- #include "sofia-sip/su.h"
- #include "sofia-sip/su_wait.h"
- #include "sofia-sip/su_log.h"
- #include "sofia-sip/su_debug.h"
- #include <stdlib.h>
- #include <string.h>
- #include <stdio.h>
- #include <assert.h>
- char const name[] = "test_su";
- #if HAVE_FUNC
- #define enter (void)SU_DEBUG_9(("%s: %s: entering\n", name, __func__))
- #define nh_enter (void)SU_DEBUG_9(("%s %s(%p): entering\n", name, __func__, nh))
- #elif HAVE_FUNCTION
- #define enter (void)SU_DEBUG_9(("%s: %s: entering\n", name, __FUNCTION__))
- #define nh_enter (void)SU_DEBUG_9(("%s %s(%p): entering\n", name, __FUNCTION__, nh))
- #define __func__ __FUNCTION__
- #else
- #define enter ((void)0)
- #define nh_enter ((void)0)
- #define __func__ "test_su"
- #endif
- struct pinger {
- enum { PINGER = 1, PONGER = 2 } const sort;
- char const * name;
- unsigned running : 1;
- unsigned : 0;
- su_root_t *root;
- su_socket_t s;
- su_timer_t *t;
- int id;
- int rindex;
- su_time_t when;
- su_sockaddr_t addr;
- double rtt_total;
- int rtt_n;
- };
- short opt_family = AF_INET;
- short opt_verbatim = 0;
- short opt_singlethread = 0;
- static su_socket_t udpsocket(void)
- {
- su_socket_t s;
- su_sockaddr_t su = { 0 };
- socklen_t sulen = sizeof(su);
- char nbuf[64];
- su.su_family = opt_family;
- su_getlocalip(&su);
- s = su_socket(su.su_family, SOCK_DGRAM, 0);
- if (s == INVALID_SOCKET) {
- su_perror("udpsocket: socket");
- exit(1);
- }
- if (bind(s, &su.su_sa, su_sockaddr_size(&su)) == SOCKET_ERROR) {
- su_perror("udpsocket: bind");
- exit(1);
- }
- if (getsockname(s, &su.su_sa, &sulen) == SOCKET_ERROR) {
- su_perror("udpsocket: getsockname");
- exit(1);
- }
- if (opt_verbatim)
- printf("udpsocket: using address [%s]:%u\n",
- su_inet_ntop(su.su_family, SU_ADDR(&su), nbuf, sizeof(nbuf)),
- ntohs(su.su_sin.sin_port));
- return s;
- }
- static char *snow(su_time_t now)
- {
- static char buf[24];
- su_time_print(buf, sizeof(buf), &now);
- return buf;
- }
- void
- do_ping(struct pinger *p, su_timer_t *t, void *p0)
- {
- char buf[1024];
- assert(p == su_root_magic(su_timer_root(t)));
- assert(p->sort == PINGER);
- p->when = su_now();
- snprintf(buf, sizeof(buf), "Ping %d at %s", p->id++, snow(p->when));
- if (su_sendto(p->s, buf, strlen(buf), 0,
- &p->addr, su_sockaddr_size(&p->addr)) == -1) {
- su_perror("do_ping: send");
- }
- if (opt_verbatim) {
- puts(buf);
- fflush(stdout);
- }
- }
- int
- do_rtt(struct pinger *p, su_wait_t *w, void *p0)
- {
- su_sockaddr_t su;
- struct sockaddr * const susa = &su.su_sa;
- socklen_t susize[] = { sizeof(su)};
- char buf[1024];
- char nbuf[1024];
- int n;
- su_time_t now = su_now();
- double rtt;
- assert(p0 == p);
- assert(p->sort == PINGER);
- rtt = su_time_diff(now, p->when);
- p->rtt_total += rtt, p->rtt_n++;
- su_wait_events(w, p->s);
- n = recvfrom(p->s, buf, sizeof(buf) - 1, 0, susa, susize);
- if (n < 0) {
- su_perror("do_rtt: recvfrom");
- return 0;
- }
- buf[n] = 0;
- if (opt_verbatim)
- printf("do_rtt: %d bytes from [%s]:%u: \"%s\", rtt = %lg ms\n",
- n, su_inet_ntop(su.su_family, SU_ADDR(&su), nbuf, sizeof(nbuf)),
- ntohs(su.su_sin.sin_port), buf, rtt / 1000);
- do_ping(p, p->t, NULL);
- return 0;
- }
- void
- do_pong(struct pinger *p, su_timer_t *t, void *p0)
- {
- char buf[1024];
- assert(p == su_root_magic(su_timer_root(t)));
- assert(p->sort == PONGER);
- p->id = 0;
- snprintf(buf, sizeof(buf), "Pong at %s", snow(su_now()));
- if (su_sendto(p->s, buf, strlen(buf), 0,
- &p->addr, su_sockaddr_size(&p->addr)) == -1) {
- su_perror("do_pong: send");
- }
- if (opt_verbatim) {
- puts(buf);
- fflush(stdout);
- }
- }
- int
- do_recv(struct pinger *p, su_wait_t *w, void *p0)
- {
- su_sockaddr_t su;
- socklen_t susize[] = { sizeof(su)};
- char buf[1024];
- char nbuf[1024];
- int n;
- su_time_t now = su_now();
- assert(p0 == p);
- assert(p->sort == PONGER);
- su_wait_events(w, p->s);
- n = recvfrom(p->s, buf, sizeof(buf) - 1, 0, &su.su_sa, susize);
- if (n < 0) {
- su_perror("do_recv: recvfrom");
- return 0;
- }
- buf[n] = 0;
- if (opt_verbatim)
- printf("do_recv: %d bytes from [%s]:%u: \"%s\" at %s\n",
- n, su_inet_ntop(su.su_family, SU_ADDR(&su), nbuf, sizeof(nbuf)),
- ntohs(su.su_sin.sin_port), buf, snow(now));
- fflush(stdout);
- #if 0
- if (p->id)
- puts("do_recv: already a pending reply");
- if (su_timer_set(p->t, do_pong, p) < 0) {
- fprintf(stderr, "do_recv: su_timer_set() error\n");
- return 0;
- }
- p->id = 1;
- #else
- do_pong(p, p->t, NULL);
- #endif
- return 0;
- }
- void
- do_exit(struct pinger *x, su_timer_t *t, void *x0)
- {
- if (opt_verbatim)
- printf("do_exit at %s\n", snow(su_now()));
- su_root_break(su_timer_root(t));
- }
- int
- do_init(su_root_t *root, struct pinger *p)
- {
- su_wait_t w;
- su_socket_t s;
- long interval;
- su_timer_t *t;
- su_wakeup_f f;
- int index;
- #if nomore
- su_wait_t w0;
- int index0
- #endif
- enter;
- switch (p->sort) {
- case PINGER: f = do_rtt; interval = 200; break;
- case PONGER: f = do_recv; interval = 40; break;
- default:
- return SU_FAILURE;
- }
- p->t = t = su_timer_create(su_root_task(root), interval);
- if (t == NULL) {
- su_perror("su_timer_create");
- return SU_FAILURE;
- }
- /* Create a sockets, */
- p->s = s = udpsocket();
- #if nomore
- if (su_wait_create(&w0, s, SU_WAIT_IN) == SOCKET_ERROR) {
- su_perror("su_wait_create");
- return SU_FAILURE;
- }
- index0 = su_root_register(root, &w0, f, p, 0);
- if (index0 == SOCKET_ERROR) {
- su_perror("su_root_register");
- return SU_FAILURE;
- }
- #endif
- if (su_wait_create(&w, s, SU_WAIT_IN) == SOCKET_ERROR) {
- su_perror("su_wait_create");
- return SU_FAILURE;
- }
- index = su_root_register(root, &w, f, p, 0);
- if (index == SOCKET_ERROR) {
- su_perror("su_root_register");
- return SU_FAILURE;
- }
- #if nomore
- su_root_deregister(root, index0);
- #endif
- p->rindex = index;
- return 0;
- }
- void
- do_destroy(su_root_t *root, struct pinger *p)
- {
- enter;
- if (opt_verbatim)
- printf("do_destroy %s at %s\n", p->name, snow(su_now()));
- su_root_deregister(root, p->rindex);
- su_timer_destroy(p->t), p->t = NULL;
- p->running = 0;
- }
- void
- start_ping(struct pinger *p, su_msg_r msg, su_sockaddr_t *arg)
- {
- enter;
- if (!p->running)
- return;
- if (opt_verbatim)
- printf("start_ping: %s\n", p->name);
- p->addr = *arg;
- p->id = 1;
- su_timer_set_interval(p->t, do_ping, p, 0);
- }
- void
- start_pong(struct pinger *p, su_msg_r msg, su_sockaddr_t *arg)
- {
- su_msg_r reply;
- enter;
- if (!p->running)
- return;
- if (opt_verbatim)
- printf("start_pong: %s\n", p->name);
- p->addr = *arg;
- if (su_msg_reply(reply, msg, start_ping, sizeof(p->addr)) == 0) {
- socklen_t sinsize[1] = { sizeof(p->addr) };
- if (getsockname(p->s, (struct sockaddr*)su_msg_data(reply), sinsize)
- == SOCKET_ERROR)
- su_perror("start_pong: getsockname()"), exit(1);
- su_msg_send(reply);
- }
- else {
- fprintf(stderr, "su_msg_reply failed!\n");
- }
- }
- void
- init_ping(struct pinger *p, su_msg_r msg, su_sockaddr_t *arg)
- {
- su_msg_r reply;
- enter;
- if (opt_verbatim)
- printf("init_ping: %s\n", p->name);
- if (su_msg_reply(reply, msg, start_pong, sizeof(p->addr)) == 0) {
- socklen_t sinsize[1] = { sizeof(p->addr) };
- if (getsockname(p->s, (struct sockaddr*)su_msg_data(reply), sinsize)
- == SOCKET_ERROR)
- su_perror("start_pong: getsockname()"), exit(1);
- su_msg_send(reply);
- }
- else {
- fprintf(stderr, "su_msg_reply failed!\n");
- }
- }
- void
- time_test(void)
- {
- su_time_t now = su_now(), then = now;
- su_duration_t t1, t2;
- su_duration_t us;
- enter;
- for (us = 0; us < 1000000; us += 300) {
- then.tv_sec = now.tv_sec;
- if ((then.tv_usec = now.tv_usec + us) >= 1000000)
- then.tv_usec -= 1000000, then.tv_sec++;
- t1 = su_duration(now, then);
- t2 = su_duration(then, now);
- assert(t1 == -t2);
- }
- if (opt_verbatim)
- printf("time_test: passed\n");
- }
- #if HAVE_SIGNAL
- #include <unistd.h>
- #include <signal.h>
- #if HAVE_ALARM
- static RETSIGTYPE sig_alarm(int s)
- {
- enter;
- fprintf(stderr, "%s: FAIL! test timeout!\n", name);
- exit(1);
- }
- static char const no_alarm[] = " [--no-alarm]";
- #else
- static char const no_alarm[] = "";
- #endif
- static
- RETSIGTYPE term(int n)
- {
- enter;
- exit(1);
- }
- #else
- static char const no_alarm[] = "";
- #endif
- void
- usage(int exitcode)
- {
- fprintf(stderr, "usage: %s [-6vs]%s\n", name, no_alarm);
- exit(exitcode);
- }
- /*
- * test su_wait functionality:
- *
- * Create a ponger, waking up do_recv() when data arrives,
- * then scheduling do_pong() by timer
- *
- * Create a pinger, executed from timer, scheduling do_ping(),
- * waking up do_rtt() when data arrives
- *
- * Create a timer, executing do_exit() after 10 seconds
- */
- int main(int argc, char *argv[])
- {
- su_root_t *root;
- su_clone_r ping = SU_CLONE_R_INIT, pong = SU_CLONE_R_INIT;
- su_msg_r start_msg = SU_MSG_R_INIT;
- su_timer_t *t;
- #if HAVE_ALARM
- int opt_alarm = 1;
- #endif
- struct pinger
- pinger = { PINGER, "ping", 1 },
- ponger = { PONGER, "pong", 1 };
- char *argv0 = argv[0];
- enter;
- while (argv[1]) {
- if (strcmp(argv[1], "-v") == 0) {
- opt_verbatim = 1;
- argv++;
- }
- #if SU_HAVE_IN6
- else if (strcmp(argv[1], "-6") == 0) {
- opt_family = AF_INET6;
- argv++;
- }
- #endif
- else if (strcmp(argv[1], "-s") == 0) {
- opt_singlethread = 1;
- argv++;
- }
- #if HAVE_ALARM
- else if (strcmp(argv[1], "--no-alarm") == 0) {
- opt_alarm = 0;
- argv++;
- }
- #endif
- else {
- usage(1);
- }
- }
- su_init(); atexit(su_deinit);
- #if HAVE_SIGNAL
- signal(SIGTERM, term);
- #if HAVE_ALARM
- if (opt_alarm) {
- alarm(60);
- signal(SIGALRM, sig_alarm);
- }
- #endif
- #endif
- time_test();
- root = su_root_create(NULL);
- if (!root) perror("su_root_create"), exit(1);
- fprintf(stdout, "test_su: testing %s port implementation\n",
- su_root_name(root));
- su_root_threading(root, !opt_singlethread);
- if (su_clone_start(root, ping, &pinger, do_init, do_destroy) != 0)
- perror("su_clone_start"), exit(1);
- if (su_clone_start(root, pong, &ponger, do_init, do_destroy) != 0)
- perror("su_clone_start"), exit(1);
- /* Test timer, exiting after 200 milliseconds */
- t = su_timer_create(su_root_task(root), 200L);
- if (t == NULL)
- su_perror("su_timer_create"), exit(1);
- su_timer_set(t, (su_timer_f)do_exit, NULL);
- su_msg_create(start_msg, su_clone_task(ping), su_clone_task(pong),
- init_ping, 0);
- su_msg_send(start_msg);
- su_root_run(root);
- su_clone_wait(root, ping);
- su_clone_wait(root, pong);
- su_timer_destroy(t);
- if (pinger.rtt_n) {
- printf("%s executed %u pings in %g, mean rtt=%g sec\n", name,
- pinger.rtt_n, pinger.rtt_total, pinger.rtt_total / pinger.rtt_n);
- }
- su_root_destroy(root);
- if (opt_verbatim)
- printf("%s exiting\n", argv0);
- return 0;
- }
|