Imported Upstream version 0.1.17
[platform/upstream/libnice.git] / tests / test-pseudotcp.c
1 /*
2  * This file is part of the Nice GLib ICE library.
3  *
4  * (C) 2010 Collabora Ltd.
5  *  Contact: Youness Alaoui
6  *
7  * The contents of this file are subject to the Mozilla Public License Version
8  * 1.1 (the "License"); you may not use this file except in compliance with
9  * the License. You may obtain a copy of the License at
10  * http://www.mozilla.org/MPL/
11  *
12  * Software distributed under the License is distributed on an "AS IS" basis,
13  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14  * for the specific language governing rights and limitations under the
15  * License.
16  *
17  * The Original Code is the Nice GLib ICE library.
18  *
19  * The Initial Developers of the Original Code are Collabora Ltd and Nokia
20  * Corporation. All Rights Reserved.
21  *
22  * Contributors:
23  *   Youness Alaoui, Collabora Ltd.
24  *
25  * Alternatively, the contents of this file may be used under the terms of the
26  * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which
27  * case the provisions of LGPL are applicable instead of those above. If you
28  * wish to allow use of your version of this file only under the terms of the
29  * LGPL and not to allow others to use your version of this file under the
30  * MPL, indicate your decision by deleting the provisions above and replace
31  * them with the notice and other provisions required by the LGPL. If you do
32  * not delete the provisions above, a recipient may use your version of this
33  * file under either the MPL or the LGPL.
34  */
35 #ifdef HAVE_CONFIG_H
36 # include "config.h"
37 #endif
38
39 #include <locale.h>
40 #include <string.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <errno.h>
44
45 #include "pseudotcp.h"
46
47 PseudoTcpSocket *left;
48 PseudoTcpSocket *right;
49 GMainLoop *mainloop = NULL;
50 FILE *in = NULL;
51 FILE *out = NULL;
52 int total_read = 0;
53 int total_wrote = 0;
54 guint left_clock = 0;
55 guint right_clock = 0;
56 gboolean left_closed;
57 gboolean right_closed;
58
59 gboolean reading_done = FALSE;
60
61 static void adjust_clock (PseudoTcpSocket *sock);
62
63 static void write_to_sock (PseudoTcpSocket *sock)
64 {
65   gchar buf[1024];
66   gsize len;
67   gint wlen;
68   guint total = 0;
69
70   while (TRUE) {
71     len = fread (buf, 1, sizeof(buf), in);
72     if (len == 0) {
73       g_debug ("Done reading data from file");
74       g_assert (feof (in));
75       reading_done = TRUE;
76       pseudo_tcp_socket_close (sock, FALSE);
77       break;
78     } else {
79       wlen = pseudo_tcp_socket_send (sock, buf, len);
80       g_debug ("Sending %" G_GSIZE_FORMAT " bytes : %d", len, wlen);
81       total += wlen;
82       total_read += wlen;
83       if (wlen < (gint) len) {
84         g_debug ("seeking  %" G_GSIZE_FORMAT " from %lu", wlen - len,
85             ftell (in));
86         fseek (in, wlen - len, SEEK_CUR);
87         g_assert (!feof (in));
88         g_debug ("Socket queue full after %d bytes written", total);
89         break;
90       }
91     }
92   }
93   adjust_clock (sock);
94 }
95
96 static void opened (PseudoTcpSocket *sock, gpointer data)
97 {
98   g_debug ("Socket %p Opened", sock);
99   if (sock == left) {
100     if (in)
101       write_to_sock (sock);
102     else {
103       pseudo_tcp_socket_send (sock, "abcdefghijklmnopqrstuvwxyz", 26);
104       reading_done = TRUE;
105       pseudo_tcp_socket_close (sock, FALSE);
106     }
107   }
108 }
109
110 static void readable (PseudoTcpSocket *sock, gpointer data)
111 {
112   gchar buf[1024];
113   gint len;
114   g_debug ("Socket %p Readable", sock);
115
116   do {
117     len = pseudo_tcp_socket_recv (sock, buf, sizeof(buf));
118
119     if (len > 0) {
120       g_debug ("Read %d bytes", len);
121       if (out) {
122         if (fwrite (buf, len, 1, out) == 0)
123           g_debug ("Error writing to output file");
124         else {
125           total_wrote += len;
126
127           g_assert_cmpint (total_wrote, <=, total_read);
128           g_debug ("Written %d bytes, need %d bytes", total_wrote, total_read);
129           if (total_wrote == total_read && feof (in)) {
130             g_assert (reading_done);
131             pseudo_tcp_socket_close (sock, FALSE);
132           }
133         }
134       } else {
135         if (len == 26 && strncmp (buf, "abcdefghijklmnopqrstuvwxyz", len) == 0) {
136           pseudo_tcp_socket_close (sock, FALSE);
137         } else {
138           g_debug ("Error reading data.. read %d bytes : %s", len, buf);
139           exit (-1);
140         }
141       }
142     } else if (len == 0) {
143       pseudo_tcp_socket_close (sock, FALSE);
144     }
145   } while (len > 0);
146
147   if (len == -1 &&
148       pseudo_tcp_socket_get_error (sock) != EWOULDBLOCK) {
149     g_debug ("Error reading from socket %p: %s", sock,
150         g_strerror (pseudo_tcp_socket_get_error (sock)));
151     exit (-1);
152   }
153 }
154
155 static void writable (PseudoTcpSocket *sock, gpointer data)
156 {
157   g_debug ("Socket %p Writable", sock);
158   if (in && sock == left)
159     write_to_sock (sock);
160 }
161
162 static void closed (PseudoTcpSocket *sock, guint32 err, gpointer data)
163 {
164   g_error ("Socket %p Closed : %d", sock, err);
165 }
166
167 struct notify_data {
168   PseudoTcpSocket *sock;
169   guint32 len;
170   gchar buffer[];
171 };
172
173 static gboolean notify_packet (gpointer user_data)
174 {
175   struct notify_data *data = (struct notify_data*) user_data;
176
177   pseudo_tcp_socket_notify_packet (data->sock, data->buffer, data->len);
178   adjust_clock (data->sock);
179
180   g_free (data);
181   return FALSE;
182 }
183
184 static PseudoTcpWriteResult write_packet (PseudoTcpSocket *sock,
185     const gchar *buffer, guint32 len, gpointer user_data)
186 {
187   struct notify_data *data;
188   PseudoTcpState state;
189   int drop_rate = rand () % 100;
190   g_object_get (sock, "state", &state, NULL);
191
192   if (drop_rate < 5) {
193     g_debug ("*********************Dropping packet (%d) from %p", drop_rate,
194         sock);
195     return WR_SUCCESS;
196   }
197
198   data = g_malloc (sizeof(struct notify_data) + len);
199
200   g_debug ("Socket %p(%d) Writing : %d bytes", sock, state, len);
201
202   memcpy (data->buffer, buffer, len);
203   data->len = len;
204
205   if (sock == left)
206     data->sock = right;
207   else
208     data->sock = left;
209
210   g_idle_add (notify_packet, data);
211
212   return WR_SUCCESS;
213 }
214
215
216 static gboolean notify_clock (gpointer data)
217 {
218   PseudoTcpSocket *sock = (PseudoTcpSocket *)data;
219   //g_debug ("Socket %p: Notifying clock", sock);
220   pseudo_tcp_socket_notify_clock (sock);
221   adjust_clock (sock);
222   return FALSE;
223 }
224
225 static void adjust_clock (PseudoTcpSocket *sock)
226 {
227   guint64 timeout = 0;
228
229   if (pseudo_tcp_socket_get_next_clock (sock, &timeout)) {
230     timeout -= g_get_monotonic_time () / 1000;
231     g_debug ("Socket %p: Adjusting clock to %" G_GUINT64_FORMAT " ms", sock, timeout);
232     if (sock == left) {
233       if (left_clock != 0)
234          g_source_remove (left_clock);
235       left_clock = g_timeout_add (timeout, notify_clock, sock);
236     } else {
237       if (right_clock != 0)
238          g_source_remove (right_clock);
239       right_clock = g_timeout_add (timeout, notify_clock, sock);
240     }
241   } else {
242     g_debug ("Socket %p should be destroyed, it's done", sock);
243     if (sock == left)
244       left_closed = TRUE;
245     else
246       right_closed = TRUE;
247     if (left_closed && right_closed)
248       g_main_loop_quit (mainloop);
249   }
250 }
251
252
253 int main (int argc, char *argv[])
254 {
255   PseudoTcpCallbacks cbs = {
256     NULL, opened, readable, writable, closed, write_packet
257   };
258
259   setlocale (LC_ALL, "");
260
261   mainloop = g_main_loop_new (NULL, FALSE);
262
263   pseudo_tcp_set_debug_level (PSEUDO_TCP_DEBUG_VERBOSE);
264
265   left_closed = right_closed = FALSE;
266
267   left = pseudo_tcp_socket_new (0, &cbs);
268   right = pseudo_tcp_socket_new (0, &cbs);
269   g_debug ("Left: %p. Right: %p", left, right);
270
271   pseudo_tcp_socket_notify_mtu (left, 1496);
272   pseudo_tcp_socket_notify_mtu (right, 1496);
273
274   pseudo_tcp_socket_connect (left);
275   adjust_clock (left);
276   adjust_clock (right);
277
278   if (argc == 3) {
279     in = fopen (argv[1], "r");
280     out = fopen (argv[2], "w");
281   }
282
283   g_main_loop_run (mainloop);
284
285   g_object_unref (left);
286   g_object_unref (right);
287
288   if (in)
289     fclose (in);
290   if (out)
291     fclose (out);
292
293   return 0;
294 }
295