From 6d19f3e68a0d0383d723adfccf5fa06c7c09c9fa Mon Sep 17 00:00:00 2001 From: Alex Graveley Date: Mon, 23 Apr 2001 07:57:45 +0000 Subject: [PATCH] SoupSocketConnectFn no longer takes a SoupAddress argument, as it can be 2001-04-23 Alex Graveley * src/soup-core/soup-socket.h: SoupSocketConnectFn no longer takes a SoupAddress argument, as it can be fetched from the SoupSocket correctly now. * src/soup-core/soup-socket.c: lots of rewrites. Cache existing SoupAddresses to avoid duplicate lookups. Handles multiple simultaneous requests for the same address. Add syncronous versions of calls which just run the main loop until completion or request. Make SoupContext use a SoupAddress instead of sockaddr. * src/soup-core/soup-uri.h: Add query_elems to SoupUri. Contains a list of query string elements, as delimited by a '&'. SoupUri.protocol is now a SoupProtocol. * src/soup-core/soup-uri.c (soup_uri_new): convert uri_string protocol to SoupProtocol equivalent. * src/soup-core/soup-private.h: remove protocol from SoupContext. Use a SoupAddress instead of a sockaddr in SoupSocket. * src/soup-core/soup-misc.c (soup_load_config_internal): kill tiny (8 byte) mem leak. * src/soup-core/soup-message.h: add SoupOwnership SOUP_BUFFER_STATIC. add SoupErrorCode SOUP_ERROR_CANT_AUTHENTICATE. * src/soup-core/soup-context.h: move SoupProtocol to soup-uri.h. * src/soup-core/soup-context.c (soup_context_new): removed. Protocol is now held only in uri. (soup_context_from_uri): added. (soup_context_get): just calls soup_context_from_uri() after creating uri. (soup_context_unref): don't evaluate a post-decremented refcount. (soup_context_connect_cb): no longer take a SoupAddress arg. (soup_context_get_protocol): removed, use uri. * src/soup-core/soup-apache.c (soup_apache_message_create): use SOUP_BUFFER_STATIC for request buffer. * src/soup-core/md5-utils.c: initial commit. MD5 encryption. * src/soup-core/soup-digest.c: initial commit. no worky. * src/soup-core/Makefile.am (libsoup_la_SOURCES): add md5-utils.h, md5-utils.c, soup-digest.h, soup-digest.c. * tests/stress-test.c (main): handle ugly refcount bug causing extra unrefs of the context. --- ChangeLog | 53 +++ libsoup/Makefile.am | 4 + libsoup/md5-utils.c | 362 +++++++++++++++++ libsoup/md5-utils.h | 52 +++ libsoup/soup-context.c | 93 ++--- libsoup/soup-context.h | 12 +- libsoup/soup-message.h | 4 +- libsoup/soup-misc.c | 7 +- libsoup/soup-private.h | 7 +- libsoup/soup-queue.c | 7 +- libsoup/soup-server.h | 2 +- libsoup/soup-socket.c | 1030 +++++++++++++++++++++++++++--------------------- libsoup/soup-socket.h | 46 ++- libsoup/soup-socks.c | 2 +- libsoup/soup-uri.c | 110 ++++-- libsoup/soup-uri.h | 30 +- 16 files changed, 1241 insertions(+), 580 deletions(-) create mode 100644 libsoup/md5-utils.c create mode 100644 libsoup/md5-utils.h diff --git a/ChangeLog b/ChangeLog index 8895c17..53c0fd1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,56 @@ +2001-04-23 Alex Graveley + + * src/soup-core/soup-socket.h: SoupSocketConnectFn no longer takes + a SoupAddress argument, as it can be fetched from the SoupSocket + correctly now. + + * src/soup-core/soup-socket.c: lots of rewrites. Cache existing + SoupAddresses to avoid duplicate lookups. Handles multiple + simultaneous requests for the same address. Add syncronous + versions of calls which just run the main loop until completion or + request. Make SoupContext use a SoupAddress instead of sockaddr. + + * src/soup-core/soup-uri.h: Add query_elems to SoupUri. Contains a + list of query string elements, as delimited by a + '&'. SoupUri.protocol is now a SoupProtocol. + + * src/soup-core/soup-uri.c (soup_uri_new): convert uri_string + protocol to SoupProtocol equivalent. + + * src/soup-core/soup-private.h: remove protocol from + SoupContext. Use a SoupAddress instead of a sockaddr in SoupSocket. + + * src/soup-core/soup-misc.c (soup_load_config_internal): kill + tiny (8 byte) mem leak. + + * src/soup-core/soup-message.h: add SoupOwnership + SOUP_BUFFER_STATIC. + add SoupErrorCode SOUP_ERROR_CANT_AUTHENTICATE. + + * src/soup-core/soup-context.h: move SoupProtocol to soup-uri.h. + + * src/soup-core/soup-context.c (soup_context_new): + removed. Protocol is now held only in uri. + (soup_context_from_uri): added. + (soup_context_get): just calls soup_context_from_uri() after + creating uri. + (soup_context_unref): don't evaluate a post-decremented refcount. + (soup_context_connect_cb): no longer take a SoupAddress arg. + (soup_context_get_protocol): removed, use uri. + + * src/soup-core/soup-apache.c (soup_apache_message_create): use + SOUP_BUFFER_STATIC for request buffer. + + * src/soup-core/md5-utils.c: initial commit. MD5 encryption. + + * src/soup-core/soup-digest.c: initial commit. no worky. + + * src/soup-core/Makefile.am (libsoup_la_SOURCES): add md5-utils.h, + md5-utils.c, soup-digest.h, soup-digest.c. + + * tests/stress-test.c (main): handle ugly refcount bug causing + extra unrefs of the context. + 2001-04-18 Alex Graveley * src/soup-core/soup-server.h: Added SoupServerBasicToken, diff --git a/libsoup/Makefile.am b/libsoup/Makefile.am index 13b2ea1..11a1c70 100644 --- a/libsoup/Makefile.am +++ b/libsoup/Makefile.am @@ -34,8 +34,12 @@ libsoup_la_LIBADD = \ $(XML_LIBS) libsoup_la_SOURCES = \ + md5-utils.h \ + md5-utils.c \ soup-cgi.c \ soup-context.c \ + soup-digest.h \ + soup-digest.c \ soup-headers.h \ soup-headers.c \ soup-message.c \ diff --git a/libsoup/md5-utils.c b/libsoup/md5-utils.c new file mode 100644 index 0000000..a4dd42a --- /dev/null +++ b/libsoup/md5-utils.c @@ -0,0 +1,362 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to md5_init, call md5_update as + * needed on buffers full of bytes, and then call md5_Final, which + * will fill a supplied 16-byte array with the digest. + */ + +/* parts of this file are : + * Written March 1993 by Branko Lankester + * Modified June 1993 by Colin Plumb for altered md5.c. + * Modified October 1995 by Erik Troan for RPM + */ + + +#include "md5-utils.h" +#include +#include + +static void md5_transform (guint32 buf[4], const guint32 in[16]); + +static gint _ie = 0x44332211; +static union _endian { gint i; gchar b[4]; } *_endian = (union _endian *)&_ie; +#define IS_BIG_ENDIAN() (_endian->b[0] == '\x44') +#define IS_LITTLE_ENDIAN() (_endian->b[0] == '\x11') + + +/* + * Note: this code is harmless on little-endian machines. + */ +static void +_byte_reverse (guchar *buf, guint32 longs) +{ + guint32 t; + do { + t = (guint32) ((guint32) buf[3] << 8 | buf[2]) << 16 | + ((guint32) buf[1] << 8 | buf[0]); + *(guint32 *) buf = t; + buf += 4; + } while (--longs); +} + +/** + * md5_init: Initialise an md5 context object + * @ctx: md5 context + * + * Initialise an md5 buffer. + * + **/ +void +md5_init (MD5Context *ctx) +{ + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + + ctx->bits[0] = 0; + ctx->bits[1] = 0; + + if (IS_BIG_ENDIAN()) + ctx->doByteReverse = 1; + else + ctx->doByteReverse = 0; +} + + + +/** + * md5_update: add a buffer to md5 hash computation + * @ctx: conetxt object used for md5 computaion + * @buf: buffer to add + * @len: buffer length + * + * Update context to reflect the concatenation of another buffer full + * of bytes. Use this to progressively construct an md5 hash. + **/ +void +md5_update (MD5Context *ctx, const guchar *buf, guint32 len) +{ + guint32 t; + + /* Update bitcount */ + + t = ctx->bits[0]; + if ((ctx->bits[0] = t + ((guint32) len << 3)) < t) + ctx->bits[1]++; /* Carry from low to high */ + ctx->bits[1] += len >> 29; + + t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ + + /* Handle any leading odd-sized chunks */ + + if (t) { + guchar *p = (guchar *) ctx->in + t; + + t = 64 - t; + if (len < t) { + memcpy (p, buf, len); + return; + } + memcpy (p, buf, t); + if (ctx->doByteReverse) + _byte_reverse (ctx->in, 16); + md5_transform (ctx->buf, (guint32 *) ctx->in); + buf += t; + len -= t; + } + /* Process data in 64-byte chunks */ + + while (len >= 64) { + memcpy (ctx->in, buf, 64); + if (ctx->doByteReverse) + _byte_reverse (ctx->in, 16); + md5_transform (ctx->buf, (guint32 *) ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + + memcpy (ctx->in, buf, len); +} + + + + + +/* + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +/** + * md5_final: copy the final md5 hash to a bufer + * @digest: 16 bytes buffer + * @ctx: context containing the calculated md5 + * + * copy the final md5 hash to a bufer + **/ +void +md5_final (MD5Context *ctx, guchar digest[16]) +{ + guint32 count; + guchar *p; + + /* Compute number of bytes mod 64 */ + count = (ctx->bits[0] >> 3) & 0x3F; + + /* Set the first char of padding to 0x80. This is safe since there is + always at least one byte free */ + p = ctx->in + count; + *p++ = 0x80; + + /* Bytes of padding needed to make 64 bytes */ + count = 64 - 1 - count; + + /* Pad out to 56 mod 64 */ + if (count < 8) { + /* Two lots of padding: Pad the first block to 64 bytes */ + memset (p, 0, count); + if (ctx->doByteReverse) + _byte_reverse (ctx->in, 16); + md5_transform (ctx->buf, (guint32 *) ctx->in); + + /* Now fill the next block with 56 bytes */ + memset (ctx->in, 0, 56); + } else { + /* Pad block to 56 bytes */ + memset (p, 0, count - 8); + } + if (ctx->doByteReverse) + _byte_reverse (ctx->in, 14); + + /* Append length in bits and transform */ + ((guint32 *) ctx->in)[14] = ctx->bits[0]; + ((guint32 *) ctx->in)[15] = ctx->bits[1]; + + md5_transform (ctx->buf, (guint32 *) ctx->in); + if (ctx->doByteReverse) + _byte_reverse ((guchar *) ctx->buf, 4); + memcpy (digest, ctx->buf, 16); +} + + + + +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f, w, x, y, z, data, s) \ + ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. md5_Update blocks + * the data and converts bytes into longwords for this routine. + */ +static void +md5_transform (guint32 buf[4], const guint32 in[16]) +{ + register guint32 a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP (F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP (F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP (F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP (F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP (F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP (F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP (F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP (F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP (F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP (F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP (F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP (F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP (F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP (F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP (F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP (F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP (F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP (F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP (F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP (F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP (F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP (F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP (F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP (F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP (F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP (F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP (F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP (F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP (F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP (F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP (F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP (F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP (F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP (F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP (F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP (F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP (F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP (F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP (F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP (F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP (F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP (F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP (F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP (F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP (F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP (F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP (F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP (F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP (F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP (F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP (F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP (F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP (F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP (F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP (F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP (F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP (F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP (F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP (F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP (F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP (F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP (F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP (F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP (F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + + + + +/** + * md5_get_digest: get the md5 hash of a buffer + * @buffer: byte buffer + * @buffer_size: buffer size (in bytes) + * @digest: 16 bytes buffer receiving the hash code. + * + * Get the md5 hash of a buffer. The result is put in + * the 16 bytes buffer @digest . + **/ +void +md5_get_digest (const gchar *buffer, gint buffer_size, guchar digest[16]) +{ + MD5Context ctx; + + md5_init (&ctx); + md5_update (&ctx, buffer, buffer_size); + md5_final (&ctx, digest); + +} + + +/** + * md5_get_digest_from_file: get the md5 hash of a file + * @filename: file name + * @digest: 16 bytes buffer receiving the hash code. + * + * Get the md5 hash of a file. The result is put in + * the 16 bytes buffer @digest . + **/ +void +md5_get_digest_from_file (const gchar *filename, guchar digest[16]) +{ + MD5Context ctx; + guchar tmp_buf[1024]; + gint nb_bytes_read; + FILE *fp; + + printf("generating checksum\n"); + + md5_init (&ctx); + fp = fopen(filename, "r"); + if (!fp) { + return; + } + + while ((nb_bytes_read = fread (tmp_buf, sizeof (guchar), 1024, fp)) > 0) + md5_update (&ctx, tmp_buf, nb_bytes_read); + + if (ferror(fp)) { + fclose(fp); + return; + } + + + md5_final (&ctx, digest); + + printf("checksum done\n"); +} + + + + diff --git a/libsoup/md5-utils.h b/libsoup/md5-utils.h new file mode 100644 index 0000000..08e014e --- /dev/null +++ b/libsoup/md5-utils.h @@ -0,0 +1,52 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to rpmMD5Init, call rpmMD5Update as + * needed on buffers full of bytes, and then call rpmMD5Final, which + * will fill a supplied 16-byte array with the digest. + */ + +/* parts of this file are : + * Written March 1993 by Branko Lankester + * Modified June 1993 by Colin Plumb for altered md5.c. + * Modified October 1995 by Erik Troan for RPM + */ + + +#ifndef MD5_UTILS_H +#define MD5_UTILS_H + +#include + +typedef struct { + guint32 buf[4]; + guint32 bits[2]; + guchar in[64]; + gint doByteReverse; + +} MD5Context ; + + +void md5_get_digest (const gchar *buffer, gint buffer_size, guchar digest[16]); + +/* use this one when speed is needed */ +/* for use in provider code only */ +void md5_get_digest_from_file (const gchar *filename, guchar digest[16]); + +/* raw routines */ +void md5_init (MD5Context *ctx); +void md5_update (MD5Context *ctx, const guchar *buf, guint32 len); +void md5_final (MD5Context *ctx, guchar digest[16]); + + +#endif /* MD5_UTILS_H */ diff --git a/libsoup/soup-context.c b/libsoup/soup-context.c index 8361fcf..e15f6bd 100644 --- a/libsoup/soup-context.c +++ b/libsoup/soup-context.c @@ -37,26 +37,27 @@ static gint connection_count = 0; static guint most_recently_used_id = 0; -static SoupContext * -soup_context_new (SoupServer *server, SoupUri *uri) +/** + * soup_context_get: + * @uri: the stringified URI. + * + * Returns a pointer to the %SoupContext representing @uri. If a context + * already exists for the URI, it is returned with an added reference. + * Otherwise, a new context is created with a reference count of one. + * + * Return value: a %SoupContext representing @uri. + */ +SoupContext * +soup_context_get (gchar *uri) { - SoupContext *ctx = g_new0 (SoupContext, 1); - ctx->server = server; - ctx->uri = uri; - ctx->refcnt = 0; - - if (g_strcasecmp (uri->protocol, "http") == 0) - ctx->protocol = SOUP_PROTOCOL_HTTP; - else if (g_strcasecmp (uri->protocol, "https") == 0) - ctx->protocol = SOUP_PROTOCOL_SHTTP; - else if (g_strcasecmp (uri->protocol, "mailto") == 0) - ctx->protocol = SOUP_PROTOCOL_SMTP; - else if (g_strcasecmp (uri->protocol, "socks4") == 0) - ctx->protocol = SOUP_PROTOCOL_SOCKS4; - else if (g_strcasecmp (uri->protocol, "socks5") == 0) - ctx->protocol = SOUP_PROTOCOL_SOCKS5; - - return ctx; + SoupUri *suri; + + g_return_val_if_fail (uri != NULL, NULL); + + suri = soup_uri_new (uri); + if (!suri) return NULL; + + return soup_context_from_uri (suri); } /** @@ -70,16 +71,13 @@ soup_context_new (SoupServer *server, SoupUri *uri) * Return value: a %SoupContext representing @uri. */ SoupContext * -soup_context_get (gchar *uri) +soup_context_from_uri (SoupUri *suri) { SoupServer *serv = NULL; SoupContext *ret = NULL; - SoupUri *suri = soup_uri_new (uri); - if (!suri->protocol) { - soup_uri_free (suri); - return NULL; - } + g_return_val_if_fail (suri != NULL, NULL); + g_return_val_if_fail (suri->protocol != 0, NULL); if (!soup_servers) soup_servers = g_hash_table_new (soup_str_case_hash, @@ -99,7 +97,11 @@ soup_context_get (gchar *uri) ret = g_hash_table_lookup (serv->contexts, suri->path); if (!ret) { - ret = soup_context_new (serv, suri); + ret = g_new0 (SoupContext, 1); + ret->server = serv; + ret->uri = suri; + ret->refcnt = 0; + g_hash_table_insert (serv->contexts, suri->path, ret); } @@ -135,7 +137,9 @@ soup_context_unref (SoupContext *ctx) { g_return_if_fail (ctx != NULL); - if (ctx->refcnt-- == 0) { + --ctx->refcnt; + + if (ctx->refcnt == 0) { SoupServer *serv = ctx->server; g_hash_table_remove (serv->contexts, ctx->uri->path); @@ -176,7 +180,6 @@ struct SoupConnectData { static void soup_context_connect_cb (SoupSocket *socket, - SoupAddress *addr, SoupSocketConnectStatus status, gpointer user_data) { @@ -188,8 +191,6 @@ soup_context_connect_cb (SoupSocket *socket, g_free (data); - if (addr) soup_address_unref(addr); - switch (status) { case SOUP_SOCKET_CONNECT_ERROR_NONE: new_conn = g_new0 (SoupConnection, 1); @@ -330,7 +331,7 @@ soup_context_get_connection (SoupContext *ctx, { SoupConnection *conn; struct SoupConnectData *data; - guint conn_limit = soup_get_connection_limit(); + guint conn_limit; g_return_val_if_fail (ctx != NULL, NULL); @@ -345,6 +346,8 @@ soup_context_get_connection (SoupContext *ctx, data->cb = cb; data->user_data = user_data; + conn_limit = soup_get_connection_limit (); + if (conn_limit && connection_count >= conn_limit && !soup_prune_least_used_connection ()) @@ -352,11 +355,12 @@ soup_context_get_connection (SoupContext *ctx, g_timeout_add (500, (GSourceFunc) soup_prune_timeout, data); - else data->connect_tag = - soup_socket_connect (ctx->uri->host, - ctx->uri->port, - soup_context_connect_cb, - data); + else + data->connect_tag = + soup_socket_connect (ctx->uri->host, + ctx->uri->port, + soup_context_connect_cb, + data); return data; } @@ -400,21 +404,6 @@ soup_context_get_uri (SoupContext *ctx) } /** - * soup_context_get_protocol: - * @ctx: a %SoupContext. - * - * Returns the %SoupProtocol used for connections created for %ctx. - * - * Return value: the %SoupProtocol used for connections to %ctx. - */ -SoupProtocol -soup_context_get_protocol (SoupContext *ctx) -{ - g_return_val_if_fail (ctx != NULL, 0); - return ctx->protocol; -} - -/** * soup_connection_release: * @conn: a %SoupConnection currently in use. * @@ -472,7 +461,7 @@ soup_connection_get_iochannel (SoupConnection *conn) soup_connection_setup_socket (conn->channel); - if (conn->context->protocol == SOUP_PROTOCOL_SHTTP) + if (conn->context->uri->protocol == SOUP_PROTOCOL_SHTTP) conn->channel = soup_ssl_get_iochannel (conn->channel); } else g_io_channel_ref (conn->channel); diff --git a/libsoup/soup-context.h b/libsoup/soup-context.h index 0c4412f..6e3b178 100644 --- a/libsoup/soup-context.h +++ b/libsoup/soup-context.h @@ -19,14 +19,6 @@ typedef struct _SoupContext SoupContext; typedef struct _SoupConnection SoupConnection; typedef enum { - SOUP_PROTOCOL_HTTP, - SOUP_PROTOCOL_SHTTP, - SOUP_PROTOCOL_SMTP, - SOUP_PROTOCOL_SOCKS4, - SOUP_PROTOCOL_SOCKS5 -} SoupProtocol; - -typedef enum { SOUP_CONNECT_ERROR_NONE, SOUP_CONNECT_ERROR_ADDR_RESOLVE, SOUP_CONNECT_ERROR_NETWORK @@ -41,6 +33,8 @@ typedef gpointer SoupConnectId; SoupContext *soup_context_get (gchar *uri); +SoupContext *soup_context_from_uri (SoupUri *suri); + void soup_context_ref (SoupContext *ctx); void soup_context_unref (SoupContext *ctx); @@ -51,8 +45,6 @@ SoupConnectId soup_context_get_connection (SoupContext *ctx, SoupUri *soup_context_get_uri (SoupContext *ctx); -SoupProtocol soup_context_get_protocol (SoupContext *ctx); - void soup_context_cancel_connect (SoupConnectId tag); diff --git a/libsoup/soup-message.h b/libsoup/soup-message.h index cbbf1f0..2289dc0 100644 --- a/libsoup/soup-message.h +++ b/libsoup/soup-message.h @@ -20,6 +20,7 @@ typedef enum { SOUP_ERROR_CANT_CONNECT, SOUP_ERROR_IO, SOUP_ERROR_MALFORMED_HEADER, + SOUP_ERROR_CANT_AUTHENTICATE, SOUP_ERROR_HANDLER } SoupErrorCode; @@ -34,7 +35,8 @@ typedef enum { typedef enum { SOUP_BUFFER_SYSTEM_OWNED = 0, - SOUP_BUFFER_USER_OWNED + SOUP_BUFFER_USER_OWNED, + SOUP_BUFFER_STATIC } SoupOwnership; typedef struct { diff --git a/libsoup/soup-misc.c b/libsoup/soup-misc.c index 4be30aa..66bf4f5 100644 --- a/libsoup/soup-misc.c +++ b/libsoup/soup-misc.c @@ -316,7 +316,12 @@ soup_load_config_internal (gchar *config_file, gboolean admin) } split = g_strsplit (g_strchomp (iter), "=", 2); - if (!split || !split[1] || split[2]) continue; + + if (!split) continue; + if (!split[1] || split[2]) { + g_strfreev (split); + continue; + } key = g_strchomp (split[0]); value = g_strchug (split[1]); diff --git a/libsoup/soup-private.h b/libsoup/soup-private.h index cf5ba6e..79d4b7a 100644 --- a/libsoup/soup-private.h +++ b/libsoup/soup-private.h @@ -42,18 +42,17 @@ typedef struct { struct _SoupAddress { gchar* name; struct sockaddr sa; - guint ref_count; + gint ref_count; }; struct _SoupSocket { gint sockfd; - struct sockaddr sa; /* Why not an InetAddr? */ + SoupAddress *addr; guint ref_count; GIOChannel *iochannel; }; struct _SoupContext { - SoupProtocol protocol; SoupUri *uri; SoupServer *server; guint refcnt; @@ -94,6 +93,8 @@ struct _SoupMessagePrivate { gpointer user_data; SoupErrorCode errorcode; + + gpointer digest_data; }; typedef struct { diff --git a/libsoup/soup-queue.c b/libsoup/soup-queue.c index a86fda7..3d19a31 100644 --- a/libsoup/soup-queue.c +++ b/libsoup/soup-queue.c @@ -512,15 +512,18 @@ soup_queue_connect (SoupContext *ctx, gpointer user_data) { SoupMessage *req = user_data; + SoupProtocol proto; GIOChannel *channel; req->priv->connect_tag = NULL; switch (err) { case SOUP_CONNECT_ERROR_NONE: + proto = soup_context_get_uri (ctx)->protocol; + if (soup_connection_is_new (conn) && - (soup_context_get_protocol (ctx) == SOUP_PROTOCOL_SOCKS4 || - soup_context_get_protocol (ctx) == SOUP_PROTOCOL_SOCKS5)) { + (proto == SOUP_PROTOCOL_SOCKS4 || + proto == SOUP_PROTOCOL_SOCKS5)) { soup_connect_socks_proxy (conn, req->context, soup_queue_connect, diff --git a/libsoup/soup-server.h b/libsoup/soup-server.h index 7b707fb..ec763a6 100644 --- a/libsoup/soup-server.h +++ b/libsoup/soup-server.h @@ -16,7 +16,7 @@ #include "soup-message.h" typedef enum { - SOUP_AUTH_TYPE_BASIC, + SOUP_AUTH_TYPE_BASIC = 1, SOUP_AUTH_TYPE_DIGEST, SOUP_AUTH_TYPE_ANONYMOUS, SOUP_AUTH_TYPE_DENY diff --git a/libsoup/soup-socket.c b/libsoup/soup-socket.c index afd40ce..b505d40 100644 --- a/libsoup/soup-socket.c +++ b/libsoup/soup-socket.c @@ -62,6 +62,12 @@ #define SOUP_CLOSE_SOCKET(SOCKFD) close(SOCKFD) #define SOUP_SOCKET_IOCHANNEL_NEW(SOCKFD) g_io_channel_unix_new(SOCKFD) +/* + * Maintains a list of all currently valid SoupAddresses or active + * SoupAddressState lookup requests. + */ +static GHashTable *active_address_hash = NULL; + #else /*********** Windows specific ***********/ #include @@ -96,10 +102,9 @@ HANDLE soup_hostent_Mutex; static int inet_aton(const char *cp, struct in_addr *inp) { - inp->s_addr = inet_addr(cp); - if (inp->s_addr == INADDR_NONE) - return 0; - return 1; + inp->s_addr = inet_addr (cp); + if (inp->s_addr == INADDR_NONE) return 0; + return 1; } #endif /*********** End Windows specific ***********/ @@ -114,60 +119,66 @@ inet_aton(const char *cp, struct in_addr *inp) G_IO_ERR | G_IO_HUP | G_IO_NVAL) typedef struct { - SoupAddress* ia; - SoupAddressNewFn func; - gpointer data; + SoupAddressNewFn func; + gpointer data; +} SoupAddressCbData; + +typedef struct { + SoupAddress ia; + SoupAddressNewFn func; + gpointer data; + GSList *cb_list; /* CONTAINS: SoupAddressCbData */ #ifndef SOUP_WIN32 - pid_t pid; - int fd; - guint watch; - guchar buffer[16]; - int len; + pid_t pid; + int fd; + guint watch; + guchar buffer [16]; + int len; #else - int WSAhandle; - char hostentBuffer[MAXGETHOSTSTRUCT]; - int errorcode; + int WSAhandle; + char hostentBuffer [MAXGETHOSTSTRUCT]; + int errorcode; #endif } SoupAddressState; typedef struct { - SoupAddress* ia; - SoupAddressGetNameFn func; - gpointer data; + SoupAddress *ia; + SoupAddressGetNameFn func; + gpointer data; #ifndef SOUP_WIN32 - pid_t pid; - int fd; - guint watch; - guchar buffer[256 + 1]; - int len; + pid_t pid; + int fd; + guint watch; + guchar buffer [256 + 1]; + int len; #else - int WSAhandle; - char hostentBuffer[MAXGETHOSTSTRUCT]; - int errorcode; + int WSAhandle; + char hostentBuffer [MAXGETHOSTSTRUCT]; + int errorcode; #endif } SoupAddressReverseState; typedef struct { - SoupSocket* socket; - SoupSocketNewFn func; - gpointer data; - gint flags; - guint connect_watch; + gint sockfd; + SoupAddress *addr; + SoupSocketNewFn func; + gpointer data; + gint flags; + guint connect_watch; #ifdef SOUP_WIN32 - gint errorcode; + gint errorcode; #endif } SoupSocketState; typedef struct { - SoupAddress* ia; - SoupSocketConnectFn func; - gpointer data; + SoupSocketConnectFn func; + gpointer data; - gpointer inetaddr_id; - gpointer tcp_id; + gpointer inetaddr_id; + gpointer tcp_id; } SoupSocketConnectState; @@ -213,13 +224,13 @@ soup_gethostbyname(const char* hostname, buf = g_renew (gchar, buf, len); } - if (res || result == NULL || result->h_addr_list[0] == NULL) + if (res || result == NULL || result->h_addr_list [0] == NULL) goto done; if (sa) { sa->sin_family = result->h_addrtype; memcpy (&sa->sin_addr, - result->h_addr_list[0], + result->h_addr_list [0], result->h_length); } @@ -252,13 +263,13 @@ soup_gethostbyname(const char* hostname, buf = g_renew (gchar, buf, len); } - if (res || hp == NULL || hp->h_addr_list[0] == NULL) + if (res || hp == NULL || hp->h_addr_list [0] == NULL) goto done; if (sa) { sa->sin_family = result->h_addrtype; memcpy (&sa->sin_addr, - result->h_addr_list[0], + result->h_addr_list [0], result->h_length); } @@ -283,7 +294,7 @@ soup_gethostbyname(const char* hostname, if (sa) { sa->sin_family = result.h_addrtype; memcpy (&sa->sin_addr, - result.h_addr_list[0], + result.h_addr_list [0], result.h_length); } @@ -302,11 +313,11 @@ soup_gethostbyname(const char* hostname, he = gethostbyname (hostname); G_UNLOCK (gethostbyname); - if (he != NULL && he->h_addr_list[0] != NULL) { + if (he != NULL && he->h_addr_list [0] != NULL) { if (sa) { sa->sin_family = he->h_addrtype; memcpy (&sa->sin_addr, - he->h_addr_list[0], + he->h_addr_list [0], he->h_length); } @@ -328,7 +339,7 @@ soup_gethostbyname(const char* hostname, if (sa) { sa->sin_family = result->h_addrtype; memcpy (&sa->sin_addr, - result->h_addr_list[0], + result->h_addr_list [0], result->h_length); } @@ -344,11 +355,11 @@ soup_gethostbyname(const char* hostname, struct hostent* he; he = gethostbyname (hostname); - if (he != NULL && he->h_addr_list[0] != NULL) { + if (he != NULL && he->h_addr_list [0] != NULL) { if (sa) { sa->sin_family = he->h_addrtype; memcpy (&sa->sin_addr, - he->h_addr_list[0], + he->h_addr_list [0], he->h_length); } @@ -500,56 +511,77 @@ soup_address_new_cb (GIOChannel* iochannel, gpointer data) { SoupAddressState* state = (SoupAddressState*) data; + int rv; + char* buf; + int length; + struct sockaddr_in* sa_in; + GSList *cb_list; /* Read from the pipe */ - if (condition & G_IO_IN) { - int rv; - char* buf; - int length; + if (!(condition & G_IO_IN)) goto ERROR; - buf = &state->buffer[state->len]; - length = sizeof (state->buffer) - state->len; + buf = &state->buffer [state->len]; + length = sizeof (state->buffer) - state->len; - if ((rv = read (state->fd, buf, length)) >= 0) { - state->len += rv; + rv = read (state->fd, buf, length); + if (rv < 0) goto ERROR; - /* Return true if there's more to read */ - if ((state->len - 1) != state->buffer[0]) - return TRUE; + state->len += rv; - /* We're done reading. Copy into the addr if we were - successful. Otherwise, we got a 0 because there was - an error */ - if (state->len > 1) { - struct sockaddr_in* sa_in; + /* Return true if there's more to read */ + if ((state->len - 1) != state->buffer [0]) return TRUE; - sa_in = (struct sockaddr_in*) &state->ia->sa; - memcpy (&sa_in->sin_addr, - &state->buffer[1], - (state->len - 1)); - } else goto error; + /* We're done reading. Copy into the addr if we were + successful. Otherwise, we got a 0 because there was + an error */ + if (state->len < 2) goto ERROR; - /* Remove the watch now in case we don't return - immediately */ - g_source_remove (state->watch); + sa_in = (struct sockaddr_in*) &state->ia.sa; + memcpy (&sa_in->sin_addr, &state->buffer [1], (state->len - 1)); - /* Call back */ - (*state->func) (state->ia, - SOUP_ADDRESS_STATUS_OK, - state->data); - close (state->fd); - waitpid (state->pid, NULL, 0); - g_free(state); - return FALSE; - } + /* Remove the watch now in case we don't return immediately */ + g_source_remove (state->watch); + + state->ia.ref_count = ~state->ia.ref_count + 1; + + /* Call back */ + (*state->func) (&state->ia, SOUP_ADDRESS_STATUS_OK, state->data); + + for (cb_list = state->cb_list; cb_list; cb_list = cb_list->next) { + SoupAddressCbData *cb_data = cb_list->data; + (*cb_data->func) (&state->ia, + SOUP_ADDRESS_STATUS_OK, + cb_data->data); + g_free (cb_data); } - error: + g_slist_free (state->cb_list); + + close (state->fd); + waitpid (state->pid, NULL, 0); + + state = g_realloc (state, sizeof (SoupAddress)); + g_hash_table_insert (active_address_hash, state->ia.name, state); + + return FALSE; + + ERROR: /* Remove the watch now in case we don't return immediately */ g_source_remove (state->watch); (*state->func) (NULL, SOUP_ADDRESS_STATUS_ERROR, state->data); + + for (cb_list = state->cb_list; cb_list; cb_list = cb_list->next) { + SoupAddressCbData *cb_data = cb_list->data; + (*cb_data->func) (NULL, + SOUP_ADDRESS_STATUS_ERROR, + cb_data->data); + } + + /* Force cancel */ + state->ia.ref_count = -1; soup_address_new_cancel (state); + return FALSE; } @@ -593,18 +625,20 @@ soup_address_new (const gchar* name, gpointer data) { pid_t pid = -1; - int pipes[2]; + int pipes [2]; struct in_addr inaddr; + struct sockaddr_in sa; + struct sockaddr_in* sa_in; + SoupAddress* ia; + SoupAddressState* state; + GIOChannel *chan; - g_return_val_if_fail(name != NULL, NULL); - g_return_val_if_fail(func != NULL, NULL); + g_return_val_if_fail (name != NULL, NULL); + g_return_val_if_fail (func != NULL, NULL); /* Try to read the name as if were dotted decimal */ if (inet_aton (name, &inaddr) != 0) { - SoupAddress* ia = NULL; - struct sockaddr_in* sa_in; - - ia = g_new0(SoupAddress, 1); + ia = g_new0 (SoupAddress, 1); ia->ref_count = 1; sa_in = (struct sockaddr_in*) &ia->sa; @@ -618,85 +652,123 @@ soup_address_new (const gchar* name, return NULL; } + if (!active_address_hash) + active_address_hash = g_hash_table_new (soup_str_case_hash, + soup_str_case_equal); + else { + ia = g_hash_table_lookup (active_address_hash, name); + + if (ia && ia->ref_count > 0) { + /* + * Existing valid request, use it. + */ + soup_address_ref (ia); + + (*func) (ia, SOUP_ADDRESS_STATUS_OK, data); + + return NULL; + } else if (ia) { + /* + * Lookup currently in progress. + * Add func to list of callbacks in state. + */ + SoupAddressCbData *cb_data; + + cb_data = g_new0 (SoupAddressCbData, 1); + cb_data->func = func; + cb_data->data = data; + + state = (SoupAddressState *) ia; + state->cb_list = g_slist_prepend (state->cb_list, + cb_data); + + state->ia.ref_count--; + + return state; + } + } + /* That didn't work - we need to fork */ /* Open a pipe */ - if (pipe(pipes) == -1) { + if (pipe (pipes) == -1) { (*func) (NULL, SOUP_ADDRESS_STATUS_ERROR, data); return NULL; } - /* Fork to do the look up. */ - fork_again: + FORK_AGAIN: errno = 0; + pid = fork (); - if ((pid = fork()) == 0) { - struct sockaddr_in sa; + switch (pid) { + case -1: + if (errno == EAGAIN) { + /* Yield the processor */ + sleep(0); + goto FORK_AGAIN; + } + + /* Else there was a goofy error */ + g_warning ("Fork error: %s (%d)\n", + g_strerror(errno), + errno); + (*func) (NULL, SOUP_ADDRESS_STATUS_ERROR, data); + + return NULL; + case 0: /* Try to get the host by name (ie, DNS) */ if (soup_gethostbyname (name, &sa, NULL)) { guchar size = 4; /* FIX for IPv6 */ - if ((write (pipes[1], &size, sizeof(guchar)) == -1) || - (write (pipes[1], &sa.sin_addr, size) == -1)) + if ((write (pipes [1], &size, sizeof(guchar)) == -1) || + (write (pipes [1], &sa.sin_addr, size) == -1)) g_warning ("Problem writing to pipe\n"); } else { /* Write a zero */ guchar zero = 0; - if (write (pipes[1], &zero, sizeof(zero)) == -1) + if (write (pipes [1], &zero, sizeof(zero)) == -1) g_warning ("Problem writing to pipe\n"); } /* Close the socket */ - close(pipes[1]); + close (pipes [1]); /* Exit (we don't want atexit called, so do _exit instead) */ - _exit(EXIT_SUCCESS); - } else if (pid > 0) { - /* Set up an IOChannel to read from the pipe */ - SoupAddress* ia; - struct sockaddr_in* sa_in; - SoupAddressState* state; - - /* Create a new SoupAddress */ - ia = g_new0(SoupAddress, 1); - ia->name = g_strdup(name); - ia->ref_count = 1; - - sa_in = (struct sockaddr_in*) &ia->sa; - sa_in->sin_family = AF_INET; - sa_in->sin_port = g_htons (port); - + _exit (EXIT_SUCCESS); + default: /* Create a structure for the call back */ state = g_new0 (SoupAddressState, 1); - state->ia = ia; + state->ia.name = g_strdup (name); + state->ia.ref_count = -1; state->func = func; state->data = data; state->pid = pid; - state->fd = pipes[0]; + state->fd = pipes [0]; - /* Add a watch */ + sa_in = (struct sockaddr_in*) &state->ia.sa; + sa_in->sin_family = AF_INET; + sa_in->sin_port = g_htons (port); + + g_hash_table_insert (active_address_hash, + state->ia.name, + state); + + chan = g_io_channel_unix_new (pipes [0]); + + /* Set up an watch to read from the pipe */ state->watch = g_io_add_watch( - g_io_channel_unix_new (pipes[0]), + chan, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, soup_address_new_cb, state); + g_io_channel_unref (chan); + return state; - } else if (errno == EAGAIN) { - /* Try again */ - /* Yield the processor */ - sleep(0); - goto fork_again; - } else { - /* Else there was a goofy error */ - g_warning ("Fork error: %s (%d)\n", g_strerror (errno), errno); - (*func) (NULL, SOUP_ADDRESS_STATUS_ERROR, data); } - - return NULL; } /** @@ -710,17 +782,28 @@ void soup_address_new_cancel (SoupAddressNewId id) { SoupAddressState* state = (SoupAddressState*) id; + GSList *cb_list; - g_return_if_fail(state != NULL); + g_return_if_fail (state != NULL); - soup_address_unref (state->ia); - g_source_remove (state->watch); + state->ia.ref_count++; - close (state->fd); - kill (state->pid, SIGKILL); - waitpid (state->pid, NULL, 0); + if (state->ia.ref_count == 0) { + g_hash_table_remove (active_address_hash, state->ia.name); + g_free (state->ia.name); - g_free(state); + for (cb_list = state->cb_list; cb_list; cb_list = cb_list->next) + g_free (cb_list->data); + g_slist_free (state->cb_list); + + g_source_remove (state->watch); + + close (state->fd); + kill (state->pid, SIGKILL); + waitpid (state->pid, NULL, 0); + + g_free (state); + } } #else /*********** Windows code ***********/ @@ -735,7 +818,7 @@ soup_address_new_cb (GIOChannel* iochannel, struct sockaddr_in *sa_in; if (state->errorcode) { - (*state->func) (state->ia, + (*state->func) (&state->ia, SOUP_ADDRESS_STATUS_ERROR, state->data); g_free (state); @@ -744,12 +827,14 @@ soup_address_new_cb (GIOChannel* iochannel, result = (struct hostent*) state->hostentBuffer; - sa_in = (struct sockaddr_in*) &state->ia->sa; - memcpy (&sa_in->sin_addr, result->h_addr_list[0], result->h_length); + sa_in = (struct sockaddr_in*) &state->ia.sa; + memcpy (&sa_in->sin_addr, result->h_addr_list [0], result->h_length); - state->ia->name = g_strdup (result->h_name); + state->ia.name = g_strdup (result->h_name); + + state = g_realloc (state, sizeof (SoupAddress)); - (*state->func) (state->ia, SOUP_ADDRESS_STATUS_OK, state->data); + (*state->func) (&state->ia, SOUP_ADDRESS_STATUS_OK, state->data); g_free (state); return FALSE; @@ -762,7 +847,6 @@ soup_address_new (const gchar* name, gpointer data) { struct in_addr inaddr; - SoupAddress* ia; struct sockaddr_in* sa_in; SoupAddressState* state; @@ -789,22 +873,18 @@ soup_address_new (const gchar* name, (*func) (ia, SOUP_ADDRESS_STATUS_OK, data); return NULL; } - - /* Create a new SoupAddress */ - ia = g_new0 (SoupAddress, 1); - ia->name = g_strdup (name); - ia->ref_count = 1; - - sa_in = (struct sockaddr_in*) &ia->sa; - sa_in->sin_family = AF_INET; - sa_in->sin_port = g_htons (port); /* Create a structure for the call back */ state = g_new0 (SoupAddressState, 1); - state->ia = ia; + state->ia.name = g_strdup (name); + state->ia.ref_count = 1; state->func = func; state->data = data; + sa_in = (struct sockaddr_in*) &state->ia.sa; + sa_in->sin_family = AF_INET; + sa_in->sin_port = g_htons (port); + state->WSAhandle = (int) WSAAsyncGetHostByName (soup_hWnd, IA_NEW_MSG, @@ -835,7 +915,7 @@ soup_address_new_cancel (SoupAddressNewId id) g_return_if_fail(state != NULL); - soup_address_delete (state->ia); + soup_address_unref (state->ia); WSACancelAsyncRequest ((HANDLE)state->WSAhandle); /*get a lock and remove the hash entry */ @@ -847,27 +927,28 @@ soup_address_new_cancel (SoupAddressNewId id) #endif /*********** End Windows code ***********/ -/** - * soup_address_clone: - * @ia: Address to clone - * - * Create an internet address from another one. - * - * Returns: a new SoupAddress, or NULL if there was a failure. - **/ -SoupAddress* -soup_address_clone (const SoupAddress* ia) +static void +soup_address_new_sync_cb (SoupAddress *addr, + SoupAddressStatus status, + gpointer user_data) { - SoupAddress* cia; + SoupAddress **ret = user_data; + *ret = addr; +} - g_return_val_if_fail (ia != NULL, NULL); +SoupAddress * +soup_address_new_sync (const gchar *name, const gint port) +{ + SoupAddress *ret = (SoupAddress *) 0xdeadbeef; - cia = g_new0(SoupAddress, 1); - cia->ref_count = 1; - cia->sa = ia->sa; - if (ia->name != NULL) cia->name = g_strdup (ia->name); + soup_address_new (name, port, soup_address_new_sync_cb, &ret); - return cia; + while (1) { + g_main_iteration (TRUE); + if (ret != (SoupAddress *) 0xdeadbeef) return ret; + } + + return ret; } /** @@ -900,7 +981,12 @@ soup_address_unref (SoupAddress* ia) --ia->ref_count; if (ia->ref_count == 0) { - if (ia->name != NULL) g_free (ia->name); + if (ia->name != NULL) { +#ifndef SOUP_WIN32 + g_hash_table_remove (active_address_hash, ia->name); +#endif + g_free (ia->name); + } g_free (ia); } } @@ -932,14 +1018,15 @@ soup_address_get_name_cb (GIOChannel* iochannel, state->len += rv; /* Return true if there's more to read */ - if ((state->len - 1) != state->buffer[0]) + if ((state->len - 1) != state->buffer [0]) return TRUE; /* Copy the name */ - name = g_new (gchar, state->buffer[0] + 1); - strncpy (name, &state->buffer[1], state->buffer[0]); - name[state->buffer[0]] = '\0'; - state->ia->name = g_strdup (name); + name = g_new (gchar, state->buffer [0] + 1); + strncpy (name, &state->buffer [1], state->buffer [0]); + name [state->buffer [0]] = '\0'; + + state->ia->name = name; /* Remove the watch now in case we don't return immediately */ @@ -950,6 +1037,7 @@ soup_address_get_name_cb (GIOChannel* iochannel, SOUP_ADDRESS_STATUS_OK, name, state->data); + close (state->fd); waitpid (state->pid, NULL, 0); g_free (state); @@ -965,7 +1053,7 @@ soup_address_get_name_cb (GIOChannel* iochannel, SOUP_ADDRESS_STATUS_ERROR, NULL, state->data); - soup_address_get_name_cancel(state); + soup_address_get_name_cancel (state); return FALSE; } @@ -989,114 +1077,118 @@ soup_address_get_name_cb (GIOChannel* iochannel, * immediate success or failure. **/ SoupAddressGetNameId -soup_address_get_name (SoupAddress* ia, +soup_address_get_name (SoupAddress* ia, SoupAddressGetNameFn func, - gpointer data) + gpointer data) { - g_return_val_if_fail(ia != NULL, NULL); - g_return_val_if_fail(func != NULL, NULL); + SoupAddressReverseState* state; + gchar* name; + guchar len; + pid_t pid = -1; + int pipes [2]; - /* If we already know the name, just copy that */ - /* Otherwise, fork and look it up */ - if (ia->name != NULL) - (func) (ia, - SOUP_ADDRESS_STATUS_OK, - g_strdup (ia->name), - data); - else { - pid_t pid = -1; - int pipes[2]; + g_return_val_if_fail (ia != NULL, NULL); + g_return_val_if_fail (func != NULL, NULL); - /* Open a pipe */ - if (pipe(pipes) == -1) { - (func) (ia, SOUP_ADDRESS_STATUS_ERROR, NULL, data); - return NULL; + if (ia->name) { + (func) (ia, SOUP_ADDRESS_STATUS_OK, ia->name, data); + return NULL; + } + + /* Open a pipe */ + if (pipe (pipes) != 0) { + (func) (ia, SOUP_ADDRESS_STATUS_ERROR, NULL, data); + return NULL; + } + + FORK_AGAIN: + errno = 0; + pid = fork (); + + switch (pid) { + case -1: + if (errno == EAGAIN) { + /* Yield the processor */ + sleep(0); + goto FORK_AGAIN; } - /* Fork to do the look up. */ - fork_again: - if ((pid = fork()) == 0) { - gchar* name; - guchar len; - - /* Write the name to the pipe. If we didn't get a name, - we just write the canonical name. */ - if ((name = soup_gethostbyaddr ((char*) &((struct sockaddr_in*)&ia->sa)->sin_addr, - sizeof (struct in_addr), AF_INET)) != NULL) { - guint lenint = strlen(name); - - if (lenint > 255) { - g_warning ("Truncating domain name: %s\n", name); - name[256] = '\0'; - lenint = 255; - } - - len = lenint; - - if ((write (pipes[1], &len, sizeof(len)) == -1) || - (write (pipes[1], name, len) == -1) ) - g_warning ("Problem writing to pipe\n"); - - g_free(name); - } else { - gchar buffer[INET_ADDRSTRLEN]; /* defined in netinet/in.h */ - guchar* p = (guchar*) &(SOUP_SOCKADDR_IN (ia->sa).sin_addr); - - g_snprintf(buffer, - sizeof (buffer), - "%d.%d.%d.%d", - p[0], - p[1], - p[2], - p[3]); - len = strlen (buffer); - - if ((write (pipes[1], &len, sizeof(len)) == -1) || - (write (pipes[1], buffer, len) == -1)) - g_warning ("Problem writing to pipe\n"); - } + /* Else there was a goofy error */ + g_warning ("Fork error: %s (%d)\n", + g_strerror(errno), + errno); - /* Close the socket */ - close(pipes[1]); + (*func) (ia, SOUP_ADDRESS_STATUS_ERROR, NULL, data); - /* Exit (we don't want atexit called, so do _exit instead) */ - _exit(EXIT_SUCCESS); + return NULL; + case 0: + /* Write the name to the pipe. If we didn't get a name, + we just write the canonical name. */ + name = soup_gethostbyaddr ( + (char*) &((struct sockaddr_in*)&ia->sa)->sin_addr, + sizeof (struct in_addr), + AF_INET); + + if (name) { + guint lenint = strlen(name); + + if (lenint > 255) { + g_warning ("Truncating domain name: %s\n", + name); + name [256] = '\0'; + lenint = 255; + } - } else if (pid > 0) { - /* Set up an IOChannel to read from the pipe */ - SoupAddressReverseState* state; + len = lenint; - /* Create a structure for the call back */ - state = g_new0 (SoupAddressReverseState, 1); - state->ia = ia; - state->func = func; - state->data = data; - state->pid = pid; - state->fd = pipes[0]; + if ((write (pipes [1], &len, sizeof(len)) == -1) || + (write (pipes [1], name, len) == -1) ) + g_warning ("Problem writing to pipe\n"); - /* Add a watch */ - state->watch = - g_io_add_watch( - g_io_channel_unix_new (pipes[0]), - G_IO_IN|G_IO_ERR|G_IO_HUP|G_IO_NVAL, - soup_address_get_name_cb, - state); - return state; - } else if (errno == EAGAIN) { - /* Try again */ - /* Yield the processor */ - sleep(0); - goto fork_again; + g_free(name); } else { - /* Else there was a goofy error */ - g_warning ("Fork error: %s (%d)\n", - g_strerror(errno), - errno); - (*func) (ia, SOUP_ADDRESS_STATUS_ERROR, NULL, data); + /* defined in netinet/in.h */ + gchar buffer [INET_ADDRSTRLEN]; + guchar* p; + p = (guchar*) &(SOUP_SOCKADDR_IN (ia->sa).sin_addr); + + g_snprintf(buffer, + sizeof (buffer), + "%d.%d.%d.%d", + p [0], + p [1], + p [2], + p [3]); + len = strlen (buffer); + + if ((write (pipes [1], &len, sizeof(len)) == -1) || + (write (pipes [1], buffer, len) == -1)) + g_warning ("Problem writing to pipe\n"); } - } - return NULL; + /* Close the socket */ + close(pipes [1]); + + /* Exit (we don't want atexit called, so do _exit instead) */ + _exit(EXIT_SUCCESS); + default: + soup_address_ref (ia); + + state = g_new0 (SoupAddressReverseState, 1); + state->ia = ia; + state->func = func; + state->data = data; + state->pid = pid; + state->fd = pipes [0]; + + /* Add a watch */ + state->watch = + g_io_add_watch(g_io_channel_unix_new (pipes [0]), + G_IO_IN|G_IO_ERR|G_IO_HUP|G_IO_NVAL, + soup_address_get_name_cb, + state); + return state; + } } /** @@ -1139,10 +1231,10 @@ soup_address_get_name_cb (GIOChannel* iochannel, result = (struct hostent*) state->hostentBuffer; if (state->errorcode) { - (*state->func)(state->ia, - SOUP_ADDRESS_STATUS_ERROR, - NULL, - state->data); + (*state->func) (state->ia, + SOUP_ADDRESS_STATUS_ERROR, + NULL, + state->data); return FALSE; } @@ -1184,15 +1276,15 @@ soup_address_get_name (SoupAddress* ia, state->func = func; state->data = data; - sa_in = (struct sockaddr_in*)&ia->sa; + sa_in = (struct sockaddr_in*) &ia->sa; state->WSAhandle = (int) - WSAAsyncGetHostByAddr(soup_hWnd, GET_NAME_MSG, - (const char*) &sa_in->sin_addr, - (int) (sizeof (&sa_in->sin_addr)), - (int) &sa_in->sin_family, - state->hostentBuffer, - sizeof (state->hostentBuffer)); + WSAAsyncGetHostByAddr (soup_hWnd, GET_NAME_MSG, + (const char*) &sa_in->sin_addr, + (int) (sizeof (&sa_in->sin_addr)), + (int) &sa_in->sin_family, + state->hostentBuffer, + sizeof (state->hostentBuffer)); if (!state->WSAhandle) { g_free (state); @@ -1218,7 +1310,7 @@ soup_address_get_name_cancel (SoupAddressGetNameId id) g_return_if_fail(state != NULL); - soup_address_delete (state->ia); + soup_address_unref (state->ia); WSACancelAsyncRequest ((HANDLE) state->WSAhandle); /*get a lock and remove the hash entry */ @@ -1244,7 +1336,7 @@ soup_address_get_name_cancel (SoupAddressGetNameId id) gchar* soup_address_get_canonical_name (SoupAddress* ia) { - gchar buffer[INET_ADDRSTRLEN]; /* defined in netinet/in.h */ + gchar buffer [INET_ADDRSTRLEN]; /* defined in netinet/in.h */ guchar* p = (guchar*) &(SOUP_SOCKADDR_IN(ia->sa).sin_addr); g_return_val_if_fail (ia != NULL, NULL); @@ -1252,10 +1344,10 @@ soup_address_get_canonical_name (SoupAddress* ia) g_snprintf(buffer, sizeof (buffer), "%d.%d.%d.%d", - p[0], - p[1], - p[2], - p[3]); + p [0], + p [1], + p [2], + p [3]); return g_strdup (buffer); } @@ -1436,6 +1528,7 @@ soup_address_gethostaddr (void) return ia; } + static void soup_socket_connect_tcp_cb (SoupSocket* socket, SoupSocketConnectStatus status, @@ -1445,12 +1538,10 @@ soup_socket_connect_tcp_cb (SoupSocket* socket, if (status == SOUP_SOCKET_NEW_STATUS_OK) (*state->func) (socket, - state->ia, SOUP_SOCKET_CONNECT_ERROR_NONE, state->data); else (*state->func) (NULL, - NULL, SOUP_SOCKET_CONNECT_ERROR_NETWORK, state->data); @@ -1465,17 +1556,13 @@ soup_socket_connect_inetaddr_cb (SoupAddress* inetaddr, SoupSocketConnectState* state = (SoupSocketConnectState*) data; if (status == SOUP_ADDRESS_STATUS_OK) { - state->ia = inetaddr; - state->inetaddr_id = NULL; - state->tcp_id = - soup_socket_new (inetaddr, - soup_socket_connect_tcp_cb, - state); - /* Note that this call may delete the state. */ + state->tcp_id = soup_socket_new (inetaddr, + soup_socket_connect_tcp_cb, + state); + soup_address_unref (inetaddr); } else { (*state->func) (NULL, - NULL, SOUP_SOCKET_CONNECT_ERROR_ADDR_RESOLVE, state->data); g_free(state); @@ -1501,18 +1588,18 @@ soup_socket_connect_inetaddr_cb (SoupAddress* inetaddr, * failure. **/ SoupSocketConnectId -soup_socket_connect (gchar* hostname, - gint port, +soup_socket_connect (const gchar* hostname, + const gint port, SoupSocketConnectFn func, - gpointer data) + gpointer data) { SoupSocketConnectState* state; gpointer id; - g_return_val_if_fail(hostname != NULL, NULL); - g_return_val_if_fail(func != NULL, NULL); + g_return_val_if_fail (hostname != NULL, NULL); + g_return_val_if_fail (func != NULL, NULL); - state = g_new0(SoupSocketConnectState, 1); + state = g_new0 (SoupSocketConnectState, 1); state->func = func; state->data = data; @@ -1545,17 +1632,40 @@ soup_socket_connect_cancel (SoupSocketConnectId id) SoupSocketConnectState* state = (SoupSocketConnectState*) id; g_return_if_fail (state != NULL); - + if (state->inetaddr_id) - soup_address_new_cancel(state->inetaddr_id); - else if (state->tcp_id) { - soup_address_unref (state->ia); + soup_address_new_cancel (state->inetaddr_id); + else if (state->tcp_id) soup_socket_new_cancel (state->tcp_id); - } g_free (state); } +static void +soup_socket_connect_sync_cb (SoupSocket *socket, + SoupSocketConnectStatus status, + gpointer data) +{ + SoupSocket **ret = data; + *ret = socket; +} + +SoupSocket * +soup_socket_connect_sync (const gchar *name, + const gint port) +{ + SoupSocket *ret = (SoupSocket *) 0xdeadbeef; + + soup_socket_connect (name, port, soup_socket_connect_sync_cb, &ret); + + while (1) { + g_main_iteration (TRUE); + if (ret != (SoupSocket *) 0xdeadbeef) return ret; + } + + return ret; +} + #ifndef SOUP_WIN32 /*********** Unix code ***********/ @@ -1565,40 +1675,41 @@ soup_socket_new_cb (GIOChannel* iochannel, gpointer data) { SoupSocketState* state = (SoupSocketState*) data; + SoupSocket* s; + gint error = 0; + gint len = sizeof (gint); /* Remove the watch now in case we don't return immediately */ g_source_remove (state->connect_watch); + if (condition & ~(G_IO_IN | G_IO_OUT)) goto ERROR; + errno = 0; - if ((condition & G_IO_IN) || (condition & G_IO_OUT)) { - gint error, len; - len = sizeof (error); - - /* Get the error option */ - if (getsockopt (state->socket->sockfd, - SOL_SOCKET, - SO_ERROR, - &error, - &len) >= 0) { - /* Check if there is an error */ - if (!error) { - /* Reset the flags */ - if (fcntl (state->socket->sockfd, - F_SETFL, - state->flags) == 0) { - (*state->func) (state->socket, - SOUP_SOCKET_NEW_STATUS_OK, - state->data); - g_free (state); - return FALSE; - } - } - } - } + if (getsockopt (state->sockfd, + SOL_SOCKET, + SO_ERROR, + &error, + &len) != 0) goto ERROR; - /* Otherwise, there was an error */ + if (error) goto ERROR; + + if (fcntl (state->sockfd, F_SETFL, state->flags) != 0) + goto ERROR; + + s = g_new0 (SoupSocket, 1); + s->ref_count = 1; + s->sockfd = state->sockfd; + s->addr = state->addr; + + (*state->func) (s, SOUP_SOCKET_NEW_STATUS_OK, state->data); + + g_free (state); + + return FALSE; + + ERROR: + soup_address_unref (state->addr); (*state->func) (NULL, SOUP_SOCKET_NEW_STATUS_ERROR, state->data); - soup_socket_unref (state->socket); g_free (state); return FALSE; @@ -1620,15 +1731,14 @@ soup_socket_new_cb (GIOChannel* iochannel, * failure. **/ SoupSocketNewId -soup_socket_new (const SoupAddress* addr, - SoupSocketNewFn func, - gpointer data) +soup_socket_new (SoupAddress *addr, + SoupSocketNewFn func, + gpointer data) { gint sockfd; gint flags; - SoupSocket* s; - struct sockaddr_in* sa_in; SoupSocketState* state; + GIOChannel *chan; g_return_val_if_fail(addr != NULL, NULL); g_return_val_if_fail(func != NULL, NULL); @@ -1636,57 +1746,60 @@ soup_socket_new (const SoupAddress* addr, /* Create socket */ sockfd = socket (AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { - (func)(NULL, SOUP_SOCKET_NEW_STATUS_ERROR, data); + (func) (NULL, SOUP_SOCKET_NEW_STATUS_ERROR, data); return NULL; } /* Get the flags (should all be 0?) */ flags = fcntl (sockfd, F_GETFL, 0); if (flags == -1) { - (func)(NULL, SOUP_SOCKET_NEW_STATUS_ERROR, data); + (func) (NULL, SOUP_SOCKET_NEW_STATUS_ERROR, data); return NULL; } if (fcntl (sockfd, F_SETFL, flags | O_NONBLOCK) == -1) { - (func)(NULL, SOUP_SOCKET_NEW_STATUS_ERROR, data); + (func) (NULL, SOUP_SOCKET_NEW_STATUS_ERROR, data); return NULL; } - /* Create our structure */ - s = g_new0 (SoupSocket, 1); - s->ref_count = 1; - s->sockfd = sockfd; - - /* Set up address and port for connection */ - memcpy (&s->sa, &addr->sa, sizeof(s->sa)); - sa_in = (struct sockaddr_in*) &s->sa; - sa_in->sin_family = AF_INET; + errno = 0; /* Connect (but non-blocking!) */ - if (connect (s->sockfd, &s->sa, sizeof(s->sa)) < 0) { - if (errno != EINPROGRESS) { - g_free(s); - (func)(NULL, SOUP_SOCKET_NEW_STATUS_ERROR, data); - return NULL; - } + if (connect (sockfd, &addr->sa, sizeof (addr->sa)) < 0 && + errno != EINPROGRESS) { + (func) (NULL, SOUP_SOCKET_NEW_STATUS_ERROR, data); + return NULL; } - /* Note that if connect returns 0, then we're already connected and - we could call the call back immediately. But, it would probably - make things too complicated for the user if we could call the - callback before we returned from this function. */ + /* Unref in soup_socket_new_cb if failure */ + soup_address_ref (addr); + + /* Connect succeeded, return immediately */ + if (!errno) { + SoupSocket *s = g_new0 (SoupSocket, 1); + s->ref_count = 1; + s->sockfd = sockfd; + s->addr = addr; + + (*func) (s, SOUP_SOCKET_NEW_STATUS_OK, data); + return NULL; + } + + chan = g_io_channel_unix_new (sockfd); /* Wait for the connection */ state = g_new0 (SoupSocketState, 1); - state->socket = s; + state->sockfd = sockfd; + state->addr = addr; state->func = func; state->data = data; state->flags = flags; - state->connect_watch = - g_io_add_watch (g_io_channel_unix_new (s->sockfd), - SOUP_ANY_IO_CONDITION, - soup_socket_new_cb, - state); + state->connect_watch = g_io_add_watch (chan, + SOUP_ANY_IO_CONDITION, + soup_socket_new_cb, + state); + + g_io_channel_unref (chan); return state; } @@ -1704,7 +1817,7 @@ soup_socket_new_cancel (SoupSocketNewId id) SoupSocketState* state = (SoupSocketState*) id; g_source_remove (state->connect_watch); - soup_socket_unref (state->socket); + soup_address_unref (state->addr); g_free (state); } @@ -1717,102 +1830,131 @@ soup_socket_new_cb (GIOChannel* iochannel, gpointer data) { SoupSocketState* state = (SoupSocketState*) data; + SoupSocket *s; if (state->errorcode) { - (*state->func)(state->socket, - SOUP_SOCKET_NEW_STATUS_OK, - state->data); - g_free(state); + soup_address_unref (state->addr); + (*state->func) (NULLL, + SOUP_SOCKET_NEW_STATUS_ERROR, + state->data); + g_free (state); return FALSE; } - (*state->func) (state->socket, - SOUP_SOCKET_NEW_STATUS_OK, - state->data); - g_free(state); + s = g_new0 (SoupSocket, 1); + s->ref_count = 1; + s->sockfd = sockfd; + s->addr = state->addr; + + (*state->func) (s, SOUP_SOCKET_NEW_STATUS_OK, state->data); + g_free (state); return FALSE; } SoupSocketNewId -soup_socket_new (const SoupAddress* addr, - SoupSocketNewFn func, - gpointer data) +soup_socket_new (SoupAddress *addr, + SoupSocketNewFn func, + gpointer data) { gint sockfd; gint status; - SoupSocket* s; - struct sockaddr_in* sa_in; SoupSocketState* state; - g_return_val_if_fail(addr != NULL, NULL); - g_return_val_if_fail(func != NULL, NULL); + g_return_val_if_fail (addr != NULL, NULL); + g_return_val_if_fail (func != NULL, NULL); /* Create socket */ - sockfd = socket(AF_INET, SOCK_STREAM, 0); + sockfd = socket (AF_INET, SOCK_STREAM, 0); if (sockfd == INVALID_SOCKET) { - (func)(NULL, SOUP_SOCKET_NEW_STATUS_ERROR, data); + (func) (NULL, SOUP_SOCKET_NEW_STATUS_ERROR, data); return NULL; } /* Note: WSAAsunc automatically sets the socket to noblocking mode */ - status = WSAAsyncSelect(sockfd, soup_hWnd, TCP_SOCK_MSG, FD_CONNECT); + status = WSAAsyncSelect (sockfd, soup_hWnd, TCP_SOCK_MSG, FD_CONNECT); if (status == SOCKET_ERROR) { - (func)(NULL, SOUP_SOCKET_NEW_STATUS_ERROR, data); + (func) (NULL, SOUP_SOCKET_NEW_STATUS_ERROR, data); return NULL; } - /* Create our structure */ - s = g_new0(SoupSocket, 1); - s->ref_count = 1; - s->sockfd = sockfd; - - /* Set up address and port for connection */ - memcpy(&s->sa, &addr->sa, sizeof(s->sa)); - sa_in = (struct sockaddr_in*) &s->sa; - sa_in->sin_family = AF_INET; - - status = connect(s->sockfd, &s->sa, sizeof(s->sa)); + status = connect (s->sockfd, &s->sa, sizeof(s->sa)); /* Returning an error is ok, unless.. */ if (status == SOCKET_ERROR) { status = WSAGetLastError(); if (status != WSAEWOULDBLOCK) { - (func)(NULL, SOUP_SOCKET_NEW_STATUS_ERROR, data); - g_free(s); + (func) (NULL, SOUP_SOCKET_NEW_STATUS_ERROR, data); + g_free (s); return NULL; } } + soup_address_ref (addr); + + if (status != SOCKET_ERROR) { + SoupSocket *s = g_new0 (SoupSocket, 1); + s->ref_count = 1; + s->sockfd = sockfd; + s->addr = addr; + + (*state->func) (s, SOUP_SOCKET_NEW_STATUS_OK, state->data); + return NULL; + } + /* Wait for the connection */ - state = g_new0(SoupSocketState, 1); - state->socket = s; + state = g_new0 (SoupSocketState, 1); + state->addr = addr; state->func = func; state->data = data; - state->socket->sockfd = sockfd; + state->sockfd = sockfd; - WaitForSingleObject(soup_select_Mutex, INFINITE); + WaitForSingleObject (soup_select_Mutex, INFINITE); /*using sockfd as the key into the 'select' hash */ - g_hash_table_insert(soup_select_hash, - (gpointer) state->socket->sockfd, - (gpointer) state); - ReleaseMutex(soup_select_Mutex); + g_hash_table_insert (soup_select_hash, + (gpointer) state->socket->sockfd, + (gpointer) state); + ReleaseMutex (soup_select_Mutex); return state; } void -soup_socket_new_cancel(SoupSocketNewId id) +soup_socket_new_cancel (SoupSocketNewId id) { SoupSocketState* state = (SoupSocketState*) id; /* Cancel event posting on the socket */ - WSAAsyncSelect(state->socket->sockfd, soup_hWnd, 0, 0); - soup_socket_delete(state->socket); + WSAAsyncSelect (state->sockfd, soup_hWnd, 0, 0); + soup_address_unref (state->addr); g_free (state); } #endif /*********** End Windows code ***********/ +static void +soup_socket_new_sync_cb (SoupSocket* socket, + SoupSocketNewStatus status, + gpointer data) +{ + SoupSocket **ret = data; + *ret = socket; +} + +SoupSocket * +soup_socket_new_sync (SoupAddress *addr) +{ + SoupSocket *ret = (SoupSocket *) 0xdeadbeef; + + soup_socket_new (addr, soup_socket_new_sync_cb, &ret); + + while (1) { + g_main_iteration (TRUE); + if (ret != (SoupSocket *) 0xdeadbeef) return ret; + } + + return ret; +} + /** * soup_socket_ref * @s: SoupSocket to reference @@ -1822,7 +1964,7 @@ soup_socket_new_cancel(SoupSocketNewId id) void soup_socket_ref (SoupSocket* s) { - g_return_if_fail(s != NULL); + g_return_if_fail (s != NULL); ++s->ref_count; } @@ -1842,10 +1984,11 @@ soup_socket_unref (SoupSocket* s) --s->ref_count; if (s->ref_count == 0) { - /* Don't care if this fails... */ - SOUP_CLOSE_SOCKET(s->sockfd); + SOUP_CLOSE_SOCKET (s->sockfd); - if (s->iochannel) g_io_channel_unref(s->iochannel); + if (s->addr) soup_address_unref (s->addr); + + if (s->iochannel) g_io_channel_unref (s->iochannel); g_free(s); } @@ -1875,14 +2018,14 @@ soup_socket_unref (SoupSocket* s) GIOChannel* soup_socket_get_iochannel (SoupSocket* socket) { - g_return_val_if_fail (socket != NULL, NULL); + g_return_val_if_fail (socket != NULL, NULL); - if (socket->iochannel == NULL) - socket->iochannel = SOUP_SOCKET_IOCHANNEL_NEW(socket->sockfd); + if (socket->iochannel == NULL) + socket->iochannel = SOUP_SOCKET_IOCHANNEL_NEW(socket->sockfd); - g_io_channel_ref (socket->iochannel); + g_io_channel_ref (socket->iochannel); - return socket->iochannel; + return socket->iochannel; } /** @@ -1901,14 +2044,12 @@ soup_socket_get_iochannel (SoupSocket* socket) SoupAddress * soup_socket_get_address (const SoupSocket* socket) { - SoupAddress* ia; - g_return_val_if_fail (socket != NULL, NULL); + g_return_val_if_fail (socket->addr != NULL, NULL); - ia = g_new0 (SoupAddress, 1); - ia->sa = socket->sa; + soup_address_ref (socket->addr); - return ia; + return socket->addr; } /** @@ -1924,7 +2065,7 @@ soup_socket_get_port(const SoupSocket* socket) { g_return_val_if_fail (socket != NULL, 0); - return g_ntohs (SOUP_SOCKADDR_IN (socket->sa).sin_port); + return g_ntohs (SOUP_SOCKADDR_IN (socket->addr->sa).sin_port); } @@ -1972,8 +2113,8 @@ soup_MainCallBack (GIOChannel *iochannel, /* Now call the callback function */ soup_address_get_name_cb (NULL, - G_IO_IN, - (gpointer) IARstate); + G_IO_IN, + (gpointer) IARstate); break; case TCP_SOCK_MSG: WaitForSingleObject (soup_select_Mutex, INFINITE); @@ -1985,8 +2126,8 @@ soup_MainCallBack (GIOChannel *iochannel, TCPNEWstate = (SoupSocketState*) data; TCPNEWstate->errorcode = WSAGETSELECTERROR (msg.lParam); soup_tcp_socket_new_cb (NULL, - G_IO_IN, - (gpointer) TCPNEWstate); + G_IO_IN, + (gpointer) TCPNEWstate); break; } @@ -2010,7 +2151,7 @@ SoupWndProc (HWND hwnd, /* handle to window */ return 0; default: - return DefWindowProc(hwnd, uMsg, wParam, lParam); + return DefWindowProc (hwnd, uMsg, wParam, lParam); } } @@ -2021,7 +2162,6 @@ RemoveHashEntry(gpointer key, gpointer value, gpointer user_data) return TRUE; } - BOOL WINAPI DllMain (HINSTANCE hinstDLL, /* handle to DLL module */ DWORD fdwReason, /* reason for calling functionm */ @@ -2036,7 +2176,7 @@ DllMain (HINSTANCE hinstDLL, /* handle to DLL module */ /* The DLL is being mapped into process's address space */ /* Do any required initialization on a per application basis, return FALSE if failed */ - wVersionRequested = MAKEWORD( 2, 0 ); + wVersionRequested = MAKEWORD (2, 0); err = WSAStartup (wVersionRequested, &wsaData); if (err != 0) { @@ -2051,11 +2191,11 @@ DllMain (HINSTANCE hinstDLL, /* handle to DLL module */ /* 2.0 in wVersion since that is the version we */ /* requested. */ - if ( LOBYTE( wsaData.wVersion ) != 2 || - HIBYTE( wsaData.wVersion ) != 0 ) { + if (LOBYTE(wsaData.wVersion) != 2 || + HIBYTE(wsaData.wVersion) != 0) { /* Tell the user that we could not find a usable */ /* WinSock DLL. */ - WSACleanup(); + WSACleanup (); return FALSE; } @@ -2108,19 +2248,19 @@ DllMain (HINSTANCE hinstDLL, /* handle to DLL module */ soup_select_hash = g_hash_table_new (NULL, NULL); - soup_Mutex = CreateMutex(NULL, FALSE, "soup_Mutex"); + soup_Mutex = CreateMutex (NULL, FALSE, "soup_Mutex"); if (soup_Mutex == NULL) return FALSE; - soup_select_Mutex = CreateMutex(NULL, - FALSE, - "soup_select_Mutex"); + soup_select_Mutex = CreateMutex (NULL, + FALSE, + "soup_select_Mutex"); if (soup_select_Mutex == NULL) return FALSE; - soup_hostent_Mutex = CreateMutex(NULL, - FALSE, - "soup_hostent_Mutex"); + soup_hostent_Mutex = CreateMutex (NULL, + FALSE, + "soup_hostent_Mutex"); if (soup_hostent_Mutex == NULL) return FALSE; @@ -2148,7 +2288,7 @@ DllMain (HINSTANCE hinstDLL, /* handle to DLL module */ ReleaseMutex (soup_select_Mutex); ReleaseMutex (soup_hostent_Mutex); - WSACleanup(); + WSACleanup (); break; } diff --git a/libsoup/soup-socket.h b/libsoup/soup-socket.h index 33537ed..446adc6 100644 --- a/libsoup/soup-socket.h +++ b/libsoup/soup-socket.h @@ -36,7 +36,8 @@ SoupAddressNewId soup_address_new (const gchar* name, void soup_address_new_cancel (SoupAddressNewId id); -SoupAddress* soup_address_clone (const SoupAddress* ia); +SoupAddress *soup_address_new_sync (const gchar *name, + const gint port); void soup_address_ref (SoupAddress* ia); @@ -47,7 +48,7 @@ typedef gpointer SoupAddressGetNameId; typedef void (*SoupAddressGetNameFn) (SoupAddress *inetaddr, SoupAddressStatus status, - gchar *name, + const gchar *name, gpointer user_data); SoupAddressGetNameId soup_address_get_name (SoupAddress* ia, @@ -86,17 +87,20 @@ typedef enum { SOUP_SOCKET_CONNECT_ERROR_NETWORK } SoupSocketConnectStatus; -typedef void (*SoupSocketConnectFn) (SoupSocket* socket, - SoupAddress* ia, - SoupSocketConnectStatus status, - gpointer data); +typedef void (*SoupSocketConnectFn) (SoupSocket *socket, + SoupSocketConnectStatus status, + gpointer data); -SoupSocketConnectId soup_socket_connect (gchar* hostname, - gint port, - SoupSocketConnectFn func, - gpointer user_data); +SoupSocketConnectId soup_socket_connect (const gchar* hostname, + const gint port, + SoupSocketConnectFn func, + gpointer user_data); + +void soup_socket_connect_cancel (SoupSocketConnectId id); + +SoupSocket *soup_socket_connect_sync (const gchar *hostname, + const gint port); -void soup_socket_connect_cancel (SoupSocketConnectId id); typedef gpointer SoupSocketNewId; @@ -110,21 +114,23 @@ typedef void (*SoupSocketNewFn) (SoupSocket* socket, SoupSocketNewStatus status, gpointer data); -SoupSocketNewId soup_socket_new (const SoupAddress* addr, - SoupSocketNewFn func, - gpointer user_data); +SoupSocketNewId soup_socket_new (SoupAddress *addr, + SoupSocketNewFn func, + gpointer user_data); + +void soup_socket_new_cancel (SoupSocketNewId id); -void soup_socket_new_cancel (SoupSocketNewId id); +SoupSocket *soup_socket_new_sync (SoupAddress *addr); -void soup_socket_ref (SoupSocket* s); +void soup_socket_ref (SoupSocket* s); -void soup_socket_unref (SoupSocket* s); +void soup_socket_unref (SoupSocket* s); -GIOChannel *soup_socket_get_iochannel (SoupSocket* socket); +GIOChannel *soup_socket_get_iochannel (SoupSocket* socket); -SoupAddress *soup_socket_get_address (const SoupSocket* socket); +SoupAddress *soup_socket_get_address (const SoupSocket* socket); -gint soup_socket_get_port (const SoupSocket* socket); +gint soup_socket_get_port (const SoupSocket* socket); #endif /* SOUP_SOCKET_H */ diff --git a/libsoup/soup-socks.c b/libsoup/soup-socks.c index 4e2d42b..d8b74f3 100644 --- a/libsoup/soup-socks.c +++ b/libsoup/soup-socks.c @@ -249,7 +249,7 @@ soup_connect_socks_proxy (SoupConnection *conn, sd->cb = cb; sd->user_data = user_data; - switch (soup_context_get_protocol (proxy_ctx)) { + switch (soup_context_get_uri (proxy_ctx)->protocol) { case SOUP_PROTOCOL_SOCKS4: soup_address_new (dest_uri->host, dest_uri->port, diff --git a/libsoup/soup-uri.c b/libsoup/soup-uri.c index 52a42a4..daee79d 100644 --- a/libsoup/soup-uri.c +++ b/libsoup/soup-uri.c @@ -5,6 +5,7 @@ * Authors : * Bertrand Guiheneuf * Dan Winship + * Alex Graveley * * Copyright 1999, 2000 Helix Code, Inc. (http://www.helixcode.com) * @@ -45,21 +46,62 @@ #include "soup-uri.h" #include "soup-misc.h" +typedef struct { + SoupProtocol proto; + gchar *str; + gint port; +} SoupKnownProtocols; + +SoupKnownProtocols known_protocols [] = { + { SOUP_PROTOCOL_HTTP, "http://", 80 }, + { SOUP_PROTOCOL_SHTTP, "https://", 443 }, + { SOUP_PROTOCOL_SMTP, "mailto:", 25 }, + { SOUP_PROTOCOL_SOCKS4, "socks4://", -1 }, + { SOUP_PROTOCOL_SOCKS5, "socks5://", -1 }, + { 0 } +}; + +static SoupProtocol +soup_uri_get_protocol (const gchar *proto, int *len) +{ + SoupKnownProtocols *known = known_protocols; + + while (known->proto) { + if (!g_strncasecmp (proto, known->str, strlen (known->str))) { + *len = strlen (known->str); + return known->proto; + } + known++; + } + + *len = 0; + return 0; +} + +static gchar * +soup_uri_protocol_to_string (SoupProtocol proto) +{ + SoupKnownProtocols *known = known_protocols; + + while (known->proto) { + if (known->proto == proto) return known->str; + known++; + } + + return ""; +} + static gint -soup_uri_get_default_port (gchar *proto) +soup_uri_get_default_port (SoupProtocol proto) { - g_return_val_if_fail (proto != NULL, -1); - - if (strcasecmp (proto, "http") == 0) - return 80; - else if (strcasecmp (proto, "https") == 0) - return 443; - else if (strcasecmp (proto, "mailto") == 0) - return 25; - else if (strcasecmp (proto, "ftp") == 0) - return 21; - else - return -1; + SoupKnownProtocols *known = known_protocols; + + while (known->proto) { + if (known->proto == proto) return known->port; + known++; + } + + return -1; } /** @@ -81,21 +123,25 @@ soup_uri_get_default_port (gchar *proto) * * Return value: a SoupUri structure containing the URL items. **/ -SoupUri *soup_uri_new (const gchar* uri_string) +SoupUri * +soup_uri_new (const gchar* uri_string) { SoupUri *g_uri; char *semi, *colon, *at, *slash, *path, *query = NULL; char **split; - g_uri = g_new (SoupUri,1); + g_uri = g_new0 (SoupUri,1); /* Find protocol: initial substring until "://" */ colon = strchr (uri_string, ':'); - if (colon && !strncmp (colon, "://", 3)) { - g_uri->protocol = g_strndup (uri_string, colon - uri_string); - uri_string = colon + 3; - } else - g_uri->protocol = NULL; + if (colon) { + gint protolen; + g_uri->protocol = soup_uri_get_protocol (uri_string, &protolen); + uri_string += protolen; + } + + /* Must have a protocol */ + if (!g_uri->protocol) return NULL; /* If there is an @ sign, look for user, authmech, and * password before it. @@ -112,7 +158,8 @@ SoupUri *soup_uri_new (const gchar* uri_string) semi = strchr(uri_string, ';'); if (semi && semi < colon && !strncasecmp (semi, ";auth=", 6)) - g_uri->authmech = g_strndup (semi + 6, colon - semi - 6); + g_uri->authmech = g_strndup (semi + 6, + colon - semi - 6); else { g_uri->authmech = NULL; semi = colon; @@ -148,7 +195,7 @@ SoupUri *soup_uri_new (const gchar* uri_string) if (slash == NULL) { slash = "/"; } - if (slash && *slash && g_uri->protocol == NULL) + if (slash && *slash && !g_uri->protocol) slash++; split = g_strsplit(slash, " ", 0); @@ -161,6 +208,7 @@ SoupUri *soup_uri_new (const gchar* uri_string) if (path && query) { g_uri->path = g_strndup (path, query - path); g_uri->querystring = g_strdup (++query); + g_uri->query_elems = g_strsplit (g_uri->querystring, "&", 0); g_free (path); } else { g_uri->path = path; @@ -174,12 +222,13 @@ SoupUri *soup_uri_new (const gchar* uri_string) gchar * soup_uri_to_string (const SoupUri *uri, gboolean show_passwd) { + g_return_val_if_fail (uri != NULL, NULL); + if (uri->port != -1 && - uri->port != soup_uri_get_default_port(uri->protocol)) + uri->port != soup_uri_get_default_port (uri->protocol)) return g_strdup_printf( - "%s%s%s%s%s%s%s%s%s:%d%s%s%s", - uri->protocol ? uri->protocol : "", - uri->protocol ? "://" : "", + "%s%s%s%s%s%s%s%s:%d%s%s%s", + soup_uri_protocol_to_string (uri->protocol), uri->user ? uri->user : "", uri->authmech ? ";auth=" : "", uri->authmech ? uri->authmech : "", @@ -193,9 +242,8 @@ soup_uri_to_string (const SoupUri *uri, gboolean show_passwd) uri->querystring ? uri->querystring : ""); else return g_strdup_printf( - "%s%s%s%s%s%s%s%s%s%s%s%s", - uri->protocol ? uri->protocol : "", - uri->protocol ? "://" : "", + "%s%s%s%s%s%s%s%s%s%s%s", + soup_uri_protocol_to_string (uri->protocol), uri->user ? uri->user : "", uri->authmech ? ";auth=" : "", uri->authmech ? uri->authmech : "", @@ -213,13 +261,13 @@ soup_uri_free (SoupUri *uri) { g_assert (uri); - g_free (uri->protocol); g_free (uri->user); g_free (uri->authmech); g_free (uri->passwd); g_free (uri->host); g_free (uri->path); g_free (uri->querystring); + g_strfreev (uri->query_elems); g_free (uri); } @@ -229,7 +277,7 @@ soup_debug_print_uri (SoupUri *uri) { g_return_if_fail (uri != NULL); - g_print ("Protocol: %s\n", uri->protocol); + g_print ("Protocol: %s\n", soup_uri_protocol_to_string (uri->protocol)); g_print ("User: %s\n", uri->user); g_print ("Authmech: %s\n", uri->authmech); g_print ("Password: %s\n", uri->passwd); diff --git a/libsoup/soup-uri.h b/libsoup/soup-uri.h index 2b8726b..ef5187a 100644 --- a/libsoup/soup-uri.h +++ b/libsoup/soup-uri.h @@ -29,25 +29,29 @@ #include +typedef enum { + SOUP_PROTOCOL_HTTP = 1, + SOUP_PROTOCOL_SHTTP, + SOUP_PROTOCOL_SMTP, + SOUP_PROTOCOL_SOCKS4, + SOUP_PROTOCOL_SOCKS5 +} SoupProtocol; + typedef struct { - gchar *protocol; + SoupProtocol protocol; - gchar *user; - gchar *authmech; - gchar *passwd; + gchar *user; + gchar *authmech; + gchar *passwd; - gchar *host; - gint port; + gchar *host; + gint port; - gchar *path; - gchar *querystring; + gchar *path; + gchar *querystring; + gchar **query_elems; } SoupUri; -/* the cache system has been disabled because it would - need the user to use accessors instead of modifying the - structure field. As the speed is not so important here, - I chose not to use it */ - SoupUri *soup_uri_new (const gchar *uri_string); gchar *soup_uri_to_string (const SoupUri *uri, gboolean show_password); -- 2.7.4