test-pseudotcp.c 7.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
/*
 * This file is part of the Nice GLib ICE library.
 *
 * (C) 2010 Collabora Ltd.
 *  Contact: Youness Alaoui
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is the Nice GLib ICE library.
 *
 * The Initial Developers of the Original Code are Collabora Ltd and Nokia
 * Corporation. All Rights Reserved.
 *
 * Contributors:
 *   Youness Alaoui, Collabora Ltd.
 *
 * Alternatively, the contents of this file may be used under the terms of the
 * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which
 * case the provisions of LGPL are applicable instead of those above. If you
 * wish to allow use of your version of this file only under the terms of the
 * LGPL and not to allow others to use your version of this file under the
 * MPL, indicate your decision by deleting the provisions above and replace
 * them with the notice and other provisions required by the LGPL. If you do
 * not delete the provisions above, a recipient may use your version of this
 * file under either the MPL or the LGPL.
 */
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

39
#include <locale.h>
40 41 42
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
43
#include <errno.h>
44 45 46 47 48 49 50 51 52 53 54 55

#include "pseudotcp.h"

PseudoTcpSocket *left;
PseudoTcpSocket *right;
GMainLoop *mainloop = NULL;
FILE *in = NULL;
FILE *out = NULL;
int total_read = 0;
int total_wrote = 0;
guint left_clock = 0;
guint right_clock = 0;
56 57
gboolean left_closed;
gboolean right_closed;
58

59 60
gboolean reading_done = FALSE;

61 62 63 64 65
static void adjust_clock (PseudoTcpSocket *sock);

static void write_to_sock (PseudoTcpSocket *sock)
{
  gchar buf[1024];
66 67
  gsize len;
  gint wlen;
68 69 70 71 72 73
  guint total = 0;

  while (TRUE) {
    len = fread (buf, 1, sizeof(buf), in);
    if (len == 0) {
      g_debug ("Done reading data from file");
74 75
      g_assert (feof (in));
      reading_done = TRUE;
76
      pseudo_tcp_socket_close (sock, FALSE);
77 78 79
      break;
    } else {
      wlen = pseudo_tcp_socket_send (sock, buf, len);
80
      g_debug ("Sending %" G_GSIZE_FORMAT " bytes : %d", len, wlen);
81 82
      total += wlen;
      total_read += wlen;
83
      if (wlen < (gint) len) {
84
        g_debug ("seeking  %ld from %lu", wlen - len, ftell (in));
85
        fseek (in, wlen - len, SEEK_CUR);
86
        g_assert (!feof (in));
87 88 89 90 91 92 93 94 95 96 97 98 99 100
        g_debug ("Socket queue full after %d bytes written", total);
        break;
      }
    }
  }
  adjust_clock (sock);
}

static void opened (PseudoTcpSocket *sock, gpointer data)
{
  g_debug ("Socket %p Opened", sock);
  if (sock == left) {
    if (in)
      write_to_sock (sock);
101
    else {
102
      pseudo_tcp_socket_send (sock, "abcdefghijklmnopqrstuvwxyz", 26);
103
      reading_done = TRUE;
104 105
      pseudo_tcp_socket_close (sock, FALSE);
    }
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
  }
}

static void readable (PseudoTcpSocket *sock, gpointer data)
{
  gchar buf[1024];
  gint len;
  g_debug ("Socket %p Readable", sock);

  do {
    len = pseudo_tcp_socket_recv (sock, buf, sizeof(buf));

    if (len > 0) {
      g_debug ("Read %d bytes", len);
      if (out) {
        if (fwrite (buf, len, 1, out) == 0)
          g_debug ("Error writing to output file");
        else {
          total_wrote += len;

126
          g_assert (total_wrote <= total_read);
127
          g_debug ("Written %d bytes, need %d bytes", total_wrote, total_read);
128
          if (total_wrote == total_read && feof (in)) {
129
            g_assert (reading_done);
130
            pseudo_tcp_socket_close (sock, FALSE);
131 132 133
          }
        }
      } else {
134
        if (len == 26 && strncmp (buf, "abcdefghijklmnopqrstuvwxyz", len) == 0) {
135
          pseudo_tcp_socket_close (sock, FALSE);
136
        } else {
137
          g_debug ("Error reading data.. read %d bytes : %s", len, buf);
138 139 140
          exit (-1);
        }
      }
141 142
    } else if (len == 0) {
      pseudo_tcp_socket_close (sock, FALSE);
143 144
    }
  } while (len > 0);
145 146 147

  if (len == -1 &&
      pseudo_tcp_socket_get_error (sock) != EWOULDBLOCK) {
148 149
    g_debug ("Error reading from socket %p: %s", sock,
        g_strerror (pseudo_tcp_socket_get_error (sock)));
150 151
    exit (-1);
  }
152 153 154 155 156
}

static void writable (PseudoTcpSocket *sock, gpointer data)
{
  g_debug ("Socket %p Writable", sock);
157
  if (in && sock == left)
158 159 160 161 162
    write_to_sock (sock);
}

static void closed (PseudoTcpSocket *sock, guint32 err, gpointer data)
{
163
  g_error ("Socket %p Closed : %d", sock, err);
164 165 166 167 168
}

struct notify_data {
  PseudoTcpSocket *sock;
  guint32 len;
169
  gchar buffer[];
170 171 172 173 174
};

static gboolean notify_packet (gpointer user_data)
{
  struct notify_data *data = (struct notify_data*) user_data;
175

176 177
  pseudo_tcp_socket_notify_packet (data->sock, data->buffer, data->len);
  adjust_clock (data->sock);
178

179 180 181 182
  g_free (data);
  return FALSE;
}

183
static PseudoTcpWriteResult write_packet (PseudoTcpSocket *sock,
184 185
    const gchar *buffer, guint32 len, gpointer user_data)
{
186
  struct notify_data *data;
187 188 189 190 191
  PseudoTcpState state;
  int drop_rate = rand () % 100;
  g_object_get (sock, "state", &state, NULL);

  if (drop_rate < 5) {
192 193
    g_debug ("*********************Dropping packet (%d) from %p", drop_rate,
        sock);
194 195 196
    return WR_SUCCESS;
  }

197
  data = g_malloc (sizeof(struct notify_data) + len);
198

199 200 201 202 203
  g_debug ("Socket %p(%d) Writing : %d bytes", sock, state, len);

  memcpy (data->buffer, buffer, len);
  data->len = len;

204
  if (sock == left)
205
    data->sock = right;
206
  else
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225
    data->sock = left;

  g_idle_add (notify_packet, data);

  return WR_SUCCESS;
}


static gboolean notify_clock (gpointer data)
{
  PseudoTcpSocket *sock = (PseudoTcpSocket *)data;
  //g_debug ("Socket %p: Notifying clock", sock);
  pseudo_tcp_socket_notify_clock (sock);
  adjust_clock (sock);
  return FALSE;
}

static void adjust_clock (PseudoTcpSocket *sock)
{
226 227
  guint64 timeout = 0;

228
  if (pseudo_tcp_socket_get_next_clock (sock, &timeout)) {
229
    timeout -= g_get_monotonic_time () / 1000;
230
    g_debug ("Socket %p: Adjusting clock to %" G_GUINT64_FORMAT " ms", sock, timeout);
231 232 233 234 235 236 237 238 239 240
    if (sock == left) {
      if (left_clock != 0)
         g_source_remove (left_clock);
      left_clock = g_timeout_add (timeout, notify_clock, sock);
    } else {
      if (right_clock != 0)
         g_source_remove (right_clock);
      right_clock = g_timeout_add (timeout, notify_clock, sock);
    }
  } else {
241
    g_debug ("Socket %p should be destroyed, it's done", sock);
242
    if (sock == left)
243
      left_closed = TRUE;
244
    else
245 246
      right_closed = TRUE;
    if (left_closed && right_closed)
247 248 249 250 251 252 253
      g_main_loop_quit (mainloop);
  }
}


int main (int argc, char *argv[])
{
254 255 256
  PseudoTcpCallbacks cbs = {
    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 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283
  left = pseudo_tcp_socket_new (0, &cbs);
  right = pseudo_tcp_socket_new (0, &cbs);
  g_debug ("Left: %p. Right: %p", left, right);

  pseudo_tcp_socket_notify_mtu (left, 1496);
  pseudo_tcp_socket_notify_mtu (right, 1496);

  pseudo_tcp_socket_connect (left);
  adjust_clock (left);
  adjust_clock (right);

  if (argc == 3) {
    in = fopen (argv[1], "r");
    out = fopen (argv[2], "w");
  }

  g_main_loop_run (mainloop);

284 285 286
  g_object_unref (left);
  g_object_unref (right);

287 288 289 290 291 292 293 294
  if (in)
    fclose (in);
  if (out)
    fclose (out);

  return 0;
}