client.c 6.3 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
#include "util.h"

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

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

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

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

    config = config_get_config ();
64
65

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

71
72
73
    config_release_config ();

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

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

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

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

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

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

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

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

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

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

157
158
159
160

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

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

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

    return bytes;
183
184
}

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

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

194
195
196
197
    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);
198

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

204
205
206
void client_send_400(client_t *client, char *message)
{
    client_send_error0(client, 400, 0, message);
207
208
}

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

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

219
220
void client_send_403(client_t *client, const char *reason)
{
221
    client_send_error0(client, 403, 1, "Forbidden");
222
}
223
224
225
226
227


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

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

233
234
235
    return ret;
}

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