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);
}