[xiph-commits] r7096 - icecast/branches/kh/icecast/src
j at dactyl.lonelymoon.com
j
Sun Jul 11 11:13:10 PDT 2004
Author: j
Date: Sun Jul 11 11:13:10 2004
New Revision: 7096
Added:
icecast/branches/kh/icecast/src/auth_cmd.c
icecast/branches/kh/icecast/src/auth_cmd.h
icecast/branches/kh/icecast/src/auth_htpasswd.c
icecast/branches/kh/icecast/src/auth_htpasswd.h
icecast/branches/kh/icecast/src/auth_url.c
icecast/branches/kh/icecast/src/auth_url.h
icecast/branches/kh/icecast/src/format_ogg.c
icecast/branches/kh/icecast/src/format_ogg.h
Log:
reimport2: add new files
Added: icecast/branches/kh/icecast/src/auth_cmd.c
===================================================================
--- icecast/branches/kh/icecast/src/auth_cmd.c 2004-07-11 18:09:05 UTC (rev 7095)
+++ icecast/branches/kh/icecast/src/auth_cmd.c 2004-07-11 18:13:09 UTC (rev 7096)
@@ -0,0 +1,185 @@
+/* Icecast
+ *
+ * This program is distributed under the GNU General Public License, version 2.
+ * A copy of this license is included with this source.
+ *
+ * Copyright 2000-2004, Jack Moffitt <jack at xiph.org,
+ * Michael Smith <msmith at xiph.org>,
+ * oddsock <oddsock at xiph.org>,
+ * Karl Heyes <karl at xiph.org>
+ * and others (see AUTHORS for details).
+ */
+
+/**
+ * Client authentication via command functions
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#ifndef WIN32
+#include <sys/wait.h>
+#endif
+
+#include "auth.h"
+#include "source.h"
+#include "client.h"
+#include "cfgfile.h"
+#include "httpp/httpp.h"
+
+#include "logging.h"
+#define CATMODULE "auth_cmd"
+
+typedef struct {
+ char *filename;
+} auth_cmd;
+
+typedef struct {
+ char *mount;
+ client_t *client;
+ char *cmd;
+} auth_client;
+
+
+static void cmd_clear(auth_t *self)
+{
+ auth_cmd *cmd = self->state;
+ free(cmd->filename);
+ free(cmd);
+}
+
+static void *auth_cmd_thread (void *arg)
+{
+ auth_client *auth_user = arg;
+ int fd[2];
+ int ok = 0;
+ int send_fail = 404;
+ pid_t pid;
+ client_t *client = auth_user->client;
+ int status, len;
+ char str[256];
+
+ DEBUG0("starting auth thread");
+ if (pipe (fd) == 0)
+ {
+ pid = fork();
+ switch (pid)
+ {
+ case 0: /* child */
+ dup2 (fd[0], fileno(stdin));
+ close (fd[0]);
+ close (fd[1]);
+ execl (auth_user->cmd, auth_user->cmd, NULL);
+ exit (EXIT_FAILURE);
+ case -1:
+ break;
+ default: /* parent */
+ close (fd[0]);
+ len = snprintf (str, sizeof(str), "%s\n%s\n%s\n",
+ auth_user->mount, client->username, client->password);
+ write (fd[1], str, len);
+ close (fd[1]);
+ DEBUG1 ("Waiting on pid %ld", (long)pid);
+ if (waitpid (pid, &status, 0) < 0)
+ {
+ DEBUG1("waitpid error %s", strerror(errno));
+ break;
+ }
+ if (WIFEXITED (status))
+ {
+ DEBUG1("command exited normally with %d", WEXITSTATUS (status));
+ if (WEXITSTATUS(status) == 0)
+ ok = 1;
+ else
+ send_fail = 401;
+ }
+ break;
+ }
+ /* try to add authenticated client */
+ if (ok)
+ {
+ source_t *source;
+ send_fail = 0;
+ avl_tree_unlock (global.source_tree);
+ source = source_find_mount (auth_user->mount);
+ if (source)
+ {
+ thread_mutex_lock (&source->lock);
+ if (source->running)
+ add_authenticated_client (source, auth_user->client);
+ else
+ send_fail = 404;
+ thread_mutex_unlock (&source->lock);
+ }
+ avl_tree_unlock (global.source_tree);
+ }
+ }
+ if (send_fail == 404)
+ client_send_404 (client, "Mount not available");
+ if (send_fail == 401)
+ client_send_401 (client);
+ free (auth_user->mount);
+ free (auth_user->cmd);
+ free (auth_user);
+ return NULL;
+}
+
+
+static auth_result auth_cmd_client (source_t *source, client_t *client)
+{
+ auth_client *auth_user = calloc (1, sizeof (auth_client));
+ auth_cmd *cmd = source->authenticator->state;
+
+ if (auth_user == NULL)
+ return AUTH_FAILED;
+
+ auth_user->cmd = strdup (cmd->filename);
+ auth_user->mount = strdup (source->mount);
+ auth_user->client = client;
+ thread_create("Auth by command thread", auth_cmd_thread, auth_user, THREAD_DETACHED);
+ return AUTH_OK;
+}
+
+static auth_result auth_cmd_adduser(auth_t *auth, const char *username, const char *password)
+{
+ return AUTH_FAILED;
+}
+
+static auth_result auth_cmd_deleteuser (auth_t *auth, const char *username)
+{
+ return AUTH_FAILED;
+}
+
+static auth_result auth_cmd_listuser (auth_t *auth, xmlNodePtr srcnode)
+{
+ return AUTH_FAILED;
+}
+
+auth_t *auth_get_cmd_auth (config_options_t *options)
+{
+ auth_t *authenticator = calloc(1, sizeof(auth_t));
+ auth_cmd *state;
+
+ authenticator->authenticate = auth_cmd_client;
+ authenticator->free = cmd_clear;
+ authenticator->adduser = auth_cmd_adduser;
+ authenticator->deleteuser = auth_cmd_deleteuser;
+ authenticator->listuser = auth_cmd_listuser;
+
+ state = calloc(1, sizeof(auth_cmd));
+
+ while(options) {
+ if(!strcmp(options->name, "filename"))
+ state->filename = strdup(options->value);
+ options = options->next;
+ }
+ authenticator->state = state;
+ INFO0("external command based authentication setup");
+ return authenticator;
+}
+
Added: icecast/branches/kh/icecast/src/auth_cmd.h
===================================================================
--- icecast/branches/kh/icecast/src/auth_cmd.h 2004-07-11 18:09:05 UTC (rev 7095)
+++ icecast/branches/kh/icecast/src/auth_cmd.h 2004-07-11 18:13:09 UTC (rev 7096)
@@ -0,0 +1,27 @@
+/* Icecast
+ *
+ * This program is distributed under the GNU General Public License, version 2.
+ * A copy of this license is included with this source.
+ *
+ * Copyright 2000-2004, Jack Moffitt <jack at xiph.org,
+ * Michael Smith <msmith at xiph.org>,
+ * oddsock <oddsock at xiph.org>,
+ * Karl Heyes <karl at xiph.org>
+ * and others (see AUTHORS for details).
+ */
+
+#ifndef __AUTH_CMD_H__
+#define __AUTH_CMD_H__
+
+#include "source.h"
+#include "client.h"
+#include "config.h"
+#include <libxml/xmlmemory.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+
+auth_t *auth_get_cmd_auth (config_options_t *options);
+
+#endif
+
+
Added: icecast/branches/kh/icecast/src/auth_htpasswd.c
===================================================================
--- icecast/branches/kh/icecast/src/auth_htpasswd.c 2004-07-11 18:09:05 UTC (rev 7095)
+++ icecast/branches/kh/icecast/src/auth_htpasswd.c 2004-07-11 18:13:09 UTC (rev 7096)
@@ -0,0 +1,363 @@
+/* Icecast
+ *
+ * This program is distributed under the GNU General Public License, version 2.
+ * A copy of this license is included with this source.
+ *
+ * Copyright 2000-2004, Jack Moffitt <jack at xiph.org,
+ * Michael Smith <msmith at xiph.org>,
+ * oddsock <oddsock at xiph.org>,
+ * Karl Heyes <karl at xiph.org>
+ * and others (see AUTHORS for details).
+ */
+
+/**
+ * Client authentication functions
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+
+#include "auth.h"
+#include "source.h"
+#include "client.h"
+#include "cfgfile.h"
+#include "httpp/httpp.h"
+#include "md5.h"
+
+#include "logging.h"
+#define CATMODULE "auth"
+
+static auth_result htpasswd_adduser (auth_t *auth, const char *username, const char *password);
+static auth_result htpasswd_deleteuser(auth_t *auth, const char *username);
+static auth_result htpasswd_userlist(auth_t *auth, xmlNodePtr srcnode);
+
+typedef struct {
+ char *filename;
+ rwlock_t file_rwlock;
+} htpasswd_auth_state;
+
+static void htpasswd_clear(auth_t *self) {
+ htpasswd_auth_state *state = self->state;
+ free(state->filename);
+ thread_rwlock_destroy(&state->file_rwlock);
+ free(state);
+}
+
+static int get_line(FILE *file, char *buf, int len)
+{
+ if(fgets(buf, len, file)) {
+ int len = strlen(buf);
+ if(len > 0 && buf[len-1] == '\n') {
+ buf[--len] = 0;
+ if(len > 0 && buf[len-1] == '\r')
+ buf[--len] = 0;
+ }
+ return 1;
+ }
+ return 0;
+}
+
+/* md5 hash */
+static char *get_hash(const char *data, int len)
+{
+ struct MD5Context context;
+ unsigned char digest[16];
+
+ MD5Init(&context);
+
+ MD5Update(&context, data, len);
+
+ MD5Final(digest, &context);
+
+ return util_bin_to_hex(digest, 16);
+}
+
+#define MAX_LINE_LEN 512
+
+/* Not efficient; opens and scans the entire file for every request */
+static auth_result htpasswd_auth(source_t *source, client_t *client)
+{
+ auth_t *auth = source->authenticator;
+ htpasswd_auth_state *state = auth->state;
+ FILE *passwdfile = fopen(state->filename, "rb");
+ char line[MAX_LINE_LEN];
+ char *sep;
+
+ thread_rwlock_rlock(&state->file_rwlock);
+ if(passwdfile == NULL) {
+ WARN2("Failed to open authentication database \"%s\": %s",
+ state->filename, strerror(errno));
+ thread_rwlock_unlock(&state->file_rwlock);
+ return AUTH_FAILED;
+ }
+
+ while(get_line(passwdfile, line, MAX_LINE_LEN)) {
+ if(!line[0] || line[0] == '#')
+ continue;
+
+ sep = strchr(line, ':');
+ if(sep == NULL) {
+ DEBUG0("No seperator in line");
+ continue;
+ }
+
+ *sep = 0;
+ if(!strcmp(client->username, line)) {
+ /* Found our user, now: does the hash of password match hash? */
+ char *hash = sep+1;
+ char *hashed_password = get_hash(client->password, strlen(client->password));
+ if(!strcmp(hash, hashed_password)) {
+ fclose(passwdfile);
+ free(hashed_password);
+ thread_rwlock_unlock(&state->file_rwlock);
+ add_authenticated_client (source, client);
+ return AUTH_OK;
+ }
+ free(hashed_password);
+ /* We don't keep searching through the file */
+ break;
+ }
+ }
+
+ fclose(passwdfile);
+
+ thread_rwlock_unlock(&state->file_rwlock);
+ return AUTH_FAILED;
+}
+
+auth_t *auth_get_htpasswd_auth(config_options_t *options)
+{
+ auth_t *authenticator = calloc(1, sizeof(auth_t));
+ htpasswd_auth_state *state;
+
+ authenticator->authenticate = htpasswd_auth;
+ authenticator->free = htpasswd_clear;
+ authenticator->adduser = htpasswd_adduser;
+ authenticator->deleteuser = htpasswd_deleteuser;
+ authenticator->listuser = htpasswd_userlist;
+
+ state = calloc(1, sizeof(htpasswd_auth_state));
+
+ while(options) {
+ if(!strcmp(options->name, "filename"))
+ state->filename = strdup(options->value);
+ options = options->next;
+ }
+
+ if(!state->filename) {
+ free(state);
+ free(authenticator);
+ ERROR0("No filename given in options for authenticator.");
+ return NULL;
+ }
+
+ authenticator->state = state;
+ DEBUG1("Configured htpasswd authentication using password file %s",
+ state->filename);
+
+ thread_rwlock_create(&state->file_rwlock);
+
+ return authenticator;
+}
+
+int auth_htpasswd_existing_user(auth_t *auth, const char *username)
+{
+ FILE *passwdfile;
+ htpasswd_auth_state *state;
+ int ret = AUTH_OK;
+ char line[MAX_LINE_LEN];
+ char *sep;
+
+ state = auth->state;
+ passwdfile = fopen(state->filename, "rb");
+
+ if(passwdfile == NULL) {
+ WARN2("Failed to open authentication database \"%s\": %s",
+ state->filename, strerror(errno));
+ return AUTH_FAILED;
+ }
+ while(get_line(passwdfile, line, MAX_LINE_LEN)) {
+ if(!line[0] || line[0] == '#')
+ continue;
+ sep = strchr(line, ':');
+ if(sep == NULL) {
+ DEBUG0("No seperator in line");
+ continue;
+ }
+ *sep = 0;
+ if (!strcmp(username, line)) {
+ /* We found the user, break out of the loop */
+ ret = AUTH_USEREXISTS;
+ break;
+ }
+ }
+
+ fclose(passwdfile);
+ return ret;
+
+}
+
+
+static int _auth_htpasswd_adduser(auth_t *auth, const char *username, const char *password)
+{
+ FILE *passwdfile;
+ char *hashed_password = NULL;
+ htpasswd_auth_state *state;
+
+ if (auth_htpasswd_existing_user(auth, username) == AUTH_USEREXISTS) {
+ return AUTH_USEREXISTS;
+ }
+ state = auth->state;
+ passwdfile = fopen(state->filename, "ab");
+
+ if(passwdfile == NULL) {
+ WARN2("Failed to open authentication database \"%s\": %s",
+ state->filename, strerror(errno));
+ return AUTH_FAILED;
+ }
+
+ hashed_password = get_hash(password, strlen(password));
+ if (hashed_password) {
+ fprintf(passwdfile, "%s:%s\n", username, hashed_password);
+ free(hashed_password);
+ }
+
+ fclose(passwdfile);
+ return AUTH_USERADDED;
+}
+
+
+static auth_result htpasswd_adduser (auth_t *auth, const char *username, const char *password)
+{
+ auth_result ret = 0;
+ htpasswd_auth_state *state;
+
+ state = auth->state;
+ thread_rwlock_wlock (&state->file_rwlock);
+ ret = _auth_htpasswd_adduser (auth, username, password);
+ thread_rwlock_unlock (&state->file_rwlock);
+
+ return ret;
+}
+
+
+static auth_result htpasswd_deleteuser(auth_t *auth, const char *username)
+{
+ FILE *passwdfile;
+ FILE *tmp_passwdfile;
+ htpasswd_auth_state *state;
+ char line[MAX_LINE_LEN];
+ char *sep;
+ char *tmpfile = NULL;
+ int tmpfile_len = 0;
+
+ state = auth->state;
+ passwdfile = fopen(state->filename, "rb");
+
+ if(passwdfile == NULL) {
+ WARN2("Failed to open authentication database \"%s\": %s",
+ state->filename, strerror(errno));
+ return AUTH_FAILED;
+ }
+ tmpfile_len = strlen(state->filename) + 6;
+ tmpfile = calloc(1, tmpfile_len);
+ sprintf(tmpfile, ".%s.tmp", state->filename);
+
+ tmp_passwdfile = fopen(tmpfile, "wb");
+
+ if(tmp_passwdfile == NULL) {
+ WARN2("Failed to open temporary authentication database \"%s\": %s",
+ tmpfile, strerror(errno));
+ fclose(passwdfile);
+ free(tmpfile);
+ return AUTH_FAILED;
+ }
+
+
+ while(get_line(passwdfile, line, MAX_LINE_LEN)) {
+ if(!line[0] || line[0] == '#')
+ continue;
+
+ sep = strchr(line, ':');
+ if(sep == NULL) {
+ DEBUG0("No seperator in line");
+ continue;
+ }
+
+ *sep = 0;
+ if (strcmp(username, line)) {
+ /* We did not match on the user, so copy it to the temp file */
+ /* and put the : back in */
+ *sep = ':';
+ fprintf(tmp_passwdfile, "%s\n", line);
+ }
+ }
+
+ fclose(tmp_passwdfile);
+ fclose(passwdfile);
+
+ /* Now move the contents of the tmp file to the original */
+ /* Windows won't let us rename a file if the destination file
+ exists...so, lets remove the original first */
+ if (remove(state->filename) != 0) {
+ ERROR3("Problem moving temp authentication file to original \"%s\" - \"%s\": %s",
+ tmpfile, state->filename, strerror(errno));
+ }
+ else {
+ if (rename(tmpfile, state->filename) != 0) {
+ ERROR3("Problem moving temp authentication file to original \"%s\" - \"%s\": %s",
+ tmpfile, state->filename, strerror(errno));
+ }
+ }
+ free(tmpfile);
+
+ return AUTH_USERDELETED;
+}
+
+
+static auth_result htpasswd_userlist(auth_t *auth, xmlNodePtr srcnode)
+{
+ htpasswd_auth_state *state;
+ FILE *passwdfile;
+ char line[MAX_LINE_LEN];
+ char *sep;
+ char *passwd;
+ xmlNodePtr newnode;
+
+ state = auth->state;
+
+ passwdfile = fopen(state->filename, "rb");
+
+ if(passwdfile == NULL) {
+ WARN2("Failed to open authentication database \"%s\": %s",
+ state->filename, strerror(errno));
+ return AUTH_FAILED;
+ }
+
+ while(get_line(passwdfile, line, MAX_LINE_LEN)) {
+ if(!line[0] || line[0] == '#')
+ continue;
+
+ sep = strchr(line, ':');
+ if(sep == NULL) {
+ DEBUG0("No seperator in line");
+ continue;
+ }
+
+ *sep = 0;
+ newnode = xmlNewChild(srcnode, NULL, "User", NULL);
+ xmlNewChild(newnode, NULL, "username", line);
+ passwd = sep+1;
+ xmlNewChild(newnode, NULL, "password", passwd);
+ }
+
+ fclose(passwdfile);
+ return AUTH_OK;
+}
+
Added: icecast/branches/kh/icecast/src/auth_htpasswd.h
===================================================================
--- icecast/branches/kh/icecast/src/auth_htpasswd.h 2004-07-11 18:09:05 UTC (rev 7095)
+++ icecast/branches/kh/icecast/src/auth_htpasswd.h 2004-07-11 18:13:09 UTC (rev 7096)
@@ -0,0 +1,27 @@
+/* Icecast
+ *
+ * This program is distributed under the GNU General Public License, version 2.
+ * A copy of this license is included with this source.
+ *
+ * Copyright 2000-2004, Jack Moffitt <jack at xiph.org,
+ * Michael Smith <msmith at xiph.org>,
+ * oddsock <oddsock at xiph.org>,
+ * Karl Heyes <karl at xiph.org>
+ * and others (see AUTHORS for details).
+ */
+
+#ifndef __AUTH_HTPASSWD_H__
+#define __AUTH_HTPASSWD_H__
+
+#include "source.h"
+#include "client.h"
+#include "config.h"
+#include <libxml/xmlmemory.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+
+auth_t *auth_get_htpasswd_auth(config_options_t *options);
+
+#endif
+
+
Added: icecast/branches/kh/icecast/src/auth_url.c
===================================================================
--- icecast/branches/kh/icecast/src/auth_url.c 2004-07-11 18:09:05 UTC (rev 7095)
+++ icecast/branches/kh/icecast/src/auth_url.c 2004-07-11 18:13:09 UTC (rev 7096)
@@ -0,0 +1,323 @@
+/* Icecast
+ *
+ * This program is distributed under the GNU General Public License, version 2.
+ * A copy of this license is included with this source.
+ *
+ * Copyright 2000-2004, Jack Moffitt <jack at xiph.org>,
+ * Michael Smith <msmith at xiph.org>,
+ * oddsock <oddsock at xiph.org>,
+ * Karl Heyes <karl at xiph.org>
+ * and others (see AUTHORS for details).
+ */
+
+/**
+ * Client authentication via URL functions
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#ifndef WIN32
+#include <sys/wait.h>
+#endif
+
+#include <curl/curl.h>
+
+#include "auth.h"
+#include "source.h"
+#include "client.h"
+#include "cfgfile.h"
+#include "httpp/httpp.h"
+
+#include "logging.h"
+#define CATMODULE "auth_url"
+
+typedef struct {
+ char *addurl;
+ char *removeurl;
+ char *username;
+ char *password;
+} auth_url;
+
+typedef struct {
+ char *mount;
+ client_t *client;
+ CURL *auth_server;
+ char *addurl;
+ char *removeurl;
+ int authenticated;
+ char *username;
+ char *password;
+} auth_client;
+
+
+static void auth_url_clear(auth_t *self)
+{
+ auth_url *url = self->state;
+ free(url->username);
+ free(url->password);
+ free(url->removeurl);
+ free(url->addurl);
+ free(url);
+}
+
+
+static int handle_returned_header (void *ptr, size_t size, size_t nmemb, void *stream)
+{
+ auth_client *auth_user = stream;
+ unsigned bytes = size * nmemb;
+
+ if (strncmp (ptr, "icecast-auth-user: 1", 20) == 0)
+ auth_user->authenticated = 1;
+
+ return (int)bytes;
+}
+
+/* capture returned data, but don't do anything with it */
+static int handle_returned_data (void *ptr, size_t size, size_t nmemb, void *stream)
+{
+ return (int)(size*nmemb);
+}
+
+
+static void *auth_removeurl_thread (void *arg)
+{
+ auth_client *auth_user = arg;
+ client_t *client = auth_user->client;
+ CURL *handle;
+ char post[1024];
+
+ if (auth_user->removeurl)
+ {
+ time_t duration = time(NULL) - client->con->con_time;
+ char *username, *password;
+
+ DEBUG0("starting auth thread");
+ username = util_url_escape (client->username);
+ password = util_url_escape (client->password);
+ snprintf (post, 1024,"id=%ld&mount=%s&user=%s&pass=%s&duration=%ld",
+ client->con->id, auth_user->mount, username, password, duration);
+ free (username);
+ free (password);
+ handle = curl_easy_init ();
+ if (handle)
+ {
+ int res;
+ char errormsg [CURL_ERROR_SIZE];
+ char *userpass = NULL;
+
+ if (auth_user->username && auth_user->password)
+ {
+ unsigned len = strlen (auth_user->username) + strlen (auth_user->password) + 1;
+ userpass = malloc (len);
+ snprintf (userpass, len, "%s:%s", auth_user->username, auth_user->password);
+ curl_easy_setopt (handle, CURLOPT_USERPWD, userpass);
+ }
+ curl_easy_setopt (handle, CURLOPT_URL, auth_user->removeurl);
+ curl_easy_setopt (handle, CURLOPT_POSTFIELDS, post);
+ curl_easy_setopt (handle, CURLOPT_HEADERFUNCTION, handle_returned_header);
+ curl_easy_setopt (handle, CURLOPT_WRITEFUNCTION, handle_returned_data);
+ curl_easy_setopt (handle, CURLOPT_WRITEHEADER, auth_user);
+ curl_easy_setopt (handle, CURLOPT_WRITEDATA, handle);
+ curl_easy_setopt (handle, CURLOPT_NOSIGNAL, 1L);
+ curl_easy_setopt (handle, CURLOPT_TIMEOUT, 15L);
+ curl_easy_setopt (handle, CURLOPT_ERRORBUFFER, errormsg);
+ res = curl_easy_perform (handle);
+ curl_easy_cleanup (handle);
+ free (userpass);
+
+ if (res)
+ WARN2 ("auth to server %s failed with %s", auth_user->removeurl, errormsg);
+ }
+ }
+ auth_close_client (client);
+
+ free (auth_user->username);
+ free (auth_user->password);
+ free (auth_user->mount);
+ free (auth_user->removeurl);
+ free (auth_user);
+ return NULL;
+}
+
+
+static void *auth_url_thread (void *arg)
+{
+ auth_client *auth_user = arg;
+ client_t *client = auth_user->client;
+ int res;
+ char *agent, *user_agent, *username, *password;
+ CURL *handle;
+ char post[1024];
+
+ DEBUG0("starting auth thread");
+ agent = httpp_getvar (client->parser, "user-agent");
+ if (agent == NULL)
+ agent = "-";
+ user_agent = util_url_escape (agent);
+ username = util_url_escape (client->username);
+ password = util_url_escape (client->password);
+ snprintf (post, 1024,"id=%ld&mount=%s&user=%s&pass=%s&ip=%s&agent=%s",
+ client->con->id, auth_user->mount, username, password,
+ client->con->ip, user_agent);
+ free (user_agent);
+ free (username);
+ free (password);
+
+ handle = curl_easy_init ();
+ if (handle)
+ {
+ char errormsg [CURL_ERROR_SIZE];
+ char *userpass = NULL;
+
+ if (auth_user->username && auth_user->password)
+ {
+ unsigned len = strlen (auth_user->username) + strlen (auth_user->password) + 1;
+ userpass = malloc (len);
+ snprintf (userpass, len, "%s:%s", auth_user->username, auth_user->password);
+ curl_easy_setopt (handle, CURLOPT_USERPWD, userpass);
+ }
+
+ curl_easy_setopt (handle, CURLOPT_URL, auth_user->addurl);
+ curl_easy_setopt (handle, CURLOPT_POSTFIELDS, post);
+ curl_easy_setopt (handle, CURLOPT_HEADERFUNCTION, handle_returned_header);
+ curl_easy_setopt (handle, CURLOPT_WRITEFUNCTION, handle_returned_data);
+ curl_easy_setopt (handle, CURLOPT_WRITEHEADER, auth_user);
+ curl_easy_setopt (handle, CURLOPT_WRITEDATA, handle);
+ curl_easy_setopt (handle, CURLOPT_NOSIGNAL, 1L);
+ curl_easy_setopt (handle, CURLOPT_TIMEOUT, 15L);
+ curl_easy_setopt (handle, CURLOPT_ERRORBUFFER, errormsg);
+ res = curl_easy_perform (handle);
+ curl_easy_cleanup (handle);
+ free (userpass);
+
+ if (res)
+ {
+ WARN2 ("auth to server %s failed with %s", auth_user->addurl, errormsg);
+ auth_close_client (client);
+ }
+ else
+ {
+ /* we received a response, lets see what it is */
+ if (auth_user->authenticated)
+ {
+ if (auth_postprocess_client (auth_user->mount, client) < 0)
+ {
+ /* do cleanup, and exit as the remove does cleanup as well */
+ free (auth_user->addurl);
+ auth_removeurl_thread (auth_user);
+ return NULL;
+ }
+ }
+ else
+ {
+ DEBUG0 ("client authentication failed");
+ auth_close_client (client);
+ }
+ }
+ }
+ else
+ auth_close_client (client);
+
+ free (auth_user->username);
+ free (auth_user->password);
+ free (auth_user->mount);
+ free (auth_user->addurl);
+ free (auth_user->removeurl);
+ free (auth_user);
+
+ return NULL;
+}
+
+
+static void auth_remove_url_client (source_t *source, client_t *client)
+{
+ auth_client *auth_user = calloc (1, sizeof (auth_client));
+ auth_url *urlinfo = source->authenticator->state;
+
+ if (auth_user == NULL)
+ return;
+
+ if (urlinfo->username)
+ auth_user->username = strdup (urlinfo->username);
+ if (urlinfo->password)
+ auth_user->password = strdup (urlinfo->password);
+ if (urlinfo->removeurl)
+ auth_user->removeurl = strdup (urlinfo->removeurl);
+ auth_user->mount = strdup (source->mount);
+ auth_user->client = client;
+ thread_create("AuthRemove by URL thread", auth_removeurl_thread,
+ auth_user, THREAD_DETACHED);
+}
+
+
+static auth_result auth_url_client (source_t *source, client_t *client)
+{
+ auth_client *auth_user = calloc (1, sizeof (auth_client));
+ auth_url *urlinfo = source->authenticator->state;
+
+ if (auth_user == NULL)
+ return AUTH_FAILED;
+
+ if (urlinfo->username)
+ auth_user->username = strdup (urlinfo->username);
+ if (urlinfo->password)
+ auth_user->password = strdup (urlinfo->password);
+ auth_user->addurl = strdup (urlinfo->addurl);
+ auth_user->removeurl = strdup (urlinfo->removeurl);
+ auth_user->mount = strdup (source->mount);
+ auth_user->client = client;
+ thread_create("Auth by URL thread", auth_url_thread, auth_user, THREAD_DETACHED);
+ return AUTH_OK;
+}
+
+static auth_result auth_url_adduser(auth_t *auth, const char *username, const char *password)
+{
+ return AUTH_FAILED;
+}
+
+static auth_result auth_url_deleteuser (auth_t *auth, const char *username)
+{
+ return AUTH_FAILED;
+}
+
+static auth_result auth_url_listuser (auth_t *auth, xmlNodePtr srcnode)
+{
+ return AUTH_FAILED;
+}
+
+auth_t *auth_get_url_auth (config_options_t *options)
+{
+ auth_t *authenticator = calloc(1, sizeof(auth_t));
+ auth_url *state;
+
+ authenticator->authenticate = auth_url_client;
+ authenticator->free = auth_url_clear;
+ authenticator->adduser = auth_url_adduser;
+ authenticator->deleteuser = auth_url_deleteuser;
+ authenticator->listuser = auth_url_listuser;
+ authenticator->release_client = auth_remove_url_client;
+
+ state = calloc(1, sizeof(auth_url));
+
+ while(options) {
+ if(!strcmp(options->name, "username"))
+ state->username = strdup(options->value);
+ if(!strcmp(options->name, "password"))
+ state->password = strdup(options->value);
+ if(!strcmp(options->name, "add"))
+ state->addurl = strdup(options->value);
+ if(!strcmp(options->name, "remove"))
+ state->removeurl = strdup(options->value);
+ options = options->next;
+ }
+ authenticator->state = state;
+ INFO0("URL based authentication setup");
+ return authenticator;
+}
+
Added: icecast/branches/kh/icecast/src/auth_url.h
===================================================================
--- icecast/branches/kh/icecast/src/auth_url.h 2004-07-11 18:09:05 UTC (rev 7095)
+++ icecast/branches/kh/icecast/src/auth_url.h 2004-07-11 18:13:09 UTC (rev 7096)
@@ -0,0 +1,28 @@
+/* Icecast
+ *
+ * This program is distributed under the GNU General Public License, version 2.
+ * A copy of this license is included with this source.
+ *
+ * Copyright 2000-2004, Jack Moffitt <jack at xiph.org,
+ * Michael Smith <msmith at xiph.org>,
+ * oddsock <oddsock at xiph.org>,
+ * Karl Heyes <karl at xiph.org>
+ * and others (see AUTHORS for details).
+ */
+
+#ifndef __AUTH_URL_H__
+#define __AUTH_URL_H__
+#ifdef HAVE_AUTH_URL
+
+#include "source.h"
+#include "client.h"
+#include "config.h"
+#include <libxml/xmlmemory.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+
+auth_t *auth_get_url_auth (config_options_t *options);
+#endif
+#endif
+
+
Added: icecast/branches/kh/icecast/src/format_ogg.c
===================================================================
--- icecast/branches/kh/icecast/src/format_ogg.c 2004-07-11 18:09:05 UTC (rev 7095)
+++ icecast/branches/kh/icecast/src/format_ogg.c 2004-07-11 18:13:09 UTC (rev 7096)
@@ -0,0 +1,798 @@
+/* Icecast
+ *
+ * This program is distributed under the GNU General Public License, version 2.
+ * A copy of this license is included with this source.
+ *
+ * Copyright 2000-2004, Jack Moffitt <jack at xiph.org,
+ * Michael Smith <msmith at xiph.org>,
+ * oddsock <oddsock at xiph.org>,
+ * Karl Heyes <karl at xiph.org>
+ * and others (see AUTHORS for details).
+ */
+
+/* format_ogg.c
+**
+** format plugin for Ogg
+**
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <ogg/ogg.h>
+#include <vorbis/codec.h>
+#ifdef HAVE_THEORA
+#include <theora/theora.h>
+#endif
+#ifdef HAVE_SPEEX
+#include <speex_header.h>
+#endif
+
+#include "refbuf.h"
+#include "source.h"
+#include "client.h"
+
+#include "stats.h"
+#include "format.h"
+
+#define CATMODULE "format-ogg"
+#include "logging.h"
+
+struct _ogg_state_tag;
+
+/* per codec/logical structure */
+typedef struct _ogg_codec_tag
+{
+ ogg_stream_state os;
+ unsigned headers;
+ void *specific;
+ struct _ogg_state_tag *feed;
+ struct _ogg_codec_tag *next;
+ refbuf_t *(*process_page)(struct _ogg_codec_tag *codec, ogg_page *page);
+ void (*codec_free)(struct _ogg_codec_tag *codec);
+ refbuf_t *possible_start;
+} ogg_codec_t;
+
+
+typedef struct _ogg_state_tag
+{
+ char *mount;
+ ogg_sync_state oy;
+
+ ogg_codec_t *codecs;
+ char *artist;
+ char *title;
+ int send_yp_info;
+ refbuf_t *file_headers;
+ refbuf_t *header_pages;
+ refbuf_t *header_pages_tail;
+ int headers_completed;
+ long bitrate;
+ ogg_codec_t *codec_sync;
+} ogg_state_t;
+
+
+struct client_vorbis
+{
+ refbuf_t *headers;
+ refbuf_t *header_page;
+ unsigned pos;
+ int headers_sent;
+};
+
+
+void refbuf_page_prerelease (struct source_tag *source, refbuf_t *refbuf)
+{
+ ogg_state_t *ogg_info = source->format->_state;
+
+ /* only theora will be marking refbufs as sync that are behind in the
+ * queue, here we just make sure that it isn't the one we are going to
+ * remove. */
+ if (ogg_info->codec_sync)
+ {
+ if (ogg_info->codec_sync->possible_start == refbuf)
+ ogg_info->codec_sync->possible_start = NULL;
+ }
+}
+
+
+static refbuf_t *make_refbuf_with_page (ogg_page *page)
+{
+ refbuf_t *refbuf = refbuf_new (page->header_len + page->body_len);
+
+ refbuf->idx = ogg_page_pageno (page);
+ memcpy (refbuf->data, page->header, page->header_len);
+ memcpy (refbuf->data+page->header_len, page->body, page->body_len);
+ refbuf->len = page->header_len + page->body_len;
+ return refbuf;
+}
+
+
+void format_ogg_attach_header (ogg_state_t *ogg_info, ogg_page *page)
+{
+ refbuf_t *refbuf = make_refbuf_with_page (page);
+
+ if (ogg_info->header_pages_tail)
+ ogg_info->header_pages_tail->next = refbuf;
+ ogg_info->header_pages_tail = refbuf;
+
+ if (ogg_info->header_pages == NULL)
+ ogg_info->header_pages = refbuf;
+}
+
+
+
+/**** vorbis ****/
+typedef struct _vorbis_codec_tag
+{
+ vorbis_info vi;
+ vorbis_comment vc;
+} vorbis_codec_t;
+
+
+static void vorbis_codec_free (ogg_codec_t *codec)
+{
+ vorbis_codec_t *vorbis = codec->specific;
+
+ codec->feed->artist = NULL;
+ codec->feed->title = NULL;
+ vorbis_info_clear (&vorbis->vi);
+ vorbis_comment_clear (&vorbis->vc);
+ ogg_stream_clear (&codec->os);
+ free (vorbis);
+ free (codec);
+}
+
+static refbuf_t *process_vorbis_page (ogg_codec_t *codec, ogg_page *page)
+{
+ refbuf_t *refbuf;
+
+ if (ogg_page_granulepos (page) == 0)
+ {
+ vorbis_codec_t *vorbis = codec->specific;
+ ogg_packet packet;
+
+ ogg_stream_pagein (&codec->os, page);
+ while (ogg_stream_packetout (&codec->os, &packet) > 0)
+ {
+ if (vorbis_synthesis_headerin (&vorbis->vi, &vorbis->vc, &packet) < 0)
+ {
+ /* set some error code */
+ return NULL;
+ }
+ codec->headers++;
+ }
+ /* add header page to associated list */
+ format_ogg_attach_header (codec->feed, page);
+ if (codec->headers == 3)
+ {
+ ogg_state_t *ogg_info = codec->feed;
+
+ ogg_info->send_yp_info = 1;
+ ogg_info->title = vorbis_comment_query (&vorbis->vc, "TITLE", 0);
+ ogg_info->artist = vorbis_comment_query (&vorbis->vc, "ARTIST", 0);
+ ogg_info->bitrate += vorbis->vi.bitrate_nominal;
+ stats_event_args (codec->feed->mount, "audio-samplerate", "%ld", (long)vorbis->vi.rate);
+ stats_event_args (codec->feed->mount, "audio-channels", "%ld", (long)vorbis->vi.channels);
+ stats_event_args (codec->feed->mount, "audio-bitrate", "%ld", (long)vorbis->vi.bitrate_nominal);
+ }
+ return NULL;
+ }
+ refbuf = make_refbuf_with_page (page);
+ if (codec->feed->codec_sync == NULL)
+ refbuf->sync_point = 1;
+ return refbuf;
+}
+
+
+static ogg_codec_t *initial_vorbis_page (ogg_page *page)
+{
+ ogg_codec_t *codec = calloc (1, sizeof (ogg_codec_t));
+ ogg_packet packet;
+
+ vorbis_codec_t *vorbis_codec = calloc (1, sizeof (vorbis_codec_t));
+
+ ogg_stream_init (&codec->os, ogg_page_serialno (page));
+ ogg_stream_pagein (&codec->os, page);
+
+ vorbis_info_init (&vorbis_codec->vi);
+ vorbis_comment_init (&vorbis_codec->vc);
+
+ ogg_stream_packetout (&codec->os, &packet);
+
+ if (vorbis_synthesis_headerin (&vorbis_codec->vi, &vorbis_codec->vc, &packet) < 0)
+ {
+ ogg_stream_clear (&codec->os);
+ vorbis_info_clear (&vorbis_codec->vi);
+ vorbis_comment_clear (&vorbis_codec->vc);
+ free (vorbis_codec);
+ free (codec);
+ return NULL;
+ }
+ INFO0 ("seen initial vorbis header");
+ codec->specific = vorbis_codec;
+ codec->process_page = process_vorbis_page;
+ codec->codec_free = vorbis_codec_free;
+ codec->headers = 1;
+ return codec;
+}
+
+#ifdef HAVE_SPEEX
+
+static void speex_codec_free (ogg_codec_t *codec)
+{
+ ogg_stream_clear (&codec->os);
+ free (codec);
+}
+
+
+static refbuf_t *process_speex_page (ogg_codec_t *codec, ogg_page *page)
+{
+ refbuf_t *refbuf;
+
+ if (codec->headers < 2)
+ {
+ ogg_packet packet;
+
+ ogg_stream_pagein (&codec->os, page);
+ while (ogg_stream_packetout (&codec->os, &packet) > 0)
+ {
+ /* first time around (normal case) yields comments */
+ codec->headers++;
+ }
+ /* add header page to associated list */
+ format_ogg_attach_header (codec->feed, page);
+ return NULL;
+ }
+ refbuf = make_refbuf_with_page (page);
+ if (codec->feed->codec_sync == NULL)
+ refbuf->sync_point = 1;
+ return refbuf;
+}
+
+
+static ogg_codec_t *initial_speex_page (ogg_page *page)
+{
+ ogg_codec_t *codec = calloc (1, sizeof (ogg_codec_t));
+ ogg_packet packet;
+ SpeexHeader *header;
+
+ ogg_stream_init (&codec->os, ogg_page_serialno (page));
+ ogg_stream_pagein (&codec->os, page);
+
+ ogg_stream_packetout (&codec->os, &packet);
+
+ header = speex_packet_to_header (packet.packet, packet.bytes);
+ if (header == NULL)
+ {
+ ogg_stream_clear (&codec->os);
+ free (header);
+ free (codec);
+ return NULL;
+ }
+ INFO0 ("seen initial speex header");
+ codec->process_page = process_speex_page;
+ codec->codec_free = speex_codec_free;
+ codec->headers = 1;
+ free (header);
+ return codec;
+}
+#endif
+
+#ifdef HAVE_THEORA
+
+typedef struct _theora_codec_tag
+{
+ theora_info ti;
+ theora_comment tc;
+ int granule_shift;
+ ogg_int64_t last_iframe;
+ ogg_int64_t prev_granulepos;
+} theora_codec_t;
+
+
+static void theora_codec_free (ogg_codec_t *codec)
+{
+ theora_codec_t *theora = codec->specific;
+
+ theora_info_clear (&theora->ti);
+ theora_comment_clear (&theora->tc);
+ ogg_stream_clear (&codec->os);
+ free (theora);
+ free (codec);
+}
+
+
+static int _ilog (unsigned int v)
+{
+ int ret=0;
+ while(v){
+ ret++;
+ v>>=1;
+ }
+ return ret;
+}
+
+
+static refbuf_t *process_theora_page (ogg_codec_t *codec, ogg_page *page)
+{
+ refbuf_t *refbuf;
+ theora_codec_t *theora = codec->specific;
+ ogg_int64_t granulepos;
+
+ granulepos = ogg_page_granulepos (page);
+ // printf (" granulepos of page %ld is %lld\n", ogg_page_pageno (page), granulepos);
+ if (granulepos == 0)
+ {
+ ogg_packet packet;
+ ogg_state_t *ogg_info = codec->feed;
+
+ ogg_stream_pagein (&codec->os, page);
+ // printf ("page %ld processing\n", ogg_page_pageno (page));
+ while (ogg_stream_packetout (&codec->os, &packet) > 0)
+ {
+ if (theora_decode_header (&theora->ti, &theora->tc, &packet) < 0)
+ {
+ /* set some error code */
+ WARN0 ("problem with theora header");
+ return NULL;
+ }
+ codec->headers++;
+ // printf ("header packets: %d\n", codec->headers);
+ if (codec->headers == 3)
+ {
+ theora->granule_shift = _ilog (theora->ti.keyframe_frequency_force - 1);
+ DEBUG1 ("granule shift is %lu", theora->granule_shift);
+ theora->last_iframe = (ogg_int64_t)-1;
+ codec->possible_start = NULL;
+ ogg_info->bitrate += theora->ti.target_bitrate;
+ stats_event_args (codec->feed->mount, "video_bitrate",
+ "%ld", (long)theora->ti.target_bitrate);
+ stats_event_args (codec->feed->mount, "frame_size",
+ "%ld x %ld", (long)theora->ti.frame_width, (long)theora->ti.frame_height);
+ stats_event_args (codec->feed->mount, "framerate",
+ "%.2f", (float)theora->ti.fps_numerator/theora->ti.fps_denominator);
+ }
+ }
+ /* add page to associated list */
+ format_ogg_attach_header (ogg_info, page);
+
+ return NULL;
+ }
+ refbuf = make_refbuf_with_page (page);
+ refbuf->idx = ogg_page_pageno (page);
+
+ // DEBUG2 ("granulepos is %lld, %p", granulepos, refbuf);
+ if (granulepos == -1 || granulepos == theora->prev_granulepos)
+ {
+ if (codec->possible_start == NULL)
+ {
+ // DEBUG1 ("granulepos is unset, possible beginning %p", refbuf);
+ codec->possible_start = refbuf;
+ }
+ // DEBUG1 ("possible start is %p", codec->possible_start);
+ }
+ else
+ {
+ if ((granulepos >> theora->granule_shift) != theora->last_iframe)
+ {
+ theora->last_iframe = (granulepos >> theora->granule_shift);
+ // DEBUG2 ("iframe changed to %lld (%p)", theora->last_iframe, refbuf);
+ if (codec->possible_start == NULL)
+ codec->possible_start = refbuf;
+ codec->possible_start->sync_point = 1;
+ // DEBUG1 ("possible start is %p", codec->possible_start);
+ }
+ else
+ {
+ if (theora->prev_granulepos != -1)
+ codec->possible_start = refbuf;
+ }
+ }
+ theora->prev_granulepos = granulepos;
+
+ return refbuf;
+}
+
+
+static ogg_codec_t *initial_theora_page (ogg_page *page)
+{
+ ogg_codec_t *codec = calloc (1, sizeof (ogg_codec_t));
+ ogg_packet packet;
+
+ theora_codec_t *theora_codec = calloc (1, sizeof (theora_codec_t));
+
+ ogg_stream_init (&codec->os, ogg_page_serialno (page));
+ ogg_stream_pagein (&codec->os, page);
+
+ theora_info_init (&theora_codec->ti);
+ theora_comment_init (&theora_codec->tc);
+
+ ogg_stream_packetout (&codec->os, &packet);
+
+ if (theora_decode_header (&theora_codec->ti, &theora_codec->tc, &packet) < 0)
+ {
+ theora_info_clear (&theora_codec->ti);
+ theora_comment_clear (&theora_codec->tc);
+ ogg_stream_clear (&codec->os);
+ free (theora_codec);
+ free (codec);
+ return NULL;
+ }
+ INFO0 ("seen initial theora header");
+ // printf ("initial page %ld processing\n", ogg_page_pageno (page));
+ codec->specific = theora_codec;
+ codec->process_page = process_theora_page;
+ codec->codec_free = theora_codec_free;
+ codec->headers = 1;
+ return codec;
+}
+#endif /* THEORA */
+
+static void format_ogg_free_plugin (format_plugin_t *plugin);
+static int create_ogg_client_data(source_t *source, client_t *client);
+static void free_ogg_client_data (client_t *client);
+
+static void write_ogg_to_file (struct source_tag *source, refbuf_t *refbuf);
+static refbuf_t *ogg_get_buffer (source_t *source);
+static int write_buf_to_client (format_plugin_t *self, client_t *client);
+
+
+static void free_ogg_codecs (ogg_state_t *ogg_info)
+{
+ ogg_codec_t *codec;
+
+ if (ogg_info == NULL)
+ return;
+ codec = ogg_info->codecs;
+ while (codec)
+ {
+ ogg_codec_t *next = codec->next;
+ codec->codec_free (codec);
+ codec = next;
+ }
+ ogg_info->codecs = NULL;
+ ogg_info->headers_completed = 0;
+}
+
+
+int format_ogg_get_plugin (source_t *source)
+{
+ format_plugin_t *plugin;
+ ogg_state_t *state = calloc (1, sizeof (ogg_state_t));
+
+ plugin = (format_plugin_t *)malloc(sizeof(format_plugin_t));
+
+ plugin->type = FORMAT_TYPE_OGG;
+ plugin->format_description = "Ogg Vorbis";
+ plugin->get_buffer = ogg_get_buffer;
+ plugin->write_buf_to_client = write_buf_to_client;
+ plugin->write_buf_to_file = write_ogg_to_file;
+ plugin->create_client_data = create_ogg_client_data;
+ plugin->free_plugin = format_ogg_free_plugin;
+ plugin->set_tag = NULL;
+ plugin->prerelease = refbuf_page_prerelease;
+
+ ogg_sync_init (&state->oy);
+
+ plugin->_state = state;
+ source->format = plugin;
+ state->mount = source->mount;
+
+ return 0;
+}
+
+
+void format_ogg_free_plugin (format_plugin_t *plugin)
+{
+ ogg_state_t *state = plugin->_state;
+
+ /* free memory associated with this plugin instance */
+ free_ogg_codecs (state);
+
+ /* free state memory */
+ ogg_sync_clear (&state->oy);
+ free (state);
+
+ /* free the plugin instance */
+ free (plugin);
+}
+
+
+
+static int process_initial_page (ogg_state_t *ogg_info, ogg_page *page)
+{
+ ogg_codec_t *codec;
+
+ if (ogg_info->headers_completed)
+ {
+ ogg_info->bitrate = 0;
+ ogg_info->codec_sync = NULL;
+ /* need to zap old list of codecs when next group of BOS pages appear */
+ free_ogg_codecs (ogg_info);
+ ogg_info->header_pages = NULL;
+ ogg_info->header_pages_tail = NULL;
+ }
+ do
+ {
+ codec = initial_vorbis_page (page);
+ if (codec)
+ break;
+#ifdef HAVE_THEORA
+ codec = initial_theora_page (page);
+ if (codec)
+ {
+ ogg_info->codec_sync = codec;
+ break;
+ }
+#endif
+#ifdef HAVE_SPEEX
+ codec = initial_speex_page (page);
+ if (codec)
+ break;
+#endif
+
+ /* any others */
+ INFO0 ("Seen BOS page with unknown type");
+ return -1;
+ } while (0);
+
+ if (codec)
+ {
+ /* add codec to list */
+ codec->next = ogg_info->codecs;
+ ogg_info->codecs = codec;
+
+ codec->feed = ogg_info;
+ format_ogg_attach_header (ogg_info, page);
+ // printf ("initial header page stored at %p\n", ogg_info->header_pages);
+ }
+
+ return 0;
+}
+
+
+static refbuf_t *process_ogg_page (ogg_state_t *ogg_info, ogg_page *page)
+{
+ ogg_codec_t *codec = ogg_info->codecs;
+
+ while (codec)
+ {
+ if (ogg_page_serialno (page) == codec->os.serialno)
+ {
+ refbuf_t *refbuf = codec->process_page (codec, page);
+ if (refbuf)
+ refbuf->associated = ogg_info->header_pages;
+ return refbuf;
+ }
+ codec = codec->next;
+ }
+ return NULL;
+}
+
+
+static refbuf_t *ogg_get_buffer (source_t *source)
+{
+ ogg_state_t *ogg_info = source->format->_state;
+ char *data = NULL;
+ int bytes;
+ ogg_page page;
+ refbuf_t *refbuf = NULL;
+
+ while (1)
+ {
+ while (1)
+ {
+ if (ogg_sync_pageout (&ogg_info->oy, &page) > 0)
+ {
+ if (ogg_page_bos (&page))
+ {
+ process_initial_page (ogg_info, &page);
+ continue;
+ }
+ // printf ("finished with BOS pages\n");
+ ogg_info->headers_completed = 1;
+ /* process the extracted page */
+ refbuf = process_ogg_page (ogg_info, &page);
+
+ if (ogg_info->send_yp_info)
+ {
+ char *tag;
+ tag = ogg_info->title;
+ if (tag == NULL)
+ tag = "unknown";
+ stats_event (source->mount, "title", tag);
+ INFO1("Updating title \"%s\"", tag);
+
+ tag = ogg_info->artist;
+ if (tag == NULL)
+ tag = "unknown";
+ stats_event (source->mount, "artist", tag);
+ if (ogg_info->bitrate)
+ stats_event_args (source->mount, "ice-bitrate", "%u", ogg_info->bitrate/1000);
+
+ INFO1("Updating artist \"%s\"", tag);
+ ogg_info->send_yp_info = 0;
+ yp_touch (source->mount);
+ }
+ if (refbuf)
+ return refbuf;
+ continue;
+ }
+ break;
+ }
+ /* we need more data to continue getting pages */
+ data = ogg_sync_buffer (&ogg_info->oy, 4096);
+
+ bytes = sock_read_bytes (source->con->sock, data, 4096);
+ if (bytes < 0)
+ {
+ if (sock_recoverable (sock_error()))
+ return NULL;
+ WARN0 ("source connection has died");
+ ogg_sync_wrote (&ogg_info->oy, 0);
+ source->running = 0;
+ return NULL;
+ }
+ if (bytes == 0)
+ {
+ INFO1 ("End of Stream %s", source->mount);
+ ogg_sync_wrote (&ogg_info->oy, 0);
+ source->running = 0;
+ return NULL;
+ }
+ ogg_sync_wrote (&ogg_info->oy, bytes);
+ }
+}
+
+
+static int create_ogg_client_data (source_t *source, client_t *client)
+{
+ struct client_vorbis *client_data = calloc (1, sizeof (struct client_vorbis));
+ int ret = -1;
+
+ if (client_data)
+ {
+ client_data->headers_sent = 1;
+ client->format_data = client_data;
+ client->free_client_data = free_ogg_client_data;
+ ret = 0;
+ }
+ return ret;
+}
+
+
+static void free_ogg_client_data (client_t *client)
+{
+ free (client->format_data);
+ client->format_data = NULL;
+}
+
+
+
+static int send_ogg_headers (client_t *client, refbuf_t *headers)
+{
+ struct client_vorbis *client_data = client->format_data;
+ refbuf_t *refbuf;
+ int written = 0;
+
+ if (client_data->headers_sent)
+ {
+ client_data->header_page = headers;
+ client_data->pos = 0;
+ client_data->headers_sent = 0;
+ }
+ refbuf = client_data->header_page;
+ while (refbuf)
+ {
+ char *data = refbuf->data + client_data->pos;
+ unsigned len = refbuf->len - client_data->pos;
+ int ret;
+
+ ret = client_send_bytes (client, data, len);
+ if (ret > 0)
+ written += ret;
+ if (ret < (int)len)
+ return written ? written : -1;
+ client_data->pos += ret;
+ if (client_data->pos == refbuf->len)
+ {
+ refbuf = refbuf->next;
+ client_data->header_page = refbuf;
+ client_data->pos = 0;
+ }
+ }
+ client_data->headers_sent = 1;
+ client_data->headers = headers;
+ return written;
+}
+
+
+static int write_buf_to_client (format_plugin_t *self, client_t *client)
+{
+ refbuf_t *refbuf = client->refbuf;
+ char *buf;
+ unsigned len;
+ struct client_vorbis *client_data = client->format_data;
+ int ret, written = 0;
+
+ /* rare but the listener could connect before audio is ready */
+ if (refbuf == NULL)
+ return 0;
+ if (refbuf->next == NULL && client->pos == refbuf->len)
+ return 0;
+
+ if (refbuf->next && client->pos == refbuf->len)
+ {
+ client->refbuf = refbuf->next;
+ client->pos = 0;
+ }
+ refbuf = client->refbuf;
+ buf = refbuf->data + client->pos;
+ len = refbuf->len - client->pos;
+ do
+ {
+ if (client_data->headers != refbuf->associated)
+ {
+ ret = send_ogg_headers (client, refbuf->associated);
+ if (client_data->headers_sent == 0)
+ break;
+ written += ret;
+ }
+ ret = client_send_bytes (client, buf, len);
+
+ if (ret > 0)
+ client->pos += ret;
+
+ if (ret < (int)len)
+ break;
+ written += ret;
+ /* we have now written the page(s) */
+ ret = 0;
+ } while (0);
+
+ if (ret > 0)
+ written += ret;
+ return written ? written : -1;
+}
+
+
+static int write_ogg_data (struct source_tag *source, refbuf_t *refbuf)
+{
+ int ret = 1;
+
+ if (fwrite (refbuf->data, 1, refbuf->len, source->dumpfile) != refbuf->len)
+ {
+ WARN0 ("Write to dump file failed, disabling");
+ fclose (source->dumpfile);
+ source->dumpfile = NULL;
+ ret = 0;
+ }
+ return ret;
+}
+
+
+static void write_ogg_to_file (struct source_tag *source, refbuf_t *refbuf)
+{
+ ogg_state_t *ogg_info = source->format->_state;
+
+ if (ogg_info->file_headers != refbuf->associated)
+ {
+ refbuf_t *header = refbuf->associated;
+ while (header)
+ {
+ if (write_ogg_data (source, header) == 0)
+ return;
+ header = header->next;
+ }
+ ogg_info->file_headers = refbuf->associated;
+ }
+ write_ogg_data (source, refbuf);
+}
+
+
Added: icecast/branches/kh/icecast/src/format_ogg.h
===================================================================
--- icecast/branches/kh/icecast/src/format_ogg.h 2004-07-11 18:09:05 UTC (rev 7095)
+++ icecast/branches/kh/icecast/src/format_ogg.h 2004-07-11 18:13:09 UTC (rev 7096)
@@ -0,0 +1,24 @@
+/* Icecast
+ *
+ * This program is distributed under the GNU General Public License, version 2.
+ * A copy of this license is included with this source.
+ *
+ * Copyright 2000-2004, Jack Moffitt <jack at xiph.org,
+ * Michael Smith <msmith at xiph.org>,
+ * oddsock <oddsock at xiph.org>,
+ * Karl Heyes <karl at xiph.org>
+ * and others (see AUTHORS for details).
+ */
+
+/* format_ogg.h
+**
+** vorbis format plugin header
+**
+*/
+#ifndef __FORMAT_OGG_H__
+#define __FORMAT_OGG_H__
+
+int format_ogg_get_plugin (source_t *source);
+#define format_ogg_initialise() do{}while(0)
+
+#endif /* __FORMAT_OGG_H__ */
More information about the commits
mailing list