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