Browse Source

use iovec based sdp rewriting

git.mgm/mediaproxy-ng/2.2
Richard Fuchs 13 years ago
parent
commit
7ca74b399e
7 changed files with 215 additions and 103 deletions
  1. +57
    -18
      daemon/bencode.c
  2. +24
    -10
      daemon/bencode.h
  3. +53
    -30
      daemon/call.c
  4. +1
    -1
      daemon/call.h
  5. +3
    -0
      daemon/control_ng.c
  6. +64
    -43
      daemon/sdp.c
  7. +13
    -1
      daemon/sdp.h

+ 57
- 18
daemon/bencode.c View File

@ -189,27 +189,47 @@ static void __bencode_container_add(bencode_item_t *parent, bencode_item_t *chil
}
}
bencode_item_t *bencode_string_len(bencode_buffer_t *buf, const char *s, int len) {
static bencode_item_t *__bencode_string_alloc(bencode_buffer_t *buf, const void *base,
int str_len, int iov_len, int iov_cnt, bencode_type_t type)
{
bencode_item_t *ret;
int len_len;
assert((len <= 99999) && (len >= 0));
ret = __bencode_item_alloc(buf, strlen(s) + 7);
assert((str_len <= 99999) && (str_len >= 0));
ret = __bencode_item_alloc(buf, 7);
if (!ret)
return NULL;
len_len = sprintf(ret->__buf, "%d:", len);
len_len = sprintf(ret->__buf, "%d:", str_len);
ret->type = BENCODE_STRING;
ret->type = type;
ret->iov[0].iov_base = ret->__buf;
ret->iov[0].iov_len = len_len;
ret->iov[1].iov_base = (void *) s;
ret->iov[1].iov_len = len;
ret->iov_cnt = 2;
ret->str_len = len_len + len;
ret->iov[1].iov_base = (void *) base;
ret->iov[1].iov_len = iov_len;
ret->iov_cnt = iov_cnt + 1;
ret->str_len = len_len + str_len;
return ret;
}
bencode_item_t *bencode_string_len(bencode_buffer_t *buf, const char *s, int len) {
return __bencode_string_alloc(buf, s, len, len, 1, BENCODE_STRING);
}
bencode_item_t *bencode_string_iovec(bencode_buffer_t *buf, const struct iovec *iov, int iov_cnt, int str_len) {
int i;
if (iov_cnt < 0)
return NULL;
if (str_len < 0) {
str_len = 0;
for (i = 0; i < iov_cnt; i++)
str_len += iov[i].iov_len;
}
return __bencode_string_alloc(buf, iov, str_len, iov_cnt, iov_cnt, BENCODE_IOVEC);
}
bencode_item_t *bencode_integer(bencode_buffer_t *buf, long long int i) {
bencode_item_t *ret;
int alen, rlen;
@ -259,12 +279,20 @@ bencode_item_t *bencode_list_add(bencode_item_t *list, bencode_item_t *item) {
return item;
}
static int __bencode_iovec_cpy(struct iovec *out, const struct iovec *in, int num) {
out -= num;
memcpy(out, in, num * sizeof(*out));
return num;
}
static int __bencode_iovec_dump_rev(struct iovec *out, bencode_item_t *item) {
bencode_item_t *child;
struct iovec *orig = out;
if (item->iov[1].iov_base)
*--out = item->iov[1];
if (item->type == BENCODE_IOVEC)
out -= __bencode_iovec_cpy(out, item->iov[1].iov_base, item->iov[1].iov_len);
else if (item->iov[1].iov_base)
out -= __bencode_iovec_cpy(out, &item->iov[1], 1);
child = item->child;
while (child) {
@ -273,20 +301,32 @@ static int __bencode_iovec_dump_rev(struct iovec *out, bencode_item_t *item) {
}
assert(item->iov[0].iov_base != NULL);
*--out = item->iov[0];
out -= __bencode_iovec_cpy(out, &item->iov[0], 1);
assert((orig - out) == item->iov_cnt);
return item->iov_cnt;
}
static int __bencode_str_cpy(char *out, const struct iovec *in, int num) {
char *orig = out;
in += num;
while (--num >= 0) {
in--;
out -= in->iov_len;
memcpy(out, in->iov_base, in->iov_len);
}
return orig - out;
}
static int __bencode_str_dump_rev(char *out, bencode_item_t *item) {
bencode_item_t *child;
char *orig = out;
if (item->iov[1].iov_base) {
out -= item->iov[1].iov_len;
memcpy(out, item->iov[1].iov_base, item->iov[1].iov_len);
}
if (item->type == BENCODE_IOVEC)
out -= __bencode_str_cpy(out, item->iov[1].iov_base, item->iov[1].iov_len);
else if (item->iov[1].iov_base)
out -= __bencode_str_cpy(out, &item->iov[1], 1);
child = item->child;
while (child) {
@ -295,8 +335,7 @@ static int __bencode_str_dump_rev(char *out, bencode_item_t *item) {
}
assert(item->iov[0].iov_base != NULL);
out -= item->iov[0].iov_len;
memcpy(out, item->iov[0].iov_base, item->iov[0].iov_len);
out -= __bencode_str_cpy(out, &item->iov[0], 1);
assert((orig - out) == item->str_len);
return item->str_len;


+ 24
- 10
daemon/bencode.h View File

@ -38,6 +38,7 @@ enum bencode_type {
BENCODE_INTEGER, /* long long int */
BENCODE_LIST, /* flat list of other objects */
BENCODE_DICTIONARY, /* dictionary of key/values pairs. keys are always strings */
BENCODE_IOVEC, /* special case of a string, built through bencode_string_iovec() */
BENCODE_END_MARKER, /* used internally only */
};
@ -115,6 +116,10 @@ static inline bencode_item_t *bencode_dictionary_add_string(bencode_item_t *dict
/* Ditto, but for a "str" object */
static inline bencode_item_t *bencode_dictionary_add_str(bencode_item_t *dict, const char *key, const str *val);
/* XXX */
static inline bencode_item_t *bencode_dictionary_add_iovec(bencode_item_t *dict, const char *key,
const struct iovec *iov, int iov_cnt, int str_len);
/* Ditto again, but adds the str object (val) to the bencode_buffer_t's internal free list. When
* the bencode_item_t object is destroyed, BENCODE_FREE will be called on this pointer. */
static inline bencode_item_t *bencode_dictionary_add_str_free(bencode_item_t *dict, const char *key, str *val);
@ -135,6 +140,12 @@ bencode_item_t *bencode_list_add(bencode_item_t *list, bencode_item_t *item);
/* Convenience function to add a string item to a list */
static inline bencode_item_t *bencode_list_add_string(bencode_item_t *list, const char *s);
/*** STRING BUILDING & HANDLING ***/
/* Creates a new byte-string object. The given string does not have to be null-terminated, instead
* the length of the string is specified by the "len" parameter. Returns NULL if no memory could
* be allocated.
@ -142,24 +153,21 @@ static inline bencode_item_t *bencode_list_add_string(bencode_item_t *list, cons
* the complete document is finally encoded or sent out. */
bencode_item_t *bencode_string_len(bencode_buffer_t *buf, const char *s, int len);
/*** STRING BUILDING & HANDLING ***/
/* Creates a new byte-string object. The given string must be null-terminated. Otherwise identical
* to bencode_string_len(). */
static inline bencode_item_t *bencode_string(bencode_buffer_t *buf, const char *s);
/* Convenience function to compare a string object to a regular C string. Returns 2 if object
* isn't a string object, otherwise returns according to strcmp(). */
static inline int bencode_strcmp(bencode_item_t *a, const char *b);
/* Creates a new byte-string object from a "str" object. The string does not have to be null-
* terminated. */
static inline bencode_item_t *bencode_str(bencode_buffer_t *buf, const str *s);
/* XXX */
bencode_item_t *bencode_string_iovec(bencode_buffer_t *buf, const struct iovec *iov, int iov_cnt, int str_len);
/* Convenience function to compare a string object to a regular C string. Returns 2 if object
* isn't a string object, otherwise returns according to strcmp(). */
static inline int bencode_strcmp(bencode_item_t *a, const char *b);
/* Converts the string object "in" into a str object "out". Returns "out" on success, or NULL on
* error ("in" was NULL or not a string object). */
static inline str *bencode_get_str(bencode_item_t *in, str *out);
@ -469,4 +477,10 @@ static inline void bencode_buffer_freelist_add(bencode_buffer_t *buf, void *p) {
bencode_buffer_destroy_add(buf, BENCODE_FREE, p);
}
static inline bencode_item_t *bencode_dictionary_add_iovec(bencode_item_t *dict, const char *key,
const struct iovec *iov, int iov_cnt, int str_len)
{
return bencode_dictionary_add(dict, key, bencode_string_iovec(dict->buffer, iov, iov_cnt, str_len));
}
#endif

+ 53
- 30
daemon/call.c View File

@ -1473,47 +1473,57 @@ static void call_destroy(struct call *c) {
static int call_stream_address4(GString *o, struct peer *p, enum stream_address_format format) {
static int call_stream_address4(char *o, struct peer *p, enum stream_address_format format, int *len) {
struct callstream *cs = p->up;
u_int32_t ip4;
struct callmaster *m = cs->call->callmaster;
int l = 0;
if (format == SAF_NG)
g_string_append(o, "IP4 ");
if (format == SAF_NG) {
strcpy(o + l, "IP4 ");
l = 4;
}
ip4 = p->rtps[0].peer.ip46.s6_addr32[3];
if (!ip4)
g_string_append(o, "0.0.0.0");
if (!ip4) {
strcpy(o + l, "0.0.0.0");
l += 7;
}
else if (m->conf.adv_ipv4)
g_string_append_printf(o, IPF, IPP(m->conf.adv_ipv4));
l += sprintf(o + l, IPF, IPP(m->conf.adv_ipv4));
else
g_string_append_printf(o, IPF, IPP(m->conf.ipv4));
l += sprintf(o + l, IPF, IPP(m->conf.ipv4));
*len = l;
return AF_INET;
}
static int call_stream_address6(GString *o, struct peer *p, enum stream_address_format format) {
char ips[64];
static int call_stream_address6(char *o, struct peer *p, enum stream_address_format format, int *len) {
struct callmaster *m = p->up->call->callmaster;
int l = 0;
if (format == SAF_NG)
g_string_append(o, "IP6 ");
if (format == SAF_NG) {
strcpy(o + l, "IP4 ");
l += 4;
}
if (IN6_IS_ADDR_UNSPECIFIED(&p->rtps[0].peer.ip46))
g_string_append(o, "::");
if (IN6_IS_ADDR_UNSPECIFIED(&p->rtps[0].peer.ip46)) {
strcpy(o + l, "::");
l += 2;
}
else {
if (!IN6_IS_ADDR_UNSPECIFIED(&m->conf.adv_ipv6))
inet_ntop(AF_INET6, &m->conf.adv_ipv6, ips, sizeof(ips));
inet_ntop(AF_INET6, &m->conf.adv_ipv6, o + l, 45); /* lies... */
else
inet_ntop(AF_INET6, &m->conf.ipv6, ips, sizeof(ips));
g_string_append(o, ips);
inet_ntop(AF_INET6, &m->conf.ipv6, o + l, 45);
l += strlen(o + l);
}
*len = l;
return AF_INET6;
}
int call_stream_address(GString *o, struct peer *p, enum stream_address_format format) {
int call_stream_address(char *o, struct peer *p, enum stream_address_format format, int *len) {
struct callmaster *m;
struct peer *other;
@ -1521,15 +1531,24 @@ int call_stream_address(GString *o, struct peer *p, enum stream_address_format f
other = &p->up->peers[p->idx ^ 1];
if (other->desired_family == AF_INET)
return call_stream_address4(o, p, format);
return call_stream_address4(o, p, format, len);
if (other->desired_family == 0 && IN6_IS_ADDR_V4MAPPED(&other->rtps[0].peer.ip46))
return call_stream_address4(o, p, format);
return call_stream_address4(o, p, format, len);
if (other->desired_family == 0 && IN6_IS_ADDR_UNSPECIFIED(&other->rtps[0].peer.ip46))
return call_stream_address4(o, p, format);
return call_stream_address4(o, p, format, len);
if (IN6_IS_ADDR_UNSPECIFIED(&m->conf.ipv6))
return call_stream_address4(o, p, format);
return call_stream_address4(o, p, format, len);
return call_stream_address6(o, p, format);
return call_stream_address6(o, p, format, len);
}
static int call_stream_address_gstring(GString *o, struct peer *p, enum stream_address_format format) {
int len, ret;
char buf[64]; /* 64 bytes ought to be enough for anybody */
ret = call_stream_address(buf, p, format, &len);
g_string_append_len(o, buf, len);
return ret;
}
@ -1556,7 +1575,7 @@ static str *streams_print(GQueue *s, int num, enum call_opmode opmode, const cha
t = s->head->data;
if (format == SAF_TCP)
call_stream_address(o, &t->peers[off], format);
call_stream_address_gstring(o, &t->peers[off], format);
for (i = 0, l = s->head; i < num && l; i++, l = l->next) {
t = l->data;
@ -1565,7 +1584,7 @@ static str *streams_print(GQueue *s, int num, enum call_opmode opmode, const cha
}
if (format == SAF_UDP) {
af = call_stream_address(o, &t->peers[off], format);
af = call_stream_address_gstring(o, &t->peers[off], format);
g_string_append_printf(o, " %c", (af == AF_INET) ? '4' : '6');
}
@ -2169,13 +2188,14 @@ static void call_ng_process_flags(struct sdp_ng_flags *out, GQueue *streams, ben
}
static const char *call_offer_answer_ng(bencode_item_t *input, struct callmaster *m, bencode_item_t *output, enum call_opmode opmode, const char *tagname) {
str sdp, fromtag, viabranch, callid, *sdp_new;
str sdp, fromtag, viabranch, callid;
char *errstr;
GQueue parsed = G_QUEUE_INIT;
GQueue streams = G_QUEUE_INIT;
struct call *call;
int num;
int ret, num;
struct sdp_ng_flags flags;
struct sdp_chopper *chopper;
if (!bencode_dictionary_get_str(input, "sdp", &sdp))
return "No SDP body in message";
@ -2201,17 +2221,20 @@ static const char *call_offer_answer_ng(bencode_item_t *input, struct callmaster
goto out;
log_info = &viabranch;
chopper = sdp_chopper_new(&sdp);
bencode_buffer_destroy_add(output->buffer, (free_func_t) sdp_chopper_destroy, chopper);
num = call_streams(call, &streams, &fromtag, opmode);
sdp_new = sdp_replace(&sdp, &parsed, call, num, opmode, &flags);
ret = sdp_replace(chopper, &parsed, call, num, opmode, &flags);
mutex_unlock(&call->lock);
obj_put(call);
errstr = "Error rewriting SDP";
if (!sdp_new)
if (ret)
goto out;
bencode_dictionary_add_str_free(output, "sdp", sdp_new);
bencode_dictionary_add_iovec(output, "sdp", &g_array_index(chopper->iov, struct iovec, 0),
chopper->iov_num, chopper->str_len);
bencode_dictionary_add_string(output, "result", "ok");
errstr = NULL;


+ 1
- 1
daemon/call.h View File

@ -165,7 +165,7 @@ struct call *call_get_or_create(const str *callid, const str *viabranch, struct
struct callstream *callstream_new(struct call *ca, int num);
void callstream_init(struct callstream *s, struct relays_cache *);
void kernelize(struct callstream *c);
int call_stream_address(GString *o, struct peer *p, enum stream_address_format);
int call_stream_address(char *o, struct peer *p, enum stream_address_format format, int *len);
static inline char *call_strdup(struct call *c, const char *s) {
char *r;


+ 3
- 0
daemon/control_ng.c View File

@ -1,3 +1,5 @@
#include <sys/types.h>
#include <sys/socket.h>
#include "control_ng.h"
#include "obj.h"
#include "poller.h"
@ -5,6 +7,7 @@
#include "log.h"
#include "cookie_cache.h"
#include "call.h"
#include "sdp.h"
static void control_ng_incoming(struct obj *obj, str *buf, struct sockaddr_in6 *sin, char *addr) {


+ 64
- 43
daemon/sdp.c View File

@ -49,12 +49,6 @@ struct sdp_media {
GQueue attributes;
};
struct string_chopper {
str *input;
GString *output;
int position;
};
@ -347,13 +341,42 @@ error:
return -1;
}
static void chopper_init(struct string_chopper *c, str *input) {
struct sdp_chopper *sdp_chopper_new(str *input) {
struct sdp_chopper *c = g_slice_alloc0(sizeof(*c));
c->input = input;
c->output = g_string_new_str();
c->position = 0;
c->chunk = g_string_chunk_new(512);
c->iov = g_array_new(0, 0, sizeof(struct iovec));
return c;
}
static void chopper_append(struct sdp_chopper *c, const char *s, int len) {
struct iovec *iov;
g_array_set_size(c->iov, ++c->iov_num);
iov = &g_array_index(c->iov, struct iovec, c->iov_num - 1);
iov->iov_base = (void *) s;
iov->iov_len = len;
c->str_len += len;
}
static void chopper_append_dup(struct sdp_chopper *c, const char *s, int len) {
return chopper_append(c, g_string_chunk_insert_len(c->chunk, s, len), len);
}
static void chopper_append_printf(struct sdp_chopper *c, const char *fmt, ...) __attribute__((format(printf,2,3)));
static void chopper_append_printf(struct sdp_chopper *c, const char *fmt, ...) {
char buf[32];
int l;
va_list va;
va_start(va, fmt);
l = vsnprintf(buf, sizeof(buf) - 1, fmt, va);
va_end(va);
chopper_append(c, g_string_chunk_insert_len(c->chunk, buf, l), l);
}
static int copy_up_to(struct string_chopper *chop, str *where) {
static int copy_up_to(struct sdp_chopper *chop, str *where) {
int offset, len;
offset = where->s - chop->input->s;
@ -365,20 +388,20 @@ static int copy_up_to(struct string_chopper *chop, str *where) {
mylog(LOG_WARNING, "Malformed SDP, cannot rewrite");
return -1;
}
g_string_append_len(chop->output, chop->input->s + chop->position, len);
chopper_append(chop, chop->input->s + chop->position, len);
chop->position += len;
return 0;
}
static void copy_remainder(struct string_chopper *chop) {
static void copy_remainder(struct sdp_chopper *chop) {
int len;
len = chop->input->len - chop->position;
assert(len >= 0);
g_string_append_len(chop->output, chop->input->s + chop->position, len);
chopper_append(chop, chop->input->s + chop->position, len);
chop->position += len;
}
static int skip_over(struct string_chopper *chop, str *where) {
static int skip_over(struct sdp_chopper *chop, str *where) {
int offset, len;
offset = (where->s - chop->input->s) + where->len;
@ -394,7 +417,7 @@ static int skip_over(struct string_chopper *chop, str *where) {
return 0;
}
static int replace_media_port(struct string_chopper *chop, struct sdp_media *media, GList *m, int off) {
static int replace_media_port(struct sdp_chopper *chop, struct sdp_media *media, GList *m, int off) {
struct callstream *cs;
struct streamrelay *sr;
str *port = &media->port;
@ -411,7 +434,7 @@ static int replace_media_port(struct string_chopper *chop, struct sdp_media *med
if (copy_up_to(chop, port))
return -1;
g_string_append_printf(chop->output, "%hu", sr->fd.localport);
chopper_append_printf(chop, "%hu", sr->fd.localport);
if (skip_over(chop, port))
return -1;
@ -431,14 +454,16 @@ warn:
}
}
g_string_append_printf(chop->output, "/%i", cons);
chopper_append_printf(chop, "/%i", cons);
return cons;
}
static int replace_network_address(struct string_chopper *chop, struct network_address *address, GList *m, int off, struct sdp_ng_flags *flags) {
static int replace_network_address(struct sdp_chopper *chop, struct network_address *address, GList *m, int off, struct sdp_ng_flags *flags) {
struct callstream *cs;
struct peer *peer;
char buf[64];
int len;
if (!m) {
mylog(LOG_ERROR, "BUG! Ran out of streams");
@ -452,12 +477,14 @@ static int replace_network_address(struct string_chopper *chop, struct network_a
return -1;
if (!flags->trust_address && flags->received_from_family.len == 3 && flags->received_from_address.len) {
g_string_append_len(chop->output, flags->received_from_family.s, flags->received_from_family.len);
g_string_append_c(chop->output, ' ');
g_string_append_len(chop->output, flags->received_from_address.s, flags->received_from_address.len);
chopper_append(chop, flags->received_from_family.s, flags->received_from_family.len);
chopper_append(chop, " ", 1);
chopper_append(chop, flags->received_from_address.s, flags->received_from_address.len);
}
else {
call_stream_address(buf, peer, SAF_NG, &len);
chopper_append_dup(chop, buf, len);
}
else
call_stream_address(chop->output, peer, SAF_NG);
if (skip_over(chop, &address->address))
return -1;
@ -465,25 +492,21 @@ static int replace_network_address(struct string_chopper *chop, struct network_a
return 0;
}
static str *chopper_done(struct string_chopper *chop) {
str *ret;
ret = g_string_free_str(chop->output);
return ret;
}
static void chopper_destroy(struct string_chopper *chop) {
g_string_free(chop->output, TRUE);
void sdp_chopper_destroy(struct sdp_chopper *chop) {
g_string_chunk_free(chop->chunk);
g_array_free(chop->iov, 1);
g_slice_free1(sizeof(*chop), chop);
}
/* XXX use stream numbers as index */
/* XXX use port numbers as index */
/* XXX get rid of num/off parameters? */
/* XXX use iovec based rewriting */
str *sdp_replace(str *body, GQueue *sessions, struct call *call, int num, enum call_opmode opmode, struct sdp_ng_flags *flags) {
int sdp_replace(struct sdp_chopper *chop, GQueue *sessions, struct call *call, int num,
enum call_opmode opmode, struct sdp_ng_flags *flags)
{
struct sdp_session *session;
struct sdp_media *media;
GList *l, *k, *m;
struct string_chopper chop;
int off, skip;
off = opmode;
@ -491,30 +514,29 @@ str *sdp_replace(str *body, GQueue *sessions, struct call *call, int num, enum c
off ^= 1;
num = abs(num);
chopper_init(&chop, body);
m = call->callstreams->head;
for (l = sessions->head; l; l = l->next) {
session = l->data;
if (session->origin.parsed && flags->replace_origin) {
if (replace_network_address(&chop, &session->origin.address, m, off, flags))
if (replace_network_address(chop, &session->origin.address, m, off, flags))
goto error;
}
if (session->connection.parsed) {
if (replace_network_address(&chop, &session->connection.address, m, off, flags))
if (replace_network_address(chop, &session->connection.address, m, off, flags))
goto error;
}
for (k = session->media_streams.head; k; k = k->next) {
media = k->data;
skip = replace_media_port(&chop, media, m, off);
skip = replace_media_port(chop, media, m, off);
if (skip < 0)
goto error;
if (media->connection.parsed && flags->replace_sess_conn) {
if (replace_network_address(&chop, &media->connection.address, m, off, flags))
if (replace_network_address(chop, &media->connection.address, m, off, flags))
goto error;
}
@ -522,11 +544,10 @@ str *sdp_replace(str *body, GQueue *sessions, struct call *call, int num, enum c
}
}
copy_remainder(&chop);
return chopper_done(&chop);
copy_remainder(chop);
return 0;
error:
mylog(LOG_ERROR, "Error rewriting SDP");
chopper_destroy(&chop);
return NULL;
return -1;
}

+ 13
- 1
daemon/sdp.h View File

@ -17,9 +17,21 @@ struct sdp_ng_flags {
replace_sess_conn:1;
};
struct sdp_chopper {
str *input;
int position;
GStringChunk *chunk;
GArray *iov;
int iov_num;
int str_len;
};
int sdp_parse(str *body, GQueue *sessions);
int sdp_streams(const GQueue *sessions, GQueue *streams);
void sdp_free(GQueue *sessions);
str *sdp_replace(str *body, GQueue *sessions, struct call *call, int num, enum call_opmode, struct sdp_ng_flags *);
int sdp_replace(struct sdp_chopper *, GQueue *, struct call *, int, enum call_opmode, struct sdp_ng_flags *);
struct sdp_chopper *sdp_chopper_new(str *input);
void sdp_chopper_destroy(struct sdp_chopper *chop);
#endif

Loading…
Cancel
Save