client.c 6.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12
/* 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@xiph.org, 
 *                      Michael Smith <msmith@xiph.org>,
 *                      oddsock <oddsock@xiph.org>,
 *                      Karl Heyes <karl@xiph.org>
 *                      and others (see AUTHORS for details).
 */

Jack Moffitt's avatar
Jack Moffitt committed
13 14 15 16 17 18
/* client.c
**
** client interface implementation
**
*/

19 20 21 22
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

Jack Moffitt's avatar
Jack Moffitt committed
23 24 25
#include <stdlib.h>
#include <string.h>

Karl Heyes's avatar
Karl Heyes committed
26 27 28
#include "thread/thread.h"
#include "avl/avl.h"
#include "httpp/httpp.h"
Jack Moffitt's avatar
Jack Moffitt committed
29

30
#include "cfgfile.h"
Jack Moffitt's avatar
Jack Moffitt committed
31 32
#include "connection.h"
#include "refbuf.h"
Karl Heyes's avatar
Karl Heyes committed
33
#include "format.h"
34
#include "stats.h"
35
#include "fserve.h"
Jack Moffitt's avatar
Jack Moffitt committed
36 37 38

#include "client.h"
#include "logging.h"
39 40 41 42

#ifdef _WIN32
#define snprintf _snprintf
#endif
Jack Moffitt's avatar
Jack Moffitt committed
43

44 45 46
#undef CATMODULE
#define CATMODULE "client"

47 48 49 50 51
/* create a client_t with the provided connection and parser details. Return
 * 0 on success, -1 if server limit has been reached.  In either case a
 * client_t is returned just in case a message needs to be returned. Should
 * be called with global lock held.
 */
52
int client_create (client_t **c_ptr, connection_t *con, http_parser_t *parser)
Jack Moffitt's avatar
Jack Moffitt committed
53
{
54
    ice_config_t *config;
55
    client_t *client = (client_t *)calloc(1, sizeof(client_t));
56 57 58
    int ret = -1;

    if (client == NULL)
59
        abort();
60 61

    config = config_get_config ();
62 63

    global.clients++;
64 65 66 67
    if (config->client_limit < global.clients)
        WARN2 ("server client limit reached (%d/%d)", config->client_limit, global.clients);
    else
        ret = 0;
Jack Moffitt's avatar
Jack Moffitt committed
68

69 70 71
    config_release_config ();

    stats_event_args (NULL, "clients", "%d", global.clients);
72 73
    client->con = con;
    client->parser = parser;
74 75
    client->refbuf = refbuf_new (PER_CLIENT_REFBUF_SIZE);
    client->refbuf->len = 0; /* force reader code to ignore buffer contents */
76
    client->pos = 0;
77
    client->write_to_client = format_generic_write_to_client;
78
    *c_ptr = client;
Jack Moffitt's avatar
Jack Moffitt committed
79

80
    return ret;
Jack Moffitt's avatar
Jack Moffitt committed
81 82 83 84
}

void client_destroy(client_t *client)
{
Karl Heyes's avatar
Karl Heyes committed
85 86
    if (client == NULL)
        return;
87

88 89 90 91 92 93 94 95
    /* release the buffer now, as the buffer could be on the source queue
     * and may of disappeared after auth completes */
    if (client->refbuf)
    {
        refbuf_release (client->refbuf);
        client->refbuf = NULL;
    }

96
    if (auth_release_listener (client))
97 98
        return;

99
    /* write log entry if ip is set (some things don't set it, like outgoing 
100 101
     * slave requests
     */
Karl Heyes's avatar
Karl Heyes committed
102
    if (client->respcode && client->parser)
103
        logging_access(client);
104

105 106
    if (client->con)
        connection_close(client->con);
Karl Heyes's avatar
Karl Heyes committed
107 108
    if (client->parser)
        httpp_destroy(client->parser);
Jack Moffitt's avatar
Jack Moffitt committed
109

110 111 112 113 114
    global_lock ();
    global.clients--;
    stats_event_args (NULL, "clients", "%d", global.clients);
    global_unlock ();

115 116 117 118
    /* we need to free client specific format data (if any) */
    if (client->free_client_data)
        client->free_client_data (client);

Michael Smith's avatar
Michael Smith committed
119
    free(client->username);
Karl Heyes's avatar
Karl Heyes committed
120
    free(client->password);
Michael Smith's avatar
Michael Smith committed
121

122
    free(client);
Jack Moffitt's avatar
Jack Moffitt committed
123
}
124

125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
/* return -1 for failed, 0 for authenticated, 1 for pending
 */
int client_check_source_auth (client_t *client, const char *mount)
{
    ice_config_t *config = config_get_config();
    char *pass = config->source_password;
    char *user = "source";
    int ret = -1;
    mount_proxy *mountinfo = config_find_mount (config, mount);

    do
    {
        if (mountinfo)
        {
            ret = 1;
            if (auth_stream_authenticate (client, mount, mountinfo) > 0)
                break;
            ret = -1;
            if (mountinfo->password)
                pass = mountinfo->password;
            if (mountinfo->username)
                user = mountinfo->username;
        }
        if (connection_check_pass (client->parser, user, pass) > 0)
            ret = 0;
    } while (0);
    config_release_config();
    return ret;
}

155 156 157 158

/* helper function for reading data from a client */
int client_read_bytes (client_t *client, void *buf, unsigned len)
{
159
    int bytes;
160

161 162 163 164 165 166
    if (client->refbuf && client->refbuf->len)
    {
        /* we have data to read from a refbuf first */
        if (client->refbuf->len < len)
            len = client->refbuf->len;
        memcpy (buf, client->refbuf->data, len);
167
        if (len < client->refbuf->len)
168 169 170 171 172 173 174
        {
            char *ptr = client->refbuf->data;
            memmove (ptr, ptr+len, client->refbuf->len - len);
        }
        client->refbuf->len -= len;
        return len;
    }
175
    bytes = client->con->read (client->con, buf, len);
176

177 178 179 180
    if (bytes == -1 && client->con->error)
        DEBUG0 ("reading from connection has failed");

    return bytes;
181 182 183
}


184
void client_send_400(client_t *client, char *message) {
185 186
    snprintf (client->refbuf->data, PER_CLIENT_REFBUF_SIZE,
            "HTTP/1.0 400 Bad Request\r\n"
187 188
            "Content-Type: text/html\r\n\r\n"
            "<b>%s</b>\r\n", message);
189
    client->respcode = 400;
190 191
    client->refbuf->len = strlen (client->refbuf->data);
    fserve_add_client (client, NULL);
192 193
}

194 195
void client_send_404(client_t *client, char *message) {

196 197
    snprintf (client->refbuf->data, PER_CLIENT_REFBUF_SIZE,
            "HTTP/1.0 404 File Not Found\r\n"
198 199
            "Content-Type: text/html\r\n\r\n"
            "<b>%s</b>\r\n", message);
200
    client->respcode = 404;
201 202
    client->refbuf->len = strlen (client->refbuf->data);
    fserve_add_client (client, NULL);
203 204
}

Michael Smith's avatar
Michael Smith committed
205

206
void client_send_401(client_t *client) {
207
    snprintf (client->refbuf->data, PER_CLIENT_REFBUF_SIZE,
208 209 210 211
            "HTTP/1.0 401 Authentication Required\r\n"
            "WWW-Authenticate: Basic realm=\"Icecast2 Server\"\r\n"
            "\r\n"
            "You need to authenticate\r\n");
212
    client->respcode = 401;
213 214
    client->refbuf->len = strlen (client->refbuf->data);
    fserve_add_client (client, NULL);
215
}
216

217 218 219 220 221 222
void client_send_403(client_t *client, const char *reason)
{
    if (reason == NULL)
        reason = "Forbidden";
    snprintf (client->refbuf->data, PER_CLIENT_REFBUF_SIZE,
            "HTTP/1.0 403 %s\r\n\r\n", reason);
223
    client->respcode = 403;
224 225
    client->refbuf->len = strlen (client->refbuf->data);
    fserve_add_client (client, NULL);
226
}
227 228 229 230 231


/* helper function for sending the data to a client */
int client_send_bytes (client_t *client, const void *buf, unsigned len)
{
232 233 234
    int ret = client->con->send (client->con, buf, len);

    if (client->con->error)
235
        DEBUG0 ("Client connection died");
236

237 238 239
    return ret;
}

Karl Heyes's avatar
Karl Heyes committed
240 241 242 243 244
void client_set_queue (client_t *client, refbuf_t *refbuf)
{
    refbuf_t *to_release = client->refbuf;

    client->refbuf = refbuf;
Karl Heyes's avatar
Karl Heyes committed
245 246
    if (refbuf)
        refbuf_addref (client->refbuf);
Karl Heyes's avatar
Karl Heyes committed
247 248 249 250 251
    client->pos = 0;
    if (to_release)
        refbuf_release (to_release);
}