|
Packit Service |
102f81 |
/* util.c: libshout utility/portability functions
|
|
Packit Service |
102f81 |
*
|
|
Packit Service |
102f81 |
* Copyright (C) 2002-2003 the Icecast team <team@icecast.org>
|
|
Packit Service |
102f81 |
*
|
|
Packit Service |
102f81 |
* This library is free software; you can redistribute it and/or
|
|
Packit Service |
102f81 |
* modify it under the terms of the GNU Library General Public
|
|
Packit Service |
102f81 |
* License as published by the Free Software Foundation; either
|
|
Packit Service |
102f81 |
* version 2 of the License, or (at your option) any later version.
|
|
Packit Service |
102f81 |
*
|
|
Packit Service |
102f81 |
* This library is distributed in the hope that it will be useful,
|
|
Packit Service |
102f81 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
102f81 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit Service |
102f81 |
* Library General Public License for more details.
|
|
Packit Service |
102f81 |
*
|
|
Packit Service |
102f81 |
* You should have received a copy of the GNU Library General Public
|
|
Packit Service |
102f81 |
* License along with this library; if not, write to the Free
|
|
Packit Service |
102f81 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
Packit Service |
102f81 |
*/
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
#ifdef HAVE_CONFIG_H
|
|
Packit Service |
102f81 |
#include <config.h>
|
|
Packit Service |
102f81 |
#endif
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
#include <stdio.h>
|
|
Packit Service |
102f81 |
#include <string.h>
|
|
Packit Service |
102f81 |
#include <stdlib.h>
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
#include <sys/types.h>
|
|
Packit Service |
102f81 |
#ifdef HAVE_SYS_SOCKET_H
|
|
Packit Service |
102f81 |
#include <sys/socket.h>
|
|
Packit Service |
102f81 |
#endif
|
|
Packit Service |
102f81 |
#ifdef HAVE_WINSOCK2_H
|
|
Packit Service |
102f81 |
#include <winsock2.h>
|
|
Packit Service |
102f81 |
#endif
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
#include <shout/shout.h>
|
|
Packit Service |
102f81 |
#include "util.h"
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
char *_shout_util_strdup(const char *s)
|
|
Packit Service |
102f81 |
{
|
|
Packit Service |
102f81 |
if (!s)
|
|
Packit Service |
102f81 |
return NULL;
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
return strdup(s);
|
|
Packit Service |
102f81 |
}
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
int _shout_util_read_header(int sock, char *buff, unsigned long len)
|
|
Packit Service |
102f81 |
{
|
|
Packit Service |
102f81 |
int read_bytes, ret;
|
|
Packit Service |
102f81 |
unsigned long pos;
|
|
Packit Service |
102f81 |
char c;
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
read_bytes = 1;
|
|
Packit Service |
102f81 |
pos = 0;
|
|
Packit Service |
102f81 |
ret = 0;
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
while ((read_bytes == 1) && (pos < (len - 1))) {
|
|
Packit Service |
102f81 |
read_bytes = 0;
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
if ((read_bytes = recv(sock, &c, 1, 0))) {
|
|
Packit Service |
102f81 |
if (c != '\r')
|
|
Packit Service |
102f81 |
buff[pos++] = c;
|
|
Packit Service |
102f81 |
if ((pos > 1) && (buff[pos - 1] == '\n' && buff[pos - 2] == '\n')) {
|
|
Packit Service |
102f81 |
ret = 1;
|
|
Packit Service |
102f81 |
break;
|
|
Packit Service |
102f81 |
}
|
|
Packit Service |
102f81 |
} else {
|
|
Packit Service |
102f81 |
break;
|
|
Packit Service |
102f81 |
}
|
|
Packit Service |
102f81 |
}
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
if (ret) buff[pos] = '\0';
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
return ret;
|
|
Packit Service |
102f81 |
}
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
static char base64table[65] = {
|
|
Packit Service |
102f81 |
'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
|
|
Packit Service |
102f81 |
'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
|
|
Packit Service |
102f81 |
'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
|
|
Packit Service |
102f81 |
'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/',
|
|
Packit Service |
102f81 |
};
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
/* This isn't efficient, but it doesn't need to be */
|
|
Packit Service |
102f81 |
char *_shout_util_base64_encode(char *data)
|
|
Packit Service |
102f81 |
{
|
|
Packit Service |
102f81 |
int len = strlen(data);
|
|
Packit Service |
102f81 |
char *out = malloc(len*4/3 + 4);
|
|
Packit Service |
102f81 |
char *result = out;
|
|
Packit Service |
102f81 |
int chunk;
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
while(len > 0) {
|
|
Packit Service |
102f81 |
chunk = (len >3)?3:len;
|
|
Packit Service |
102f81 |
*out++ = base64table[(*data & 0xFC)>>2];
|
|
Packit Service |
102f81 |
*out++ = base64table[((*data & 0x03)<<4) | ((*(data+1) & 0xF0) >> 4)];
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
switch(chunk) {
|
|
Packit Service |
102f81 |
case 3:
|
|
Packit Service |
102f81 |
*out++ = base64table[((*(data+1) & 0x0F)<<2) | ((*(data+2) & 0xC0)>>6)];
|
|
Packit Service |
102f81 |
*out++ = base64table[(*(data+2)) & 0x3F];
|
|
Packit Service |
102f81 |
break;
|
|
Packit Service |
102f81 |
case 2:
|
|
Packit Service |
102f81 |
*out++ = base64table[((*(data+1) & 0x0F)<<2)];
|
|
Packit Service |
102f81 |
*out++ = '=';
|
|
Packit Service |
102f81 |
break;
|
|
Packit Service |
102f81 |
case 1:
|
|
Packit Service |
102f81 |
*out++ = '=';
|
|
Packit Service |
102f81 |
*out++ = '=';
|
|
Packit Service |
102f81 |
break;
|
|
Packit Service |
102f81 |
}
|
|
Packit Service |
102f81 |
data += chunk;
|
|
Packit Service |
102f81 |
len -= chunk;
|
|
Packit Service |
102f81 |
}
|
|
Packit Service |
102f81 |
*out = 0;
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
return result;
|
|
Packit Service |
102f81 |
}
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
static char urltable[16] = {
|
|
Packit Service |
102f81 |
'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'
|
|
Packit Service |
102f81 |
};
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
static char safechars[256] = {
|
|
Packit Service |
102f81 |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
Packit Service |
102f81 |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
Packit Service |
102f81 |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
Packit Service |
102f81 |
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
|
|
Packit Service |
102f81 |
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
Packit Service |
102f81 |
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
|
|
Packit Service |
102f81 |
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
Packit Service |
102f81 |
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
|
|
Packit Service |
102f81 |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
Packit Service |
102f81 |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
Packit Service |
102f81 |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
Packit Service |
102f81 |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
Packit Service |
102f81 |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
Packit Service |
102f81 |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
Packit Service |
102f81 |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
Packit Service |
102f81 |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
Packit Service |
102f81 |
};
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
/* modified from libshout1, which credits Rick Franchuk <rickf@transpect.net>.
|
|
Packit Service |
102f81 |
* Caller must free result. */
|
|
Packit Service |
102f81 |
char *_shout_util_url_encode(const char *data) {
|
|
Packit Service |
102f81 |
const char *p;
|
|
Packit Service |
102f81 |
char *q, *dest;
|
|
Packit Service |
102f81 |
int digit;
|
|
Packit Service |
102f81 |
size_t n;
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
for (p = data, n = 0; *p; p++) {
|
|
Packit Service |
102f81 |
n++;
|
|
Packit Service |
102f81 |
if (!safechars[(unsigned char)(*p)])
|
|
Packit Service |
102f81 |
n += 2;
|
|
Packit Service |
102f81 |
}
|
|
Packit Service |
102f81 |
if (!(dest = malloc(n+1)))
|
|
Packit Service |
102f81 |
return NULL;
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
for (p = data, q = dest; *p; p++, q++) {
|
|
Packit Service |
102f81 |
if (safechars[(unsigned char)(*p)]) {
|
|
Packit Service |
102f81 |
*q = *p;
|
|
Packit Service |
102f81 |
} else {
|
|
Packit Service |
102f81 |
*q++ = '%';
|
|
Packit Service |
102f81 |
digit = (*p >> 4) & 0xF;
|
|
Packit Service |
102f81 |
*q++ = urltable[digit];
|
|
Packit Service |
102f81 |
digit = *p & 0xf;
|
|
Packit Service |
102f81 |
*q = urltable[digit];
|
|
Packit Service |
102f81 |
n += 2;
|
|
Packit Service |
102f81 |
}
|
|
Packit Service |
102f81 |
}
|
|
Packit Service |
102f81 |
*q = '\0';
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
return dest;
|
|
Packit Service |
102f81 |
}
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
util_dict *_shout_util_dict_new(void)
|
|
Packit Service |
102f81 |
{
|
|
Packit Service |
102f81 |
return (util_dict *)calloc(1, sizeof(util_dict));
|
|
Packit Service |
102f81 |
}
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
void _shout_util_dict_free(util_dict *dict)
|
|
Packit Service |
102f81 |
{
|
|
Packit Service |
102f81 |
util_dict *next;
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
while (dict) {
|
|
Packit Service |
102f81 |
next = dict->next;
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
if (dict->key)
|
|
Packit Service |
102f81 |
free (dict->key);
|
|
Packit Service |
102f81 |
if (dict->val)
|
|
Packit Service |
102f81 |
free (dict->val);
|
|
Packit Service |
102f81 |
free (dict);
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
dict = next;
|
|
Packit Service |
102f81 |
}
|
|
Packit Service |
102f81 |
}
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
const char *_shout_util_dict_get(util_dict *dict, const char *key)
|
|
Packit Service |
102f81 |
{
|
|
Packit Service |
102f81 |
while (dict) {
|
|
Packit Service |
102f81 |
if (dict->key && !strcmp(key, dict->key))
|
|
Packit Service |
102f81 |
return dict->val;
|
|
Packit Service |
102f81 |
dict = dict->next;
|
|
Packit Service |
102f81 |
}
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
return NULL;
|
|
Packit Service |
102f81 |
}
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
int _shout_util_dict_set(util_dict *dict, const char *key, const char *val)
|
|
Packit Service |
102f81 |
{
|
|
Packit Service |
102f81 |
util_dict *prev;
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
if (!dict || !key)
|
|
Packit Service |
102f81 |
return SHOUTERR_INSANE;
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
prev = NULL;
|
|
Packit Service |
102f81 |
while (dict) {
|
|
Packit Service |
102f81 |
if (!dict->key || !strcmp(dict->key, key))
|
|
Packit Service |
102f81 |
break;
|
|
Packit Service |
102f81 |
prev = dict;
|
|
Packit Service |
102f81 |
dict = dict->next;
|
|
Packit Service |
102f81 |
}
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
if (!dict) {
|
|
Packit Service |
102f81 |
dict = _shout_util_dict_new();
|
|
Packit Service |
102f81 |
if (!dict)
|
|
Packit Service |
102f81 |
return SHOUTERR_MALLOC;
|
|
Packit Service |
102f81 |
if (prev)
|
|
Packit Service |
102f81 |
prev->next = dict;
|
|
Packit Service |
102f81 |
}
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
if (dict->key)
|
|
Packit Service |
102f81 |
free (dict->val);
|
|
Packit Service |
102f81 |
else if (!(dict->key = strdup(key))) {
|
|
Packit Service |
102f81 |
if (prev)
|
|
Packit Service |
102f81 |
prev->next = NULL;
|
|
Packit Service |
102f81 |
_shout_util_dict_free (dict);
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
return SHOUTERR_MALLOC;
|
|
Packit Service |
102f81 |
}
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
dict->val = strdup(val);
|
|
Packit Service |
102f81 |
if (!dict->val) {
|
|
Packit Service |
102f81 |
return SHOUTERR_MALLOC;
|
|
Packit Service |
102f81 |
}
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
return SHOUTERR_SUCCESS;
|
|
Packit Service |
102f81 |
}
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
/* given a dictionary, URL-encode each key and val and stringify them in order as
|
|
Packit Service |
102f81 |
key=val&key=val... if val is set, or just key&key if val is NULL.
|
|
Packit Service |
102f81 |
TODO: Memory management needs overhaul. */
|
|
Packit Service |
102f81 |
char *_shout_util_dict_urlencode(util_dict *dict, char delim)
|
|
Packit Service |
102f81 |
{
|
|
Packit Service |
102f81 |
char *res, *tmp;
|
|
Packit Service |
102f81 |
char *enc;
|
|
Packit Service |
102f81 |
int start = 1;
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
for (res = NULL; dict; dict = dict->next) {
|
|
Packit Service |
102f81 |
/* encode key */
|
|
Packit Service |
102f81 |
if (!dict->key)
|
|
Packit Service |
102f81 |
continue;
|
|
Packit Service |
102f81 |
if (!(enc = _shout_util_url_encode(dict->key))) {
|
|
Packit Service |
102f81 |
if (res)
|
|
Packit Service |
102f81 |
free(res);
|
|
Packit Service |
102f81 |
return NULL;
|
|
Packit Service |
102f81 |
}
|
|
Packit Service |
102f81 |
if (start) {
|
|
Packit Service |
102f81 |
if (!(res = malloc(strlen(enc) + 1))) {
|
|
Packit Service |
102f81 |
free(enc);
|
|
Packit Service |
102f81 |
return NULL;
|
|
Packit Service |
102f81 |
}
|
|
Packit Service |
102f81 |
sprintf(res, "%s", enc);
|
|
Packit Service |
102f81 |
free(enc);
|
|
Packit Service |
102f81 |
start = 0;
|
|
Packit Service |
102f81 |
} else {
|
|
Packit Service |
102f81 |
if (!(tmp = realloc(res, strlen(res) + strlen(enc) + 2))) {
|
|
Packit Service |
102f81 |
free(enc);
|
|
Packit Service |
102f81 |
free(res);
|
|
Packit Service |
102f81 |
return NULL;
|
|
Packit Service |
102f81 |
} else
|
|
Packit Service |
102f81 |
res = tmp;
|
|
Packit Service |
102f81 |
sprintf(res + strlen(res), "%c%s", delim, enc);
|
|
Packit Service |
102f81 |
free(enc);
|
|
Packit Service |
102f81 |
}
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
/* encode value */
|
|
Packit Service |
102f81 |
if (!dict->val)
|
|
Packit Service |
102f81 |
continue;
|
|
Packit Service |
102f81 |
if (!(enc = _shout_util_url_encode(dict->val))) {
|
|
Packit Service |
102f81 |
free(res);
|
|
Packit Service |
102f81 |
return NULL;
|
|
Packit Service |
102f81 |
}
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
if (!(tmp = realloc(res, strlen(res) + strlen(enc) + 2))) {
|
|
Packit Service |
102f81 |
free(enc);
|
|
Packit Service |
102f81 |
free(res);
|
|
Packit Service |
102f81 |
return NULL;
|
|
Packit Service |
102f81 |
} else
|
|
Packit Service |
102f81 |
res = tmp;
|
|
Packit Service |
102f81 |
sprintf(res + strlen(res), "=%s", enc);
|
|
Packit Service |
102f81 |
free(enc);
|
|
Packit Service |
102f81 |
}
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
return res;
|
|
Packit Service |
102f81 |
}
|