event_url.c 4.75 KB
Newer Older
1
2
3
4
5
/* Icecast
 *
 * This program is distributed under the GNU General Public License, version 2.
 * A copy of this license is included with this source.
 *
6
 * Copyright 2014-2018, Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org>,
7
8
9
10
11
12
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

Philipp Schafft's avatar
Philipp Schafft committed
13
#include <string.h>
14

15
#include "curl.h"
16
#include "event.h"
17
18
#include "cfgfile.h"
#include "util.h"
19
20
21
22
23
24
25
26
27
28
29
30
31
#include "logging.h"
#define CATMODULE "event_url"


typedef struct event_url {
    char *url;
    char *action;
    char *userpwd;
    CURL *handle;
    char errormsg[CURL_ERROR_SIZE];
} event_url_t;

static size_t handle_returned (void *ptr, size_t size, size_t nmemb, void *stream) {
32
    (void)ptr, (void)stream;
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
    return size * nmemb;
}

static inline char *__escape(const char *src, const char *default_value) {
    if (src)
        return util_url_escape(src);

    return strdup(default_value);
}

static int event_url_emit(void *state, event_t *event) {
    event_url_t *self = state;
    ice_config_t *config;
    char *action, *mount, *server, *role, *username, *ip, *agent;
    time_t duration;
    char post[4096];

    action   = util_url_escape(self->action ? self->action : event->trigger);
    mount    = __escape(event->uri, "");
    role     = __escape(event->client_role, "");
    username = __escape(event->client_username, "");
    ip       = __escape(event->connection_ip, "");
    agent    = __escape(event->client_useragent, "-");

    if (event->connection_time) {
        duration = time(NULL) - event->connection_time;
    } else {
        duration = 0;
    }

    config = config_get_config();
    server   = __escape(config->hostname, "");

    snprintf (post, sizeof (post),
            "action=%s&mount=%s&server=%s&port=%d&client=%lu&role=%s&username=%s&ip=%s&agent=%s&duration=%lli&admin=%i",
            action, mount, server, config->port,
            event->connection_id, role, username, ip, agent, (long long int)duration, event->client_admin_command);
    config_release_config();

    free(action);
    free(mount);
    free(server);
    free(role);
    free(username);
    free(ip);
    free(agent);

    if (strchr(self->url, '@') == NULL && self->userpwd) {
        curl_easy_setopt(self->handle, CURLOPT_USERPWD, self->userpwd);
    } else {
        curl_easy_setopt(self->handle, CURLOPT_USERPWD, "");
    }

86
    curl_easy_setopt(self->handle, CURLOPT_URL, self->url);
87
88
89
    curl_easy_setopt(self->handle, CURLOPT_POSTFIELDS, post);

    if (curl_easy_perform(self->handle))
90
        ICECAST_LOG_WARN("auth to server %s failed with %s", self->url, self->errormsg);
91
92
93
94
95
96

    return 0;
}

static void event_url_free(void *state) {
    event_url_t *self = state;
97
    icecast_curl_free(self->handle);
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
    free(self->url);
    free(self->action);
    free(self->userpwd);
    free(self);
}

int event_get_url(event_registration_t *er, config_options_t *options) {
    event_url_t *self = calloc(1, sizeof(event_url_t));
    const char *username = NULL;
    const char *password = NULL;

    if (!self)
        return -1;

    if (options) {
        do {
            if (options->type)
                continue;
            if (!options->name)
                continue;
118
            /* BEFORE RELEASE 2.5.0 DOCUMENT: Document supported options:
119
120
121
122
123
124
             * <option name="url" value="..." />
             * <option name="username" value="..." />
             * <option name="password" value="..." />
             * <option name="action" value="..." />
             */
            if (strcmp(options->name, "url") == 0) {
125
                util_replace_string(&(self->url), options->value);
126
127
128
129
130
            } else if (strcmp(options->name, "username") == 0) {
                username = options->value;
            } else if (strcmp(options->name, "password") == 0) {
                password = options->value;
            } else if (strcmp(options->name, "action") == 0) {
131
                util_replace_string(&(self->action), options->value);
132
133
134
135
136
137
            } else {
                ICECAST_LOG_ERROR("Unknown <option> tag with name %s.", options->name);
            }
        } while ((options = options->next));
    }

138
    self->handle = icecast_curl_new(NULL, NULL);
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163

    /* check if we are in sane state */
    if (!self->url || !self->handle) {
        event_url_free(self);
        return -1;
    }

    curl_easy_setopt(self->handle, CURLOPT_HEADERFUNCTION, handle_returned);
    curl_easy_setopt(self->handle, CURLOPT_ERRORBUFFER, self->errormsg);

    if (username && password) {
        size_t len = strlen(username) + strlen(password) + 2;
        self->userpwd = malloc(len);
        if (!self->userpwd) {
            event_url_free(self);
            return -1;
        }
        snprintf(self->userpwd, len, "%s:%s", username, password);
    }

    er->state = self;
    er->emit = event_url_emit;
    er->free = event_url_free;
    return 0;
}