blob: e106b71d6988c47a9725934897f46c24b658331d [file] [log] [blame]
Benny Prijono4bac2c12008-05-11 18:12:16 +00001/* $Id$ */
2/*
Benny Prijono32177c02008-06-20 22:44:47 +00003 * Copyright (C)2003-2008 Benny Prijono <benny@prijono.org>
Benny Prijono4bac2c12008-05-11 18:12:16 +00004 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19#include "test.h"
20#include <pjlib.h>
21
22/**
23 * \page page_pjlib_activesock_test Test: Active Socket
24 *
25 * This file is <b>pjlib-test/activesock.c</b>
26 *
27 * \include pjlib-test/activesock.c
28 */
29
30#if INCLUDE_ACTIVESOCK_TEST
31
32#define THIS_FILE "activesock.c"
33
34
35/*******************************************************************
36 * Simple UDP echo server.
37 */
38struct udp_echo_srv
39{
40 pj_activesock_t *asock;
41 pj_bool_t echo_enabled;
42 pj_uint16_t port;
43 pj_ioqueue_op_key_t send_key;
44 pj_status_t status;
45 unsigned rx_cnt;
46 unsigned rx_err_cnt, tx_err_cnt;
47};
48
49static void udp_echo_err(const char *title, pj_status_t status)
50{
51 char errmsg[PJ_ERR_MSG_SIZE];
52
53 pj_strerror(status, errmsg, sizeof(errmsg));
54 PJ_LOG(3,(THIS_FILE, " error: %s: %s", title, errmsg));
55}
56
57static pj_bool_t udp_echo_srv_on_data_recvfrom(pj_activesock_t *asock,
58 void *data,
59 pj_size_t size,
60 const pj_sockaddr_t *src_addr,
61 int addr_len,
62 pj_status_t status)
63{
64 struct udp_echo_srv *srv;
65 pj_ssize_t sent;
66
67
68 srv = (struct udp_echo_srv*) pj_activesock_get_user_data(asock);
69
70 if (status != PJ_SUCCESS) {
71 srv->status = status;
72 srv->rx_err_cnt++;
73 udp_echo_err("recvfrom() callback", status);
74 return PJ_TRUE;
75 }
76
77 srv->rx_cnt++;
78
79 /* Send back if echo is enabled */
80 if (srv->echo_enabled) {
81 sent = size;
82 srv->status = pj_activesock_sendto(asock, &srv->send_key, data,
83 &sent, 0,
84 src_addr, addr_len);
85 if (srv->status != PJ_SUCCESS) {
86 srv->tx_err_cnt++;
87 udp_echo_err("sendto()", status);
88 }
89 }
90
91 return PJ_TRUE;
92}
93
94
95static pj_status_t udp_echo_srv_create(pj_pool_t *pool,
96 pj_ioqueue_t *ioqueue,
97 pj_bool_t enable_echo,
98 struct udp_echo_srv **p_srv)
99{
100 struct udp_echo_srv *srv;
101 pj_sock_t sock_fd = PJ_INVALID_SOCKET;
102 pj_sockaddr addr;
103 int addr_len;
104 pj_activesock_cb activesock_cb;
105 pj_status_t status;
106
107 srv = PJ_POOL_ZALLOC_T(pool, struct udp_echo_srv);
108 srv->echo_enabled = enable_echo;
109
110 pj_sockaddr_in_init(&addr.ipv4, NULL, 0);
111 addr_len = sizeof(addr);
112
113 pj_bzero(&activesock_cb, sizeof(activesock_cb));
114 activesock_cb.on_data_recvfrom = &udp_echo_srv_on_data_recvfrom;
115
116 status = pj_activesock_create_udp(pool, &addr, NULL, ioqueue, &activesock_cb,
Benny Prijonoea8e4362008-06-06 14:12:23 +0000117 srv, &srv->asock, &addr);
Benny Prijono4bac2c12008-05-11 18:12:16 +0000118 if (status != PJ_SUCCESS) {
119 pj_sock_close(sock_fd);
120 udp_echo_err("pj_activesock_create()", status);
121 return status;
122 }
123
124 srv->port = pj_ntohs(addr.ipv4.sin_port);
125
Benny Prijono4bac2c12008-05-11 18:12:16 +0000126 pj_ioqueue_op_key_init(&srv->send_key, sizeof(srv->send_key));
127
128 status = pj_activesock_start_recvfrom(srv->asock, pool, 32, 0);
129 if (status != PJ_SUCCESS) {
130 pj_activesock_close(srv->asock);
131 udp_echo_err("pj_activesock_start_recvfrom()", status);
132 return status;
133 }
134
135
136 *p_srv = srv;
137 return PJ_SUCCESS;
138}
139
140static void udp_echo_srv_destroy(struct udp_echo_srv *srv)
141{
142 pj_activesock_close(srv->asock);
143}
144
145/*******************************************************************
146 * UDP ping pong test (send packet back and forth between two UDP echo
147 * servers.
148 */
149static int udp_ping_pong_test(void)
150{
151 pj_ioqueue_t *ioqueue = NULL;
152 pj_pool_t *pool = NULL;
153 struct udp_echo_srv *srv1=NULL, *srv2=NULL;
154 pj_bool_t need_send = PJ_TRUE;
155 unsigned data = 0;
156 int count, ret;
157 pj_status_t status;
158
159 pool = pj_pool_create(mem, "pingpong", 512, 512, NULL);
160 if (!pool)
161 return -10;
162
163 status = pj_ioqueue_create(pool, 4, &ioqueue);
164 if (status != PJ_SUCCESS) {
165 ret = -20;
166 udp_echo_err("pj_ioqueue_create()", status);
167 goto on_return;
168 }
169
170 status = udp_echo_srv_create(pool, ioqueue, PJ_TRUE, &srv1);
171 if (status != PJ_SUCCESS) {
172 ret = -30;
173 goto on_return;
174 }
175
176 status = udp_echo_srv_create(pool, ioqueue, PJ_TRUE, &srv2);
177 if (status != PJ_SUCCESS) {
178 ret = -40;
179 goto on_return;
180 }
181
182 /* initiate the first send */
183 for (count=0; count<1000; ++count) {
184 unsigned last_rx1, last_rx2;
185 unsigned i;
186
187 if (need_send) {
188 pj_str_t loopback;
189 pj_sockaddr_in addr;
190 pj_ssize_t sent;
191
192 ++data;
193
194 sent = sizeof(data);
195 loopback = pj_str("127.0.0.1");
196 pj_sockaddr_in_init(&addr, &loopback, srv2->port);
197 status = pj_activesock_sendto(srv1->asock, &srv1->send_key,
198 &data, &sent, 0,
199 &addr, sizeof(addr));
200 if (status != PJ_SUCCESS && status != PJ_EPENDING) {
201 ret = -50;
202 udp_echo_err("sendto()", status);
203 goto on_return;
204 }
205
206 need_send = PJ_FALSE;
207 }
208
209 last_rx1 = srv1->rx_cnt;
210 last_rx2 = srv2->rx_cnt;
211
212 for (i=0; i<10 && last_rx1 == srv1->rx_cnt && last_rx2 == srv2->rx_cnt; ++i) {
213 pj_time_val delay = {0, 10};
214 pj_ioqueue_poll(ioqueue, &delay);
215 }
216
217 if (srv1->rx_err_cnt+srv1->tx_err_cnt != 0 ||
218 srv2->rx_err_cnt+srv2->tx_err_cnt != 0)
219 {
220 /* Got error */
221 ret = -60;
222 goto on_return;
223 }
224
225 if (last_rx1 == srv1->rx_cnt && last_rx2 == srv2->rx_cnt) {
226 /* Packet lost */
227 ret = -70;
228 udp_echo_err("packets have been lost", PJ_ETIMEDOUT);
229 goto on_return;
230 }
231 }
232
233 ret = 0;
234
235on_return:
236 if (srv2)
237 udp_echo_srv_destroy(srv2);
238 if (srv1)
239 udp_echo_srv_destroy(srv1);
240 if (ioqueue)
241 pj_ioqueue_destroy(ioqueue);
242 if (pool)
243 pj_pool_release(pool);
244
245 return ret;
246}
247
248
249int activesock_test(void)
250{
251 int ret;
252
253 PJ_LOG(3,("", "..udp ping/pong test"));
254 ret = udp_ping_pong_test();
255 if (ret != 0)
256 return ret;
257
258 return 0;
259}
260
261#else /* INCLUDE_ACTIVESOCK_TEST */
262/* To prevent warning about "translation unit is empty"
263 * when this test is disabled.
264 */
265int dummy_active_sock_test;
266#endif /* INCLUDE_ACTIVESOCK_TEST */
267