test_su_osx.c 12 KB

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