[xiph-cvs] cvs commit: libshout/src Makefile.am shout.c shout_private.h util.c util.h
Michael Smith
msmith at xiph.org
Fri Aug 16 07:22:16 PDT 2002
msmith 02/08/16 10:22:16
Modified: . configure.in
include/shout shout.h
src Makefile.am shout.c shout_private.h util.c util.h
Log:
HTTP Basic authentication for libshout.
Revision Changes Path
1.6 +4 -4 libshout/configure.in
Index: configure.in
===================================================================
RCS file: /usr/local/cvsroot/libshout/configure.in,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- configure.in 23 Jan 2002 03:08:38 -0000 1.5
+++ configure.in 16 Aug 2002 14:22:16 -0000 1.6
@@ -29,9 +29,9 @@
else
case $host in
*-*-linux*)
- DEBUG="-g -Wall -W -fsigned-char -D_REENTRANT"
- CFLAGS="-Wall -W -O20 -ffast-math -fsigned-char -D_REENTRANT"
- PROFILE="-Wall -W -pg -g -O20 -ffast-math -fsigned-char -D_REENTRANT"
+ DEBUG="-g -Wall -W -fsigned-char -D_REENTRANT -D_GNU_SOURCE"
+ CFLAGS="-Wall -W -O20 -ffast-math -fsigned-char -D_REENTRANT -D_GNU_SOURCE"
+ PROFILE="-Wall -W -pg -g -O20 -ffast-math -fsigned-char -D_REENTRANT -D_GNU_SOURCE"
;;
sparc-sun-*)
DEBUG="-g -Wall -fsigned-char -mv8"
@@ -93,4 +93,4 @@
AC_SUBST(CFLAGS)
AC_SUBST(PROFILE)
-AC_OUTPUT(Makefile include/Makefile include/shout/Makefile src/Makefile src/net/Makefile src/timing/Makefile examples/Makefile)
+AC_OUTPUT(Makefile include/Makefile include/shout/Makefile src/Makefile src/net/Makefile src/timing/Makefile src/thread/Makefile src/avl/Makefile src/httpp/Makefile examples/Makefile)
<p><p>1.9 +5 -0 libshout/include/shout/shout.h
Index: shout.h
===================================================================
RCS file: /usr/local/cvsroot/libshout/include/shout/shout.h,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -r1.8 -r1.9
--- shout.h 4 Aug 2002 02:29:12 -0000 1.8
+++ shout.h 16 Aug 2002 14:22:16 -0000 1.9
@@ -17,6 +17,7 @@
#define SHOUTERR_CONNECTED (7)
#define SHOUTERR_UNCONNECTED (8)
#define SHOUTERR_UNSUPPORTED (9)
+#define SHOUTERR_REFUSED (10)
#define SHOUT_FORMAT_VORBIS (0)
#define SHOUT_FORMAT_MP3 (1)
@@ -24,6 +25,7 @@
#define SHOUT_PROTOCOL_ICE (0)
#define SHOUT_PROTOCOL_XAUDIOCAST (1)
#define SHOUT_PROTOCOL_ICY (2)
+#define SHOUT_PROTOCOL_HTTP (3)
typedef struct shout shout_t;
typedef struct shout_metadata shout_metadata_t;
@@ -74,6 +76,9 @@
int shout_set_genre(shout_t *self, const char *genre);
const char *shout_get_genre(shout_t *self);
+
+int shout_set_user(shout_t *self, const char *username);
+const char *shout_get_user(shout_t *self);
int shout_set_description(shout_t *self, const char *description);
const char *shout_get_description(shout_t *self);
<p><p>1.4 +4 -3 libshout/src/Makefile.am
Index: Makefile.am
===================================================================
RCS file: /usr/local/cvsroot/libshout/src/Makefile.am,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- Makefile.am 14 May 2002 05:14:34 -0000 1.3
+++ Makefile.am 16 Aug 2002 14:22:16 -0000 1.4
@@ -2,16 +2,17 @@
AUTOMAKE_OPTIONS = foreign
-SUBDIRS = net timing
+SUBDIRS = avl net timing httpp thread
lib_LTLIBRARIES = libshout.la
noinst_HEADERS = shout_private.h util.h
libshout_la_SOURCES = shout.c util.c vorbis.c mp3.c
-libshout_la_LIBADD = net/libicenet.la timing/libicetiming.la
+libshout_la_LIBADD = net/libicenet.la timing/libicetiming.la avl/libiceavl.la\
+ httpp/libicehttpp.la thread/libicethread.la
-INCLUDES = -I$(top_srcdir)/include/shout -I$(srcdir)/net -I$(srcdir)/timing
+INCLUDES = -I$(top_srcdir)/include/shout -I$(srcdir)/net -I$(srcdir)/timing -I$(srcdir)/avl -I$(srcdir)/thread -I$(srcdir)/httpp
debug:
$(MAKE) all CFLAGS="@DEBUG@"
<p><p>1.7 +171 -7 libshout/src/shout.c
Index: shout.c
===================================================================
RCS file: /usr/local/cvsroot/libshout/src/shout.c,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -r1.6 -r1.7
--- shout.c 4 Aug 2002 02:29:13 -0000 1.6
+++ shout.c 16 Aug 2002 14:22:16 -0000 1.7
@@ -11,11 +11,13 @@
#include "sock.h"
#include "timing.h"
#include "util.h"
+#include "httpp/httpp.h"
/* -- local prototypes -- */
static int login_ice(shout_t *self);
static int login_xaudiocast(shout_t *self);
static int login_icy(shout_t *self);
+static int login_http_basic(shout_t *self);
/* -- public functions -- */
@@ -50,6 +52,7 @@
if (self->url) free(self->url);
if (self->genre) free(self->genre);
if (self->description) free(self->description);
+ if (self->user) free(self->user);
free(self);
}
@@ -63,14 +66,19 @@
if (!self->host || !self->password || !self->port || self->connected)
return self->error = SHOUTERR_INSANE;
- if (self->format == SHOUT_FORMAT_VORBIS && self->protocol != SHOUT_PROTOCOL_ICE)
+ if (self->format == SHOUT_FORMAT_VORBIS && self->protocol != SHOUT_PROTOCOL_ICE && self->protocol != SHOUT_PROTOCOL_HTTP)
return self->error = SHOUTERR_UNSUPPORTED;
- self->socket = sock_connect(self->host, self->port);
- if (self->socket <= 0)
- return self->error = SHOUTERR_NOCONNECT;
-
- if (self->protocol == SHOUT_PROTOCOL_ICE) {
+ if(self->protocol != SHOUT_PROTOCOL_HTTP) {
+ self->socket = sock_connect(self->host, self->port);
+ if (self->socket <= 0)
+ return self->error = SHOUTERR_NOCONNECT;
+ }
+
+ if (self->protocol == SHOUT_PROTOCOL_HTTP) {
+ return login_http_basic(self);
+ }
+ else if (self->protocol == SHOUT_PROTOCOL_ICE) {
if ((self->error = login_ice(self)) != SHOUTERR_SUCCESS) {
sock_close(self->socket);
return self->error;
@@ -388,6 +396,31 @@
return self->genre;
}
+int shout_set_user(shout_t *self, const char *username)
+{
+ if (!self)
+ return SHOUTERR_INSANE;
+
+ if (self->connected)
+ return self->error = SHOUTERR_CONNECTED;
+
+ if (self->user)
+ free(self->user);
+
+ if (! (self->user = util_strdup (username)))
+ return self->error = SHOUTERR_MALLOC;
+
+ return self->error = SHOUTERR_SUCCESS;
+}
+
+const char *shout_get_user(shout_t *self)
+{
+ if (!self)
+ return NULL;
+
+ return self->user;
+}
+
int shout_set_description(shout_t *self, const char *description)
{
if (!self)
@@ -489,7 +522,8 @@
if (protocol != SHOUT_PROTOCOL_ICE &&
protocol != SHOUT_PROTOCOL_XAUDIOCAST &&
- protocol != SHOUT_PROTOCOL_ICY)
+ protocol != SHOUT_PROTOCOL_ICY &&
+ protocol != SHOUT_PROTOCOL_HTTP)
return self->error = SHOUTERR_UNSUPPORTED;
self->protocol = protocol;
@@ -506,6 +540,136 @@
}
/* -- static function definitions -- */
+
+static int send_http_request(shout_t *self, char *username, char *password)
+{
+ if (!sock_write(self->socket, "SOURCE %s HTTP/1.0\r\n", self->mount))
+ return SHOUTERR_SOCKET;
+
+ if (!sock_write(self->socket, "ice-name: %s\r\n", self->name != NULL ? self->name : "no name"))
+ return SHOUTERR_SOCKET;
+ if (self->url) {
+ if (!sock_write(self->socket, "ice-url: %s\r\n", self->url))
+ return SHOUTERR_SOCKET;
+ }
+ if (self->genre) {
+ if (!sock_write(self->socket, "ice-genre: %s\r\n", self->genre))
+ return SHOUTERR_SOCKET;
+ }
+ if (!sock_write(self->socket, "ice-bitrate: %d\r\n", self->bitrate))
+ return SHOUTERR_SOCKET;
+ if (!sock_write(self->socket, "ice-public: %d\r\n", self->public))
+ return SHOUTERR_SOCKET;
+ if (self->description) {
+ if (!sock_write(self->socket, "ice-description: %s\r\n", self->description))
+ return SHOUTERR_SOCKET;
+ }
+ if (self->format == SHOUT_FORMAT_VORBIS) {
+ if (!sock_write(self->socket, "Content-Type: application/x-ogg\r\n"))
+ return SHOUTERR_SOCKET;
+ } else if (self->format == SHOUT_FORMAT_MP3) {
+ if (!sock_write(self->socket, "Content-Type: audio/mpeg\r\n"))
+ return SHOUTERR_SOCKET;
+ }
+ if (username && password) {
+ char *data;
+ int len = strlen(username) + strlen(password) + 1;
+ char *orig = malloc(len+1);
+ strcpy(orig, username);
+ strcat(orig, ":");
+ strcat(orig, password);
+
+ data = util_base64_encode(orig);
+
+ if(!sock_write(self->socket, "Authorization: Basic %s\r\n", data)) {
+ free(data);
+ return SHOUTERR_SOCKET;
+ }
+ free(data);
+ }
+
+ if (!sock_write(self->socket, "\r\n"))
+ return SHOUTERR_SOCKET;
+
+ return SHOUTERR_SUCCESS;
+}
+
+
+static int login_http_basic(shout_t *self)
+{
+ char header[4096];
+ http_parser_t *parser;
+ int code;
+ char *retcode, *realm;
+
+ self->error = SHOUTERR_SOCKET;
+
+ self->socket = sock_connect(self->host, self->port);
+ if (self->socket <= 0) {
+ return self->error = SHOUTERR_NOCONNECT;
+ }
+
+ if(send_http_request(self, NULL, NULL) != 0) {
+ sock_close(self->socket);
+ return self->error = SHOUTERR_SOCKET;
+ }
+
+ if (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;
+ }
+ 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 (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;
+ }
+ }
+ }
+ }
+ }
+
+ httpp_destroy(parser);
+ sock_close(self->socket);
+ return self->error = SHOUTERR_REFUSED;
+}
static int login_ice(shout_t *self)
{
<p><p>1.2 +2 -0 libshout/src/shout_private.h
Index: shout_private.h
===================================================================
RCS file: /usr/local/cvsroot/libshout/src/shout_private.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- shout_private.h 23 Jan 2002 03:08:39 -0000 1.1
+++ shout_private.h 16 Aug 2002 14:22:16 -0000 1.2
@@ -58,6 +58,8 @@
char *genre;
/* description of the stream */
char *description;
+ /* username to use for HTTP auth. */
+ char *user;
/* bitrate of this stream */
int bitrate;
/* is this stream private? */
<p><p>1.2 +74 -0 libshout/src/util.c
Index: util.c
===================================================================
RCS file: /usr/local/cvsroot/libshout/src/util.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- util.c 23 Jan 2002 03:08:39 -0000 1.1
+++ util.c 16 Aug 2002 14:22:16 -0000 1.2
@@ -2,6 +2,10 @@
#include <stdio.h>
#include <string.h>
+#include <stdlib.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
#include "util.h"
@@ -10,3 +14,73 @@
if (!s) return NULL;
return strdup(s);
}
+
+int util_read_header(int sock, char *buff, unsigned long len)
+{
+ int read_bytes, ret;
+ unsigned long pos;
+ char c;
+
+ read_bytes = 1;
+ pos = 0;
+ ret = 0;
+
+ while ((read_bytes == 1) && (pos < (len - 1))) {
+ read_bytes = 0;
+
+ if ((read_bytes = recv(sock, &c, 1, 0))) {
+ if (c != '\r') buff[pos++] = c;
+ if ((pos > 1) && (buff[pos - 1] == '\n' && buff[pos - 2] == '\n')) {
+ ret = 1;
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+
+ if (ret) buff[pos] = '\0';
+
+ return ret;
+}
+
+static char base64table[64] = {
+ 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
+ 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
+ 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
+ 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
+};
+
+/* This isn't efficient, but it doesn't need to be */
+char *util_base64_encode(char *data)
+{
+ int len = strlen(data);
+ char *out = malloc(len*4/3 + 4);
+ char *result = out;
+ int chunk;
+
+ while(len > 0) {
+ chunk = (len >3)?3:len;
+ *out++ = base64table[(*data & 0xFC)>>2];
+ *out++ = base64table[((*data & 0x03)<<4) | ((*(data+1) & 0xF0) >> 4)];
+ switch(chunk) {
+ case 3:
+ *out++ = base64table[((*(data+1) & 0x0F)<<2) | ((*(data+2) & 0xC0)>>6)];
+ *out++ = base64table[(*(data+2)) & 0x3F];
+ break;
+ case 2:
+ *out++ = base64table[((*(data+1) & 0x0F)<<2)];
+ *out++ = '=';
+ break;
+ case 1:
+ *out++ = '=';
+ *out++ = '=';
+ break;
+ }
+ data += chunk;
+ len -= chunk;
+ }
+
+ return result;
+}
+
<p><p>1.2 +2 -0 libshout/src/util.h
Index: util.h
===================================================================
RCS file: /usr/local/cvsroot/libshout/src/util.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- util.h 23 Jan 2002 03:08:39 -0000 1.1
+++ util.h 16 Aug 2002 14:22:16 -0000 1.2
@@ -4,5 +4,7 @@
#define __LIBSHOUT_UTIL_H__
char *util_strdup(const char *s);
+char *util_base64_encode(char *data);
+int util_read_header(int sock, char *buff, unsigned long len);
#endif /* __LIBSHOUT_UTIL_H__ */
<p><p>--- >8 ----
List archives: http://www.xiph.org/archives/
Ogg project homepage: http://www.xiph.org/ogg/
To unsubscribe from this list, send a message to 'cvs-request at xiph.org'
containing only the word 'unsubscribe' in the body. No subject is needed.
Unsubscribe messages sent to the list will be ignored/filtered.
More information about the commits
mailing list