Re: [gupnp] handling of sequence numbers in gupnp-service-proxy.c



Hi,

On Wed, 2009-03-25 at 20:04 +0200, Zeeshan Ali (Khattak) wrote:

> > If we receive messages out-of-order, does that really mean that we have
> > missed a message? Isn't it possible that the message order is changed
> > due to asynchronous code?
> 
>   No, that will only happen because of some bug in libsoup since
> SoupServer is guaranteed to call the server_handler for each message
> synchronously as they arrive (assuming they are on the same
> connection, which afaik is true in our case). I am telling you this
> after confirming my assumption with Dan Winship on IRC.

Attached is a small test case that my colleague wrote. It sets up a
SoupServer listening on a local port and then uses a SoupSession to send
messages to this port. These messages have a sequence number and a
random payload of up to 5MB. The server looks at the sequence number of
the incoming messages and will abort if the messages are received out of
order. This test fails reliably after a few messages.

As far as I can see this setup is comparable to what GUPnP does. So is
this really a bug in libsoup? I think not. IMO the bug is that
GUPnPService makes a wrong assumption about the libsoup behavior here.
Or is there something wrong about our test case?


Sven


PKGS = libsoup-2.4
CFLAGS = `pkg-config --cflags $(PKGS)` -O0 -g -Wall
LDFLAGS = `pkg-config --libs $(PKGS)`

OBJS = Outrunner.o

TARGET = Outrunner

%.o: %.c $(DEPS)
	$(CC) -c -o $@ $< $(CFLAGS)

$(TARGET): $(OBJS)
	$(CC) $(LDFLAGS) $(OBJS) -o $@


all:	$(TARGET)

clean:
	rm -f $(OBJS) $(TARGET)
//============================================================================
// Name        : Outrunner.cpp
// Author      :
// Version     :
// Copyright   : Your copyright notice
// Description : Proof of two soup messages, outrunning each other
//============================================================================

#include <stdio.h>
#include <stdlib.h>

#include <glib.h>

#include <libsoup/soup.h>

static GMainLoop *theMainLoop          = NULL;
static int        latestReceivedNumber = 0;
static int        latestSentNumber     = 0;
static guint      port                 = 49152; // first port to try


static void
server_callback (SoupServer  *soup_server,
                 SoupMessage *msg)
{
  const char *sequenceNumber;
  int         number;

  sequenceNumber = soup_message_headers_get (msg->request_headers,
                                             "SequenceNumber");
  number = atoi (sequenceNumber);

  g_printerr (" %d", number);
  g_assert (number > latestReceivedNumber);

  latestReceivedNumber = number;
}

static gboolean
queueSomeMessages (SoupSession *session)
{
  GRand *rand = g_rand_new_with_seed (time (NULL));
  gint   i;
  char   txt[128];

  for (i = 0; i < 10; i++)
    {
      SoupMessage *msg;
      int          len;

      sprintf (txt, "http://localhost:%d";, port);
      msg = soup_message_new ("GET", txt);

      sprintf (txt, "%d", ++latestSentNumber);
      soup_message_headers_append (msg->request_headers, "SequenceNumber", txt);
      soup_session_queue_message (session, msg, NULL, NULL);

      // append a body with random length
      len = g_rand_int_range (rand, 10, 1024 * 1024 * 5);
      soup_message_body_append (msg->request_body,
                                SOUP_MEMORY_TAKE, g_malloc (len), len);
    }

  g_rand_free (rand);

  return TRUE; // infinite, until the error occurs
}

static void
quit (int sig)
{
  if (theMainLoop)
    {
      g_main_loop_quit (theMainLoop);
      theMainLoop = NULL;
    }
}

int
main (void)
{
  SoupServer  *server;
  SoupSession *session;

  signal(SIGINT, quit);

  g_type_init ();
  g_thread_init (NULL);

  do
    {
      server = soup_server_new (SOUP_SERVER_PORT, ++port, NULL);
    }
  while (!server && port < 55000);

  if (server)
    {
      soup_server_add_handler (server, NULL,
                               (SoupServerCallback) server_callback,
                               NULL, NULL);
      soup_server_run_async (server);
    }

  session = soup_session_async_new ();

  theMainLoop = g_main_loop_new (NULL, FALSE);
  g_idle_add ((GSourceFunc) &queueSomeMessages, session);

  g_main_loop_run (theMainLoop);
  g_main_loop_unref (theMainLoop);

  return EXIT_SUCCESS;
}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]