[xiph-commits] r7354 - in icecast/trunk/libshout: include/shout src

brendan at dactyl.lonelymoon.com brendan
Mon Jul 26 12:22:37 PDT 2004


Author: brendan
Date: Mon Jul 26 12:22:37 2004
New Revision: 7354

Modified:
icecast/trunk/libshout/include/shout/shout.h.in
icecast/trunk/libshout/src/shout.c
icecast/trunk/libshout/src/shout_private.h
Log:
nonblocking API WIP. Don't use yet, this is just to keep from losing work.
Everything should still work in blocking mode.


Modified: icecast/trunk/libshout/include/shout/shout.h.in
===================================================================
--- icecast/trunk/libshout/include/shout/shout.h.in	2004-07-26 19:20:56 UTC (rev 7353)
+++ icecast/trunk/libshout/include/shout/shout.h.in	2004-07-26 19:22:36 UTC (rev 7354)
@@ -139,6 +139,11 @@
int shout_set_protocol(shout_t *self, unsigned int protocol);
unsigned int shout_get_protocol(shout_t *self);

+/* Instructs libshout to use nonblocking I/O. Must be called before
+ * shout_open (no switching back and forth midstream at the moment). */
+int shout_set_nonblocking(shout_t* self, unsigned int nonblocking);
+unsigned int shout_get_nonblocking(shout_t *self);
+
/* Opens a connection to the server.  All parameters must already be set */
int shout_open(shout_t *self);


Modified: icecast/trunk/libshout/src/shout.c
===================================================================
--- icecast/trunk/libshout/src/shout.c	2004-07-26 19:20:56 UTC (rev 7353)
+++ icecast/trunk/libshout/src/shout.c	2004-07-26 19:22:36 UTC (rev 7354)
@@ -45,11 +45,17 @@
static void queue_free(shout_buf_t *queue);
static int send_queue(shout_t *self);
static int get_response(shout_t *self);
+static int try_connect (shout_t *self);
static int try_write (shout_t *self, const void *data, size_t len);

-static int login_xaudiocast(shout_t *self);
-static int login_icy(shout_t *self);
-static int login_http_basic(shout_t *self);
+static int create_request(shout_t *self);
+static int create_http_request(shout_t *self);
+static int create_xaudiocast_request(shout_t *self);
+static int create_icy_request(shout_t *self);
+static int parse_response(shout_t *self);
+static int parse_http_response(shout_t *self);
+static int parse_xaudiocast_response(shout_t *self);
+
static char *http_basic_authorization(shout_t *self);

/* -- static data -- */
@@ -138,61 +144,14 @@
/* sanity check */
if (!self)
return SHOUTERR_INSANE;
-
-	if (self->connected)
+	if (self->state != SHOUT_STATE_UNCONNECTED)
return SHOUTERR_CONNECTED;
-
if (!self->host || !self->password || !self->port)
return self->error = SHOUTERR_INSANE;
-
if (self->format == SHOUT_FORMAT_OGG && self->protocol != SHOUT_PROTOCOL_HTTP)
return self->error = SHOUTERR_UNSUPPORTED;

-	if(self->protocol != SHOUT_PROTOCOL_HTTP) {
-		if (self->protocol == SHOUT_PROTOCOL_ICY)
-			self->socket = sock_connect(self->host, self->port+1);
-		else
-			self->socket = sock_connect(self->host, self->port);
-		if (self->socket <= 0)
-			return self->error = SHOUTERR_NOCONNECT;
-	}
-
-	if (self->protocol == SHOUT_PROTOCOL_HTTP) {
-		if ((self->error = login_http_basic(self)) != SHOUTERR_SUCCESS) {
-			return self->error;
-		}
-	} else if (self->protocol == SHOUT_PROTOCOL_XAUDIOCAST) {
-		if ((self->error = login_xaudiocast(self)) != SHOUTERR_SUCCESS) {
-			sock_close(self->socket);
-			return self->error;
-		}
-	} else if (self->protocol == SHOUT_PROTOCOL_ICY) {
-		if ((self->error = login_icy(self)) != SHOUTERR_SUCCESS) {
-			sock_close(self->socket);
-			return self->error;
-		}
-
-	} else
-		return self->error = SHOUTERR_INSANE;
-
-	if (self->format == SHOUT_FORMAT_OGG) {
-		if ((self->error = shout_open_ogg(self)) != SHOUTERR_SUCCESS) {
-			sock_close(self->socket);
-			return self->error;
-		}
-	} else if (self->format == SHOUT_FORMAT_MP3) {
-		if ((self->error = shout_open_mp3(self)) != SHOUTERR_SUCCESS) {
-			sock_close(self->socket);
-			return self->error;
-		}
-	} else {
-		sock_close(self->socket);
-		return self->error = SHOUTERR_INSANE;
-	}
-
-	self->connected = 1;
-
-	return self->error;
+	return self->error = try_connect(self);
}


@@ -201,14 +160,14 @@
if (!self)
return SHOUTERR_INSANE;

-	if (!self->connected)
+	if (self->state != SHOUT_STATE_UNCONNECTED)
return self->error = SHOUTERR_UNCONNECTED;

if (self->close)
self->close(self);

sock_close(self->socket);
-	self->connected = 0;
+	self->state = SHOUT_STATE_UNCONNECTED;

return self->error = SHOUTERR_SUCCESS;
}
@@ -218,7 +177,7 @@
if (!self)
return SHOUTERR_INSANE;

-	if (!self->connected)
+	if (self->state != SHOUT_STATE_CONNECTED)
return self->error = SHOUTERR_UNCONNECTED;

if (self->starttime <= 0)
@@ -235,7 +194,7 @@
if (!self)
return SHOUTERR_INSANE;

-	if (!self->connected)
+	if (self->state != SHOUT_STATE_CONNECTED)
return SHOUTERR_UNCONNECTED;

self->error = SHOUTERR_SUCCESS;
@@ -392,12 +351,29 @@
}
}

+/* Returns:
+ *   SHOUTERR_CONNECTED if the connection is open,
+ *   SHOUTERR_UNCONNECTED if it has not yet been opened,
+ *   or an error from try_connect, including SHOUTERR_BUSY
+ */
int shout_get_connected(shout_t *self)
{
-	if (self->connected)
+	int rc;
+
+	if (!self)
+		return SHOUTERR_INSANE;
+
+	if (self->state == SHOUT_STATE_CONNECTED)
return SHOUTERR_CONNECTED;
-	else
-		return SHOUTERR_UNCONNECTED;
+	if (self->state != SHOUT_STATE_UNCONNECTED) {
+		if ((rc = try_connect(self)) == SHOUTERR_SUCCESS)
+			return SHOUTERR_CONNECTED;
+		if (rc == SHOUTERR_BUSY)
+			return SHOUTERR_UNCONNECTED;
+		else return rc;
+	}
+
+	return SHOUTERR_UNCONNECTED;
}

int shout_set_host(shout_t *self, const char *host)
@@ -405,7 +381,7 @@
if (!self)
return SHOUTERR_INSANE;

-	if (self->connected)
+	if (self->state != SHOUT_STATE_UNCONNECTED)
return self->error = SHOUTERR_CONNECTED;

if (self->host)
@@ -430,7 +406,7 @@
if (!self)
return SHOUTERR_INSANE;

-	if (self->connected)
+	if (self->state != SHOUT_STATE_UNCONNECTED)
return self->error = SHOUTERR_CONNECTED;

self->port = port;
@@ -451,7 +427,7 @@
if (!self)
return SHOUTERR_INSANE;

-	if (self->connected)
+	if (self->state != SHOUT_STATE_UNCONNECTED)
return self->error = SHOUTERR_CONNECTED;

if (self->password)
@@ -478,7 +454,7 @@
if (!self || !mount)
return SHOUTERR_INSANE;

-	if (self->connected)
+	if (self->state != SHOUT_STATE_UNCONNECTED)
return self->error = SHOUTERR_CONNECTED;

if (self->mount)
@@ -509,7 +485,7 @@
if (!self)
return SHOUTERR_INSANE;

-	if (self->connected)
+	if (self->state != SHOUT_STATE_UNCONNECTED)
return self->error = SHOUTERR_CONNECTED;

if (self->name)
@@ -534,7 +510,7 @@
if (!self)
return SHOUTERR_INSANE;

-	if (self->connected)
+	if (self->state != SHOUT_STATE_UNCONNECTED)
return self->error = SHOUTERR_CONNECTED;

if (self->url)
@@ -559,7 +535,7 @@
if (!self)
return SHOUTERR_INSANE;

-	if (self->connected)
+	if (self->state != SHOUT_STATE_UNCONNECTED)
return self->error = SHOUTERR_CONNECTED;

if (self->genre)
@@ -584,7 +560,7 @@
if (!self)
return SHOUTERR_INSANE;

-	if (self->connected)
+	if (self->state != SHOUT_STATE_UNCONNECTED)
return self->error = SHOUTERR_CONNECTED;

if (self->useragent)
@@ -610,7 +586,7 @@
if (!self)
return SHOUTERR_INSANE;

-	if (self->connected)
+	if (self->state != SHOUT_STATE_UNCONNECTED)
return self->error = SHOUTERR_CONNECTED;

if (self->user)
@@ -635,7 +611,7 @@
if (!self)
return SHOUTERR_INSANE;

-	if (self->connected)
+	if (self->state != SHOUT_STATE_UNCONNECTED)
return self->error = SHOUTERR_CONNECTED;

if (self->description)
@@ -660,7 +636,7 @@
if (!self)
return SHOUTERR_INSANE;

-	if (self->connected)
+	if (self->state != SHOUT_STATE_UNCONNECTED)
return SHOUTERR_CONNECTED;

if (self->dumpfile)
@@ -695,7 +671,7 @@
if (!self || (public != 0 && public != 1))
return SHOUTERR_INSANE;

-	if (self->connected)
+	if (self->state != SHOUT_STATE_UNCONNECTED)
return self->error = SHOUTERR_CONNECTED;

self->public = public;
@@ -716,7 +692,7 @@
if (!self)
return SHOUTERR_INSANE;

-	if (self->connected)
+	if (self->state != SHOUT_STATE_UNCONNECTED)
return self->error = SHOUTERR_CONNECTED;

if (format != SHOUT_FORMAT_OGG && format != SHOUT_FORMAT_MP3)
@@ -740,7 +716,7 @@
if (!self)
return SHOUTERR_INSANE;

-	if (self->connected)
+	if (self->state != SHOUT_STATE_UNCONNECTED)
return self->error = SHOUTERR_CONNECTED;

if (protocol != SHOUT_PROTOCOL_HTTP &&
@@ -761,6 +737,27 @@
return self->protocol;
}

+int shout_set_nonblocking(shout_t *self, unsigned int nonblocking)
+{
+	if (!self || (nonblocking != 0 && nonblocking != 1))
+		return SHOUTERR_INSANE;
+
+	if (self->state != SHOUT_STATE_UNCONNECTED)
+		return self->error = SHOUTERR_CONNECTED;
+
+	self->nonblocking = nonblocking;
+
+	return SHOUTERR_SUCCESS;
+}
+
+unsigned int shout_get_nonblocking(shout_t *self)
+{
+	if (!self)
+		return 0;
+
+	return self->nonblocking;
+}
+
/* -- static function definitions -- */

/* queue data in pages of SHOUT_BUFSIZE bytes */
@@ -899,6 +896,82 @@
return SHOUTERR_BUSY;
}

+static int try_connect (shout_t *self)
+{
+	int rc;
+	int port;
+
+	/* the breaks between cases are omitted intentionally */
+	switch (self->state) {
+	case SHOUT_STATE_UNCONNECTED:
+		port = self->port;
+		if (shout_get_protocol(self) == SHOUT_PROTOCOL_ICY)
+			port++;
+
+		if (shout_get_nonblocking(self)) {
+			if ((self->socket = sock_connect_non_blocking(self->host, port)) < 0)
+				return self->error = SHOUTERR_NOCONNECT;
+			self->state = SHOUT_STATE_CONNECT_PENDING;
+		} else {
+			if ((self->socket = sock_connect(self->host, port)) < 0)
+				return self->error = SHOUTERR_NOCONNECT;
+			if ((rc = create_request(self)) != SHOUTERR_SUCCESS)
+				return rc;
+			self->state = SHOUT_STATE_REQ_PENDING;
+		}
+
+	case SHOUT_STATE_CONNECT_PENDING:
+		if (shout_get_nonblocking(self)) {
+			if (!sock_connected(self->socket, 0))
+				return SHOUTERR_BUSY;
+			if ((rc = create_request(self)) != SHOUTERR_SUCCESS)
+				return rc;
+		}
+		self->state = SHOUT_STATE_REQ_PENDING;
+
+	case SHOUT_STATE_REQ_PENDING:
+		do
+			rc = send_queue(self);
+		while (!shout_get_nonblocking(self) && rc == SHOUTERR_BUSY);
+		if (rc != SHOUTERR_SUCCESS)
+			return rc;
+		self->state = SHOUT_STATE_RESP_PENDING;
+
+	case SHOUT_STATE_RESP_PENDING:
+		do
+			rc = get_response(self);
+		while (!shout_get_nonblocking(self) && rc == SHOUTERR_BUSY);
+		if (rc != SHOUTERR_SUCCESS)
+			return rc;
+
+		if ((rc = parse_response(self)) != SHOUTERR_SUCCESS)
+			return rc;
+
+		if (self->format == SHOUT_FORMAT_OGG) {
+			if ((self->error = shout_open_ogg(self)) != SHOUTERR_SUCCESS) {
+				self->state = SHOUT_STATE_UNCONNECTED;
+				sock_close(self->socket);
+				return self->error;
+			}
+		} else if (self->format == SHOUT_FORMAT_MP3) {
+			if ((self->error = shout_open_mp3(self)) != SHOUTERR_SUCCESS) {
+				self->state = SHOUT_STATE_UNCONNECTED;
+				sock_close(self->socket);
+				return self->error;
+			}
+		} else {
+			self->state = SHOUT_STATE_UNCONNECTED;
+			sock_close(self->socket);
+			return self->error = SHOUTERR_INSANE;
+		}
+
+	case SHOUT_STATE_CONNECTED:
+		self->state = SHOUT_STATE_CONNECTED;
+	}
+
+	return SHOUTERR_SUCCESS;
+}
+
static int try_write (shout_t *self, const void *data, size_t len)
{
int ret = sock_write_bytes (self->socket, data, len);
@@ -942,7 +1015,7 @@
int ret;

if (!self->wqueue)
-		return 0;
+		return SHOUTERR_SUCCESS;

buf = self->wqueue;
while (buf) {
@@ -958,12 +1031,24 @@
if (buf)
buf->prev = NULL;
} else /* incomplete write */
-			return SHOUTERR_SUCCESS;
+			return SHOUTERR_BUSY;
}

return self->error = SHOUTERR_SUCCESS;
}

+static int create_request(shout_t *self)
+{
+	if (self->protocol == SHOUT_PROTOCOL_HTTP)
+		return create_http_request(self);
+	else if (self->protocol == SHOUT_PROTOCOL_XAUDIOCAST)
+		return create_xaudiocast_request(self);
+	else if (self->protocol == SHOUT_PROTOCOL_ICY)
+		return create_icy_request(self);
+
+	return self->error = SHOUTERR_UNSUPPORTED;
+}
+
static int create_http_request(shout_t *self)
{
char *auth;
@@ -1043,8 +1128,19 @@
return in;
}

-static int login_http_basic(shout_t *self)
+static int parse_response(shout_t *self)
{
+	if (self->protocol == SHOUT_PROTOCOL_HTTP)
+		return parse_http_response(self);
+	else if (self->protocol == SHOUT_PROTOCOL_XAUDIOCAST ||
+		 self->protocol == SHOUT_PROTOCOL_ICY)
+		return parse_xaudiocast_response(self);
+
+	return self->error = SHOUTERR_UNSUPPORTED;
+}
+
+static int parse_http_response(shout_t *self)
+{
http_parser_t *parser;
char *header;
int hlen = 0;
@@ -1053,24 +1149,7 @@
#if 0
char *realm;
#endif
-
-	self->error = SHOUTERR_SOCKET;

-   	self->socket = sock_connect(self->host, self->port);
-	if (self->socket < 0)
-		return self->error = SHOUTERR_NOCONNECT;
-
-	/* assume we'll have to authenticate, saves round trips on basic */
-	if(create_http_request(self) != SHOUTERR_SUCCESS)
-		return self->error;
-
-	if (send_queue(self) != SHOUTERR_SUCCESS)
-		return self->error;
-
-	while ((code = get_response(self)) == SHOUTERR_BUSY);
-	if (code != SHOUTERR_SUCCESS)
-		return code;
-
/* all this copying! */
hlen = collect_queue(self->rqueue, &header);
if (hlen <= 0)
@@ -1088,43 +1167,6 @@
httpp_destroy(parser);
return SHOUTERR_SUCCESS;
}
-#if 0
-		else if(code == 401) {
-			/* Don't really use this right now other than to check that it's
-			* present.
-			*/
-			realm = httpp_getvar(parser, "www-authenticate");
-			if(realm) {
-				httpp_destroy(parser);
-				sock_close(self->socket);
-
-				self->socket = sock_connect(self->host, self->port);
-				if (self->socket <= 0)
-					return self->error = SHOUTERR_NOCONNECT;
-
-				if(send_http_request(self, self->user, self->password) != 0) {
-					sock_close(self->socket);
-					return self->error = SHOUTERR_SOCKET;
-				}
-
-				if (_shout_util_read_header(self->socket, header, 4096) == 0) {
-					/* either we didn't get a complete header, or we timed out */
-					sock_close(self->socket);
-					return self->error = SHOUTERR_SOCKET;
-				}
-				parser = httpp_create_parser();
-				httpp_initialize(parser, NULL);
-				if (httpp_parse_response(parser, header, strlen(header), self->mount)) {
-					retcode = httpp_getvar(parser, HTTPP_VAR_ERROR_CODE);
-					code = atoi(retcode);
-					if(code >= 200 && code < 300) {
-						httpp_destroy(parser);
-						return SHOUTERR_SUCCESS;
-					}
-				}
-			}
-		}
-#endif
}

free(header);
@@ -1132,9 +1174,8 @@
return self->error = SHOUTERR_NOLOGIN;
}

-static int login_xaudiocast(shout_t *self)
+static int create_xaudiocast_request(shout_t *self)
{
-	char response[4096];
const char *bitrate;
int ret;

@@ -1166,24 +1207,29 @@
ret = SHOUTERR_SUCCESS;
} while (0);

-	if (ret != SHOUTERR_SUCCESS)
-		return ret;
+	return ret;
+}

-	if ((ret = send_queue(self)) != SHOUTERR_SUCCESS)
-		return ret;
+static int parse_xaudiocast_response(shout_t *self)
+{
+	char *response;

-	if (!sock_read_line(self->socket, response, sizeof(response)))
-		return SHOUTERR_SOCKET;
+	if (collect_queue(self->rqueue, &response) <= 0)
+		return SHOUTERR_MALLOC;
+	queue_free(self->rqueue);
+	self->rqueue = NULL;

-	if (!strstr(response, "OK"))
+	if (!strstr(response, "OK")) {
+		free(response);
return SHOUTERR_NOLOGIN;
+	}
+	free(response);

return SHOUTERR_SUCCESS;
}

-static int login_icy(shout_t *self)
+static int create_icy_request(shout_t *self)
{
-	char response[4096];
const char *bitrate;
int ret;

@@ -1211,17 +1257,5 @@
ret = SHOUTERR_SUCCESS;
} while (0);

-	if (ret != SHOUTERR_SUCCESS)
-		return ret;
-
-	if ((ret = send_queue(self)) != SHOUTERR_SUCCESS)
-		return ret;
-
-	if (!sock_read_line(self->socket, response, sizeof(response)))
-		return SHOUTERR_SOCKET;
-
-	if (!strstr(response, "OK"))
-		return SHOUTERR_NOLOGIN;
-
-	return SHOUTERR_SUCCESS;
+	return ret;
}

Modified: icecast/trunk/libshout/src/shout_private.h
===================================================================
--- icecast/trunk/libshout/src/shout_private.h	2004-07-26 19:20:56 UTC (rev 7353)
+++ icecast/trunk/libshout/src/shout_private.h	2004-07-26 19:22:36 UTC (rev 7354)
@@ -41,6 +41,14 @@
struct _shout_buf *next;
} shout_buf_t;

+typedef enum {
+	SHOUT_STATE_UNCONNECTED = 0,
+	SHOUT_STATE_CONNECT_PENDING,
+	SHOUT_STATE_REQ_PENDING,
+	SHOUT_STATE_RESP_PENDING,
+	SHOUT_STATE_CONNECTED
+} shout_state_e;
+
struct shout {
/* hostname or IP of icecast server */
char *host;
@@ -74,10 +82,10 @@
/* is this stream private? */
int public;

-	/* are we connected to a server? */
-	int connected;
/* socket the connection is on */
sock_t socket;
+	shout_state_e state;
+	int nonblocking;

void *format_data;
int (*send)(shout_t* self, const unsigned char* buff, size_t len);



More information about the commits mailing list