OOPS, I forgot to attach the source code!
MAX
-----Original Message-----
From: owner-icecast-dev@xiph.org [mailto:owner-icecast-dev@xiph.org] On
Behalf Of Macsym
Sent: Saturday, December 06, 2003 7:12 AM
To: icecast-dev@xiph.org
Subject: RE: [icecast-dev] Missing headers in Icecast2
Hi Karl,
I just checked in Icecast1 source, the line:
if (client_wants_content_length (con))
sock_write (con->sock, "Cache-Control: no-cache\r\nPragma:
no-cache\r\nConnection: close\r\nContent-Length: 54000000\r\n");
is located in "client.c". Shouldn't I add this line in
"client.c" of
Icecast2 instead of "format_mp3.c" as you advised me? If so, what
should I
add exactly and where in the code (of Icecast2's client.c)?
Thanks in advance,
MAX
<p><p><p><p><p><p><p><p><p><p><p>-----Original
Message-----
From: owner-icecast-dev@xiph.org [mailto:owner-icecast-dev@xiph.org] On
Behalf Of Macsym
Sent: Saturday, December 06, 2003 5:42 AM
To: icecast-dev@xiph.org
Subject: RE: [icecast-dev] Missing headers in Icecast2
Hi Karl,
Thanks for your help,
About the "Connection:" header, you are right, it's:
"Connection: close" and NOT "Connection: keep-alive". The
protocol when the
SERVER sends the data is http 1.0. It's http 1.1 when the browser requests
the data.
I don't understand the "Content-Length: 54000000" header either.
Also I
noticed the flash player on Windows/IE seems to stop after 52734KB are
loaded (54000000 bytes/1024 = 52734KB). I tried to change the
"Content-Length:" value but it didn't change anything...
I'll try changing the source code of Icecast2 as you advised, and compile
the modified code.
Thanks again,
MAX
<p>-----Original Message-----
From: owner-icecast-dev@xiph.org [mailto:owner-icecast-dev@xiph.org] On
Behalf Of Karl Heyes
Sent: Saturday, December 06, 2003 3:21 AM
To: icecast-dev@xiph.org
Subject: Re: [icecast-dev] Missing headers in Icecast2
On Sat, 2003-12-06 at 01:43, Macsym wrote:
> For Windows (Internet Explorer or AOL) some headers sent by Icecast2 are
> missing. These headers are sent by Icecast1 but NOT Icecast2 (it is the
> reason why it always works with Icecast1). These necessary headers are:
> -Cache-Control: no-cache
possibly
> -Pragma: no-cache
Isn't this from the client.
> -Connection: keep-alive
http 1.0 and http 1.1 differ on this. Sending "Connection: close"
should
be ok though. keep-alive isn't going to do anything with these types of
connections.
> -Content-Length: 54000000
well you don't know the length.
> Now that we identified the exact problem, we would like to force Icecast2
to> send these headers to the client because it would avoid passing through
the> PHP script (which is less reliable, slower the connection and uses more
> CPU). It is why I am contacting the dev-list today.
<p>> Can anybody advise us the best solution to force Icecast2 to send
these> headers to the browser? Should we build a patch or simply change some
source> codes and compile the modified source?
add a couple of lines to verify it
in format_mp3.c at the end of function format_mp3_send_headers
Add something like
ock_write(client->con->sock, "Cache-Control: no-cache\r\n");
and whatever else.
karl.
<p>--- >8 ----
List archives: http://www.xiph.org/archives/
icecast project homepage: http://www.icecast.org/
To unsubscribe from this list, send a message to
'icecast-dev-request@xiph.org'
containing only the word 'unsubscribe' in the body. No subject is
needed.
Unsubscribe messages sent to the list will be ignored/filtered.
<p>--- >8 ----
List archives: http://www.xiph.org/archives/
icecast project homepage: http://www.icecast.org/
To unsubscribe from this list, send a message to
'icecast-dev-request@xiph.org'
containing only the word 'unsubscribe' in the body. No subject is
needed.
Unsubscribe messages sent to the list will be ignored/filtered.
<p>--- >8 ----
List archives: http://www.xiph.org/archives/
icecast project homepage: http://www.icecast.org/
To unsubscribe from this list, send a message to
'icecast-dev-request@xiph.org'
containing only the word 'unsubscribe' in the body. No subject is
needed.
Unsubscribe messages sent to the list will be ignored/filtered.
-------------- next part --------------
/* client.c
* - Client functions
* Copyright (c) 1999 Jack Moffitt, Barath Raghavan, and Alexander Haväng
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
/* Last overhauled 990420 <eel@musiknet.se> */
#ifdef HAVE_CONFIG_H
#ifdef _WIN32
#include <win32config.h>
#else
#include <config.h>
#endif
#endif
#include "definitions.h"
#include <stdio.h>
#include "definitions.h"
#ifdef HAVE_SIGNAL_H
#include <signal.h>
#endif
#include <stdlib.h>
#include <stdarg.h>
# ifndef __USE_BSD
# define __USE_BSD
# endif
#include <string.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <sys/types.h>
#include <ctype.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#if defined (_WIN32)
#include <windows.h>
#define strncasecmp strnicmp
#else
#include <sys/socket.h>
#include <sys/wait.h>
#include <netinet/in.h>
#endif
#include "avl.h"
#include "avl_functions.h"
#include "threads.h"
#include "icetypes.h"
#include "icecast.h"
#include "utility.h"
#include "ice_string.h"
#include "client.h"
#include "threads.h"
#include "connection.h"
#include "log.h"
#include "source.h"
#include "sock.h"
#include "restrict.h"
#include "static.h"
#include "memory.h"
#include "admin.h"
#include "http.h"
#include "vars.h"
#include "commands.h"
#include "authenticate/basic.h"
#include "match.h"
#include "pool.h"
#include <signal.h>
extern server_info_t info;
static void client_send_fake_file (connection_t *con);
/* Brand new client. Check what he wants, and either add him to
the correct tree of clients (inside a source), or kill him off */
void client_login(connection_t *con, char *expr)
{
char line[BUFSIZE];
int go_on = 1;
connection_t *source;
request_t req;
xa_debug(3, "Client login...\n");
if (!con || !expr) {
write_log(LOG_DEFAULT, "WARNING: client_login called with NULL
pointer");
return;
}
if (info.throttle_on) {
sock_write(con->sock, "HTTP/1.0 406 Not Acceptable (using too much
bandwidth)");
kick_not_connected(con, "Bandwidth usage too high (throttling)");
return;
}
#ifdef HAVE_LIBWRAP
if (!sock_check_libwrap (con->sock, client_e)) {
write_http_code_page (con, 403, "Forbidden");
kick_not_connected (con, "Access Denied (libwrap (client
connection))");
return;
}
#endif
if (!allowed(con, client_e)) {
write_http_code_page (con, 403, "Forbidden");
kick_not_connected (con, "Access Denied (internal acl list (client
connection))");
return;
}
zero_request(&req);
con->headervars = create_header_vars ();
do {
if (splitc(line, expr, '\n') == NULL) {
strncpy(line, expr, BUFSIZE);
go_on = 0;
}
if (ice_strncmp(line, "GET", 3) == 0) {
build_request(line, &req);
} else {
if (ice_strncmp(line, "Host:", 5) == 0 ||
(ice_strncmp(line, "HOST:", 5) == 0))
build_request(line, &req);
else
extract_header_vars (line, con->headervars);
}
} while (go_on);
if (need_authentication (&req))
{
if (!authenticate_user_request (con, &req))
{
write_401 (con, req.path);
kick_not_connected (con, "Not authorized");
return;
}
}
if (ice_strcmp(req.path, "/list.cgi") == 0) {
show_mountlist(con, &req);
kick_not_connected(con, "Displayed mountlist");
return;
}
if (ice_strncmp(req.path, "/playlist.pls", 13) == 0) {
gen_playlist(con, &req);
kick_not_connected (con, "Generated playlist");
return;
}
if (ice_strncmp(req.path, "/admin", 6) == 0)
{
int err;
char *secfile = get_icecast_file (info.mountfile, conf_file_e, R_OK);
if (!secfile && strstr (req.path, "updinfo") == NULL) {
write_http_code_page (con, 403, "Forbidden");
write_log (LOG_DEFAULT, "No mountfile found, refusing access to WWW
admin for %s", con_host (con));
kick_not_connected (con, "No mountfile found");
return;
}
err = http_admin_command (con, &req);
if (err)
{
xa_debug (2, "DEBUG: kicking %s, executed admin command", con_host
(con));
kick_not_connected (con, NULL);
} else
kick_not_connected (con, "Failed to execute admin command");
return;
}
if (ice_strncmp(req.path, "/file/", 6) == 0) {
thread_rename("Static File Thread");
if (req.path[ice_strlen (req.path) - 1] == '/')
{
list_directory (con, req.path);
kick_not_connected (con, "Displayed directory list");
} else {
send_file(con, &req);
kick_not_connected(con, "Sent static file");
}
return;
}
xa_debug (1, "Looking for mount [%s:%d%s]", req.host, req.port,
req.path);
/* Try to find a mount point with this name */
thread_mutex_lock (&info.double_mutex);
thread_mutex_lock (&info.mount_mutex);
thread_mutex_lock (&info.source_mutex);
source = find_mount_with_req (&req);
thread_mutex_unlock (&info.source_mutex);
thread_mutex_unlock (&info.mount_mutex);
thread_mutex_unlock (&info.double_mutex);
/* Ok, none found, give him the default mount */
if (source == NULL && info.mount_fallback)
source = get_default_mount();
/* No LOG_DEFAULT, then no encoder, kick him out */
if (source == NULL) {
write_http_code_page (con, 404, "Stream not found");
kick_not_connected (con, "No encoder");
return;
}
if (need_authentication_on_mount (source->food.source->audiocast.mount))
{
if (!authenticate_user_request (con, &req))
{
write_401 (con, req.path);
kick_not_connected (con, "Not authorized");
return;
}
}
if ((info.num_clients >= info.max_clients)
|| (source->food.source->num_clients >=
info.max_clients_per_source))
{
write_http_code_page (con, 504, "Server Full");
if (info.num_clients >= info.max_clients)
xa_debug (2, "DEBUG: inc > imc: %lu %lu", info.num_clients,
info.max_clients);
else if (source->food.source->num_clients >=
info.max_clients_per_source)
xa_debug (2, "DEBUG: snc > smc: %lu %lu",
source->food.source->num_clients, info.max_clients_per_source);
else
xa_debug (1, "ERROR: Erroneous number of clients, what the hell is going
on?");
kick_not_connected (con, "Server Full (too many listeners)");
return;
}
put_client(con);
con->food.client->type = listener_e;
{
const char *umd = get_con_variable (con, "Icy-MetaData");
if (umd)
con->food.client->use_icy_metadata = atoi (umd);
}
{
const char *ref = get_con_variable (con, "Referer");
if (ref && ice_strcmp (ref, "RELAY") == 0)
con->food.client->type = pulling_client_e;
}
/* Change the sockaddr_in for the client to point to the port the client
specified */
if (con->sin)
{
const char *sport = get_con_variable (con, "x-audiocast-udpport");
if (sport)
{
con->sin->sin_port = htons (atoi (sport));
con->food.client->use_udp = 1;
xa_debug (1, "DEBUG: client_login(): Client listening on udp port
%d", atoi (sport));
}
}
if (con->food.client->use_icy_metadata &&
con->food.client->use_udp)
con->food.client->use_icy_metadata = 0;
util_increase_total_clients ();
con->food.client->source = source->food.source;
/* FIXME: Dangerous */
source->food.source->stats.client_connections++;
pool_add (con);
write_log(LOG_DEFAULT, "Accepted client %d from [%s] on mountpoint [%s].
%d clients connected", con->id,
con_host (con), source->food.source->audiocast.mount,
info.num_clients);
greet_client(con, source->food.source);
}
client_t *
create_client()
{
client_t *client = (client_t *)nmalloc(sizeof(client_t));
client->type = unknown_client_e;
return client;
}
void put_client(connection_t *con)
{
client_t *cli = create_client();
con->food.client = cli;
cli->errors = 0;
cli->type = unknown_client_e;
cli->write_bytes = 0;
cli->virgin = -1;
cli->source = NULL;
cli->cid = -1;
cli->offset = 0;
cli->alive = CLIENT_ALIVE;
cli->use_icy_metadata = 0;
cli->metadataoffset = 0;
cli->metadatalen = 0;
cli->metadatawritten = 0;
cli->use_icy = 0;
cli->use_udp = 0;
con->type = client_e;
cli->udpseqnr = 0;
}
void
gen_playlist (connection_t *con, request_t *req)
{
const char *mount_point;
vartree_t *req_vars = avl_create(compare_vars, &info);
extract_vars(req_vars, req->path);
mount_point = get_variable(req_vars, "mount");
xa_debug (1, "DEBUG: Generating playlist");
write_http_header(con->sock, 200, "OK");
sock_write_line (con->sock, "Connection: close");
sock_write_line (con->sock, "Content-Type: audio/x-scpls\r\n");
sock_write_line (con->sock, "[playlist]\r\n");
sock_write_line (con->sock, "NumberOfEntries=1");
sock_write_line (con->sock, "File1=http://%s:%i%s",
info.server_name, info.port[0], mount_point ? mount_point : "/");
free_variables(req_vars);
}
void
show_mountlist(connection_t *con, request_t *req)
{
char *filename = get_template ("mountlist.html");
avl_traverser trav = {0};
connection_t *sourcecon;
int i = 0;
xa_debug (1, "DEBUG: Displaying mountlist [%s]", filename ? filename
: "internal");
if (filename)
{
write_template_parsed_html_page (con, NULL, filename, -1, NULL);
nfree (filename);
return;
}
thread_mutex_lock(&info.source_mutex);
write_http_header(con->sock, 200, "OK");
sock_write_line (con->sock, "Connection: close");
sock_write_line (con->sock, "Content-Type: text/html\r\n");
sock_write_line (con->sock,
"<html><head><title>icecast server, version %s, running
on %s</title></head>", VERSION, info.server_name);
sock_write_line (con->sock, "<body bgcolor=black text=white
link=lightblue alink=lightblue vlink=lightblue><h3><tt>icecast
server, version %s, running on %s</tt></h3><br>",
VERSION, info.server_name);
for (i = 0; i < MAXLISTEN; i++)
if (info.port[i] > 0)
sock_write_line (con->sock, "<p>Listening on port
%d<br>", info.port[i]);
if (info.location)
sock_write_line (con->sock, "Server location: %s<br>",
info.location);
if (info.rp_email)
sock_write_line (con->sock, "Server admin: <a
href=\"mailto:%s\">%s</a><br>", info.rp_email,
info.rp_email);
if (info.server_url)
sock_write_line (con->sock, "Server URL: <a
href=\"%s\">%s</a><br></p>",
info.server_url, info.server_url);
sock_write_line (con->sock, "<table border=0 cellspacing=0
cellpadding=3><tr><td><font face=\"sans-serif\"
size=+2>Stream Link</font></td><td><font
face=\"sans-serif\"
size=+2>Name</font></td><td><font
face=\"sans-serif\"
size=+2>URL</font></td><td><font
face=\"sans-serif\"
size=+2>Genre</font></td><td><font
face=\"sans-serif\"
size=+2>Description</font></td></tr>");
while ((sourcecon = avl_traverse(info.sources, &trav))) {
i++;
i % 2 ? sock_write_line (con->sock, "<tr
bgcolor=#000000>") : sock_write_line (con->sock, "<tr
bgcolor=#333333>");
sock_write_line (con->sock, "<td><tt><a
href=\"/playlist.pls?mount=%s&file=dummy.pls\">%s</a></tt></td><td><tt>%s</tt></td><td><tt><a
href=\"%s\">%s</a></tt></td><td><tt>%s</tt></td><td><tt>%s</tt></td></tr>",
sourcecon->food.source->audiocast.mount,
sourcecon->food.source->audiocast.mount,
sourcecon->food.source->audiocast.name,
sourcecon->food.source->audiocast.url,
sourcecon->food.source->audiocast.url,
sourcecon->food.source->audiocast.genre,
sourcecon->food.source->audiocast.description);
}
sock_write_line (con->sock,
"</table></body></html>");
thread_mutex_unlock(&info.source_mutex);
}
void util_increase_total_clients ()
{
internal_lock_mutex (&info.misc_mutex);
info.num_clients++;
info.hourly_stats.client_connections++;
internal_unlock_mutex (&info.misc_mutex);
}
void
util_decrease_total_clients ()
{
internal_lock_mutex (&info.misc_mutex);
info.num_clients--;
internal_unlock_mutex (&info.misc_mutex);
}
void
del_client(connection_t *client, source_t *source)
{
if (!client || !source) {
write_log(LOG_DEFAULT, "WARNING: del_client() called with NULL
pointer");
return;
}
if (source && client->food.client &&
(client->food.client->virgin != 1) &&
(client->food.client->virgin != -1)) {
if (source->num_clients == 0)
write_log (LOG_DEFAULT, "WARNING: Bloody going below limits on client
count!");
else
source->num_clients--;
}
util_decrease_total_clients ();
}
int
client_wants_udp_info (connection_t *con)
{
const char *val;
if (!con)
return 0;
val = get_con_variable (con, "x-audiocast-udpport");
if (!val)
return 0;
return 1;
}
int
client_wants_content_length(connection_t *con)
{
const char *val;
if (!con)
return 0;
val = get_user_agent (con);
if (!val)
return 0;
if (strstr(val, "MSIE"))
return 1;
if (strstr(val, "RMA/1.0"))
return 1;
if (strstr(val, "NSPlayer"))
return 1;
return 0;
}
int
client_wants_icy_headers (connection_t *con)
{
const char *val;
if (!con)
return 1;
val = get_user_agent (con);
if (!val || !val[0] || strcmp (val, "(null)") == 0)
return 1;
if (con->food.client->use_icy)
return 1;
if (strncasecmp (val, "winamp", 6) == 0)
return 1;
if (strncasecmp (val, "Shoutcast", 9) == 0)
return 1;
return 0;
}
int
client_wants_metadata (connection_t *con)
{
if (!con)
return 0;
if (con->food.client->use_icy_metadata && info.use_meta_data)
return 1;
return 0;
}
void
print_relay_ids (connection_t *con, source_t *source)
{
avl_traverser trav = {0};
relay_id_t *rid;
thread_mutex_lock (&source->mutex);
while ((rid = avl_traverse (source->relay_tree, &trav)))
{
if (!rid || !rid->host)
{
write_log (LOG_DEFAULT, "ERROR: Erroneous relay id:s...");
continue;
}
xa_debug (1, "DEBUG: Displaying dir-id: %s:%d to %d", rid->host,
rid->id, con->id);
sock_write_line (con->sock, "x-audiocast-directory: %s:%d",
rid->host, rid->id);
}
thread_mutex_unlock (&source->mutex);
}
int
client_wants_relay_ids (connection_t *con)
{
return 0; /* Currently disabled awaiting new interface */
}
void
greet_client(connection_t *con, source_t *source)
{
#ifdef _WIN32
int bufsize = 16384; /* Is that a buffer in your pocket, or are you just happy
to see me? :) */
#endif
if (!con) {
write_log(LOG_DEFAULT, "WARNING: greet_client called with NULL
pointer");
return;
}
con->food.client->udpseqnr = source->info.udpseqnr > 0 ?
source->info.udpseqnr - 1 : source->info.udpseqnr;
if (client_wants_icy_headers (con)) {
xa_debug (2, "DEBUG: client [%s] wants icy headers", con_host
(con));
sock_write_line (con->sock, "ICY 200 OK");
sock_write_line (con->sock,
"icy-notice1:<BR>This stream requires <a
href=\"http://www.winamp.com/\">Winamp</a><BR>");
sock_write_line (con->sock, "icy-notice2:SHOUTcast Distributed
Network Audio Server/posix v1.6.0rc2<BR>");
if (client_wants_metadata (con))
sock_write_line (con->sock, "icy-metaint:%u",
info.metainterval);
if (client_wants_udp_info (con))
sock_write_line (con->sock, "x-audiocast-udpport: %d",
info.port[0]);
sock_write (con->sock,
"icy-name:%s\r\nicy-genre:%s\r\nicy-url:%s\r\nicy-pub:%d\nicy-br:%d\r\n\r\n",
source->audiocast.name, source->audiocast.genre,
source->audiocast.url, source->audiocast.public,
source->audiocast.bitrate);
} else {
xa_debug (2, "DEBUG: client [%s] wants xaudiocast headers",
con_host (con));
write_http_header (con->sock, 200, "OK");
if (source->audiocast.streammimetype)
sock_write_line (con->sock, "Content-Type: %s",
source->audiocast.streammimetype);
else
sock_write_line (con->sock, "Content-Type: audio/mpeg");
if (client_wants_content_length (con))
sock_write (con->sock, "Cache-Control: no-cache\r\nPragma:
no-cache\r\nConnection: close\r\nContent-Length: 54000000\r\n");
if (info.location)
sock_write_line (con->sock, "x-audiocast-location: %s",
info.location);
if (info.rp_email)
sock_write_line (con->sock, "x-audiocast-admin: %s",
info.rp_email);
if (info.server_url)
sock_write_line (con->sock, "x-audiocast-server-url: %s",
info.server_url);
if (client_wants_relay_ids (con))
print_relay_ids (con, source);
if (client_wants_metadata (con))
sock_write_line (con->sock, "icy-metaint:%u",
info.metainterval);
if (client_wants_udp_info (con))
sock_write_line (con->sock, "x-audiocast-udpport: %d",
info.port[0]);
sock_write (con->sock,
"x-audiocast-mount:%s\r\nx-audiocast-name:%s\r\nx-audiocast-description:%s\r\nx-audiocast-url:%s\r\nx-audiocast-genre:%s\r\nx-audiocast-bitrate:%d\r\nx-audiocast-public:%d\r\n\r\n",
nullcheck_string (source->audiocast.mount), nullcheck_string
(source->audiocast.name), nullcheck_string
(source->audiocast.description), nullcheck_string (source->audiocast.url),
nullcheck_string (source->audiocast.genre), source->audiocast.bitrate,
source->audiocast.public);
}
sock_set_blocking(con->sock, SOCK_NONBLOCK);
#ifdef _WIN32
setsockopt(con->sock, SOL_SOCKET, SO_SNDBUF, (char *)&bufsize,
sizeof(int));
#endif
con->food.client->virgin = 1;
if (con->food.client->type == pulling_client_e) {
char* title = NULL;
char* msg = NULL;
char length[11];
char* url = NULL;
url_encode (source->info.streamtitle, &title);
url_encode (source->info.streammsg, &msg);
snprintf (length, sizeof (length), "%ld",
source->info.streamlength);
url_encode (source->info.streamurl, &url);
update_metadata_on_relay (con, source->audiocast.mount, title, msg,
length, url);
nfree (title);
nfree (msg);
nfree (url);
}
}
void
describe_client (const com_request_t *req, const connection_t *clicon)
{
const client_t *client;
if (!req || !clicon)
{
xa_debug (1, "WARNING: describe_client(): called with NULL
pointers");
return;
}
if (clicon->type != client_e)
{
xa_debug (1, "WARNING: describe_client(): called with invalid
type");
return;
}
describe_connection (req, clicon);
client = clicon->food.client;
admin_write_line (req, ADMIN_SHOW_DESCRIBE_CLIENT_START, "Misc client
info:");
admin_write_line (req, ADMIN_SHOW_DESCRIBE_CLIENT_MISC, "UDPinfo:
%s", client->use_udp ? "yes" : "no");
if (client->use_udp)
admin_write_line (req, ADMIN_SHOW_DESCRIBE_CLIENT_MISC, "UDP client port:
%d", htons (clicon->sin->sin_port));
admin_write_line (req, ADMIN_SHOW_DESCRIBE_CLIENT_MISC, "UDP sequence
number: %d", client->udpseqnr);
admin_write_line (req, ADMIN_SHOW_DESCRIBE_CLIENT_MISC, "ICY metadata:
%s", client->use_icy_metadata ? "yes" : "no");
admin_write_line (req, ADMIN_SHOW_DESCRIBE_CLIENT_MISC, "Transfer error
balance: %d", client_errors (client));
admin_write_line (req, ADMIN_SHOW_DESCRIBE_CLIENT_MISC, "Transfer chunk id
and offset: %d : %d", client->cid, client->offset);
admin_write_line (req, ADMIN_SHOW_DESCRIBE_CLIENT_MISC, "Bytes transfered:
%lu", client->write_bytes);
admin_write_line (req, ADMIN_SHOW_DESCRIBE_CLIENT_MISC, "Virgin: %s",
client->virgin ? "yes" : "no");
admin_write_line (req, ADMIN_SHOW_DESCRIBE_CLIENT_MISC, "Client type:
%s", client_type (clicon));
if (client->source && client->source->audiocast.mount)
admin_write_line (req, ADMIN_SHOW_DESCRIBE_CLIENT_MISC, "Mountpoint:
%s", client->source->audiocast.mount);
admin_write_line (req, ADMIN_SHOW_DESCRIBE_CLIENT_END, "End of client
info");
}
const char client_types[4][16] = { "listener", "pusher",
"puller", "unknown listener" };
const char *
client_type (const connection_t *clicon)
{
switch (clicon->food.client->type)
{
case listener_e:
return client_types[0];
break;
case pusher_e:
return client_types[1];
break;
case pulling_client_e:
return client_types[2];
break;
default:
return client_types[3];
break;
}
}
int
client_errors (const client_t *client)
{
if (!client || !client->source)
return 0;
return (CHUNKLEN - (client->cid - client->source->cid)) % CHUNKLEN;
}
-------------- next part --------------
/* client.c
**
** client interface implementation
**
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h>
#include <string.h>
#include "thread/thread.h"
#include "avl/avl.h"
#include "httpp/httpp.h"
#include "connection.h"
#include "refbuf.h"
#include "client.h"
#include "logging.h"
client_t *client_create(connection_t *con, http_parser_t *parser)
{
client_t *client = (client_t *)calloc(1, sizeof(client_t));
client->con = con;
client->parser = parser;
client->queue = NULL;
client->pos = 0;
return client;
}
void client_destroy(client_t *client)
{
refbuf_t *refbuf;
/* write log entry if ip is set (some things don't set it, like outgoing
* slave requests
*/
if(client->con->ip)
logging_access(client);
connection_close(client->con);
httpp_destroy(client->parser);
while ((refbuf = refbuf_queue_remove(&client->queue)))
refbuf_release(refbuf);
free(client);
}
void client_send_400(client_t *client, char *message) {
int bytes;
bytes = sock_write(client->con->sock, "HTTP/1.0 404 File Not
Found\r\n"
"Content-Type: text/html\r\n\r\n"
"<b>%s</b>\r\n", message);
if(bytes > 0) client->con->sent_bytes = bytes;
client->respcode = 404;
client_destroy(client);
}
void client_send_404(client_t *client, char *message) {
int bytes;
bytes = sock_write(client->con->sock, "HTTP/1.0 404 File Not
Found\r\n"
"Content-Type: text/html\r\n\r\n"
"<b>%s</b>\r\n", message);
if(bytes > 0) client->con->sent_bytes = bytes;
client->respcode = 404;
client_destroy(client);
}
void client_send_504(client_t *client, char *message) {
int bytes;
client->respcode = 504;
bytes = sock_write(client->con->sock,
"HTTP/1.0 504 Server Full\r\n"
"Content-Type: text/html\r\n\r\n"
"<b>%s</b>\r\n", message);
if (bytes > 0) client->con->sent_bytes = bytes;
client_destroy(client);
}
void client_send_401(client_t *client) {
int bytes = sock_write(client->con->sock,
"HTTP/1.0 401 Authentication Required\r\n"
"WWW-Authenticate: Basic realm=\"Icecast2
Server\"\r\n"
"\r\n"
"You need to authenticate\r\n");
if(bytes > 0) client->con->sent_bytes = bytes;
client->respcode = 401;
client_destroy(client);
}