test_su.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583
  1. /*
  2. * This file is part of the Sofia-SIP package
  3. *
  4. * Copyright (C) 2005 Nokia Corporation.
  5. *
  6. * Contact: Pekka Pessi <pekka.pessi@nokia.com>
  7. *
  8. * This library is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU Lesser General Public License
  10. * as published by the Free Software Foundation; either version 2.1 of
  11. * the License, or (at your option) any later version.
  12. *
  13. * This library is distributed in the hope that it will be useful, but
  14. * WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. * Lesser General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with this library; if not, write to the Free Software
  20. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  21. * 02110-1301 USA
  22. *
  23. */
  24. /**@ingroup su_root_ex
  25. * @CFILE test_su.c
  26. *
  27. * @brief Test program for su wait objects, root, timers, clones, and messages.
  28. *
  29. * @internal
  30. *
  31. * @author Pekka Pessi <Pekka.Pessi@nokia.com>
  32. *
  33. * @date Created: Thu Mar 18 19:40:51 1999 pessi
  34. */
  35. #include "config.h"
  36. struct pinger;
  37. #define SU_ROOT_MAGIC_T struct pinger
  38. #define SU_INTERNAL_P su_root_t *
  39. #define SU_MSG_ARG_T su_sockaddr_t
  40. #include "sofia-sip/su.h"
  41. #include "sofia-sip/su_wait.h"
  42. #include "sofia-sip/su_log.h"
  43. #include "sofia-sip/su_debug.h"
  44. #include <stdlib.h>
  45. #include <string.h>
  46. #include <stdio.h>
  47. #include <assert.h>
  48. char const name[] = "test_su";
  49. #if HAVE_FUNC
  50. #define enter (void)SU_DEBUG_9(("%s: %s: entering\n", name, __func__))
  51. #define nh_enter (void)SU_DEBUG_9(("%s %s(%p): entering\n", name, __func__, nh))
  52. #elif HAVE_FUNCTION
  53. #define enter (void)SU_DEBUG_9(("%s: %s: entering\n", name, __FUNCTION__))
  54. #define nh_enter (void)SU_DEBUG_9(("%s %s(%p): entering\n", name, __FUNCTION__, nh))
  55. #define __func__ __FUNCTION__
  56. #else
  57. #define enter ((void)0)
  58. #define nh_enter ((void)0)
  59. #define __func__ "test_su"
  60. #endif
  61. struct pinger {
  62. enum { PINGER = 1, PONGER = 2 } const sort;
  63. char const * name;
  64. unsigned running : 1;
  65. unsigned : 0;
  66. su_root_t *root;
  67. su_socket_t s;
  68. su_timer_t *t;
  69. int id;
  70. int rindex;
  71. su_time_t when;
  72. su_sockaddr_t addr;
  73. double rtt_total;
  74. int rtt_n;
  75. };
  76. short opt_family = AF_INET;
  77. short opt_verbatim = 0;
  78. short opt_singlethread = 0;
  79. static su_socket_t udpsocket(void)
  80. {
  81. su_socket_t s;
  82. su_sockaddr_t su = { 0 };
  83. socklen_t sulen = sizeof(su);
  84. char nbuf[64];
  85. su.su_family = opt_family;
  86. su_getlocalip(&su);
  87. s = su_socket(su.su_family, SOCK_DGRAM, 0);
  88. if (s == INVALID_SOCKET) {
  89. su_perror("udpsocket: socket");
  90. exit(1);
  91. }
  92. if (bind(s, &su.su_sa, su_sockaddr_size(&su)) == SOCKET_ERROR) {
  93. su_perror("udpsocket: bind");
  94. exit(1);
  95. }
  96. if (getsockname(s, &su.su_sa, &sulen) == SOCKET_ERROR) {
  97. su_perror("udpsocket: getsockname");
  98. exit(1);
  99. }
  100. if (opt_verbatim)
  101. printf("udpsocket: using address [%s]:%u\n",
  102. su_inet_ntop(su.su_family, SU_ADDR(&su), nbuf, sizeof(nbuf)),
  103. ntohs(su.su_sin.sin_port));
  104. return s;
  105. }
  106. static char *snow(su_time_t now)
  107. {
  108. static char buf[24];
  109. su_time_print(buf, sizeof(buf), &now);
  110. return buf;
  111. }
  112. void
  113. do_ping(struct pinger *p, su_timer_t *t, void *p0)
  114. {
  115. char buf[1024];
  116. assert(p == su_root_magic(su_timer_root(t)));
  117. assert(p->sort == PINGER);
  118. p->when = su_now();
  119. snprintf(buf, sizeof(buf), "Ping %d at %s", p->id++, snow(p->when));
  120. if (su_sendto(p->s, buf, strlen(buf), 0,
  121. &p->addr, su_sockaddr_size(&p->addr)) == -1) {
  122. su_perror("do_ping: send");
  123. }
  124. if (opt_verbatim) {
  125. puts(buf);
  126. fflush(stdout);
  127. }
  128. }
  129. int
  130. do_rtt(struct pinger *p, su_wait_t *w, void *p0)
  131. {
  132. su_sockaddr_t su;
  133. struct sockaddr * const susa = &su.su_sa;
  134. socklen_t susize[] = { sizeof(su)};
  135. char buf[1024];
  136. char nbuf[1024];
  137. int n;
  138. su_time_t now = su_now();
  139. double rtt;
  140. assert(p0 == p);
  141. assert(p->sort == PINGER);
  142. rtt = su_time_diff(now, p->when);
  143. p->rtt_total += rtt, p->rtt_n++;
  144. su_wait_events(w, p->s);
  145. n = recvfrom(p->s, buf, sizeof(buf) - 1, 0, susa, susize);
  146. if (n < 0) {
  147. su_perror("do_rtt: recvfrom");
  148. return 0;
  149. }
  150. buf[n] = 0;
  151. if (opt_verbatim)
  152. printf("do_rtt: %d bytes from [%s]:%u: \"%s\", rtt = %lg ms\n",
  153. n, su_inet_ntop(su.su_family, SU_ADDR(&su), nbuf, sizeof(nbuf)),
  154. ntohs(su.su_sin.sin_port), buf, rtt / 1000);
  155. do_ping(p, p->t, NULL);
  156. return 0;
  157. }
  158. void
  159. do_pong(struct pinger *p, su_timer_t *t, void *p0)
  160. {
  161. char buf[1024];
  162. assert(p == su_root_magic(su_timer_root(t)));
  163. assert(p->sort == PONGER);
  164. p->id = 0;
  165. snprintf(buf, sizeof(buf), "Pong at %s", snow(su_now()));
  166. if (su_sendto(p->s, buf, strlen(buf), 0,
  167. &p->addr, su_sockaddr_size(&p->addr)) == -1) {
  168. su_perror("do_pong: send");
  169. }
  170. if (opt_verbatim) {
  171. puts(buf);
  172. fflush(stdout);
  173. }
  174. }
  175. int
  176. do_recv(struct pinger *p, su_wait_t *w, void *p0)
  177. {
  178. su_sockaddr_t su;
  179. socklen_t susize[] = { sizeof(su)};
  180. char buf[1024];
  181. char nbuf[1024];
  182. int n;
  183. su_time_t now = su_now();
  184. assert(p0 == p);
  185. assert(p->sort == PONGER);
  186. su_wait_events(w, p->s);
  187. n = recvfrom(p->s, buf, sizeof(buf) - 1, 0, &su.su_sa, susize);
  188. if (n < 0) {
  189. su_perror("do_recv: recvfrom");
  190. return 0;
  191. }
  192. buf[n] = 0;
  193. if (opt_verbatim)
  194. printf("do_recv: %d bytes from [%s]:%u: \"%s\" at %s\n",
  195. n, su_inet_ntop(su.su_family, SU_ADDR(&su), nbuf, sizeof(nbuf)),
  196. ntohs(su.su_sin.sin_port), buf, snow(now));
  197. fflush(stdout);
  198. #if 0
  199. if (p->id)
  200. puts("do_recv: already a pending reply");
  201. if (su_timer_set(p->t, do_pong, p) < 0) {
  202. fprintf(stderr, "do_recv: su_timer_set() error\n");
  203. return 0;
  204. }
  205. p->id = 1;
  206. #else
  207. do_pong(p, p->t, NULL);
  208. #endif
  209. return 0;
  210. }
  211. void
  212. do_exit(struct pinger *x, su_timer_t *t, void *x0)
  213. {
  214. if (opt_verbatim)
  215. printf("do_exit at %s\n", snow(su_now()));
  216. su_root_break(su_timer_root(t));
  217. }
  218. int
  219. do_init(su_root_t *root, struct pinger *p)
  220. {
  221. su_wait_t w;
  222. su_socket_t s;
  223. long interval;
  224. su_timer_t *t;
  225. su_wakeup_f f;
  226. int index;
  227. #if nomore
  228. su_wait_t w0;
  229. int index0
  230. #endif
  231. enter;
  232. switch (p->sort) {
  233. case PINGER: f = do_rtt; interval = 200; break;
  234. case PONGER: f = do_recv; interval = 40; break;
  235. default:
  236. return SU_FAILURE;
  237. }
  238. p->t = t = su_timer_create(su_root_task(root), interval);
  239. if (t == NULL) {
  240. su_perror("su_timer_create");
  241. return SU_FAILURE;
  242. }
  243. /* Create a sockets, */
  244. p->s = s = udpsocket();
  245. #if nomore
  246. if (su_wait_create(&w0, s, SU_WAIT_IN) == SOCKET_ERROR) {
  247. su_perror("su_wait_create");
  248. return SU_FAILURE;
  249. }
  250. index0 = su_root_register(root, &w0, f, p, 0);
  251. if (index0 == SOCKET_ERROR) {
  252. su_perror("su_root_register");
  253. return SU_FAILURE;
  254. }
  255. #endif
  256. if (su_wait_create(&w, s, SU_WAIT_IN) == SOCKET_ERROR) {
  257. su_perror("su_wait_create");
  258. return SU_FAILURE;
  259. }
  260. index = su_root_register(root, &w, f, p, 0);
  261. if (index == SOCKET_ERROR) {
  262. su_perror("su_root_register");
  263. return SU_FAILURE;
  264. }
  265. #if nomore
  266. su_root_deregister(root, index0);
  267. #endif
  268. p->rindex = index;
  269. return 0;
  270. }
  271. void
  272. do_destroy(su_root_t *root, struct pinger *p)
  273. {
  274. enter;
  275. if (opt_verbatim)
  276. printf("do_destroy %s at %s\n", p->name, snow(su_now()));
  277. su_root_deregister(root, p->rindex);
  278. su_timer_destroy(p->t), p->t = NULL;
  279. p->running = 0;
  280. }
  281. void
  282. start_ping(struct pinger *p, su_msg_r msg, su_sockaddr_t *arg)
  283. {
  284. enter;
  285. if (!p->running)
  286. return;
  287. if (opt_verbatim)
  288. printf("start_ping: %s\n", p->name);
  289. p->addr = *arg;
  290. p->id = 1;
  291. su_timer_set_interval(p->t, do_ping, p, 0);
  292. }
  293. void
  294. start_pong(struct pinger *p, su_msg_r msg, su_sockaddr_t *arg)
  295. {
  296. su_msg_r reply;
  297. enter;
  298. if (!p->running)
  299. return;
  300. if (opt_verbatim)
  301. printf("start_pong: %s\n", p->name);
  302. p->addr = *arg;
  303. if (su_msg_reply(reply, msg, start_ping, sizeof(p->addr)) == 0) {
  304. socklen_t sinsize[1] = { sizeof(p->addr) };
  305. if (getsockname(p->s, (struct sockaddr*)su_msg_data(reply), sinsize)
  306. == SOCKET_ERROR)
  307. su_perror("start_pong: getsockname()"), exit(1);
  308. su_msg_send(reply);
  309. }
  310. else {
  311. fprintf(stderr, "su_msg_reply failed!\n");
  312. }
  313. }
  314. void
  315. init_ping(struct pinger *p, su_msg_r msg, su_sockaddr_t *arg)
  316. {
  317. su_msg_r reply;
  318. enter;
  319. if (opt_verbatim)
  320. printf("init_ping: %s\n", p->name);
  321. if (su_msg_reply(reply, msg, start_pong, sizeof(p->addr)) == 0) {
  322. socklen_t sinsize[1] = { sizeof(p->addr) };
  323. if (getsockname(p->s, (struct sockaddr*)su_msg_data(reply), sinsize)
  324. == SOCKET_ERROR)
  325. su_perror("start_pong: getsockname()"), exit(1);
  326. su_msg_send(reply);
  327. }
  328. else {
  329. fprintf(stderr, "su_msg_reply failed!\n");
  330. }
  331. }
  332. void
  333. time_test(void)
  334. {
  335. su_time_t now = su_now(), then = now;
  336. su_duration_t t1, t2;
  337. su_duration_t us;
  338. enter;
  339. for (us = 0; us < 1000000; us += 300) {
  340. then.tv_sec = now.tv_sec;
  341. if ((then.tv_usec = now.tv_usec + us) >= 1000000)
  342. then.tv_usec -= 1000000, then.tv_sec++;
  343. t1 = su_duration(now, then);
  344. t2 = su_duration(then, now);
  345. assert(t1 == -t2);
  346. }
  347. if (opt_verbatim)
  348. printf("time_test: passed\n");
  349. }
  350. #if HAVE_SIGNAL
  351. #include <unistd.h>
  352. #include <signal.h>
  353. #if HAVE_ALARM
  354. static RETSIGTYPE sig_alarm(int s)
  355. {
  356. enter;
  357. fprintf(stderr, "%s: FAIL! test timeout!\n", name);
  358. exit(1);
  359. }
  360. static char const no_alarm[] = " [--no-alarm]";
  361. #else
  362. static char const no_alarm[] = "";
  363. #endif
  364. static
  365. RETSIGTYPE term(int n)
  366. {
  367. enter;
  368. exit(1);
  369. }
  370. #else
  371. static char const no_alarm[] = "";
  372. #endif
  373. void
  374. usage(int exitcode)
  375. {
  376. fprintf(stderr, "usage: %s [-6vs]%s\n", name, no_alarm);
  377. exit(exitcode);
  378. }
  379. /*
  380. * test su_wait functionality:
  381. *
  382. * Create a ponger, waking up do_recv() when data arrives,
  383. * then scheduling do_pong() by timer
  384. *
  385. * Create a pinger, executed from timer, scheduling do_ping(),
  386. * waking up do_rtt() when data arrives
  387. *
  388. * Create a timer, executing do_exit() after 10 seconds
  389. */
  390. int main(int argc, char *argv[])
  391. {
  392. su_root_t *root;
  393. su_clone_r ping = SU_CLONE_R_INIT, pong = SU_CLONE_R_INIT;
  394. su_msg_r start_msg = SU_MSG_R_INIT;
  395. su_timer_t *t;
  396. #if HAVE_ALARM
  397. int opt_alarm = 1;
  398. #endif
  399. struct pinger
  400. pinger = { PINGER, "ping", 1 },
  401. ponger = { PONGER, "pong", 1 };
  402. char *argv0 = argv[0];
  403. enter;
  404. while (argv[1]) {
  405. if (strcmp(argv[1], "-v") == 0) {
  406. opt_verbatim = 1;
  407. argv++;
  408. }
  409. #if SU_HAVE_IN6
  410. else if (strcmp(argv[1], "-6") == 0) {
  411. opt_family = AF_INET6;
  412. argv++;
  413. }
  414. #endif
  415. else if (strcmp(argv[1], "-s") == 0) {
  416. opt_singlethread = 1;
  417. argv++;
  418. }
  419. #if HAVE_ALARM
  420. else if (strcmp(argv[1], "--no-alarm") == 0) {
  421. opt_alarm = 0;
  422. argv++;
  423. }
  424. #endif
  425. else {
  426. usage(1);
  427. }
  428. }
  429. su_init(); atexit(su_deinit);
  430. #if HAVE_SIGNAL
  431. signal(SIGTERM, term);
  432. #if HAVE_ALARM
  433. if (opt_alarm) {
  434. alarm(60);
  435. signal(SIGALRM, sig_alarm);
  436. }
  437. #endif
  438. #endif
  439. time_test();
  440. root = su_root_create(NULL);
  441. if (!root) perror("su_root_create"), exit(1);
  442. fprintf(stdout, "test_su: testing %s port implementation\n",
  443. su_root_name(root));
  444. su_root_threading(root, !opt_singlethread);
  445. if (su_clone_start(root, ping, &pinger, do_init, do_destroy) != 0)
  446. perror("su_clone_start"), exit(1);
  447. if (su_clone_start(root, pong, &ponger, do_init, do_destroy) != 0)
  448. perror("su_clone_start"), exit(1);
  449. /* Test timer, exiting after 200 milliseconds */
  450. t = su_timer_create(su_root_task(root), 200L);
  451. if (t == NULL)
  452. su_perror("su_timer_create"), exit(1);
  453. su_timer_set(t, (su_timer_f)do_exit, NULL);
  454. su_msg_create(start_msg, su_clone_task(ping), su_clone_task(pong),
  455. init_ping, 0);
  456. su_msg_send(start_msg);
  457. su_root_run(root);
  458. su_clone_wait(root, ping);
  459. su_clone_wait(root, pong);
  460. su_timer_destroy(t);
  461. if (pinger.rtt_n) {
  462. printf("%s executed %u pings in %g, mean rtt=%g sec\n", name,
  463. pinger.rtt_n, pinger.rtt_total, pinger.rtt_total / pinger.rtt_n);
  464. }
  465. su_root_destroy(root);
  466. if (opt_verbatim)
  467. printf("%s exiting\n", argv0);
  468. return 0;
  469. }