#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <libsoup/soup-address.h>
#include <libsoup/soup-socket.h>

#include <glib/gthread.h>

static void rev_read (SoupSocket *sock, GString *buf);
static void rev_write (SoupSocket *sock, GString *buf);

static void
reverse (GString *buf)
{
	char tmp, *a, *b;

	a = buf->str;
	b = buf->str + buf->len - 1;

	while (isspace ((unsigned char)*b) && b > a)
		b--;

	while (a < b) {
		tmp = *a;
		*a++ = *b;
		*b-- = tmp;
	}
}

static void
rev_done (SoupSocket *sock, GString *buf)
{
	g_object_unref (sock);
	g_string_free (buf, TRUE);
}

static void
rev_write (SoupSocket *sock, GString *buf)
{
	SoupSocketIOStatus status;
	gsize nwrote;

	do {
		status = soup_socket_write (sock, buf->str, buf->len, &nwrote);
		memmove (buf->str, buf->str + nwrote, buf->len - nwrote);
		buf->len -= nwrote;
	} while (status == SOUP_SOCKET_OK && buf->len);

	switch (status) {
	case SOUP_SOCKET_OK:
		rev_read (sock, buf);
		break;

	case SOUP_SOCKET_WOULD_BLOCK:
		g_error ("Can't happen");
		break;

	default:
		g_warning ("Socket error");
		/* fall through */

	case SOUP_SOCKET_EOF:
		rev_done (sock, buf);
		break;
	}
}

static void
rev_read (SoupSocket *sock, GString *buf)
{
	SoupSocketIOStatus status;
	char tmp[10];
	gsize nread;
	gboolean eol;

	do {
		status = soup_socket_read_until (sock, tmp, sizeof (tmp),
						 "\n", 1, &nread, &eol);
		if (status == SOUP_SOCKET_OK)
			g_string_append_len (buf, tmp, nread);
	} while (status == SOUP_SOCKET_OK && !eol);

	switch (status) {
	case SOUP_SOCKET_OK:
		reverse (buf);
		rev_write (sock, buf);
		break;

	case SOUP_SOCKET_WOULD_BLOCK:
		g_error ("Can't happen");
		break;

	default:
		g_warning ("Socket error");
		/* fall through */

	case SOUP_SOCKET_EOF:
		rev_done (sock, buf);
		break;
	}
}

static void *
start_thread (void *client)
{
	rev_read (client, g_string_new (NULL));

	return NULL;
}

static void
new_connection (SoupSocket *listener, SoupSocket *client, gpointer user_data)
{
	GThread *thread;
	GError *error = NULL;

	g_object_ref (client);
	g_object_set (G_OBJECT (client),
		      SOUP_SOCKET_FLAG_NONBLOCKING, FALSE,
		      NULL);

	thread = g_thread_create (start_thread, client, FALSE, &error);
	if (thread == NULL) {
		g_warning ("Could not start thread: %s", error->message);
		g_error_free (error);
		g_object_unref (client);
	}
}

int
main (int argc, char **argv)
{
	SoupSocket *listener;
	SoupAddressFamily family = SOUP_ADDRESS_FAMILY_IPV4;
	guint port = SOUP_ADDRESS_ANY_PORT;
	SoupAddress *addr;
	GMainLoop *loop;
	int opt;

	g_type_init ();
	g_thread_init (NULL);

	while ((opt = getopt (argc, argv, "6p:")) != -1) {
		switch (opt) {
		case '6':
			family = SOUP_ADDRESS_FAMILY_IPV6;
			break;
		case 'p':
			port = atoi (optarg);
			break;
		default:
			fprintf (stderr, "Usage: %s [-6] [-p port]\n",
				 argv[0]);
			exit (1);
		}
	}

	addr = soup_address_new_any (family, port);
	if (!addr) {
		fprintf (stderr, "Could not create listener address\n");
		exit (1);
	}

	listener = soup_socket_server_new (addr, NULL,
					   new_connection, NULL);
	g_object_unref (addr);
	if (!listener) {
		fprintf (stderr, "Could not create listening socket\n");
		exit (1);
	}
	printf ("Listening on port %d\n",
		soup_address_get_port (
			soup_socket_get_local_address (listener)));

	loop = g_main_loop_new (NULL, TRUE);
	g_main_loop_run (loop);

	g_object_unref (listener);
	return 0;
}


syntax highlighted by Code2HTML, v. 0.9.1