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