client.c 6.85 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 187 188 189 190 191 192 193 194
    ssize_t ret;

    ret = util_http_build_header(client->refbuf->data, PER_CLIENT_REFBUF_SIZE, 0,
                                 0, 400, NULL,
                                 "text/html", NULL,
                                 "");

    snprintf(client->refbuf->data + ret, PER_CLIENT_REFBUF_SIZE - ret,
             "<b>%s</b>\r\n", message);

195
    client->respcode = 400;
196 197
    client->refbuf->len = strlen (client->refbuf->data);
    fserve_add_client (client, NULL);
198 199
}

200
void client_send_404(client_t *client, char *message) {
201 202 203 204 205 206 207 208 209
    ssize_t ret;

    ret = util_http_build_header(client->refbuf->data, PER_CLIENT_REFBUF_SIZE, 0,
                                 0, 404, NULL,
                                 "text/html", NULL,
                                 "");

    snprintf(client->refbuf->data + ret, PER_CLIENT_REFBUF_SIZE - ret,
             "<b>%s</b>\r\n", message);
210

211
    client->respcode = 404;
212 213
    client->refbuf->len = strlen (client->refbuf->data);
    fserve_add_client (client, NULL);
214 215
}

Michael Smith's avatar
Michael Smith committed
216

217
void client_send_401(client_t *client) {
218 219 220 221
    util_http_build_header(client->refbuf->data, PER_CLIENT_REFBUF_SIZE, 0,
                           0, 401, NULL,
			   "text/plain", NULL,
			   "You need to authenticate\r\n");
222
    client->respcode = 401;
223 224
    client->refbuf->len = strlen (client->refbuf->data);
    fserve_add_client (client, NULL);
225
}
226

227 228
void client_send_403(client_t *client, const char *reason)
{
229 230 231 232
    util_http_build_header(client->refbuf->data, PER_CLIENT_REFBUF_SIZE, 0,
                           0, 403, reason,
			   "text/plain", NULL,
			   "Forbidden");
233
    client->respcode = 403;
234 235
    client->refbuf->len = strlen (client->refbuf->data);
    fserve_add_client (client, NULL);
236
}
237 238 239 240 241


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

    if (client->con->error)
245
        DEBUG0 ("Client connection died");
246

247 248 249
    return ret;
}

Karl Heyes's avatar
Karl Heyes committed
250 251 252 253 254
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
255 256
    if (refbuf)
        refbuf_addref (client->refbuf);
Karl Heyes's avatar
Karl Heyes committed
257 258 259 260 261
    client->pos = 0;
    if (to_release)
        refbuf_release (to_release);
}