Browse Source

first take on SDP rewriting

git.mgm/mediaproxy-ng/2.2
Richard Fuchs 13 years ago
parent
commit
c75394d3cd
9 changed files with 303 additions and 45 deletions
  1. +19
    -2
      daemon/bencode.c
  2. +20
    -0
      daemon/bencode.h
  3. +95
    -40
      daemon/call.c
  4. +1
    -0
      daemon/call.h
  5. +1
    -1
      daemon/control_ng.c
  6. +1
    -0
      daemon/log.h
  7. +162
    -1
      daemon/sdp.c
  8. +2
    -0
      daemon/sdp.h
  9. +2
    -1
      daemon/str.h

+ 19
- 2
daemon/bencode.c View File

@ -16,6 +16,10 @@ struct __bencode_buffer_piece {
struct __bencode_buffer_piece *next;
char buf[0];
};
struct __bencode_free_list {
void *ptr;
struct __bencode_free_list *next;
};
@ -356,7 +360,7 @@ static bencode_item_t *bencode_decode_dictionary(bencode_buffer_t *buf, const ch
return NULL;
bencode_dictionary_init(ret);
while (s > end) {
while (s < end) {
item = __bencode_decode(buf, s, end);
if (!item)
return NULL;
@ -393,7 +397,7 @@ static bencode_item_t *bencode_decode_list(bencode_buffer_t *buf, const char *s,
return NULL;
bencode_list_init(ret);
while (s > end) {
while (s < end) {
item = __bencode_decode(buf, s, end);
if (!item)
return NULL;
@ -552,3 +556,16 @@ bencode_item_t *bencode_dictionary_get_len(bencode_item_t *dict, const char *key
return NULL;
}
void bencode_buffer_freelist_add(bencode_buffer_t *buf, void *p) {
struct __bencode_free_list *li;
if (!p)
return;
li = __bencode_alloc(buf, sizeof(*li));
if (!li)
return;
li->ptr = p;
li->next = buf->free_list;
buf->free_list = li;
}

+ 20
- 0
daemon/bencode.h View File

@ -25,6 +25,7 @@ struct bencode_buffer;
enum bencode_type;
struct bencode_item;
struct __bencode_buffer_piece;
struct __bencode_free_list;
typedef enum bencode_type bencode_type_t;
typedef struct bencode_buffer bencode_buffer_t;
@ -52,6 +53,7 @@ struct bencode_item {
struct bencode_buffer {
struct __bencode_buffer_piece *pieces;
struct __bencode_free_list *free_list;
};
/* Initializes a bencode_buffer_t object. This object is used to group together all memory allocations
@ -73,6 +75,10 @@ bencode_item_t *bencode_dictionary(bencode_buffer_t *buf);
* Returns NULL if no memory could be allocated. */
bencode_item_t *bencode_list(bencode_buffer_t *buf);
/* Adds a pointer to the bencode_buffer_t object's internal free list. When the bencode_buffer_t
* object is destroyed, BENCODE_FREE will be called on this pointer. */
void bencode_buffer_freelist_add(bencode_buffer_t *buf, void *);
/* Adds a new key/value pair to a dictionary. Memory will be allocated from the same bencode_buffer_t
* object as the dictionary was allocated from. Returns NULL if no memory could be allocated, otherwise
* returns "val".
@ -91,6 +97,11 @@ 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);
/* Ditto again, but adds the buffer which contains the string (val->s) to the bencode_buffer_t's
* internal free list. When the bencode_item_t object is destroyed, BENCODE_FREE will be called
* on this buffer. */
static inline bencode_item_t *bencode_dictionary_add_str_free(bencode_item_t *dict, const char *key, const str *val);
/* Convenience function to add an integer value to a dictionary */
static inline bencode_item_t *bencode_dictionary_add_integer(bencode_item_t *dict, const char *key, long long int val);
@ -264,6 +275,13 @@ static inline bencode_item_t *bencode_dictionary_add_str(bencode_item_t *dict, c
return bencode_dictionary_add(dict, key, bencode_str(dict->buffer, val));
}
static inline bencode_item_t *bencode_dictionary_add_str_free(bencode_item_t *dict, const char *key, const str *val) {
if (!val)
return NULL;
bencode_buffer_freelist_add(dict->buffer, val->s);
return bencode_dictionary_add(dict, key, bencode_str(dict->buffer, val));
}
static inline bencode_item_t *bencode_dictionary_add_integer(bencode_item_t *dict, const char *key, long long int val) {
return bencode_dictionary_add(dict, key, bencode_integer(dict->buffer, val));
}
@ -289,6 +307,8 @@ static inline char *bencode_dictionary_get_string(bencode_item_t *dict, const ch
static inline char *bencode_dictionary_get_str(bencode_item_t *dict, const char *key, str *str) {
str->s = bencode_dictionary_get_string(dict, key, &str->len);
if (!str->s)
str->len = 0;
return str->s;
}


+ 95
- 40
daemon/call.c View File

@ -1450,16 +1450,73 @@ static void call_destroy(struct call *c) {
/* XXX use enum format */
static int call_stream_address4(GString *o, struct peer *p, int format) {
struct callstream *cs = p->up;
u_int32_t ip4;
struct callmaster *m = cs->call->callmaster;
if (format == 2)
g_string_append(o, "IP4 ");
ip4 = p->rtps[0].peer.ip46.s6_addr32[3];
if (!ip4)
g_string_append(o, "0.0.0.0");
else if (m->conf.adv_ipv4)
g_string_append_printf(o, IPF, IPP(m->conf.adv_ipv4));
else
g_string_append_printf(o, IPF, IPP(m->conf.ipv4));
return AF_INET;
}
static int call_stream_address6(GString *o, struct peer *p, int format) {
char ips[64];
struct callmaster *m = p->up->call->callmaster;
if (format == 2)
g_string_append(o, "IP4 ");
if (IN6_IS_ADDR_UNSPECIFIED(&p->rtps[0].peer.ip46))
g_string_append(o, "::");
else {
if (!IN6_IS_ADDR_UNSPECIFIED(&m->conf.adv_ipv6))
inet_ntop(AF_INET6, &m->conf.adv_ipv6, ips, sizeof(ips));
else
inet_ntop(AF_INET6, &m->conf.ipv6, ips, sizeof(ips));
g_string_append(o, ips);
}
return AF_INET6;
}
int call_stream_address(GString *o, struct peer *p, int format) {
struct callmaster *m;
struct peer *other;
m = p->up->call->callmaster;
other = &p->up->peers[p->idx ^ 1];
if (other->desired_family == AF_INET)
return call_stream_address4(o, p, format);
if (other->desired_family == 0 && IN6_IS_ADDR_V4MAPPED(&other->rtps[0].peer.ip46))
return call_stream_address4(o, p, format);
if (IN6_IS_ADDR_UNSPECIFIED(&m->conf.ipv6))
return call_stream_address4(o, p, format);
return call_stream_address6(o, p, format);
}
static str *streams_print(GQueue *s, unsigned int num, unsigned int off, const char *prefix, int format) {
GString *o;
int i;
GList *l;
struct callstream *t;
struct streamrelay *x;
char ips[64];
u_int32_t ip4;
int other_off;
char af;
int af;
o = g_string_new_str();
if (prefix)
@ -1469,35 +1526,8 @@ static str *streams_print(GQueue *s, unsigned int num, unsigned int off, const c
goto out;
t = s->head->data;
other_off = (off == 0) ? 1 : 0;
if (t->peers[other_off].desired_family == AF_INET
|| (t->peers[other_off].desired_family == 0
&& IN6_IS_ADDR_V4MAPPED(&t->peers[other_off].rtps[0].peer.ip46))
|| IN6_IS_ADDR_UNSPECIFIED(&t->call->callmaster->conf.ipv6)) {
ip4 = t->peers[off].rtps[0].peer.ip46.s6_addr32[3];
if (!ip4)
strcpy(ips, "0.0.0.0");
else if (t->call->callmaster->conf.adv_ipv4)
sprintf(ips, IPF, IPP(t->call->callmaster->conf.adv_ipv4));
else
sprintf(ips, IPF, IPP(t->call->callmaster->conf.ipv4));
af = '4';
}
else {
if (IN6_IS_ADDR_UNSPECIFIED(&t->peers[off].rtps[0].peer.ip46))
strcpy(ips, "::");
else if (!IN6_IS_ADDR_UNSPECIFIED(&t->call->callmaster->conf.adv_ipv6))
inet_ntop(AF_INET6, &t->call->callmaster->conf.adv_ipv6, ips, sizeof(ips));
else
inet_ntop(AF_INET6, &t->call->callmaster->conf.ipv6, ips, sizeof(ips));
af = '6';
}
if (format == 0)
g_string_append(o, ips);
call_stream_address(o, &t->peers[off], format);
for (i = 0, l = s->head; i < num && l; i++, l = l->next) {
t = l->data;
@ -1505,8 +1535,10 @@ static str *streams_print(GQueue *s, unsigned int num, unsigned int off, const c
g_string_append_printf(o, (format == 1) ? "%u " : " %u", x->localport);
}
if (format == 1)
g_string_append_printf(o, "%s %c", ips, af);
if (format == 1) {
af = call_stream_address(o, &t->peers[off], format);
g_string_append_printf(o, " %c", (af == AF_INET) ? '4' : '6');
}
out:
g_string_append(o, "\n");
@ -2102,18 +2134,23 @@ struct callstream *callstream_new(struct call *ca, int num) {
const char *call_offer(bencode_item_t *input, struct callmaster *m, bencode_item_t *output) {
str sdp, fromtag;
str sdp, fromtag, viabranch, callid, *sdp_new;
char *errstr;
GQueue parsed = G_QUEUE_INIT;
GQueue streams = G_QUEUE_INIT;
int ret;
struct call *call;
int num;
bencode_dictionary_get_str(input, "sdp", &sdp);
if (!sdp.s)
if (!bencode_dictionary_get_str(input, "sdp", &sdp))
return "No SDP body in message";
bencode_dictionary_get_str(input, "from-tag", &fromtag);
if (!fromtag.s)
if (!bencode_dictionary_get_str(input, "call-id", &callid))
return "No call-id in message";
if (!bencode_dictionary_get_str(input, "from-tag", &fromtag))
return "No from-tag in message";
bencode_dictionary_get_str(input, "via-branch", &viabranch);
log_info = &viabranch;
/* XXX get rid of "direction" and use "desired_family" as intended? */
if (sdp_parse(&sdp, &parsed))
return "Failed to parse SDP";
@ -2122,10 +2159,28 @@ const char *call_offer(bencode_item_t *input, struct callmaster *m, bencode_item
if (sdp_streams(&parsed, &streams))
goto out;
call = call_get_or_create(&callid, &viabranch, m);
log_info = &viabranch;
call->calling_agent = "UNKNOWN(ng)"; /* XXX get rid of, or make use of */
num = call_streams(call, &streams, &fromtag, 0);
sdp_new = sdp_replace(&sdp, &parsed, call, abs(num), (num >= 0) ? 0 : 1);
mutex_unlock(&call->lock);
obj_put(call);
errstr = "Error rewriting SDP";
if (!sdp_new)
goto out;
bencode_dictionary_add_str_free(output, "sdp", sdp_new);
bencode_dictionary_add_string(output, "result", "ok");
errstr = NULL;
out:
sdp_free(&parsed);
streams_free(&streams);
log_info = NULL;
return errstr;
}


+ 1
- 0
daemon/call.h View File

@ -140,6 +140,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, int port1, int port2);
void kernelize(struct callstream *c);
int call_stream_address(GString *o, struct peer *p, int format);
static inline char *call_strdup(struct call *c, const char *s) {
char *r;


+ 1
- 1
daemon/control_ng.c View File

@ -26,7 +26,7 @@ static void control_ng_incoming(struct obj *obj, str *buf, struct sockaddr_in6 *
resp = bencode_dictionary(&bencbuf);
cookie = *buf;
cookie.len = data.s - buf->s;
cookie.len -= data.len;
*data.s++ = '\0';
data.len--;


+ 1
- 0
daemon/log.h View File

@ -6,6 +6,7 @@
#define mylog(x,y...) syslog(x,y)
#define LOG_ERROR LOG_ERR


+ 162
- 1
daemon/sdp.c View File

@ -7,6 +7,7 @@
#include "call.h"
#include "log.h"
#include "str.h"
#include "call.h"
struct network_address {
str network_type;
@ -31,8 +32,8 @@ struct sdp_connection {
struct sdp_session {
struct sdp_origin origin;
struct sdp_connection connection;
GQueue media_streams;
GQueue attributes;
GQueue media_streams;
};
struct sdp_media {
@ -48,6 +49,12 @@ struct sdp_media {
GQueue attributes;
};
struct string_chopper {
str *input;
GString *output;
int position;
};
@ -321,8 +328,12 @@ int sdp_streams(const GQueue *sessions, GQueue *streams) {
else
goto error;
/* XXX ports must be consecutive */
/* XXX check for RTP type */
stream->port = (media->port_num + (i * 2)) & 0xffff;
stream->num = ++num;
g_queue_push_tail(streams, stream);
}
}
}
@ -333,3 +344,153 @@ error:
mylog(LOG_WARNING, "Failed to extract streams from SDP: %s", errstr);
return -1;
}
static void chopper_init(struct string_chopper *c, str *input) {
c->input = input;
c->output = g_string_new_str();
c->position = 0;
}
static int copy_up_to(struct string_chopper *chop, str *where) {
int offset, len;
offset = where->s - chop->input->s;
assert(offset >= 0);
assert(offset < chop->input->len);
len = offset - chop->position;
if (len < 0) {
mylog(LOG_WARNING, "Malformed SDP, cannot rewrite");
return -1;
}
g_string_append_len(chop->output, chop->input->s + chop->position, len);
chop->position += len;
return 0;
}
static void copy_remainder(struct string_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);
chop->position += len;
}
static int skip_over(struct string_chopper *chop, str *where) {
int offset, len;
offset = (where->s - chop->input->s) + where->len;
assert(offset >= 0);
assert(offset < chop->input->len);
len = offset - chop->position;
if (len < 0) {
mylog(LOG_WARNING, "Malformed SDP, cannot rewrite");
return -1;
}
chop->position += len;
return 0;
}
static int replace_port(struct string_chopper *chop, str *port, GList *m, int off) {
struct callstream *cs;
struct streamrelay *sr;
if (!m) {
mylog(LOG_ERROR, "BUG! Ran out of streams");
return -1;
}
cs = m->data;
sr = &cs->peers[off].rtps[0];
if (copy_up_to(chop, port))
return -1;
g_string_append_printf(chop->output, "%hu", sr->localport);
if (skip_over(chop, port))
return -1;
return 0;
}
static int replace_network_address(struct string_chopper *chop, struct network_address *address, GList *m, int off) {
struct callstream *cs;
struct peer *peer;
if (!m) {
mylog(LOG_ERROR, "BUG! Ran out of streams");
return -1;
}
cs = m->data;
peer = &cs->peers[off];
if (copy_up_to(chop, &address->address_type))
return -1;
call_stream_address(chop->output, peer, 2);
if (skip_over(chop, &address->address))
return -1;
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);
}
/* XXX use stream numbers as index */
/* XXX use port numbers as index */
/* XXX get rid of num/off parameters? */
str *sdp_replace(str *body, GQueue *sessions, struct call *call, int num, int off) {
struct sdp_session *session;
struct sdp_media *media;
GList *l, *k, *m;
struct string_chopper chop;
chopper_init(&chop, body);
m = call->callstreams->head;
for (l = sessions->head; l; l = l->next) {
session = l->data;
if (session->origin.parsed) {
if (replace_network_address(&chop, &session->origin.address, m, off))
goto error;
}
if (session->connection.parsed) {
if (replace_network_address(&chop, &session->connection.address, m, off))
goto error;
}
for (k = session->media_streams.head; k; k = k->next) {
media = k->data;
/* XXX take multiple ports into account */
if (replace_port(&chop, &media->port, m, off))
goto error;
if (media->connection.parsed) {
if (replace_network_address(&chop, &media->connection.address, m, off))
goto error;
}
}
}
copy_remainder(&chop);
return chopper_done(&chop);
error:
mylog(LOG_ERROR, "Error rewriting SDP");
chopper_destroy(&chop);
return NULL;
}

+ 2
- 0
daemon/sdp.h View File

@ -3,9 +3,11 @@
#include <glib.h>
#include "str.h"
#include "call.h"
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, int off);
#endif

+ 2
- 1
daemon/str.h View File

@ -76,7 +76,7 @@ static inline char *str_chr(const str *s, int c) {
}
static inline str *str_chr_str(str *out, const str *s, int c) {
out->s = str_chr(s, c);
out->len = out->s ? out->s - s->s : 0;
out->len = out->s ? (s->len - (out->s - s->s)) : 0;
return out;
}
static inline int str_cmp(const str *a, const char *b) {
@ -169,6 +169,7 @@ static inline str *g_string_free_str(GString *gs) {
pl = strlen(STR_MALLOC_PADDING);
assert(gs->len >= pl);
assert(memcmp(gs->str, STR_MALLOC_PADDING, pl) == 0);
ret = (void *) gs->str;
ret->s = gs->str + pl;
ret->len = gs->len - pl;


Loading…
Cancel
Save