client.c 6.39 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
/* 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).
Philipp Schafft's avatar
Philipp Schafft committed
11
 * Copyright 2011-2012, Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org>,
12 13
 */

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

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

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

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

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

#include "client.h"
#include "logging.h"
40

41 42
#include "util.h"

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

47 48 49
#undef CATMODULE
#define CATMODULE "client"

50 51 52 53 54
/* 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.
 */
55
int client_create (client_t **c_ptr, connection_t *con, http_parser_t *parser)
Jack Moffitt's avatar
Jack Moffitt committed
56
{
57
    ice_config_t *config;
58
    client_t *client = (client_t *)calloc(1, sizeof(client_t));
59 60 61
    int ret = -1;

    if (client == NULL)
62
        abort();
63 64

    config = config_get_config ();
65 66

    global.clients++;
67 68 69 70
    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
71

72 73 74
    config_release_config ();

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

83
    return ret;
Jack Moffitt's avatar
Jack Moffitt committed
84 85 86 87
}

void client_destroy(client_t *client)
{
Karl Heyes's avatar
Karl Heyes committed
88 89
    if (client == NULL)
        return;
90

91 92 93 94 95 96 97 98
    /* 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;
    }

99
    if (auth_release_listener (client))
100 101
        return;

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

108 109
    if (client->con)
        connection_close(client->con);
Karl Heyes's avatar
Karl Heyes committed
110 111
    if (client->parser)
        httpp_destroy(client->parser);
Jack Moffitt's avatar
Jack Moffitt committed
112

113 114 115 116 117
    global_lock ();
    global.clients--;
    stats_event_args (NULL, "clients", "%d", global.clients);
    global_unlock ();

118 119 120 121
    /* 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
122
    free(client->username);
Karl Heyes's avatar
Karl Heyes committed
123
    free(client->password);
Michael Smith's avatar
Michael Smith committed
124

125
    free(client);
Jack Moffitt's avatar
Jack Moffitt committed
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 155 156 157
/* 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;
}

158 159 160 161

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

164 165 166 167 168 169
    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);
170
        if (len < client->refbuf->len)
171 172 173 174 175 176 177
        {
            char *ptr = client->refbuf->data;
            memmove (ptr, ptr+len, client->refbuf->len - len);
        }
        client->refbuf->len -= len;
        return len;
    }
178
    bytes = client->con->read (client->con, buf, len);
179

180 181 182 183
    if (bytes == -1 && client->con->error)
        DEBUG0 ("reading from connection has failed");

    return bytes;
184 185
}

186
static void client_send_error(client_t *client, int status, int plain, const char *message)
187
{
188 189 190
    ssize_t ret;

    ret = util_http_build_header(client->refbuf->data, PER_CLIENT_REFBUF_SIZE, 0,
191 192 193
                                 0, status, NULL,
                                 plain ? "text/plain" : "text/html", NULL,
                                 plain ? message : "");
194

195 196 197 198
    if (!plain)
        snprintf(client->refbuf->data + ret, PER_CLIENT_REFBUF_SIZE - ret,
                 "<html><head><title>Error %i</title></head><body><b>%i - %s</b></body></html>\r\n",
                 status, status, message);
199

200
    client->respcode = status;
201 202
    client->refbuf->len = strlen (client->refbuf->data);
    fserve_add_client (client, NULL);
203 204
}

205
void client_send_400(client_t *client, const char *message)
206
{
207
    client_send_error(client, 400, 0, message);
208 209
}

210
void client_send_404(client_t *client, const char *message)
211
{
212
    client_send_error(client, 404, 0, message);
213
}
Michael Smith's avatar
Michael Smith committed
214

215 216
void client_send_401(client_t *client)
{
217
    client_send_error(client, 401, 1, "You need to authenticate\r\n");
218
}
219

220
void client_send_403(client_t *client, const char *message)
221
{
222
    client_send_error(client, 403, 1, message);
223
}
224 225 226 227 228


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

    if (client->con->error)
232
        DEBUG0 ("Client connection died");
233

234 235 236
    return ret;
}

Karl Heyes's avatar
Karl Heyes committed
237 238 239 240 241
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
242 243
    if (refbuf)
        refbuf_addref (client->refbuf);
Karl Heyes's avatar
Karl Heyes committed
244 245 246 247 248
    client->pos = 0;
    if (to_release)
        refbuf_release (to_release);
}