remove uuid helper code

git.mgm/mediaproxy-ng/2.1
Richard Fuchs 13 years ago
commit dc7517121d

@ -0,0 +1,51 @@
CC= gcc
CFLAGS= -g -Wall `pkg-config --cflags glib-2.0` `pcre-config --cflags` -fno-strict-aliasing
CFLAGS+= -I/lib/modules/`uname -r`/build/include/ -I../kernel-module/
CFLAGS+= -D_GNU_SOURCE
CFLAGS+= -DMEDIAPROXY_VERSION="\"$(shell dpkg-parsechangelog -l../debian/changelog | awk '/^Version: / {print $$2}')\""
CFLAGS+= -DMP_PLUGIN_DIR="\"/usr/lib/mediaproxy-ng\""
ifeq ($(DBG),yes)
CFLAGS+= -D__DEBUG=1
else
CFLAGS+= -O2
endif
LDFLAGS= `pkg-config --libs glib-2.0` `pcre-config --libs`
LDFLAGS+= `xmlrpc-c-config client --libs`
LDFLAGS+= -ldl -rdynamic
SRCS= main.c kernel.c poller.c aux.c control.c streambuf.c call.c control_udp.c redis.c
OBJS= $(SRCS:.c=.o)
.PHONY: all dep clean tests debug
all:
$(MAKE) mediaproxy-ng
debug:
$(MAKE) DBG=yes all
tests:
$(MAKE) aux-test poller-test
dep: .depend
clean:
rm -f $(OBJS) mediaproxy-ng aux-test poller-test aux-test.o poller-test.o .depend core
.depend: $(SRCS) Makefile
$(CC) $(CFLAGS) -M $(SRCS) | sed -e 's/:/ .depend:/' > .depend
mediaproxy-ng: $(OBJS) .depend
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LDFLAGS)
aux-test: aux.o aux-test.o .depend
$(CC) $(CFLAGS) -o $@ aux-test.o aux.o $(LDFLAGS)
poller-test: poller.o poller-test.o aux.o .depend
$(CC) $(CFLAGS) -o $@ poller-test.o poller.o aux.o $(LDFLAGS)
include .depend

@ -0,0 +1,305 @@
#include <stdio.h>
#include "aux.h"
int test[32] = {
0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80,
0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, 0xff,
0x10ff, 0x20ff, 0x30ff, 0x40ff, 0x50ff, 0x60ff, 0x70ff, 0x80ff,
0x90ff, 0xa0ff, 0xb0ff, 0xc0ff, 0xd0ff, 0xe0ff, 0xf0ff, 0xffff,
};
void exsrx(int x, int exp, unsigned int s, int ex) {
int ret = mybsearch(test, s, sizeof(int), &x, 0, sizeof(x), ex);
if (ret != exp)
fprintf(stderr, "TEST FAILED! params=%u %i; result=%i, expected=%i\n", s, ex, ret, exp);
}
void exsr1(int x, int exp) {
exsrx(x, exp, 16, 1);
}
void exsr2(int x, int exp) {
exsrx(x, exp, 15, 1);
}
void exsr3(int x, int exp) {
exsrx(x, exp, 2, 1);
}
void exsr4(int x, int exp) {
exsrx(x, exp, 1, 1);
}
void exsr5(int x, int exp) {
exsrx(x, exp, 32, 1);
}
void exsr6(int x, int exp) {
exsrx(x, exp, 31, 1);
}
void exsr7(int x, int exp) {
exsrx(x, exp, 16, 0);
}
void exsr8(int x, int exp) {
exsrx(x, exp, 15, 0);
}
void exsr9(int x, int exp) {
exsrx(x, exp, 2, 0);
}
void exsr10(int x, int exp) {
exsrx(x, exp, 1, 0);
}
void exsr11(int x, int exp) {
exsrx(x, exp, 32, 0);
}
void exsr12(int x, int exp) {
exsrx(x, exp, 31, 0);
}
int main() {
exsr1(0x10, 0);
exsr1(0x20, 1);
exsr1(0x30, 2);
exsr1(0x40, 3);
exsr1(0x50, 4);
exsr1(0x60, 5);
exsr1(0x70, 6);
exsr1(0x80, 7);
exsr1(0x90, 8);
exsr1(0xa0, 9);
exsr1(0xb0, 10);
exsr1(0xc0, 11);
exsr1(0xd0, 12);
exsr1(0xe0, 13);
exsr1(0xf0, 14);
exsr1(0xff, 15);
exsr1(0xffff, -1);
exsr1(0xfe, -1);
exsr2(0x10, 0);
exsr2(0x20, 1);
exsr2(0x30, 2);
exsr2(0x40, 3);
exsr2(0x50, 4);
exsr2(0x60, 5);
exsr2(0x70, 6);
exsr2(0x80, 7);
exsr2(0x90, 8);
exsr2(0xa0, 9);
exsr2(0xb0, 10);
exsr2(0xc0, 11);
exsr2(0xd0, 12);
exsr2(0xe0, 13);
exsr2(0xf0, 14);
exsr2(0xff, -1);
exsr3(0x10, 0);
exsr3(0x20, 1);
exsr3(0x30, -1);
exsr4(0x10, 0);
exsr4(0x20, -1);
exsr5(0x10, 0);
exsr5(0x20, 1);
exsr5(0x30, 2);
exsr5(0x40, 3);
exsr5(0x50, 4);
exsr5(0x60, 5);
exsr5(0x70, 6);
exsr5(0x80, 7);
exsr5(0x90, 8);
exsr5(0xa0, 9);
exsr5(0xb0, 10);
exsr5(0xc0, 11);
exsr5(0xd0, 12);
exsr5(0xe0, 13);
exsr5(0xf0, 14);
exsr5(0xff, 15);
exsr5(0x10ff, 16);
exsr5(0x20ff, 17);
exsr5(0x30ff, 18);
exsr5(0x40ff, 19);
exsr5(0x50ff, 20);
exsr5(0x60ff, 21);
exsr5(0x70ff, 22);
exsr5(0x80ff, 23);
exsr5(0x90ff, 24);
exsr5(0xa0ff, 25);
exsr5(0xb0ff, 26);
exsr5(0xc0ff, 27);
exsr5(0xd0ff, 28);
exsr5(0xe0ff, 29);
exsr5(0xf0ff, 30);
exsr5(0xffff, 31);
exsr5(0xfff3, -1);
exsr5(0xffffff, -1);
exsr6(0x10, 0);
exsr6(0x20, 1);
exsr6(0x30, 2);
exsr6(0x40, 3);
exsr6(0x50, 4);
exsr6(0x60, 5);
exsr6(0x70, 6);
exsr6(0x80, 7);
exsr6(0x90, 8);
exsr6(0xa0, 9);
exsr6(0xb0, 10);
exsr6(0xc0, 11);
exsr6(0xd0, 12);
exsr6(0xe0, 13);
exsr6(0xf0, 14);
exsr6(0xff, 15);
exsr6(0x10ff, 16);
exsr6(0x20ff, 17);
exsr6(0x30ff, 18);
exsr6(0x40ff, 19);
exsr6(0x50ff, 20);
exsr6(0x60ff, 21);
exsr6(0x70ff, 22);
exsr6(0x80ff, 23);
exsr6(0x90ff, 24);
exsr6(0xa0ff, 25);
exsr6(0xb0ff, 26);
exsr6(0xc0ff, 27);
exsr6(0xd0ff, 28);
exsr6(0xe0ff, 29);
exsr6(0xf0ff, 30);
exsr6(0xffff, -1);
exsr7(0x10, 0);
exsr7(0x20, 1);
exsr7(0x30, 2);
exsr7(0x40, 3);
exsr7(0x50, 4);
exsr7(0x60, 5);
exsr7(0x70, 6);
exsr7(0x80, 7);
exsr7(0x90, 8);
exsr7(0xa0, 9);
exsr7(0xb0, 10);
exsr7(0xc0, 11);
exsr7(0xd0, 12);
exsr7(0xe0, 13);
exsr7(0xf0, 14);
exsr7(0xff, 15);
exsr7(0xffff, -17);
exsr7(0xfe, -16);
exsr7(0x00, -1);
exsr8(0x05, -1);
exsr8(0x15, -2);
exsr8(0x10, 0);
exsr8(0x20, 1);
exsr8(0x30, 2);
exsr8(0x40, 3);
exsr8(0x50, 4);
exsr8(0x60, 5);
exsr8(0x70, 6);
exsr8(0x80, 7);
exsr8(0x90, 8);
exsr8(0xa0, 9);
exsr8(0xb0, 10);
exsr8(0xc0, 11);
exsr8(0xd0, 12);
exsr8(0xe0, 13);
exsr8(0xf0, 14);
exsr8(0xff, -16);
exsr8(0xffff, -16);
exsr8(0xef, -15);
exsr8(0x00, -1);
exsr8(0x05, -1);
exsr8(0x15, -2);
exsr9(0x10, 0);
exsr9(0x20, 1);
exsr9(0x30, -3);
exsr10(0x10, 0);
exsr10(0x20, -2);
exsr11(0x10, 0);
exsr11(0x20, 1);
exsr11(0x30, 2);
exsr11(0x40, 3);
exsr11(0x50, 4);
exsr11(0x60, 5);
exsr11(0x70, 6);
exsr11(0x80, 7);
exsr11(0x90, 8);
exsr11(0xa0, 9);
exsr11(0xb0, 10);
exsr11(0xc0, 11);
exsr11(0xd0, 12);
exsr11(0xe0, 13);
exsr11(0xf0, 14);
exsr11(0xff, 15);
exsr11(0x10ff, 16);
exsr11(0x20ff, 17);
exsr11(0x30ff, 18);
exsr11(0x40ff, 19);
exsr11(0x50ff, 20);
exsr11(0x60ff, 21);
exsr11(0x70ff, 22);
exsr11(0x80ff, 23);
exsr11(0x90ff, 24);
exsr11(0xa0ff, 25);
exsr11(0xb0ff, 26);
exsr11(0xc0ff, 27);
exsr11(0xd0ff, 28);
exsr11(0xe0ff, 29);
exsr11(0xf0ff, 30);
exsr11(0xffff, 31);
exsr11(0xfff3, -16);
exsr11(0xffffff, -33);
exsr12(0x10, 0);
exsr12(0x20, 1);
exsr12(0x30, 2);
exsr12(0x40, 3);
exsr12(0x50, 4);
exsr12(0x60, 5);
exsr12(0x70, 6);
exsr12(0x80, 7);
exsr12(0x90, 8);
exsr12(0xa0, 9);
exsr12(0xb0, 10);
exsr12(0xc0, 11);
exsr12(0xd0, 12);
exsr12(0xe0, 13);
exsr12(0xf0, 14);
exsr12(0xff, 15);
exsr12(0x10ff, 16);
exsr12(0x20ff, 17);
exsr12(0x30ff, 18);
exsr12(0x40ff, 19);
exsr12(0x50ff, 20);
exsr12(0x60ff, 21);
exsr12(0x70ff, 22);
exsr12(0x80ff, 23);
exsr12(0x90ff, 24);
exsr12(0xa0ff, 25);
exsr12(0xb0ff, 26);
exsr12(0xc0ff, 27);
exsr12(0xd0ff, 28);
exsr12(0xe0ff, 29);
exsr12(0xf0ff, 30);
exsr12(0xffff, -32);
printf("all done\n");
return 0;
}

@ -0,0 +1,175 @@
#include <string.h>
#include <stdio.h>
#include <glib.h>
#include <pcre.h>
#include "aux.h"
#if 0
#define BSDB(x...) fprintf(stderr, x)
#else
#define BSDB(x...) ((void)0)
#endif
int mybsearch(void *base, unsigned int len, unsigned int size, void *key, unsigned int key_off, unsigned int key_size, int exact) {
unsigned char *cbase = base;
int pos;
unsigned char *cur;
int res;
unsigned int num;
if (!len) {
BSDB("zero length array\n");
return -1;
}
pos = len / 2;
num = pos;
num += 3;
num /= 2;
pos--;
if (pos < 0)
pos = 0;
BSDB("starting pos=%u, num=%u\n", pos, num);
for (;;) {
cur = cbase + (pos * size);
res = memcmp(cur + key_off, key, key_size);
BSDB("compare=%i\n", res);
if (!res)
return pos;
if (!num) {
BSDB("nothing found\n");
if (exact)
return -1;
if (res > 0) /* cur > key */
return -1 * pos - 1;
return -1 * pos - 2;
}
if (res < 0) { /* cur < key */
pos += num;
if (pos >= len)
pos = len - 1;
}
else {
pos -= num;
if (pos < 0)
pos = 0;
}
BSDB("new pos=%u\n", pos);
if (num == 1)
num = 0;
else {
num++;
num /= 2;
}
BSDB("new num=%u\n", num);
}
}
GList *g_list_link(GList *list, GList *el) {
el->prev = NULL;
el->next = list;
if (list)
list->prev = el;
return el;
}
GQueue *pcre_multi_match(pcre **re, pcre_extra **ree, const char *rex, const char *s, unsigned int num, parse_func f, void *p) {
GQueue *q;
const char *errptr;
int erroff;
unsigned int start, len;
int ovec[60];
int *ov;
char **el;
unsigned int i;
void *ins;
if (!*re) {
*re = pcre_compile(rex, PCRE_DOLLAR_ENDONLY | PCRE_DOTALL, &errptr, &erroff, NULL);
if (!*re)
return NULL;
*ree = pcre_study(*re, 0, &errptr);
}
q = g_queue_new();
el = malloc(sizeof(*el) * num);
for (start = 0, len = strlen(s); pcre_exec(*re, *ree, s + start, len - start, 0, 0, ovec, G_N_ELEMENTS(ovec)) > 0; start += ovec[1]) {
for (i = 0; i < num; i++) {
ov = ovec + 2 + i*2;
el[i] = (ov[0] == -1) ? NULL : g_strndup(s + start + ov[0], ov[1] - ov[0]);
}
if (!f(el, &ins, p))
g_queue_push_tail(q, ins);
for (i = 0; i < num; i++) {
if (el[i])
free(el[i]);
}
}
free(el);
return q;
}
void strmove(char **d, char **s) {
if (*d)
free(*d);
*d = *s;
*s = strdup("");
}
void strdupfree(char **d, const char *s) {
if (*d)
free(*d);
*d = strdup(s);
}
#if !GLIB_CHECK_VERSION(2,14,0)
void g_string_vprintf(GString *string, const gchar *format, va_list args) {
char *s;
int r;
r = vasprintf(&s, format, args);
if (r < 0)
return;
g_string_assign(string, s);
free(s);
}
void g_queue_clear(GQueue *q) {
GList *l, *n;
if (!q)
return;
for (l = q->head; l; l = n) {
n = l->next;
g_list_free_1(l);
}
q->head = q->tail = NULL;
q->length = 0;
}
#endif

@ -0,0 +1,150 @@
#ifndef __AUX_H__
#define __AUX_H__
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <fcntl.h>
#include <glib.h>
#include <pcre.h>
#include <stdarg.h>
#include <arpa/inet.h>
#define OFFSET_OF(t,e) ((unsigned int) (unsigned long) &(((t *) 0)->e))
#define ZERO(x) memset(&(x), 0, sizeof(x))
#define IPF "%u.%u.%u.%u"
#define IPP(x) ((unsigned char *) (&(x)))[0], ((unsigned char *) (&(x)))[1], ((unsigned char *) (&(x)))[2], ((unsigned char *) (&(x)))[3]
#define IP6F "%x:%x:%x:%x:%x:%x:%x:%x"
#define IP6P(x) ntohs(((u_int16_t *) (x))[0]), \
ntohs(((u_int16_t *) (x))[1]), \
ntohs(((u_int16_t *) (x))[2]), \
ntohs(((u_int16_t *) (x))[3]), \
ntohs(((u_int16_t *) (x))[4]), \
ntohs(((u_int16_t *) (x))[5]), \
ntohs(((u_int16_t *) (x))[6]), \
ntohs(((u_int16_t *) (x))[7])
#define D6F "["IP6F"]:%u"
#define D6P(x) IP6P((x).sin6_addr.s6_addr), ntohs((x).sin6_port)
#define DF IPF ":%u"
#define DP(x) IPP((x).sin_addr.s_addr), ntohs((x).sin_port)
#define BIT_ARRAY_DECLARE(name, size) int name[((size) + sizeof(int) * 8 - 1) / (sizeof(int) * 8)]
typedef int (*parse_func)(char **, void **, void *);
int mybsearch(void *, unsigned int, unsigned int, void *, unsigned int, unsigned int, int);
GList *g_list_link(GList *, GList *);
GQueue *pcre_multi_match(pcre **, pcre_extra **, const char *, const char *, unsigned int, parse_func, void *);
void strmove(char **, char **);
void strdupfree(char **, const char *);
#if !GLIB_CHECK_VERSION(2,14,0)
#define G_QUEUE_INIT { NULL, NULL, 0 }
void g_string_vprintf(GString *string, const gchar *format, va_list args);
void g_queue_clear(GQueue *);
#endif
static inline void nonblock(int fd) {
fcntl(fd, F_SETFL, O_NONBLOCK);
}
static inline void reuseaddr(int fd) {
int one = 1;
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
}
static inline void ipv6only(int fd, int yn) {
setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &yn, sizeof(yn));
}
static inline int bit_array_isset(int *name, unsigned int bit) {
return name[(bit) / (sizeof(int) * 8)] & (1 << ((bit) % (sizeof(int) * 8)));
}
static inline void bit_array_set(int *name, unsigned int bit) {
name[(bit) / (sizeof(int) * 8)] |= 1 << ((bit) % (sizeof(int) * 8));
}
static inline void bit_array_clear(int *name, unsigned int bit) {
name[(bit) / (sizeof(int) * 8)] &= ~(1 << ((bit) % (sizeof(int) * 8)));
}
static inline char chrtoupper(char x) {
return x & 0xdf;
}
static inline void swap_ptrs(void *a, void *b) {
void *t, **aa, **bb;
aa = a;
bb = b;
t = *aa;
*aa = *bb;
*bb = t;
}
static inline void in4_to_6(struct in6_addr *o, u_int32_t ip) {
o->s6_addr32[0] = 0;
o->s6_addr32[1] = 0;
o->s6_addr32[2] = htonl(0xffff);
o->s6_addr32[3] = ip;
}
static inline void smart_ntop(char *o, struct in6_addr *a, size_t len) {
const char *r;
if (IN6_IS_ADDR_V4MAPPED(a))
r = inet_ntop(AF_INET, &(a->s6_addr32[3]), o, len);
else
r = inet_ntop(AF_INET6, a, o, len);
if (!r)
*o = '\0';
}
static inline void smart_ntop_p(char *o, struct in6_addr *a, size_t len) {
int l;
if (IN6_IS_ADDR_V4MAPPED(a)) {
if (!inet_ntop(AF_INET, &(a->s6_addr32[3]), o, len))
*o = '\0';
}
else {
*o = '[';
if (!inet_ntop(AF_INET6, a, o+1, len-2)) {
*o = '\0';
return;
}
l = strlen(o);
o[l] = ']';
o[l+1] = '\0';
}
}
static inline int smart_pton(int af, char *src, void *dst) {
char *p;
int ret;
if (af == AF_INET6) {
if (src[0] == '[' && (p = strchr(src, ']'))) {
*p = '\0';
ret = inet_pton(af, src+1, dst);
*p = ']';
return ret;
}
}
return inet_pton(af, src, dst);
}
#endif

File diff suppressed because it is too large Load Diff

@ -0,0 +1,138 @@
#ifndef __CALL_H__
#define __CALL_H__
#include <sys/types.h>
#include <glib.h>
#include <time.h>
#include "control.h"
#include "control_udp.h"
struct poller;
struct control_stream;
struct peer;
struct callstream;
struct call;
struct callmaster;
struct redis;
struct stats {
u_int64_t packets;
u_int64_t bytes;
u_int64_t errors;
};
struct stream {
struct in6_addr ip46;
u_int16_t port;
char *mediatype;
enum {
DIR_UNKNOWN = 0,
DIR_INTERNAL,
DIR_EXTERNAL,
} direction[2];
int num;
};
struct streamrelay {
int fd;
int fd_family;
struct stream peer;
struct stream peer_advertised;
u_int16_t localport;
unsigned char idx;
struct peer *up;
struct stats stats;
struct stats kstats;
time_t last;
};
struct peer {
struct streamrelay rtps[2];
char *tag;
char *mediatype;
char *codec;
unsigned char idx;
struct callstream *up;
int desired_family;
int kernelized:1;
int filled:1;
int confirmed:1;
};
struct callstream {
struct peer peers[2];
struct call *call;
int num;
};
struct call {
struct callmaster *callmaster;
GQueue *callstreams;
char *callid;
char redis_uuid[37];
time_t created;
char *calling_agent;
char *called_agent;
GHashTable *infohash;
GHashTable *branches;
time_t lookup_done;
const char *log_info; /* branch */
};
struct callmaster {
GHashTable *callhash;
u_int16_t lastport;
struct stats statsps;
struct stats stats;
struct poller *poller;
struct redis *redis;
int kernelfd;
unsigned int kernelid;
u_int32_t ipv4;
u_int32_t adv_ipv4;
struct in6_addr ipv6;
struct in6_addr adv_ipv6;
int port_min;
int port_max;
unsigned int timeout;
unsigned int silent_timeout;
char *b2b_url;
unsigned char tos;
};
struct callmaster *callmaster_new(struct poller *);
char *call_request(const char **, struct callmaster *);
char *call_update_udp(const char **, struct callmaster *);
char *call_lookup(const char **, struct callmaster *);
char *call_lookup_udp(const char **, struct callmaster *);
void call_delete(const char **, struct callmaster *);
char *call_delete_udp(const char **, struct callmaster *);
void calls_status(struct callmaster *, struct control_stream *);
void calls_dump_redis(struct callmaster *);
struct call *call_get_or_create(const char *callid, const char *viabranch, struct callmaster *m);
void callstream_init(struct callstream *s, struct call *ca, int port1, int port2, int num);
void kernelize(struct callstream *c);
#endif

@ -0,0 +1,244 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <pcre.h>
#include "control.h"
#include "poller.h"
#include "aux.h"
#include "streambuf.h"
#include "log.h"
#include "call.h"
static pcre *parse_re;
static pcre_extra *parse_ree;
static void control_stream_closed(int fd, void *p) {
struct control_stream *s = p;
struct control *c;
mylog(LOG_INFO, "Control connection from " DF " closed", DP(s->inaddr));
c = s->control;
c->stream_head = g_list_remove_link(c->stream_head, &s->link);
close(fd);
if (poller_del_item(s->poller, fd))
abort();
streambuf_destroy(s->inbuf);
streambuf_destroy(s->outbuf);
free(s);
}
static void control_list(struct control *c, struct control_stream *s) {
struct control_stream *i;
for (i = (void *) c->stream_head; i; i = (void *) i->link.next)
streambuf_printf(s->outbuf, DF "\n", DP(s->inaddr));
streambuf_printf(s->outbuf, "End.\n");
}
static int control_stream_parse(struct control_stream *s, char *line) {
const char *errptr;
int erroff;
int ovec[60];
int ret;
const char **out;
struct control *c = s->control;
char *output = NULL;
if (!parse_re) {
parse_re = pcre_compile(
/* reqtype callid streams ip fromdom fromtype todom totype agent info |reqtype callid info | reqtype */
"^(?:(request|lookup)\\s+(\\S+)\\s+(\\S+)\\s+(\\S+)\\s+(\\S+)\\s+(\\S+)\\s+(\\S+)\\s+(\\S+)\\s+(\\S+)\\s+info=(\\S*)|(delete)\\s+(\\S+)\\s+info=(\\S*)|(build|version|controls|quit|exit|status))$",
PCRE_DOLLAR_ENDONLY | PCRE_DOTALL, &errptr, &erroff, NULL);
parse_ree = pcre_study(parse_re, 0, &errptr);
}
ret = pcre_exec(parse_re, parse_ree, line, strlen(line), 0, 0, ovec, G_N_ELEMENTS(ovec));
if (ret <= 0) {
mylog(LOG_WARNING, "Unable to parse command line from " DF ": %s", DP(s->inaddr), line);
return -1;
}
mylog(LOG_INFO, "Got valid command from " DF ": %s", DP(s->inaddr), line);
pcre_get_substring_list(line, ovec, ret, &out);
if (!strcmp(out[RE_TCP_RL_CMD], "request"))
output = call_request(out, c->callmaster);
else if (!strcmp(out[RE_TCP_RL_CMD], "lookup"))
output = call_lookup(out, c->callmaster);
else if (!strcmp(out[RE_TCP_D_CMD], "delete"))
call_delete(out, c->callmaster);
else if (!strcmp(out[RE_TCP_DIV_CMD], "status"))
calls_status(c->callmaster, s);
else if (!strcmp(out[RE_TCP_DIV_CMD], "build") | !strcmp(out[RE_TCP_DIV_CMD], "version"))
streambuf_printf(s->outbuf, "Version: %s\n", MEDIAPROXY_VERSION);
else if (!strcmp(out[RE_TCP_DIV_CMD], "controls"))
control_list(c, s);
else if (!strcmp(out[RE_TCP_DIV_CMD], "quit") || !strcmp(out[RE_TCP_DIV_CMD], "exit"))
;
if (output) {
streambuf_write(s->outbuf, output, strlen(output));
free(output);
}
pcre_free(out);
return -1;
}
static void control_stream_timer(int fd, void *p) {
struct control_stream *s = p;
struct poller *o = s->poller;
if ((o->now - s->inbuf->active) >= 60 || (o->now - s->outbuf->active) >= 60)
control_stream_closed(s->fd, s);
}
static void control_stream_readable(int fd, void *p) {
struct control_stream *s = p;
char *line;
int ret;
if (streambuf_readable(s->inbuf))
goto close;
while ((line = streambuf_getline(s->inbuf))) {
mylog(LOG_DEBUG, "Got control line from " DF ": %s", DP(s->inaddr), line);
ret = control_stream_parse(s, line);
free(line);
if (ret)
goto close;
}
if (streambuf_bufsize(s->inbuf) > 1024) {
mylog(LOG_WARNING, "Buffer length exceeded in control connection from " DF, DP(s->inaddr));
goto close;
}
return;
close:
control_stream_closed(fd, s);
}
static void control_stream_writeable(int fd, void *p) {
struct control_stream *s = p;
if (streambuf_writeable(s->outbuf))
control_stream_closed(fd, s);
}
static void control_closed(int fd, void *p) {
abort();
}
static void control_incoming(int fd, void *p) {
int nfd;
struct control *c = p;
struct control_stream *s;
struct poller_item i;
struct sockaddr_in sin;
socklen_t sinl;
sinl = sizeof(sin);
nfd = accept(fd, (struct sockaddr *) &sin, &sinl);
if (nfd == -1)
return;
nonblock(nfd);
mylog(LOG_INFO, "New control connection from " DF, DP(sin));
s = malloc(sizeof(*s));
ZERO(*s);
ZERO(i);
i.fd = nfd;
i.closed = control_stream_closed;
i.readable = control_stream_readable;
i.writeable = control_stream_writeable;
i.timer = control_stream_timer;
i.ptr = s;
if (poller_add_item(c->poller, &i))
goto fail;
s->fd = nfd;
s->control = c;
s->poller = c->poller;
s->inbuf = streambuf_new(c->poller, nfd);
s->outbuf = streambuf_new(c->poller, nfd);
memcpy(&s->inaddr, &sin, sizeof(s->inaddr));
c->stream_head = g_list_link(c->stream_head, &s->link);
return;
fail:
free(s);
close(nfd);
}
struct control *control_new(struct poller *p, u_int32_t ip, u_int16_t port, struct callmaster *m) {
int fd;
struct control *c;
struct poller_item i;
struct sockaddr_in sin;
if (!p)
return NULL;
if (!m)
return NULL;
fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd == -1)
return NULL;
nonblock(fd);
reuseaddr(fd);
ZERO(sin);
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = ip;
sin.sin_port = htons(port);
if (bind(fd, (struct sockaddr *) &sin, sizeof(sin)))
goto fail;
if (listen(fd, 5))
goto fail;
c = malloc(sizeof(*c));
ZERO(*c);
c->fd = fd;
c->poller = p;
c->callmaster = m;
ZERO(i);
i.fd = fd;
i.closed = control_closed;
i.readable = control_incoming;
i.ptr = c;
if (poller_add_item(p, &i))
goto fail2;
return c;
fail2:
free(c);
fail:
close(fd);
return NULL;
}

@ -0,0 +1,61 @@
#ifndef __CONTROL_H__
#define __CONTROL_H__
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <glib.h>
#define RE_TCP_RL_CMD 1
#define RE_TCP_RL_CALLID 2
#define RE_TCP_RL_STREAMS 3
#define RE_TCP_RL_IP 4
#define RE_TCP_RL_FROMDOM 5
#define RE_TCP_RL_FROMTYPE 6
#define RE_TCP_RL_TODOM 7
#define RE_TCP_RL_TOTYPE 8
#define RE_TCP_RL_AGENT 9
#define RE_TCP_RL_INFO 10
#define RE_TCP_D_CMD 11
#define RE_TCP_D_CALLID 12
#define RE_TCP_D_INFO 13
#define RE_TCP_DIV_CMD 14
struct poller;
struct control;
struct streambuf;
struct callmaster;
struct control_stream {
GList link; /* must be first */
int fd;
struct streambuf *inbuf;
struct streambuf *outbuf;
struct sockaddr_in inaddr;
struct control *control;
struct poller *poller;
};
struct control {
int fd;
GList *stream_head;
struct poller *poller;
struct callmaster *callmaster;
};
struct control *control_new(struct poller *, u_int32_t, u_int16_t, struct callmaster *);
#endif

@ -0,0 +1,236 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <pcre.h>
#include <glib.h>
#include <time.h>
#include <netinet/in.h>
#include "control_udp.h"
#include "poller.h"
#include "aux.h"
#include "log.h"
#include "call.h"
static void control_udp_closed(int fd, void *p) {
abort();
}
static void control_udp_incoming(int fd, void *p) {
struct control_udp *u = p;
int ret, len;
char buf[8192];
struct sockaddr_in6 sin;
socklen_t sin_len;
int ovec[100];
const char **out;
char *reply;
struct msghdr mh;
struct iovec iov[10];
char addr[64];
sin_len = sizeof(sin);
len = recvfrom(fd, buf, sizeof(buf) - 1, 0, (struct sockaddr *) &sin, &sin_len);
if (len <= 0) {
mylog(LOG_WARNING, "Error reading from UDP socket");
return;
}
buf[len] = '\0';
smart_ntop_p(addr, &sin.sin6_addr, sizeof(addr));
ret = pcre_exec(u->parse_re, u->parse_ree, buf, len, 0, 0, ovec, G_N_ELEMENTS(ovec));
if (ret <= 0) {
ret = pcre_exec(u->fallback_re, NULL, buf, len, 0, 0, ovec, G_N_ELEMENTS(ovec));
if (ret <= 0) {
mylog(LOG_WARNING, "Unable to parse command line from udp:%s:%u: %s", addr, ntohs(sin.sin6_port), buf);
return;
}
mylog(LOG_WARNING, "Failed to properly parse UDP command line '%s' from %s:%u, using fallback RE", buf, addr, ntohs(sin.sin6_port));
pcre_get_substring_list(buf, ovec, ret, &out);
ZERO(mh);
mh.msg_name = &sin;
mh.msg_namelen = sizeof(sin);
mh.msg_iov = iov;
iov[0].iov_base = (void *) out[RE_UDP_COOKIE];
iov[0].iov_len = strlen(out[RE_UDP_COOKIE]);
if (out[RE_UDP_UL_CMD] && (chrtoupper(out[RE_UDP_UL_CMD][0]) == 'U' || chrtoupper(out[RE_UDP_UL_CMD][0]) == 'L')) {
iov[1].iov_base = (void *) out[RE_UDP_UL_CALLID];
iov[1].iov_len = strlen(out[RE_UDP_UL_CALLID]);
iov[2].iov_base = (void *) out[RE_UDP_UL_FLAGS];
iov[2].iov_len = strlen(out[RE_UDP_UL_FLAGS]);
iov[3].iov_base = "\n";
iov[3].iov_len = 1;
mh.msg_iovlen = 4;
}
else {
iov[1].iov_base = " E8\n";
iov[1].iov_len = 4;
mh.msg_iovlen = 2;
}
sendmsg(fd, &mh, 0);
pcre_free(out);
return;
}
mylog(LOG_INFO, "Got valid command from udp:%s:%u: %s", addr, ntohs(sin.sin6_port), buf);
pcre_get_substring_list(buf, ovec, ret, &out);
if (u->poller->now - u->oven_time >= 30) {
g_hash_table_remove_all(u->stale_cookies);
#if GLIB_CHECK_VERSION(2,14,0)
g_string_chunk_clear(u->stale_chunks);
swap_ptrs(&u->stale_chunks, &u->fresh_chunks);
#else
g_string_chunk_free(u->stale_chunks);
u->stale_chunks = u->fresh_chunks;
u->fresh_chunks = g_string_chunk_new(4 * 1024);
#endif
swap_ptrs(&u->stale_cookies, &u->fresh_cookies);
u->oven_time = u->poller->now; /* baked new cookies! */
}
/* XXX better hashing */
reply = g_hash_table_lookup(u->fresh_cookies, out[RE_UDP_COOKIE]);
if (!reply)
reply = g_hash_table_lookup(u->stale_cookies, out[RE_UDP_COOKIE]);
if (reply) {
mylog(LOG_INFO, "Detected command from udp:%s:%u as a duplicate", addr, ntohs(sin.sin6_port));
sendto(fd, reply, strlen(reply), 0, (struct sockaddr *) &sin, sin_len);
goto out;
}
if (chrtoupper(out[RE_UDP_UL_CMD][0]) == 'U')
reply = call_update_udp(out, u->callmaster);
else if (chrtoupper(out[RE_UDP_UL_CMD][0]) == 'L')
reply = call_lookup_udp(out, u->callmaster);
else if (chrtoupper(out[RE_UDP_D_CMD][0]) == 'D')
reply = call_delete_udp(out, u->callmaster);
else if (chrtoupper(out[RE_UDP_V_CMD][0]) == 'V') {
ZERO(mh);
mh.msg_name = &sin;
mh.msg_namelen = sizeof(sin);
mh.msg_iov = iov;
mh.msg_iovlen = 2;
iov[0].iov_base = (void *) out[RE_UDP_COOKIE];
iov[0].iov_len = strlen(out[RE_UDP_COOKIE]);
iov[1].iov_base = " ";
iov[1].iov_len = 1;
if (chrtoupper(out[RE_UDP_V_FLAGS][0]) == 'F') {
ret = 0;
if (!strcmp(out[RE_UDP_V_PARMS], "20040107"))
ret = 1;
else if (!strcmp(out[RE_UDP_V_PARMS], "20050322"))
ret = 1;
else if (!strcmp(out[RE_UDP_V_PARMS], "20060704"))
ret = 1;
iov[2].iov_base = ret ? "1\n" : "0\n";
iov[2].iov_len = 2;
mh.msg_iovlen++;
}
else {
iov[2].iov_base = "20040107\n";
iov[2].iov_len = 9;
mh.msg_iovlen++;
}
sendmsg(fd, &mh, 0);
}
if (reply) {
sendto(fd, reply, strlen(reply), 0, (struct sockaddr *) &sin, sin_len);
g_hash_table_insert(u->fresh_cookies, g_string_chunk_insert(u->fresh_chunks, out[RE_UDP_COOKIE]),
g_string_chunk_insert(u->fresh_chunks, reply));
free(reply);
}
out:
pcre_free(out);
}
struct control_udp *control_udp_new(struct poller *p, struct in6_addr ip, u_int16_t port, struct callmaster *m) {
int fd;
struct control_udp *c;
struct poller_item i;
struct sockaddr_in6 sin;
const char *errptr;
int erroff;
if (!p || !m)
return NULL;
fd = socket(AF_INET6, SOCK_DGRAM, 0);
if (fd == -1)
return NULL;
nonblock(fd);
reuseaddr(fd);
ipv6only(fd, 0);
ZERO(sin);
sin.sin6_family = AF_INET6;
sin.sin6_addr = ip;
sin.sin6_port = htons(port);
if (bind(fd, (struct sockaddr *) &sin, sizeof(sin)))
goto fail;
c = malloc(sizeof(*c));
ZERO(*c);
c->fd = fd;
c->poller = p;
c->callmaster = m;
c->fresh_cookies = g_hash_table_new(g_str_hash, g_str_equal);
c->stale_cookies = g_hash_table_new(g_str_hash, g_str_equal);
c->fresh_chunks = g_string_chunk_new(4 * 1024);
c->stale_chunks = g_string_chunk_new(4 * 1024);
c->oven_time = p->now;
c->parse_re = pcre_compile(
/* cookie cmd flags callid viabranch:5 */
"^(\\S+)\\s+(?:([ul])(\\S*)\\s+([^;]+)(?:;(\\S+))?\\s+" \
/* addr4 addr6:7 */
"(?:([\\d.]+)|([\\da-f:]+(?::ffff:[\\d.]+)?))" \
/* port fromtag num totag:11 */
"\\s+(\\d+)\\s+(\\S+?);(\\d+)(?:\\s+(\\S+?);\\d+(?:\\s+.*)?)?\r?\n?$" \
/* "d" flags callid viabranch fromtag totag:17 */
"|(d)(\\S*)\\s+([^;\\s]+)(?:;(\\S+))?\\s+(\\S+?)(?:\\s+(\\S+?))?\r?\n?$" \
/* v flags params:20 */
"|(v)(\\S*)(?:\\s+(\\S+))?)",
PCRE_DOLLAR_ENDONLY | PCRE_DOTALL | PCRE_CASELESS, &errptr, &erroff, NULL);
c->parse_ree = pcre_study(c->parse_re, 0, &errptr);
/* cookie cmd flags callid addr port */
c->fallback_re = pcre_compile("^(\\S+)(?:\\s+(\\S)\\S*\\s+\\S+(\\s+\\S+)(\\s+\\S+))?", PCRE_DOLLAR_ENDONLY | PCRE_DOTALL | PCRE_CASELESS, &errptr, &erroff, NULL);
if (!c->parse_re || !c->fallback_re)
goto fail2;
ZERO(i);
i.fd = fd;
i.closed = control_udp_closed;
i.readable = control_udp_incoming;
i.ptr = c;
if (poller_add_item(p, &i))
goto fail2;
return c;
fail2:
free(c);
fail:
close(fd);
return NULL;
}

@ -0,0 +1,63 @@
#ifndef __CONTROL_UDP_H__
#define __CONTROL_UDP_H__
#include <pcre.h>
#include <glib.h>
#include <time.h>
#include <netinet/in.h>
#define RE_UDP_COOKIE 1
#define RE_UDP_UL_CMD 2
#define RE_UDP_UL_FLAGS 3
#define RE_UDP_UL_CALLID 4
#define RE_UDP_UL_VIABRANCH 5
#define RE_UDP_UL_ADDR4 6
#define RE_UDP_UL_ADDR6 7
#define RE_UDP_UL_PORT 8
#define RE_UDP_UL_FROMTAG 9
#define RE_UDP_UL_NUM 10
#define RE_UDP_UL_TOTAG 11
#define RE_UDP_D_CMD 12
#define RE_UDP_D_FLAGS 13
#define RE_UDP_D_CALLID 14
#define RE_UDP_D_VIABRANCH 15
#define RE_UDP_D_FROMTAG 16
#define RE_UDP_D_TOTAG 17
#define RE_UDP_V_CMD 18
#define RE_UDP_V_FLAGS 19
#define RE_UDP_V_PARMS 20
struct poller;
struct callmaster;
struct control_udp {
int fd;
struct poller *poller;
struct callmaster *callmaster;
pcre *parse_re;
pcre_extra *parse_ree;
pcre *fallback_re;
GHashTable *fresh_cookies, *stale_cookies;
GStringChunk *fresh_chunks, *stale_chunks;
time_t oven_time;
};
struct control_udp *control_udp_new(struct poller *, struct in6_addr, u_int16_t, struct callmaster *);
#endif

@ -0,0 +1,142 @@
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <glib.h>
#include "xt_MEDIAPROXY.h"
#include "aux.h"
#include "kernel.h"
#if 1
#define PREFIX "/proc/mediaproxy"
#else
#define PREFIX "/tmp/mediaproxy"
#endif
int kernel_create_table(unsigned int id) {
char str[64];
int fd;
int i;
fd = open(PREFIX "/control", O_WRONLY | O_TRUNC);
if (fd == -1)
return -1;
sprintf(str, "add %u\n", id);
i = write(fd, str, strlen(str));
if (i == -1)
goto fail;
close(fd);
return 0;
fail:
close(fd);
return -1;
}
int kernel_open_table(unsigned int id) {
char str[64];
int fd;
struct mediaproxy_message msg;
int i;
sprintf(str, PREFIX "/%u/control", id);
fd = open(str, O_WRONLY | O_TRUNC);
if (fd == -1)
return -1;
ZERO(msg);
msg.cmd = MMG_NOOP;
i = write(fd, &msg, sizeof(msg));
if (i <= 0)
goto fail;
return fd;
fail:
close(fd);
return -1;
}
static void addr_copy(struct mp_address *mp, struct ip_port *ap) {
mp->family = ap->family;
mp->port = ap->port;
switch (mp->family) {
case AF_INET:
mp->ipv4 = ap->ipv4;
break;
case AF_INET6:
memcpy(mp->ipv6, &ap->ipv6, 16);
break;
default:
/* XXX panic */
break;
}
}
int kernel_add_stream(int fd, struct kernel_stream *info, int update) {
struct mediaproxy_message msg;
ZERO(msg);
msg.cmd = update ? MMG_UPDATE : MMG_ADD;
msg.target.target_port = info->local_port;
addr_copy(&msg.target.src_addr, &info->src);
addr_copy(&msg.target.dst_addr, &info->dest);
addr_copy(&msg.target.mirror_addr, &info->mirror);
msg.target.tos = info->tos;
return write(fd, &msg, sizeof(msg)) <= 0 ? -1 : 0;
}
int kernel_del_stream(int fd, u_int16_t p) {
struct mediaproxy_message msg;
ZERO(msg);
msg.cmd = MMG_DEL;
msg.target.target_port = p;
return write(fd, &msg, sizeof(msg)) <= 0 ? -1 : 0;
}
GList *kernel_list(unsigned int id) {
char str[64];
int fd;
struct mediaproxy_list_entry *buf;
GList *li = NULL;
int ret;
sprintf(str, PREFIX "/%u/blist", id);
fd = open(str, O_RDONLY);
if (fd == -1)
return NULL;
for (;;) {
buf = g_slice_alloc(sizeof(*buf));
ret = read(fd, buf, sizeof(*buf));
if (ret != sizeof(*buf))
break;
li = g_list_prepend(li, buf);
}
g_slice_free1(sizeof(*buf), buf);
close(fd);
return li;
}

@ -0,0 +1,42 @@
#ifndef __KERNEL_H__
#define __KERNEL_H__
#include <sys/types.h>
#include <glib.h>
struct ip_port {
int family;
union {
u_int32_t ipv4;
struct in6_addr ipv6;
};
u_int16_t port;
};
struct kernel_stream {
u_int16_t local_port;
struct ip_port src;
struct ip_port dest;
struct ip_port mirror;
unsigned char tos;
};
int kernel_create_table(unsigned int);
int kernel_open_table(unsigned int);
int kernel_add_stream(int, struct kernel_stream *, int);
int kernel_del_stream(int, u_int16_t);
GList *kernel_list(unsigned int);
#endif

@ -0,0 +1,12 @@
#ifndef __LOG_H__
#define __LOG_H__
#include <syslog.h>
#define mylog(x,y...) syslog(x,y)
#endif

@ -0,0 +1,370 @@
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sys/resource.h>
#include <glib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <dlfcn.h>
#include "poller.h"
#include "control.h"
#include "control_udp.h"
#include "aux.h"
#include "log.h"
#include "call.h"
#include "kernel.h"
#include "redis.h"
#define die(x...) do { fprintf(stderr, x); exit(-1); } while(0)
#define dlresolve(m,n) do { \
n = dlsym(m, "mod_" #n); \
if (!n) \
die("Failed to resolve symbol from plugin: %s\n", #n); \
} while(0)
static char *pidfile;
static gboolean foreground;
static u_int32_t ipv4;
static u_int32_t adv_ipv4;
static struct in6_addr ipv6;
static struct in6_addr adv_ipv6;
static u_int32_t listenp;
static u_int16_t listenport;
static struct in6_addr udp_listenp;
static u_int16_t udp_listenport;
static int tos;
static int table;
static int no_fallback;
static int timeout;
static int silent_timeout;
static int port_min;
static int port_max;
static u_int32_t redis_ip;
static u_int16_t redis_port;
static int redis_db = -1;
static char *b2b_url;
static void signals(void) {
signal(SIGPIPE, SIG_IGN);
signal(SIGCHLD, SIG_IGN);
}
static int rlim(int res, rlim_t val) {
struct rlimit rlim;
ZERO(rlim);
rlim.rlim_cur = rlim.rlim_max = val;
return setrlimit(res, &rlim);
}
static void resources(void) {
int tryv;
rlim(RLIMIT_CORE, RLIM_INFINITY);
for (tryv = ((1<<16) - 1); tryv && rlim(RLIMIT_NOFILE, tryv) == -1; tryv >>= 1)
;
rlim(RLIMIT_DATA, RLIM_INFINITY);
rlim(RLIMIT_RSS, RLIM_INFINITY);
rlim(RLIMIT_AS, RLIM_INFINITY);
}
static int parse_ip_port(u_int32_t *ip, u_int16_t *port, char *s) {
char *p = NULL;
int ret = -1;
p = strchr(s, ':');
if (p) {
*p++ = 0;
*ip = inet_addr(s);
if (*ip == -1)
goto out;
*port = atoi(p);
}
else {
*ip = 0;
if (strchr(s, '.'))
goto out;
*port = atoi(s);
}
if (!*port)
goto out;
ret = 0;
out:
if (p)
*--p = ':';
return ret;
}
static int parse_ip6_port(struct in6_addr *ip6, u_int16_t *port, char *s) {
u_int32_t ip;
char *p;
if (!parse_ip_port(&ip, port, s)) {
if (ip)
in4_to_6(ip6, ip);
else
*ip6 = in6addr_any;
return 0;
}
if (*s != '[')
return -1;
p = strstr(s, "]:");
if (!p)
return -1;
*p = '\0';
if (inet_pton(AF_INET6, s+1, ip6) != 1)
goto fail;
*p = ']';
*port = atoi(p+2);
if (!*port)
return -1;
return 0;
fail:
*p = ']';
return -1;
}
static void options(int *argc, char ***argv) {
static char *ipv4s;
static char *adv_ipv4s;
static char *ipv6s;
static char *adv_ipv6s;
static char *listenps;
static char *listenudps;
static char *redisps;
static int version;
static GOptionEntry e[] = {
{ "version", 'v', 0, G_OPTION_ARG_NONE, &version, "Print build time and exit", NULL },
{ "table", 't', 0, G_OPTION_ARG_INT, &table, "Kernel table to use", "INT" },
{ "no-fallback",'F', 0, G_OPTION_ARG_NONE, &no_fallback, "Only start when kernel module is available", NULL },
{ "ip", 'i', 0, G_OPTION_ARG_STRING, &ipv4s, "Local IPv4 address for RTP", "IP" },
{ "advertised-ip", 'a', 0, G_OPTION_ARG_STRING, &adv_ipv4s, "IPv4 address to advertise", "IP" },
{ "ip6", 'I', 0, G_OPTION_ARG_STRING, &ipv6s, "Local IPv6 address for RTP", "IP6" },
{ "advertised-ip6",'A',0,G_OPTION_ARG_STRING, &adv_ipv6s, "IPv6 address to advertise", "IP6" },
{ "listen", 'l', 0, G_OPTION_ARG_STRING, &listenps, "TCP port to listen on", "[IP:]PORT" },
{ "listen-udp", 'u', 0, G_OPTION_ARG_STRING, &listenudps, "UDP port to listen on", "[IP46:]PORT" },
{ "tos", 'T', 0, G_OPTION_ARG_INT, &tos, "TOS value to set on streams", "INT" },
{ "timeout", 'o', 0, G_OPTION_ARG_INT, &timeout, "RTP timeout", "SECS" },
{ "silent-timeout",'s',0,G_OPTION_ARG_INT, &silent_timeout,"RTP timeout for muted", "SECS" },
{ "pidfile", 'p', 0, G_OPTION_ARG_STRING, &pidfile, "Write PID to file", "FILE" },
{ "foreground", 'f', 0, G_OPTION_ARG_NONE, &foreground, "Don't fork to background", NULL },
{ "port-min", 'm', 0, G_OPTION_ARG_INT, &port_min, "Lowest port to use for RTP", "INT" },
{ "port-max", 'M', 0, G_OPTION_ARG_INT, &port_max, "Highest port to use for RTP", "INT" },
{ "redis", 'r', 0, G_OPTION_ARG_STRING, &redisps, "Connect to Redis database", "IP:PORT" },
{ "redis-db", 'R', 0, G_OPTION_ARG_INT, &redis_db, "Which Redis DB to use", "INT" },
{ "b2b-url", 'b', 0, G_OPTION_ARG_STRING, &b2b_url, "XMLRPC URL of B2B UA" , "STRING" },
{ NULL, }
};
GOptionContext *c;
GError *er = NULL;
c = g_option_context_new(" - next-generation media proxy");
g_option_context_add_main_entries(c, e, NULL);
if (!g_option_context_parse(c, argc, argv, &er))
die("Bad command line: %s\n", er->message);
if (version)
die("%s\n", MEDIAPROXY_VERSION);
if (!ipv4s)
die("Missing option --ip\n");
if (!listenps && !listenudps)
die("Missing option --listen or --listen-udp\n");
ipv4 = inet_addr(ipv4s);
if (ipv4 == -1)
die("Invalid IPv4 address (--ip)\n");
if (adv_ipv4s) {
adv_ipv4 = inet_addr(adv_ipv4s);
if (adv_ipv4 == -1)
die("Invalid IPv4 address (--advertised-ip)\n");
}
if (ipv6s) {
if (smart_pton(AF_INET6, ipv6s, &ipv6) != 1)
die("Invalid IPv6 address (--ip6)\n");
}
if (adv_ipv6s) {
if (smart_pton(AF_INET6, adv_ipv6s, &adv_ipv6) != 1)
die("Invalid IPv6 address (--advertised-ip6)\n");
}
if (listenps) {
if (parse_ip_port(&listenp, &listenport, listenps))
die("Invalid IP or port (--listen)\n");
}
if (listenudps) {
if (parse_ip6_port(&udp_listenp, &udp_listenport, listenudps))
die("Invalid IP or port (--listen-udp)\n");
}
if (tos < 0 || tos > 255)
die("Invalid TOS value\n");
if (timeout <= 0)
timeout = 60;
if (silent_timeout <= 0)
silent_timeout = 3600;
if (redisps) {
if (parse_ip_port(&redis_ip, &redis_port, redisps) || !redis_ip)
die("Invalid IP or port (--redis)\n");
if (redis_db < 0)
die("Must specify Redis DB number (--redis-db) when using Redis\n");
}
}
static void daemonize(void) {
printf("Going to background...\n");
if (fork())
_exit(0);
freopen("/dev/null", "r", stdin);
freopen("/dev/null", "w", stdout);
freopen("/dev/null", "w", stderr);
setpgrp();
}
static void wpidfile(void) {
FILE *fp;
if (!pidfile)
return;
fp = fopen(pidfile, "w");
if (fp) {
fprintf(fp, "%u\n", getpid());
fclose(fp);
}
}
int main(int argc, char **argv) {
struct poller *p;
struct callmaster *m;
struct control *c;
struct control_udp *cu;
int kfd = -1;
int ret;
void *dlh;
const char **strp;
options(&argc, &argv);
signals();
resources();
if (table >= 0 && kernel_create_table(table)) {
fprintf(stderr, "FAILED TO CREATE KERNEL TABLE %i, KERNEL FORWARDING DISABLED\n", table);
mylog(LOG_CRIT, "FAILED TO CREATE KERNEL TABLE %i, KERNEL FORWARDING DISABLED\n", table);
table = -1;
if (no_fallback)
exit(-1);
}
if (table >= 0) {
kfd = kernel_open_table(table);
if (kfd == -1) {
fprintf(stderr, "FAILED TO OPEN KERNEL TABLE %i, KERNEL FORWARDING DISABLED\n", table);
mylog(LOG_CRIT, "FAILED TO OPEN KERNEL TABLE %i, KERNEL FORWARDING DISABLED\n", table);
table = -1;
if (no_fallback)
exit(-1);
}
}
p = poller_new();
if (!p)
die("poller creation failed\n");
m = callmaster_new(p);
if (!m)
return -1;
m->kernelfd = kfd;
m->kernelid = table;
m->ipv4 = ipv4;
m->adv_ipv4 = adv_ipv4;
m->ipv6 = ipv6;
m->adv_ipv6 = adv_ipv6;
m->port_min = port_min;
m->port_max = port_max;
m->timeout = timeout;
m->silent_timeout = silent_timeout;
m->tos = tos;
m->b2b_url = b2b_url;
c = NULL;
if (listenport) {
c = control_new(p, listenp, listenport, m);
if (!c)
die("Failed to open TCP control connection port\n");
}
cu = NULL;
if (udp_listenport) {
cu = control_udp_new(p, udp_listenp, udp_listenport, m);
if (!cu)
die("Failed to open UDP control connection port\n");
}
if (redis_ip) {
dlh = dlopen(MP_PLUGIN_DIR "/redis.so", RTLD_NOW | RTLD_GLOBAL);
if (!dlh)
die("Failed to open redis plugin, aborting (%s)\n", dlerror());
strp = dlsym(dlh, "__module_version");
if (!strp || !*strp || strcmp(*strp, "redis/1.0.0"))
die("Incorrect redis module version: %s\n", *strp);
dlresolve(dlh, redis_new);
dlresolve(dlh, redis_restore);
dlresolve(dlh, redis_update);
dlresolve(dlh, redis_delete);
dlresolve(dlh, redis_wipe);
m->redis = redis_new(redis_ip, redis_port, redis_db);
if (!m->redis)
die("Cannot start up without Redis database\n");
}
mylog(LOG_INFO, "Startup complete");
if (!foreground)
daemonize();
wpidfile();
if (m->redis) {
if (redis_restore(m))
die("Refusing to continue without working Redis database\n");
}
for (;;) {
ret = poller_poll(p, 100);
if (ret == -1)
break;
}
return 0;
}

@ -0,0 +1,60 @@
#include <stdio.h>
#include <assert.h>
#include "poller.h"
void dummy(int a, void *b) {
}
int main() {
struct poller *p;
struct poller_item i;
p = poller_new();
if (!p) {
fprintf(stderr, "poller creation failed\n");
return -1;
}
assert(p->items_size == 0);
assert(p->pollfds_size == 0);
i.readable = dummy;
i.writeable = dummy;
i.closed = dummy;
i.fd = 3;
assert(poller_add_item(p, &i) == 0);
i.fd = 4;
assert(poller_add_item(p, &i) == 0);
i.fd = 2;
assert(poller_add_item(p, &i) == 0);
i.fd = 6;
assert(poller_add_item(p, &i) == 0);
i.fd = 0;
assert(poller_add_item(p, &i) == 0);
i.fd = 1;
assert(poller_add_item(p, &i) == 0);
i.fd = 5;
assert(poller_add_item(p, &i) == 0);
i.fd = 7;
assert(poller_add_item(p, &i) == 0);
i.fd = 9;
assert(poller_add_item(p, &i) == 0);
assert(poller_del_item(p, 10) == -1);
assert(poller_del_item(p, 6) == 0);
assert(poller_del_item(p, 8) == -1);
assert(poller_del_item(p, 0) == 0);
assert(poller_del_item(p, 3) == 0);
assert(poller_del_item(p, 11) == -1);
assert(poller_del_item(p, 9) == 0);
assert(poller_del_item(p, 11) == -1);
assert(poller_del_item(p, 4) == 0);
return 0;
}

@ -0,0 +1,311 @@
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <poll.h>
#include <string.h>
#include <time.h>
#include <assert.h>
#include <errno.h>
#include "poller.h"
#include "aux.h"
#define POLLER_BSEARCH(b,l,k,e) mybsearch(b, l, sizeof(struct pollfd), k, OFFSET_OF(struct pollfd, fd), sizeof(*(k)), e)
struct timer_item {
void (*func)(void *);
void *ptr;
};
struct poller *poller_new(void) {
struct poller *p;
p = malloc(sizeof(*p));
memset(p, 0, sizeof(*p));
p->now = time(NULL);
return p;
}
int poller_add_item(struct poller *p, struct poller_item *i) {
struct poller_item *ip;
struct pollfd *pf;
int idx;
unsigned int u;
if (!p || !i)
return -1;
if (i->fd < 0)
return -1;
if (!i->readable && !i->writeable)
return -1;
if (!i->closed)
return -1;
if (i->fd < p->items_size && p->items[i->fd])
return -1;
idx = POLLER_BSEARCH(p->pollfds, p->pollfds_size, &i->fd, 0);
assert(idx < 0);
idx *= -1;
idx--;
p->pollfds_size++;
p->pollfds = realloc(p->pollfds, p->pollfds_size * sizeof(*p->pollfds));
memmove(p->pollfds + idx + 1, p->pollfds + idx, (p->pollfds_size - idx - 1) * sizeof(*p->pollfds));
pf = &p->pollfds[idx];
pf->fd = i->fd;
pf->events = POLLHUP | POLLERR | ((i->writeable && i->blocked) ? POLLOUT : 0) | (i->readable ? POLLIN : 0);
pf->revents = 0;
if (i->fd >= p->items_size) {
u = p->items_size;
p->items_size = i->fd + 1;
p->items = realloc(p->items, sizeof(*p->items) * p->items_size);
memset(p->items + u, 0, sizeof(*p->items) * (p->items_size - u - 1));
}
ip = malloc(sizeof(*ip));
memcpy(ip, i, sizeof(*ip));
p->items[i->fd] = ip;
return 0;
}
int poller_del_item(struct poller *p, int fd) {
int idx;
if (!p || fd < 0)
return -1;
if (fd >= p->items_size)
return -1;
if (!p->items || !p->items[fd])
return -1;
if (!p->pollfds || !p->pollfds_size)
return -1;
idx = POLLER_BSEARCH(p->pollfds, p->pollfds_size, &fd, 1);
assert(idx != -1);
memmove(p->pollfds + idx, p->pollfds + idx + 1, (p->pollfds_size - idx - 1) * sizeof(*p->pollfds));
p->pollfds_size--;
p->pollfds = realloc(p->pollfds, p->pollfds_size * sizeof(*p->pollfds));
if (p->pollfds_work) {
idx = POLLER_BSEARCH(p->pollfds_work, p->pollfds_work_size, &fd, 1);
if (idx != -1)
p->pollfds_work[idx].fd = -1;
}
free(p->items[fd]);
p->items[fd] = NULL;
return 0;
}
int poller_update_item(struct poller *p, struct poller_item *i) {
struct poller_item *np;
if (!p || !i)
return -1;
if (i->fd < 0)
return -1;
if (!i->readable && !i->writeable)
return -1;
if (!i->closed)
return -1;
if (i->fd >= p->items_size || !(np = p->items[i->fd]))
return poller_add_item(p, i);
np->ptr = i->ptr;
np->readable = i->readable;
np->writeable = i->writeable;
np->closed = i->closed;
np->timer = i->timer;
return 0;
}
int poller_poll(struct poller *p, int timeout) {
struct pollfd *pfd, *pf;
int ret, i;
struct poller_item *it;
int idx;
time_t last;
int do_timer;
GList *li;
struct timer_item *ti;
if (!p)
return -1;
if (!p->pollfds || !p->pollfds_size)
return -1;
if (!p->items || !p->items_size)
return -1;
p->pollfds_work_size = i = p->pollfds_size;
p->pollfds_work = pfd = malloc(sizeof(*pfd) * i);
memcpy(pfd, p->pollfds, sizeof(*pfd) * i);
do_timer = 0;
last = p->now;
p->now = time(NULL);
if (last != p->now) {
do_timer = 1;
ret = i;
for (li = p->timers; li; li = li->next) {
ti = li->data;
ti->func(ti->ptr);
}
}
else {
ret = poll(pfd, i, timeout);
if (errno == EINTR)
ret = 0;
if (ret < 0)
goto out;
}
pf = pfd;
for (pf = pfd; i; pf++) {
i--;
if (pf->fd < 0)
continue;
it = (pf->fd < p->items_size) ? p->items[pf->fd] : NULL;
if (!it)
continue;
if (do_timer) {
if (it->timer)
it->timer(it->fd, it->ptr);
continue;
}
if (it->error) {
it->closed(it->fd, it->ptr);
continue;
}
if ((pf->revents & (POLLERR | POLLHUP)))
it->closed(it->fd, it->ptr);
else if ((pf->revents & POLLOUT)) {
it->blocked = 0;
idx = POLLER_BSEARCH(p->pollfds, p->pollfds_size, &it->fd, 1);
assert(idx != -1);
p->pollfds[idx].events &= ~POLLOUT;
it->writeable(it->fd, it->ptr);
}
else if ((pf->revents & POLLIN))
it->readable(it->fd, it->ptr);
else if (!pf->revents)
continue;
else
abort();
}
out:
free(pfd);
p->pollfds_work = NULL;
p->pollfds_work_size = 0;
return ret;
}
void poller_blocked(struct poller *p, int fd) {
int idx;
if (!p || fd < 0)
return;
if (fd >= p->items_size)
return;
if (!p->items || !p->items[fd])
return;
if (!p->pollfds || !p->pollfds_size)
return;
if (!p->items[fd]->writeable)
return;
p->items[fd]->blocked = 1;
idx = POLLER_BSEARCH(p->pollfds, p->pollfds_size, &fd, 1);
assert(idx != -1);
p->pollfds[idx].events |= POLLOUT;
}
void poller_error(struct poller *p, int fd) {
if (!p || fd < 0)
return;
if (fd >= p->items_size)
return;
if (!p->items || !p->items[fd])
return;
if (!p->pollfds || !p->pollfds_size)
return;
if (!p->items[fd]->writeable)
return;
p->items[fd]->error = 1;
p->items[fd]->blocked = 1;
}
int poller_isblocked(struct poller *p, int fd) {
if (!p || fd < 0)
return -1;
if (fd >= p->items_size)
return -1;
if (!p->items || !p->items[fd])
return -1;
if (!p->pollfds || !p->pollfds_size)
return -1;
if (!p->items[fd]->writeable)
return -1;
return p->items[fd]->blocked;
}
int poller_timer(struct poller *p, void (*f)(void *), void *ptr) {
struct timer_item *i;
if (!p || !f)
return -1;
i = malloc(sizeof(*i));
ZERO(*i);
i->func = f;
i->ptr = ptr;
p->timers = g_list_prepend(p->timers, i);
return 0;
}

@ -0,0 +1,51 @@
#ifndef __POLLER_H__
#define __POLLER_H__
#include <sys/types.h>
#include <time.h>
#include <glib.h>
struct poller_item {
int fd;
void *ptr;
void (*readable)(int, void *);
void (*writeable)(int, void *);
void (*closed)(int, void *);
void (*timer)(int, void *);
int blocked:1;
int error:1;
};
struct poller {
struct poller_item **items;
unsigned int items_size;
struct pollfd *pollfds;
unsigned int pollfds_size;
GList *timers;
time_t now;
struct pollfd *pollfds_work;
unsigned int pollfds_work_size;
};
struct poller *poller_new(void);
int poller_add_item(struct poller *, struct poller_item *);
int poller_update_item(struct poller *, struct poller_item *);
int poller_del_item(struct poller *, int);
int poller_poll(struct poller *, int);
void poller_blocked(struct poller *, int);
int poller_isblocked(struct poller *, int);
void poller_error(struct poller *, int);
int poller_timer(struct poller *, void (*)(void *), void *);
#endif

@ -0,0 +1,7 @@
#include "redis.h"
struct redis *(*redis_new)(u_int32_t, u_int16_t, int);
int (*redis_restore)(struct callmaster *);
void (*redis_update)(struct call *);
void (*redis_delete)(struct call *);
void (*redis_wipe)(struct callmaster *);

@ -0,0 +1,26 @@
#ifndef __REDIS_H__
#define __REDIS_H__
#include <sys/types.h>
struct callmaster;
struct call;
extern struct redis *(*redis_new)(u_int32_t, u_int16_t, int);
extern int (*redis_restore)(struct callmaster *);
extern void (*redis_update)(struct call *);
extern void (*redis_delete)(struct call *);
extern void (*redis_wipe)(struct callmaster *);
#endif

@ -0,0 +1,172 @@
#include <stdio.h>
#include <glib.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <stdarg.h>
#include <time.h>
#include "streambuf.h"
#include "poller.h"
#include "aux.h"
struct streambuf *streambuf_new(struct poller *p, int fd) {
struct streambuf *b;
b = malloc(sizeof(*b));
ZERO(*b);
b->buf = g_string_new("");
b->fd = fd;
b->poller = p;
b->active = p->now;
return b;
}
void streambuf_destroy(struct streambuf *b) {
g_string_free(b->buf, TRUE);
free(b);
}
int streambuf_writeable(struct streambuf *b) {
int ret;
unsigned int out;
for (;;) {
if (!b->buf->len)
break;
out = (b->buf->len > 1024) ? 1024 : b->buf->len;
ret = write(b->fd, b->buf->str, out);
if (ret < 0) {
if (errno != EINTR && errno != EAGAIN && errno != EWOULDBLOCK)
return -1;
ret = 0;
}
if (ret > 0) {
g_string_erase(b->buf, 0, ret);
b->active = b->poller->now;
}
if (ret != out) {
poller_blocked(b->poller, b->fd);
break;
}
}
return 0;
}
int streambuf_readable(struct streambuf *b) {
int ret;
char buf[1024];
for (;;) {
ret = read(b->fd, buf, 1024);
if (ret == 0)
return -1;
if (ret < 0) {
if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
break;
return -1;
}
g_string_append_len(b->buf, buf, ret);
b->active = b->poller->now;
}
return 0;
}
char *streambuf_getline(struct streambuf *b) {
char *p;
int len;
char *s = NULL;
for (;;) {
if (s)
free(s);
p = memchr(b->buf->str, '\n', b->buf->len);
if (!p)
return NULL;
len = p - b->buf->str;
if (len == 0) {
g_string_erase(b->buf, 0, 1);
continue;
}
s = malloc(len + 1);
memcpy(s, b->buf->str, len);
s[len] = '\0';
g_string_erase(b->buf, 0, len + 1);
if (s[--len] == '\r') {
if (len == 0)
continue;
s[len] = '\0';
}
break;
}
return s;
}
unsigned int streambuf_bufsize(struct streambuf *b) {
return b->buf->len;
}
void streambuf_printf(struct streambuf *b, char *f, ...) {
va_list va;
GString *gs;
va_start(va, f);
gs = g_string_new("");
g_string_vprintf(gs, f, va);
va_end(va);
streambuf_write(b, gs->str, gs->len);
g_string_free(gs, TRUE);
}
void streambuf_write(struct streambuf *b, char *s, unsigned int len) {
unsigned int out;
int ret;
while (len && !poller_isblocked(b->poller, b->fd)) {
out = (len > 1024) ? 1024 : len;
ret = write(b->fd, s, out);
if (ret < 0) {
if (errno != EINTR && errno != EAGAIN && errno != EWOULDBLOCK) {
poller_error(b->poller, b->fd);
break;
}
poller_blocked(b->poller, b->fd);
break;
}
if (ret == 0)
break;
s += ret;
len -= ret;
b->active = b->poller->now;
}
if (b->buf->len > 5242880)
poller_error(b->poller, b->fd);
else if (len)
g_string_append_len(b->buf, s, len);
}

@ -0,0 +1,35 @@
#ifndef __BUFFER_H__
#define __BUFFER_H__
#include <sys/types.h>
#include <time.h>
#include <glib.h>
struct poller;
struct streambuf {
GString *buf;
int fd;
struct poller *poller;
time_t active;
};
struct streambuf *streambuf_new(struct poller *, int);
void streambuf_destroy(struct streambuf *);
int streambuf_writeable(struct streambuf *);
int streambuf_readable(struct streambuf *);
char *streambuf_getline(struct streambuf *);
unsigned int streambuf_bufsize(struct streambuf *);
void streambuf_printf(struct streambuf *, char *, ...) __attribute__ ((format (printf, 2, 3)));
void streambuf_write(struct streambuf *, char *, unsigned int);
#endif

@ -0,0 +1,25 @@
ngcp-mediaproxy-ng-kernel for Debian
------------------------------------
This package only works with kernels >= 2.6.32.
Instructions for usage
~~~~~~~~~~~~~~~~~~~~~~
1) module-assistant:
% sudo apt-get install linux-headers-$(uname -r)
% sudo apt-get install ngcp-mediaproxy-ng-kernel-source
% sudo m-a prepare
% sudo m-a -v -f -l $(uname -r) -k /usr/src/linux-headers-$(uname -r) a-b ngcp-mediaproxy-ng-kernel
How to debug build process:
% sudo m-a -d -v --text-mode -l $(uname -r) -k /usr/src/linux-headers-$(uname -r) a-i ngcp-mediaproxy-ng-kernel
2) DKMS:
% sudo apt-get install ngcp-mediaproxy-ng-kernel-dkms
% sudo dkms add -m ngcp-mediaproxy-ng -v 0.1
% sudo dkms build --kernelsourcedir /usr/src/linux-headers-$(uname -r) -m ngcp-mediaproxy-ng -v 0.1
% sudo dkms install -m ngcp-mediaproxy-ng -v 0.1

138
debian/changelog vendored

@ -0,0 +1,138 @@
ngcp-mediaproxy-ng (1.6.6) unstable; urgency=low
* Support userspace-only operation mode
-- Richard Fuchs <rfuchs@sipwise.com> Wed, 16 May 2012 09:33:18 -0400
ngcp-mediaproxy-ng (1.6.5) unstable; urgency=low
* Fix daemon failing to correctly interpret "delete full call" message
-- Richard Fuchs <rfuchs@sipwise.com> Fri, 04 May 2012 11:21:11 -0400
ngcp-mediaproxy-ng (1.6.4) unstable; urgency=low
* Fix segfault
-- Richard Fuchs <rfuchs@sipwise.com> Tue, 06 Mar 2012 09:51:07 -0500
ngcp-mediaproxy-ng (1.6.3) unstable; urgency=low
* Fix the UDP control protocol
-- Richard Fuchs <rfuchs@sipwise.com> Tue, 06 Mar 2012 07:12:47 -0500
ngcp-mediaproxy-ng (1.6.2) unstable; urgency=low
* Check from/to tags in delete message
* Implement via-branch handling
* Don't strip debug symbols
-- Richard Fuchs <rfuchs@sipwise.com> Mon, 05 Mar 2012 04:31:07 -0500
ngcp-mediaproxy-ng (1.6.1) unstable; urgency=low
* Correctly remember address family across re-invites etc
-- Richard Fuchs <rfuchs@sipwise.com> Wed, 08 Feb 2012 10:34:33 -0500
ngcp-mediaproxy-ng (1.6.0) unstable; urgency=low
* Add full IPv6 support
* Attempt to handle unparsable proxy commands as much as possible
* Improve human-readable output in /proc
* Fix handling of calls with multiple media streams
-- Richard Fuchs <rfuchs@sipwise.com> Thu, 26 Jan 2012 07:30:25 -0500
ngcp-mediaproxy-ng (1.5.3) unstable; urgency=low
* Fix incorrect handling of lookups received without prior request
* Fix a long-standing bug that caused from/to tags to be ignored when using UDP protocol
* Properly timeout and cleanup UDP cookies
* Fix table 0 not showing up in /proc/mediaproxy/list
-- Richard Fuchs <rfuchs@sipwise.com> Thu, 08 Dec 2011 11:05:30 -0500
ngcp-mediaproxy-ng (1.5.2) unstable; urgency=low
* Fix bad tagging
-- Richard Fuchs <rfuchs@sipwise.com> Tue, 20 Sep 2011 10:41:42 -0400
ngcp-mediaproxy-ng (1.5.1) unstable; urgency=low
* Return a dummy/error reply over UDP when a call doesn't exist, so
kamailio doesn't think we're dead
-- Richard Fuchs <rfuchs@sipwise.com> Tue, 20 Sep 2011 10:41:42 -0400
ngcp-mediaproxy-ng (1.5.0) unstable; urgency=low
* Rework port re-use logic so it never opens new ports when it doesn't
need to.
-- Richard Fuchs <rfuchs@sipwise.com> Thu, 15 Sep 2011 10:42:57 -0400
ngcp-mediaproxy-ng (1.4.2) unstable; urgency=low
* Slightly increase syslog verbosity
* Fix obscure 3-way call connect issue
-- Richard Fuchs <rfuchs@sipwise.com> Fri, 02 Sep 2011 17:09:38 -0400
ngcp-mediaproxy-ng (1.4.1) unstable; urgency=low
* Fix a memory leak
-- Richard Fuchs <rfuchs@sipwise.com> Wed, 10 Aug 2011 17:01:56 -0400
ngcp-mediaproxy-ng (1.4.0) unstable; urgency=low
* Support HA through persistent Redis storage
-- Richard Fuchs <rfuchs@sipwise.com> Fri, 10 Jun 2011 13:50:50 -0400
ngcp-mediaproxy-ng (1.3.5) unstable; urgency=low
* Fix dst reference count issues causing kernel warnings under some circumstances
-- Richard Fuchs <rfuchs@sipwise.com> Thu, 19 May 2011 13:43:16 -0400
ngcp-mediaproxy-ng (1.3.4) unstable; urgency=low
* Make the daemon more aggressive with invalidating peer information
-- Richard Fuchs <rfuchs@sipwise.com> Thu, 05 May 2011 16:08:31 -0400
ngcp-mediaproxy-ng (1.3.3) unstable; urgency=low
* Add --advertised-ip to defaults file.
-- Andreas Granig <agranig@sipwise.com> Wed, 04 May 2011 23:26:30 +0200
ngcp-mediaproxy-ng (1.3.2) unstable; urgency=low
* Introduce --advertised-ip parameter
* Minor code & help text cleanups
-- Richard Fuchs <rfuchs@sipwise.com> Tue, 03 May 2011 17:20:11 -0400
ngcp-mediaproxy-ng (1.3.1) unstable; urgency=low
* dkms postinst: do not execute init script if it is not present yet.
-- Michael Prokop <mprokop@sipwise.com> Fri, 29 Apr 2011 17:18:41 +0200
ngcp-mediaproxy-ng (1.3.0) unstable; urgency=low
* Release for 2.2
* Fixed version number to align with old, non-debianized versioning scheme.
-- Andreas Granig <agranig@sipwise.com> Fri, 29 Apr 2011 12:01:56 +0200
ngcp-mediaproxy-ng (0.1) unstable; urgency=low
* Initial release.
-- Andreas Granig <agranig@sipwise.com> Tue, 26 Apr 2011 18:55:01 +0200

1
debian/compat vendored

@ -0,0 +1 @@
5

60
debian/control vendored

@ -0,0 +1,60 @@
Source: ngcp-mediaproxy-ng
Section: net
Priority: extra
Maintainer: Sipwise Development Team <support@sipwise.com>
Build-Depends: debhelper (>= 5), iptables-dev (>= 1.4), libglib2.0-dev, libpcre3-dev,
libxmlrpc-c3-dev (>= 1.16.07) | libxmlrpc-core-c3-dev (>= 1.16.07), libcurl4-openssl-dev | libcurl4-gnutls-dev |
libcurl3-openssl-dev | libcurl3-gnutls-dev
Standards-Version: 3.9.2
Homepage: http://sipwise.com/
Package: ngcp-mediaproxy-ng-daemon
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}
Pre-Depends: ngcp-mediaproxy-ng-kernel-dkms (>= ${source:Version})
Description: Proxy for RTP and media streams used in NGCP, userspace part.
This daemon handles the first stages of proxying media streams and talks to
the kernel part of the proxy for eventual high-performance packet forwarding.
Package: ngcp-mediaproxy-ng-iptables
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}
Description: IPtables extension module for the kernel-space NGCP media proxy.
Provides the IPtables extension needed to configure the mediaproxy rule.
Package: ngcp-mediaproxy-ng
Architecture: all
Depends: ngcp-mediaproxy-ng-daemon (>= ${source:Version}), ngcp-mediaproxy-ng-iptables (>= ${source:Version}),
ngcp-mediaproxy-ng-kernel-dkms (>= ${source:Version})
Description: NGCP RTP/media proxy - meta package.
This is a meta package for easy installation of all three parts of the NGCP
media proxy. It will install the user-space daemon, the kernel-space IPtables
module, and the IPtables extension module.
Package: ngcp-mediaproxy-ng-kernel-source
Architecture: all
Depends: debhelper (>= 5), module-assistant, ${misc:Depends}
Description: IPtables kernel module for the NGCP media proxy - source.
Provides the kernel-space part of the NGCP media proxy for high-
performance packet forwarding.
This package contains the source to be built with module-assistant or
kernel-package.
Package: ngcp-mediaproxy-ng-kernel-dkms
Architecture: all
Depends: dkms (>= 1.95), ${misc:Depends}
Description: IPtables kernel module for the NGCP media proxy - DKMS.
Provides the kernel-space part of the NGCP media proxy for high-
performance packet forwarding.
This package contains the source to be built with dkms.
Package: ngcp-mediaproxy-ng-dev
Architecture: all
Section: libdevel
Depends: debhelper (>= 5), ${misc:Depends}
Description: Development files for mediaproxy-ng
This package provides the header files of the mediaproxy-ng
software.
.
Install this package if you wish to develop your own programs using
mediaproxy-ng.

@ -0,0 +1,15 @@
Source: ngcp-mediaproxy-ng-kernel
Section: kernel
Priority: optional
Maintainer: Richard Fuchs <rfuchs@sipwise.com>
Build-Depends: debhelper (>= 5)
Standards-Version: 3.9.1
Homepage: http://sipwise.com/
Package: ngcp-mediaproxy-ng-kernel-modules-_KVERS_
Architecture: any
Depends: linux-modules-_KVERS_ | linux-image-_KVERS_
Provides: ngcp-mediaproxy-ng-kernel
Description: TODO
This package provides the ngcp-mediaproxy-ng module for
the Linux kernel version _KVERS_.

7
debian/copyright vendored

@ -0,0 +1,7 @@
Upstream Author: The Sipwise Team - http://sipwise.com/
Copyright: Copyright (c) 2007-2011 Sipwise GmbH, Austria
License: All software included in this package is
Copyright (c) Sipwise GmbH, Austria.
All rights reserved. You may not copy, distribute
or modify without prior written permission from
Sipwise GmbH, Austria.

1
debian/dirs vendored

@ -0,0 +1 @@
usr/sbin

@ -0,0 +1,7 @@
PACKAGE_NAME="ngcp-mediaproxy-ng"
PACKAGE_VERSION="__VERSION__"
MAKE[0]="make -C ${kernel_source_dir} M=${dkms_tree}/${PACKAGE_NAME}/${PACKAGE_VERSION}/build MEDIAPROXY_VERSION=\"__VERSION__\""
CLEAN="make -C ${kernel_source_dir} M=${dkms_tree}/${PACKAGE_NAME}/${PACKAGE_VERSION}/build clean"
AUTOINSTALL=yes
BUILT_MODULE_NAME[0]="xt_MEDIAPROXY"
DEST_MODULE_LOCATION[0]=/extra

@ -0,0 +1,19 @@
RUN_MEDIAPROXY=no
LISTEN=25060
LISTEN_UDP=12222
# ADDRESS=...
# ADV_ADDRESS=...
# ADDRESS_IPV6=...
# ADV_ADDRESS_IPV6=...
TIMEOUT=60
SILENT_TIMEOUT=3600
PIDFILE=/var/run/ngcp-mediaproxy-ng-daemon.pid
FORK=yes
# TOS=184
TABLE=0
# NO_FALLBACK=yes
# PORT_MIN=30000
# PORT_MAX=50000
# REDIS=127.0.0.1:6379
# REDIS_DB=1
# B2B_URL=http://127.0.0.1:8090/

@ -0,0 +1,138 @@
#! /bin/sh
### BEGIN INIT INFO
# Provides: mediaproxy-ng
# Required-Start: $remote_fs $syslog
# Required-Stop: $remote_fs $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Ngcp Mediaproxy-ng
# Description: Proxy for RTP and other media streams
### END INIT INFO
PATH=/sbin:/bin:/usr/sbin:/usr/bin
NAME=ngcp-mediaproxy-ng-daemon
DESC="RTP/media proxy"
RUN_MEDIAPROXY=no
TABLE=0
case $(dirname $0) in
/*) FULLPATH=$(dirname $0);;
*) FULLPATH=$(pwd)/$(dirname $0);;
esac
DAEMON=`which mediaproxy-ng`
DEFAULTS=/etc/default/${NAME}
test -f $DAEMON || exit 0
# Load startup options if available
if [ -f $DEFAULTS ]; then
. $DEFAULTS || true
fi
if [ "$RUN_MEDIAPROXY" != "yes" ]; then
echo "mediaproxy-ng not yet configured. Edit $DEFAULTS first."
exit 0
fi
[ -z "$PIDFILE" ] && PIDFILE="/var/run/mediaproxy-ng.pid"
set -e
. /lib/lsb/init-functions
OPTIONS=""
[ -z "$ADDRESS" ] || OPTIONS="$OPTIONS --ip=$ADDRESS"
[ -z "$LISTEN" ] || OPTIONS="$OPTIONS --listen=$LISTEN"
[ -z "$LISTEN_UDP" ] || OPTIONS="$OPTIONS --listen-udp=$LISTEN_UDP"
[ -z "$TIMEOUT" ] || OPTIONS="$OPTIONS --timeout=$TIMEOUT"
[ -z "$SILENT_TIMEOUT" ] || OPTIONS="$OPTIONS --silent-timeout=$SILENT_TIMEOUT"
[ -z "$PIDFILE" ] || OPTIONS="$OPTIONS --pidfile=$PIDFILE"
[ -z "$TOS" ] || OPTIONS="$OPTIONS --tos=$TOS"
[ -z "$PORT_MIN" ] || OPTIONS="$OPTIONS --port-min=$PORT_MIN"
[ -z "$PORT_MAX" ] || OPTIONS="$OPTIONS --port-max=$PORT_MAX"
[ -z "$ADV_ADDRESS" ] || OPTIONS="$OPTIONS --advertised-ip=$ADV_ADDRESS"
[ -z "$ADDRESS_IPV6" ] || OPTIONS="$OPTIONS --ip6=$ADDRESS_IPV6"
[ -z "$ADV_ADDRESS_IPV6" ] || OPTIONS="$OPTIONS --advertised-ip6=$ADV_ADDRESS_IPV6"
[ -z "$REDIS" ] || OPTIONS="$OPTIONS --redis=$REDIS"
[ -z "$REDIS_DB" ] || OPTIONS="$OPTIONS --redis-db=$REDIS_DB"
[ -z "$B2B_URL" ] || OPTIONS="$OPTIONS --b2b-url=$B2B_URL"
[ -z "$NO_FALLBACK" -o \( "$NO_FALLBACK" != "1" -a "$NO_FALLBACK" != "yes" \) ] || OPTIONS="$OPTIONS --no-fallback"
OPTIONS="$OPTIONS --table=$TABLE"
if test "$FORK" = "no" ; then
OPTIONS="$OPTIONS --foreground"
fi
case "$1" in
start)
echo -n "Starting $DESC: $NAME"
set +e
modprobe xt_MEDIAPROXY
echo "del $TABLE" > /proc/mediaproxy/control 2>/dev/null
iptables -D INPUT -j MEDIAPROXY --id $TABLE 2>/dev/null
iptables -D INPUT -p udp -j MEDIAPROXY --id $TABLE 2>/dev/null
ip6tables -D INPUT -p udp -j MEDIAPROXY --id $TABLE 2>/dev/null
iptables -I INPUT -p udp -j MEDIAPROXY --id $TABLE
ip6tables -I INPUT -p udp -j MEDIAPROXY --id $TABLE
set -e
start-stop-daemon --start --quiet --pidfile $PIDFILE \
--exec $DAEMON -- $OPTIONS || echo -n " already running"
log_end_msg $?
;;
stop)
echo -n "Stopping $DESC: $NAME"
start-stop-daemon --oknodo --stop --quiet --pidfile $PIDFILE \
--exec $DAEMON
if [ "$?" -ne 0 ]; then
return $?
fi
set +e
echo "del $TABLE" > /proc/mediaproxy/control 2>/dev/null
iptables -D INPUT -j MEDIAPROXY --id $TABLE 2>/dev/null
iptables -D INPUT -p udp -j MEDIAPROXY --id $TABLE 2>/dev/null
ip6tables -D INPUT -p udp -j MEDIAPROXY --id $TABLE 2>/dev/null
rmmod ipt_MEDIAPROXY 2>/dev/null
rmmod xt_MEDIAPROXY 2>/dev/null
set -e
rm -f $PIDFILE
log_end_msg $?
;;
restart|force-reload)
echo -n "Restarting $DESC: $NAME"
start-stop-daemon --oknodo --stop --quiet --pidfile \
$PIDFILE --exec $DAEMON
if [ "$?" -ne 0 ]; then
return $?
fi
rm -f $PIDFILE
sleep 1
set +e
if [ -e /proc/mediaproxy/control ]; then
echo "del $TABLE" > /proc/mediaproxy/control 2>/dev/null
fi
iptables -D INPUT -j MEDIAPROXY --id $TABLE 2>/dev/null
iptables -D INPUT -p udp -j MEDIAPROXY --id $TABLE 2>/dev/null
ip6tables -D INPUT -p udp -j MEDIAPROXY --id $TABLE 2>/dev/null
rmmod ipt_MEDIAPROXY 2>/dev/null
rmmod xt_MEDIAPROXY 2>/dev/null
modprobe xt_MEDIAPROXY
iptables -I INPUT -p udp -j MEDIAPROXY --id $TABLE
ip6tables -I INPUT -p udp -j MEDIAPROXY --id $TABLE
set -e
start-stop-daemon --start --quiet --pidfile \
$PIDFILE --exec $DAEMON -- $OPTIONS
log_end_msg $?
;;
status)
status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
;;
*)
echo "Usage: $0 {start|stop|restart|force-reload|status}" >&2
exit 1
;;
esac
exit 0

@ -0,0 +1 @@
daemon/mediaproxy-ng /usr/sbin/

@ -0,0 +1,54 @@
#!/bin/sh
# postinst script for ngcp-mediaproxy-ng-daemon
set -e
restart_handler() {
if [ -x "/etc/init.d/ngcp-mediaproxy-ng-daemon" ]; then
if [ -x "$(which invoke-rc.d 2>/dev/null)" ]; then
invoke-rc.d ngcp-mediaproxy-ng-daemon restart || exit $?
else
/etc/init.d/ngcp-mediaproxy-ng-daemon restart || exit $?
fi
fi
}
initscript_handler() {
if [ -x "/etc/init.d/ngcp-mediaproxy-ng-daemon" ]; then
update-rc.d ngcp-mediaproxy-ng-daemon defaults >/dev/null
invoke-rc.d ngcp-mediaproxy-ng-daemon start || exit $?
fi
}
init_handler() {
# just invoke init script wrappers on ce systems since
# they do not provide ngcp-check_active and we don't
# have to handle inactive nodes
if ! [ -x "$(which ngcp-check_active 2>/dev/null)" ]; then
restart_handler
initscript_handler
else # do not restart daemon on inactive node in pro systems
if ngcp-check_active ; then
echo "Active node detected, restarting ngcp-mediaproxy-ng-daemon"
restart_handler
else
echo "Inactive node detected, ignoring request to restart ngcp-mediaproxy-ng-daemon"
fi
fi
}
case "$1" in
configure)
init_handler
;;
abort-upgrade|abort-remove|abort-deconfigure)
;;
*)
echo "postinst called with unknown argument \`$1'" >&2
exit 1
;;
esac
exit 0

@ -0,0 +1,18 @@
#!/bin/sh
# postrm script for ngcp-mediaproxy-ng-daemon
set -e
removal_wrapper() {
# remove the init script only on ce systems, as the
# the pro system handle it inside the monitoring/HA setup
if ! [ -x "$(which ngcp-check_active 2>/dev/null)" ]; then
update-rc.d ngcp-mediaproxy-ng-daemon remove >/dev/null
fi
}
if [ "$1" = "purge" ] ; then
removal_wrapper
fi
exit 0

@ -0,0 +1,33 @@
#!/bin/sh
# prerm script for ngcp-mediaproxy-ng-daemon
set -e
stop_handler() {
if [ -x "/etc/init.d/ngcp-mediaproxy-ng-daemon" ]; then
invoke-rc.d ngcp-mediaproxy-ng-daemon stop || exit $?
fi
}
stop_daemon() {
# just stop the service on ce systems because
# the pro system handle it as part of their monitoring/HA setup
if ! [ -x "$(which ngcp-check_active 2>/dev/null)" ]; then
stop_handler
else
case "$2" in
upgrade)
echo "Detected upgrade procedure, not stopping ngcp-mediaproxy-ng-daemon service."
;;
remove|purge)
stop_handler
;;
esac
fi
}
if [ "$1" = "prerm" ] ; then
stop_daemon
fi
exit 0

@ -0,0 +1 @@
daemon/*.h /usr/include/mediaproxy-ng/

@ -0,0 +1 @@
iptables-extension/libxt_MEDIAPROXY.so /lib/xtables/

@ -0,0 +1,29 @@
#!/bin/sh
set -e
package=ngcp-mediaproxy-ng-kernel-dkms
name=ngcp-mediaproxy-ng
version=`dpkg-query -W -f='${Version}' "$package" \
|rev|cut -d- -f2-|rev|cut -d':' -f2|tr -d "\n"`
isadded=`dkms status -m "$name" -v "$version"`
if [ "x${isadded}" = "x" ] ; then
dkms add -m "$name" -v "$version"
fi
if [ "$1" = 'configure' ] ; then
dkms build -m "$name" -v "$version" && dkms install -m "$name" -v "$version" || true
# try to start the daemon
if [ -x /etc/init.d/ngcp-mediaproxy-ng-daemon ] ; then
invoke-rc.d ngcp-mediaproxy-ng-daemon start || true
fi
fi
#DEBHELPER#
exit 0

@ -0,0 +1,20 @@
#!/bin/sh
set -e
package=ngcp-mediaproxy-ng-kernel-dkms
name=ngcp-mediaproxy-ng
version=`dpkg-query -W -f='${Version}' "$package" \
|rev|cut -d- -f2-|rev|cut -d':' -f2|tr -d "\n"`
# make sure it's not running
if [ -x /etc/init.d/ngcp-mediaproxy-ng-daemon ] ; then
invoke-rc.d ngcp-mediaproxy-ng-daemon stop || true
fi
dkms remove -m "$name" -v "$version" --all || true
#DEBHELPER#
exit 0

@ -0,0 +1 @@
/usr/share/modass/packages/default.sh /usr/share/modass/overrides/ngcp-mediaproxy-ng-kernel-source

108
debian/rules vendored

@ -0,0 +1,108 @@
#!/usr/bin/make -f
# -*- makefile -*-
# Sample debian/rules that uses debhelper.
# This file was originally written by Joey Hess and Craig Small.
# As a special exception, when this file is copied by dh-make into a
# dh-make output file, you may use that output file without restriction.
# This special exception was added by Craig Small in version 0.37 of dh-make.
# Uncomment this to turn on verbose mode.
# export DH_VERBOSE=1
b=$(CURDIR)/debian
## kernel package specific stuff
# Name of the source package
psource:=ngcp-mediaproxy-ng-kernel-source
# Name of the dkms package
pdkms:=ngcp-mediaproxy-ng-kernel-dkms
# short upstream name, used for module source directory
sname:=ngcp-mediaproxy-ng
# Source version
sversion:=$(shell dpkg-parsechangelog|grep "^Version:"|cut -d" " -f2|rev|cut -d- -f2-|rev|cut -d':' -f2)
PACKAGE=ngcp-mediaproxy-ng-kernel
MA_DIR ?= /usr/share/modass
-include $(MA_DIR)/include/generic.make
-include $(MA_DIR)/include/common-rules.make
kdist_configure: prep-deb-files
kdist_clean: clean
$(MAKE) $(MFLAGS) -f debian/rules clean
## end of kernel package specific stuff
build: build-stamp
build-stamp:
dh_testdir
make -C iptables-extension
make -C daemon
touch $@
clean:
dh_testdir
dh_testroot
cd daemon && $(MAKE) clean && cd ..
rm -f build-stamp
rm -f iptables-extension/libxt_MEDIAPROXY.so
rm -f daemon/mediaproxy-ng daemon/build_time.h daemon/.depend kernel-module/.xt_MEDIAPROXY.o.d
rm -rf kernel-module/.tmp_versions
dh_clean
-rm -rf debian/build
install: build
dh_testdir
dh_testroot
dh_clean -k
dh_installdirs
# Create the directories to install the source into
dh_installdirs -p$(psource) usr/src/modules/$(sname)/debian
dh_installdirs -p$(pdkms) usr/src/$(sname)-$(sversion)
# Copy only the driver source to the proper locations
cd kernel-module && cp Makefile *.c *.h ../debian/$(psource)/usr/src/modules/$(sname)
cd kernel-module && cp Makefile *.c *.h ../debian/$(pdkms)/usr/src/$(sname)-$(sversion)
# Copy the needed debian/ pieces to the proper location
cp debian/*.modules.in* debian/$(psource)/usr/src/modules/$(sname)/debian
cp debian/control debian/changelog debian/copyright debian/README.Debian \
debian/compat debian/$(psource)/usr/src/modules/$(sname)/debian/
install -m 0755 debian/rules.modules debian/$(psource)/usr/src/modules/$(sname)/debian/rules
cd debian/$(psource)/usr/src && tar c modules | bzip2 -9 > $(sname).tar.bz2 && rm -rf modules
# Prepare dkms.conf from the dkms.conf.in template
sed "s/__VERSION__/$(sversion)/g" debian/dkms.conf.in > debian/$(pdkms)/usr/src/$(sname)-$(sversion)/dkms.conf
dh_install
%:
@echo "--- Building: $@"
dh_installdirs -p$@ -P$(b)/$@
dh_link -p$@ -P$(b)/$@
dh_installdocs -p$@ -P$(b)/$@
dh_installchangelogs -p$@ -P$(b)/$@
dh_installinit -p$@ -P$(b)/$@
dh_install -p$@ -P$(b)/$@
dh_strip -p$@ -P$(b)/$@ --keep-debug
dh_compress -p$@ -P$(b)/$@
dh_fixperms -p$@ -P$(b)/$@
dh_makeshlibs -p$@ -P$(b)/$@ -V
dh_installdeb -p$@ -P$(b)/$@
dh_shlibdeps -p$@ -P$(b)/$@
dh_installdebconf -p$@ -P$(b)/$@
dh_gencontrol -p$@ -P$(b)/$@
dh_md5sums -p$@ -P$(b)/$@
dh_builddeb -p$@ -P$(b)/$@
# Build architecture dependant packages
binary-arch: install \
ngcp-mediaproxy-ng-iptables ngcp-mediaproxy-ng
# Build architecture independant packages
binary-indep: build install \
ngcp-mediaproxy-ng-daemon ngcp-mediaproxy-ng-kernel-dkms ngcp-mediaproxy-ng-kernel-source ngcp-mediaproxy-ng-dev
binary: binary-indep binary-arch
.PHONY: build clean binary-indep binary-arch binary install kdist kdist_configure kdist_image kdist_clean

@ -0,0 +1,83 @@
#!/usr/bin/make -f
# Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1
CFLAGS ?= -Wall -g
ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS)))
CFLAGS += -O0
else
CFLAGS += -O2
endif
# Name of the source package
psource:=ngcp-mediaproxy-ng-kernel-source
# The short upstream name, used for the module source directory
sname:=ngcp-mediaproxy-ng
### KERNEL SETUP
### Setup the stuff needed for making kernel module packages
### taken from /usr/share/kernel-package/sample.module.rules
# prefix of the target package name
PACKAGE=ngcp-mediaproxy-ng-kernel-modules
# modifieable for experiments or debugging m-a
MA_DIR ?= /usr/share/modass
# load generic variable handling
-include $(MA_DIR)/include/generic.make
# load default rules, including kdist, kdist_image, ...
-include $(MA_DIR)/include/common-rules.make
# module assistant calculates all needed things for us and sets
# following variables:
# KSRC (kernel source directory), KVERS (kernel version string), KDREV
# (revision of the Debian kernel-image package), CC (the correct
# compiler), VERSION (the final package version string), PKGNAME (full
# package name with KVERS included), DEB_DESTDIR (path to store DEBs)
# The kdist_configure target is called by make-kpkg modules_config and
# by kdist* rules by dependency. It should configure the module so it is
# ready for compilation (mostly useful for calling configure).
# prep-deb-files from module-assistant creates the neccessary debian/ files
kdist_configure: prep-deb-files
# the kdist_clean target is called by make-kpkg modules_clean and from
# kdist* rules. It is responsible for cleaning up any changes that have
# been made by the other kdist_commands (except for the .deb files created)
kdist_clean: clean
$(MAKE) $(MFLAGS) -f debian/rules clean
#
### end KERNEL SETUP
# the binary-modules rule is invoked by module-assistant while processing the
# kdist* targets. It is called by module-assistant or make-kpkg and *not*
# during a normal build
binary-modules: prep-deb-files
dh_testroot
dh_clean -k
# Build the module
$(MAKE) modules KSRC=$(KSRC) KVER=$(KVERS)
# Install the module
install -D -m 0644 xt_MEDIAPROXY.ko debian/$(PACKAGE)-$(KVERS)/lib/modules/$(KVERS)/extra/xt_MEDIAPROXY.ko
dh_installdocs
dh_installchangelogs
dh_compress
dh_fixperms
dh_installmodules
dh_installdeb
dh_gencontrol -- -v$(VERSION)
dh_md5sums
dh_builddeb --destdir=$(DEB_DESTDIR)
dh_clean -k
clean:
dh_testdir
$(MAKE) clean
dh_clean
.PHONY: clean binary-modules kdist kdist_configure kdist_image kdist_clean

@ -0,0 +1,37 @@
CFLAGS = -O2 -Wall -shared -fPIC
CFLAGS += -DMEDIAPROXY_VERSION="\"$(shell dpkg-parsechangelog -l../debian/changelog | awk '/^Version: / {print $$2}')\""
XTABLES = $(shell test -e /usr/include/xtables.h && echo 1)
IPTABLES = $(shell test -e /usr/include/iptables.h && echo 1)
IP6TABLES = $(shell test -e /usr/include/ip6tables.h && echo 1)
.PHONY: all module clean
all: module
ifeq ($(XTABLES),1)
module: libxt_MEDIAPROXY.so
libxt_MEDIAPROXY.so: libxt_MEDIAPROXY.c
gcc $(CFLAGS) -o libxt_MEDIAPROXY.so libxt_MEDIAPROXY.c
else
ifeq ($(IPTABLES),1)
module: libipt_MEDIAPROXY.so
endif
ifeq ($(IP6TABLES),1)
module: libip6t_MEDIAPROXY.so
endif
libipt_MEDIAPROXY.so: libxt_MEDIAPROXY.c
gcc $(CFLAGS) -D__ipt -o libipt_MEDIAPROXY.so libxt_MEDIAPROXY.c
libip6t_MEDIAPROXY.so: libxt_MEDIAPROXY.c
gcc $(CFLAGS) -D__ip6t -o libip6t_MEDIAPROXY.so libxt_MEDIAPROXY.c
endif
clean:
rm -f libxt_MEDIAPROXY.so libipt_MEDIAPROXY.so libip6t_MEDIAPROXY.so

@ -0,0 +1,179 @@
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#if defined(__ipt)
#include <iptables.h>
#elif defined(__ip6t)
#include <ip6tables.h>
#else
#include <xtables.h>
#endif
#include <linux/netfilter.h>
#if defined(__ipt)
#include <linux/netfilter_ipv4/ip_tables.h>
#elif defined(__ip6t)
#include <linux/netfilter_ipv6/ip6_tables.h>
#else
#include <linux/netfilter/x_tables.h>
#endif
#include "../kernel-module/xt_MEDIAPROXY.h"
static void help(void) {
printf(
"MEDIAPROXY (version %s) target options:\n"
" --id <id>\n"
" Unique ID for this instance\n",
MEDIAPROXY_VERSION
);
}
#if defined(__ipt)
static int parse(int c,
char **argv,
int invert,
unsigned int *flags,
const struct ipt_entry *entry,
struct ipt_entry_target **target) {
#elif defined(__ip6t)
static int parse(int c,
char **argv,
int invert,
unsigned int *flags,
const struct ip6t_entry *entry,
struct ip6t_entry_target **target) {
#else
static int parse(int c,
char **argv,
int invert,
unsigned int *flags,
const void *entry,
struct xt_entry_target **target) {
#endif
struct xt_mediaproxy_info *info = (void *) (*target)->data;
if (c == '1') {
info->id = atoi(optarg);
if (flags)
*flags = 1;
}
else
return 0;
return 1;
}
static void final_check(unsigned int flags) {
#if defined(__ipt) || defined(__ip6t)
if (!flags)
exit_error(PARAMETER_PROBLEM, "You must specify --id");
#else
if (!flags)
xtables_error(PARAMETER_PROBLEM, "You must specify --id");
#endif
}
#if defined(__ipt)
static void print(const struct ipt_ip *ip, const struct xt_entry_target *target, int numeric) {
#elif defined(__ip6t)
static void print(const struct ip6t_ip6 *ip, const struct xt_entry_target *target, int numeric) {
#else
static void print(const void *ip, const struct xt_entry_target *target, int numeric) {
#endif
struct xt_mediaproxy_info *info = (void *) target->data;
printf("id %u", info->id);
}
#if defined(__ipt)
static void save(const struct ipt_ip *ip, const struct xt_entry_target *target) {
#elif defined(__ip6t)
static void save(const struct ip6t_ip6 *ip, const struct xt_entry_target *target) {
#else
static void save(const void *ip, const struct xt_entry_target *target) {
#endif
struct xt_mediaproxy_info *info = (void *) target->data;
printf("--id %u", info->id);
}
static struct option opts[] = {
{ "id", 1, NULL, '1' },
{ NULL, },
};
#if defined(__ipt)
static struct iptables_target mediaproxy4 = {
.name = "MEDIAPROXY",
.version = "1.3.6",
.size = IPT_ALIGN(sizeof(struct xt_mediaproxy_info)),
.userspacesize = IPT_ALIGN(sizeof(struct xt_mediaproxy_info)),
.help = help,
.parse = parse,
.final_check = final_check,
.print = print,
.save = save,
.extra_opts = opts,
};
#elif defined(__ip6t)
static struct ip6tables_target mediaproxy6 = {
.name = "MEDIAPROXY",
.version = "1.3.6",
.size = IP6T_ALIGN(sizeof(struct xt_mediaproxy_info)),
.userspacesize = IP6T_ALIGN(sizeof(struct xt_mediaproxy_info)),
.help = help,
.parse = parse,
.final_check = final_check,
.print = print,
.save = save,
.extra_opts = opts,
};
#else
static struct xtables_target mediaproxy4 = {
.name = "MEDIAPROXY",
.family = NFPROTO_IPV4,
.version = XTABLES_VERSION,
.size = XT_ALIGN(sizeof(struct xt_mediaproxy_info)),
.userspacesize = XT_ALIGN(sizeof(struct xt_mediaproxy_info)),
.help = help,
.parse = parse,
.final_check = final_check,
.print = print,
.save = save,
.extra_opts = opts,
};
static struct xtables_target mediaproxy6 = {
.name = "MEDIAPROXY",
.family = NFPROTO_IPV6,
.version = XTABLES_VERSION,
.size = XT_ALIGN(sizeof(struct xt_mediaproxy_info)),
.userspacesize = XT_ALIGN(sizeof(struct xt_mediaproxy_info)),
.help = help,
.parse = parse,
.final_check = final_check,
.print = print,
.save = save,
.extra_opts = opts,
};
#endif
void _init(void) {
#if defined(__ipt)
register_target(&mediaproxy4);
#elif defined(__ip6t)
register_target6(&mediaproxy6);
#else
xtables_register_target(&mediaproxy4);
xtables_register_target(&mediaproxy6);
#endif
}

@ -0,0 +1,21 @@
PWD := $(shell pwd)
KSRC ?= /lib/modules/$(shell uname -r)/build
KBUILD := $(KSRC)
ifeq ($(origin MEDIAPROXY_VERSION), undefined)
MEDIAPROXY_VERSION := $(shell dpkg-parsechangelog -l../debian/changelog | awk '/^Version: / {print $$2}')
export MEDIAPROXY_VERSION
endif
EXTRA_CFLAGS += -DMEDIAPROXY_VERSION="\"$(MEDIAPROXY_VERSION)\"" -D__MP_EXTERNAL
obj-m += xt_MEDIAPROXY.o
.PHONY: modules clean patch
modules:
make -C $(KBUILD) M=$(PWD) O=$(KBUILD) modules
clean:
make -C $(KBUILD) M=$(PWD) clean
patch:
../utils/patch-kernel magic "$(PWD)" "$(KERNEL)" "$(MEDIAPROXY_VERSION)"

File diff suppressed because it is too large Load Diff

@ -0,0 +1,85 @@
#ifndef IPT_RTPPROXY_H
#define IPT_RTPPROXY_H
struct xt_mediaproxy_info {
u_int32_t id;
};
struct mediaproxy_stats {
u_int64_t packets;
u_int64_t bytes;
u_int64_t errors;
};
struct mp_address {
int family;
union {
unsigned char ipv6[16];
u_int32_t ipv4;
unsigned char u8[16];
u_int16_t u16[8];
u_int32_t u32[4];
};
u_int16_t port;
};
struct mediaproxy_target_info {
u_int16_t target_port;
struct mp_address src_addr;
struct mp_address dst_addr;
struct mp_address mirror_addr;
unsigned char tos;
};
struct mediaproxy_message {
enum {
MMG_NOOP = 1,
MMG_ADD,
MMG_DEL,
MMG_UPDATE,
} cmd;
struct mediaproxy_target_info target;
};
struct mediaproxy_list_entry {
struct mediaproxy_target_info target;
struct mediaproxy_stats stats;
};
#ifdef __KERNEL__
struct mediaproxy_target {
atomic_t refcnt;
u_int32_t table;
struct mediaproxy_target_info target;
spinlock_t lock;
struct mediaproxy_stats stats;
};
struct mediaproxy_table {
atomic_t refcnt;
rwlock_t target_lock;
pid_t pid;
u_int32_t id;
struct proc_dir_entry *proc;
struct proc_dir_entry *status;
struct proc_dir_entry *control;
struct proc_dir_entry *list;
struct proc_dir_entry *blist;
struct mediaproxy_target **target[256];
unsigned int buckets;
unsigned int targets;
};
#endif
#endif

@ -0,0 +1,246 @@
#!/usr/bin/perl
use warnings;
use strict;
use Socket;
$| = 1;
my $local_ip = '192.168.1.90';
sub brk {
sleep(1);
}
sub mp_msg {
my ($cmd) = @_;
my $fd;
socket($fd, AF_INET, SOCK_STREAM, 0) or die;
connect($fd, sockaddr_in(25060, inet_aton('127.0.0.1'))) or die;
my $old = select($fd);
$| = 1;
print("$cmd\n");
my $ret = <$fd>;
select($old);
close($fd);
chomp($ret);
return $ret;
}
sub udp_sock {
while (1) {
my $fd;
socket($fd, AF_INET, SOCK_DGRAM, 0) or die;
bind($fd, sockaddr_in(0, inet_aton('0.0.0.0'))) or die;
my $sa = getsockname($fd);
my ($port, $addr) = sockaddr_in($sa);
(($port % 2) == 0) or next;
return ($fd, $port);
}
}
sub send_rcv {
my ($sendfd, $sendtoip, $sendtoport, $recvfd) = @_;
print("sending to $sendtoip:$sendtoport... ");
my $pkt = join('',map(rand,1..10));
send($sendfd, $pkt, 0, sockaddr_in($sendtoport, inet_aton($sendtoip))) or die;
my $inc;
{
local $SIG{ALRM} = sub {
print("timeout!\n");
};
alarm(1);
recv($recvfd, $inc, length($pkt), 0);
alarm(0);
}
$inc eq $pkt or print("NOT received packed ok\n"), return;
print("received packet ok\n");
}
sub send_rcv4 {
for (1 .. 4) {
send_rcv(@_[0,1,2,3]);
sleep(1);
send_rcv(@_[3,4,5,0]);
sleep(1);
}
}
sub sim_req_lk {
my ($method, $callid, $ip, $port, $fromtag, $totag) = @_;
$totag or $totag = '';
my $ret = mp_msg("$method $callid $ip:$port:audio 192.168.101.11 80.110.1.48 remote 212.41.253.181 remote CS2000_NGSS/9.0 info=domain:voip.sipwise.local,from:431960681661\@80.110.1.48:5060,totag:$totag,to:43720890289\@77.244.249.84:5060,fromtag:$fromtag");
return split(/ /, $ret);
}
sub sim_rq {
return sim_req_lk("request", @_);
}
sub sim_lk {
return sim_req_lk("lookup", @_);
}
my $callid1 = join('',map(rand,1..2));
my $fromtag1 = join('',map(rand,1..4));
my $totag1 = join('',map(rand,1..4));
my $callid2 = join('',map(rand,1..2));
my $fromtag2 = join('',map(rand,1..4));
my $totag2 = join('',map(rand,1..4));
my ($client1, $lp1) = udp_sock();
my ($client2, $lp2) = udp_sock();
my ($client3, $lp3) = udp_sock();
my ($client4, $lp4) = udp_sock();
print("call-ids: $callid1 & $callid2\n");
print("opened ports $lp1 [A->B], $lp2 [B->A], $lp3 [B->C], $lp4 [C->B] as RTP clients\n");
brk();
print("CALL 1: A calling B\n");
print("A tells B: send RTP to $lp1\n");
brk();
my ($mpip1, $mpport1) = sim_rq($callid1, $local_ip, $lp1, $fromtag1);
print("mediaproxy: tell B to send to $mpport1 instead of $lp1\n");
brk();
print("B tells A: send RTP to $lp2\n");
brk();
my ($mpip2, $mpport2) = sim_lk($callid1, $local_ip, $lp2, $fromtag1, $totag1);
print("mediaproxy: tell A to send to $mpport2 instead of $lp2\n");
brk();
send_rcv4($client2, $mpip1, $mpport1, $client1, $mpip2, $mpport2);
brk();
print("B puts A on hold\n");
print("B tells A: send RTP to 0.0.0.0\n");
brk();
my ($mpip3, $mpport3) = sim_rq($callid1, '0.0.0.0', $lp2, $totag1, $fromtag1);
print("mediaproxy: tell A to send to $mpip3:$mpport3 instead of 0.0.0.0:$lp2\n");
brk();
print("A tells B: send RTP to 0.0.0.0\n");
brk();
my ($mpip4, $mpport4) = sim_lk($callid1, '0.0.0.0', $lp1, $totag1, $fromtag1);
print("mediaproxy: tell B to send to $mpip4:$mpport4 instead of 0.0.0.0:$lp1\n");
brk();
print("CALL 2: B calling C\n");
print("B tells C: send RTP to $lp3\n");
brk();
my ($mpip5, $mpport5) = sim_rq($callid2, $local_ip, $lp3, $fromtag2);
print("mediaproxy: tell C to send to $mpport5 instead of $lp3\n");
brk();
print("C tells B: send RTP to $lp4\n");
brk();
my ($mpip6, $mpport6) = sim_lk($callid2, $local_ip, $lp4, $fromtag2, $totag2);
print("mediaproxy: tell B to send to $mpport6 instead of $lp4\n");
brk();
send_rcv4($client4, $mpip5, $mpport5, $client3, $mpip6, $mpport6);
brk();
print("B un-holds A\n");
print("B tells A: send RTP to $lp2\n");
brk();
my ($mpip7, $mpport7) = sim_rq($callid1, $local_ip, $lp2, $totag1, $fromtag1);
print("mediaproxy: tell A to send to $mpport7 instead of $lp2\n");
brk();
print("A tells B: send RTP to $lp1\n");
brk();
my ($mpip8, $mpport8) = sim_lk($callid1, $local_ip, $lp1, $totag1, $fromtag1);
print("mediaproxy: tell B to send to $mpport8 instead of $lp1\n");
brk();
send_rcv4($client2, $mpip1, $mpport1, $client1, $mpip2, $mpport2);
brk();
print("CONNECT: B connects A to C\n");
print("B tells C [call 2]: send RTP to $mpip8:$mpport8\n");
brk();
my ($mpip9, $mpport9) = sim_rq($callid2, $mpip8, $mpport8, $fromtag2, $totag2);
print("mediaproxy: tell C to send to $mpport9 instead of $mpip8:$mpport8\n");
brk();
print("C tells B: send RTP to $lp4\n");
my ($mpip10, $mpport10) = sim_lk($callid2, $local_ip, $lp4, $fromtag2, $totag2);
print("mediaproxy: tell B to send to $mpport10 instead of $lp4\n");
brk();
print("B tells A [call 1]: send RTP to $mpip10:$mpport10\n");
my ($mpip11, $mpport11) = sim_rq($callid1, $mpip10, $mpport10, $totag1, $fromtag1);
print("mediaproxy: tell A to send to $mpport11 instead of $mpip10:$mpport10\n");
brk();
if (1) {
###### error trigger
send_rcv($client1, $mpip11, $mpport11, $client4);
}
print("A tells B: send RTP to $lp1\n");
my ($mpip12, $mpport12) = sim_lk($callid1, $local_ip, $lp1, $totag1, $fromtag1);
print("mediaproxy: tell B to send to $mpport12 instead of $lp1\n");
brk();
send_rcv4($client4, $mpip9, $mpport9, $client1, $mpip11, $mpport11);

@ -0,0 +1,32 @@
#!/usr/bin/perl
use strict;
use warnings;
use Socket;
use Socket6;
my $t = $ARGV[0] || "0";
my $format = 'SS ia16SS ia16SS ia16SS CCCC LLLLLL';
my $len = length(pack($format, (0) x 100));
open(X, "<", "/proc/mediaproxy/$t/blist") or die;
my $buf;
while (sysread(X, $buf, $len)) {
my @b = unpack($format, $buf);
for (2,6,10) {
if ($b[$_] == AF_INET) {
$b[$_ + 1] = inet_ntoa($b[$_ + 1]);
}
elsif ($b[$_] == AF_INET6) {
$b[$_ + 1] = inet_ntop(AF_INET6, $b[$_ + 1]);
}
elsif ($b[$_] == 0) {
$b[$_ + 1] = '---';
}
}
for (18, 20, 22) {
$b[$_] += $b[$_ + 1] * 2**32;
}
printf("%5u %15s:%-5u -> %15s:%-5u (-> %15s:%-5u) [%u] [%llu %llu %llu]\n", @b[0,3,4,7,8,11,12,14,18,20,22]);
}

@ -0,0 +1,92 @@
#!/usr/bin/perl
use strict;
use warnings;
use Socket;
use Socket6;
my %cmds = (noop => 1, add => 2, delete => 3, update => 4);
$| = 1;
open(F, "> /proc/mediaproxy/0/control") or die;
{
my $x = select(F);
$| = 1;
select($x);
}
sub mp_address {
my ($fam, $addr, $port) = @_;
if ($fam eq 'inet') {
return pack('i a4 a12 S S', 2, inet_aton($addr), '', $port, 0);
}
if ($fam eq 'inet6') {
return pack('i a16 S S', 10, inet_pton(AF_INET6, $addr), $port, 0);
}
if ($fam eq '') {
return pack('i a16 S S', 0, '', 0, 0);
}
die;
}
sub mediaproxy_message {
my ($cmd, $target_port,
$src_addr_family, $src_addr_addr, $src_addr_port,
$dst_addr_family, $dst_addr_addr, $dst_addr_port,
$mirror_addr_family, $mirror_addr_addr, $mirror_addr_port,
$tos) = @_;
my $ret = '';
$ret .= pack('I SS', $cmds{$cmd}, $target_port, 0);
$ret .= mp_address($src_addr_family, $src_addr_addr, $src_addr_port);
$ret .= mp_address($dst_addr_family, $dst_addr_addr, $dst_addr_port);
$ret .= mp_address($mirror_addr_family, $mirror_addr_addr, $mirror_addr_port);
$ret .= pack('C CS', $tos, 0, 0);
}
my $sleep = 5;
#my @src = qw(inet 10.15.20.61);
#my @dst = qw(inet 10.15.20.58);
my @src = qw(inet6 2a00:4600:1:0:a00:27ff:feb0:f7fe);
my @dst = qw(inet6 2a00:4600:1:0:6884:adff:fe98:6ac5);
my @nul = ('', '', '');
print("add 9876 -> 1234/6543\n");
syswrite(F, mediaproxy_message('add', 9876, @src, 1234, @dst, 6543, @nul, 184));
sleep($sleep);
print("add fail\n");
syswrite(F, mediaproxy_message('add', 9876, @src, 1234, @dst, 6543, @dst, 6789, 184));
sleep($sleep);
print("update 9876 -> 1234/6543 & 6789\n");
syswrite(F, mediaproxy_message('update', 9876, @src, 1234, @dst, 6543, @dst, 6789, 184));
sleep($sleep);
print("update 9876 -> 2345/7890 & 4321\n");
syswrite(F, mediaproxy_message('update', 9876, @src, 2345, @dst, 7890, @dst, 4321, 184));
sleep($sleep);
print("add fail\n");
syswrite(F, mediaproxy_message('add', 9876, @src, 1234, @dst, 6543, @dst, 6789, 184));
sleep($sleep);
print("update 9876 -> 1234/6543\n");
syswrite(F, mediaproxy_message('update', 9876, @src, 1234, @dst, 6543, @nul, 184));
sleep($sleep);
print("delete\n");
syswrite(F, mediaproxy_message('delete', 9876, @nul, @nul, @nul, 0));
sleep($sleep);
print("delete fail\n");
syswrite(F, mediaproxy_message('delete', 9876, @nul, @nul, @nul, 0));
sleep($sleep);
print("update fail\n");
syswrite(F, mediaproxy_message('update', 9876, @src, 1234, @dst, 6543, @nul, 184));
sleep($sleep);
close(F);

@ -0,0 +1,370 @@
#!/usr/bin/perl
use warnings;
use strict;
use Socket;
$| = 1;
my $local_ip = '192.168.1.90';
sub brk {
sleep(1);
}
sub mp_msg {
my ($cmd) = @_;
my $fd;
socket($fd, AF_INET, SOCK_STREAM, 0) or die;
connect($fd, sockaddr_in(25060, inet_aton('127.0.0.1'))) or die;
my $old = select($fd);
$| = 1;
print("$cmd\n");
my $ret = <$fd>;
select($old);
close($fd);
chomp($ret);
return $ret;
}
sub udp_sock {
while (1) {
my $fd;
socket($fd, AF_INET, SOCK_DGRAM, 0) or die;
bind($fd, sockaddr_in(0, inet_aton('0.0.0.0'))) or die;
my $sa = getsockname($fd);
my ($port, $addr) = sockaddr_in($sa);
(($port % 2) == 0) or next;
return ($fd, $port);
}
}
sub send_rcv {
my ($sendfd, $sendtoip, $sendtoport, $recvfd) = @_;
my $laddr = getsockname($sendfd);
my ($lport, $lip) = sockaddr_in($laddr);
print("local port $lport sending to $sendtoip:$sendtoport... ");
my $pkt = join('',map(rand,1..10));
send($sendfd, $pkt, 0, sockaddr_in($sendtoport, inet_aton($sendtoip))) or die;
my ($inc, $addr);
{
local $SIG{ALRM} = sub {
print("timeout!\n");
return;
};
alarm(1);
$addr = recv($recvfd, $inc, length($pkt), 0);
alarm(0);
}
$inc eq $pkt or print("did NOT receive packet\n"), return;
my ($port, $ip) = sockaddr_in($addr);
$laddr = getsockname($recvfd);
($lport, $lip) = sockaddr_in($laddr);
print("received packet ok on port $lport, from port $port\n");
}
sub send_rcv_brk {
send_rcv(@_);
brk();
}
sub send_rcv4 {
for (1 .. 4) {
send_rcv(@_[0,1,2,3]);
sleep(1);
send_rcv(@_[3,4,5,0]);
sleep(1);
}
}
sub sim_req_lk {
my ($method, $callid, $ip, $port, $fromtag, $totag) = @_;
$totag or $totag = '';
my $ret = mp_msg("$method $callid $ip:$port:audio 192.168.101.11 80.110.1.48 remote 212.41.253.181 remote CS2000_NGSS/9.0 info=domain:voip.sipwise.local,from:431960681661\@80.110.1.48:5060,totag:$totag,to:43720890289\@77.244.249.84:5060,fromtag:$fromtag");
return split(/ /, $ret);
}
sub sim_rq {
return sim_req_lk("request", @_);
}
sub sim_lk {
return sim_req_lk("lookup", @_);
}
my $callid = join('',map(rand,1..2));
my $fromtag = join('',map(rand,1..4));
my $totag = join('',map(rand,1..4));
my ($client1, $lp1) = udp_sock();
my ($client2, $lp2) = udp_sock();
print("call-id: $callid\n");
print("opened ports $lp1 [A->B], $lp2 [B->A] as RTP clients\n");
brk();
{
print("A tells B: send RTP to $lp1\n");
brk();
my ($mpip1, $mpport1) = sim_rq($callid, $local_ip, $lp1, $fromtag);
print("mediaproxy: tell B to send to $mpport1 instead of $lp1\n");
brk();
print("B tells A: send RTP to $lp2\n");
brk();
my ($mpip2, $mpport2) = sim_lk($callid, $local_ip, $lp2, $fromtag, $totag);
print("mediaproxy: tell A to send to $mpport2 instead of $lp2\n");
brk();
send_rcv4($client2, $mpip1, $mpport1, $client1, $mpip2, $mpport2);
brk();
}
for my $case (0 .. 3) {
my $sub;
if ($case == 0) {
$sub = sub { ; };
}
elsif ($case == 1) {
$sub = sub {
print("\tchanging ports on client 1\n");
($client1, $lp1) = udp_sock();
};
}
elsif ($case == 2) {
$sub = sub {
print("\tchanging ports on client 2\n");
($client2, $lp2) = udp_sock();
};
}
elsif ($case == 3) {
$sub = sub {
print("\tchanging ports on client 1 and 2\n");
($client1, $lp1) = udp_sock();
($client2, $lp2) = udp_sock();
};
}
my @forward = ('A', 'B', \$lp1, \$lp2, \$client1, \$client2, $fromtag, $totag);
my @backward = ('B', 'A', \$lp2, \$lp1, \$client2, \$client1, $totag, $fromtag);
my ($src, $dst, $p1, $p2, $c1, $c2, $ft, $tt);
for my $tuple (\@forward, \@backward) {
($src, $dst, $p1, $p2, $c1, $c2, $ft, $tt) = @$tuple;
$sub->();
print("\n\n\n");
print("re-invite coming from $src with no intermediate traffic\n");
print("$src tells $dst: send RTP to $$p1\n");
brk();
my ($mpip1, $mpport1) = sim_rq($callid, $local_ip, $$p1, $ft);
print("mediaproxy: tell $dst to send to $mpport1 instead of $$p1\n");
brk();
print("$dst tells $src: send RTP to $$p2\n");
brk();
my ($mpip2, $mpport2) = sim_lk($callid, $local_ip, $$p2, $ft, $tt);
print("mediaproxy: tell $src to send to $mpport2 instead of $$p2\n");
brk();
send_rcv4($$c2, $mpip1, $mpport1, $$c1, $mpip2, $mpport2);
brk();
}
for my $tuple (\@forward, \@backward) {
($src, $dst, $p1, $p2, $c1, $c2, $ft, $tt) = @$tuple;
$sub->();
print("\n\n\n");
print("re-invite coming from $src with intermediate traffic from $dst to the new port only\n");
print("$src tells $dst: send RTP to $$p1\n");
brk();
my ($mpip1, $mpport1) = sim_rq($callid, $local_ip, $$p1, $ft);
print("mediaproxy: tell $dst to send to $mpport1 instead of $$p1\n");
brk();
for (1 .. 4) {
send_rcv_brk($$c2, $mpip1, $mpport1, $$c1);
}
print("$dst tells $src: send RTP to $$p2\n");
brk();
my ($mpip2, $mpport2) = sim_lk($callid, $local_ip, $$p2, $ft, $tt);
print("mediaproxy: tell $src to send to $mpport2 instead of $$p2\n");
brk();
send_rcv4($$c2, $mpip1, $mpport1, $$c1, $mpip2, $mpport2);
brk();
$sub->();
print("\n\n\n");
print("re-invite coming from $src with intermediate traffic from both sides to both old and new ports\n");
print("$src tells $dst: send RTP to $$p1\n");
brk();
my ($mpip3, $mpport3) = sim_rq($callid, $local_ip, $$p1, $ft);
print("mediaproxy: tell $dst to send to $mpport3 instead of $$p1\n");
brk();
send_rcv4($$c2, $mpip1, $mpport1, $$c1, $mpip2, $mpport2);
print("switching to new port...\n");
send_rcv4($$c2, $mpip3, $mpport3, $$c1, $mpip2, $mpport2);
print("$dst tells $src: send RTP to $$p2\n");
brk();
my ($mpip4, $mpport4) = sim_lk($callid, $local_ip, $$p2, $ft, $tt);
print("mediaproxy: tell $src to send to $mpport4 instead of $$p2\n");
brk();
send_rcv4($$c2, $mpip3, $mpport3, $$c1, $mpip2, $mpport2);
print("switching to new port...\n");
send_rcv4($$c2, $mpip3, $mpport3, $$c1, $mpip4, $mpport4);
brk();
$sub->();
print("\n\n\n");
print("re-invite coming from $src with intermediate traffic from $dst only to both old and new ports\n");
print("$src tells $dst: send RTP to $$p1\n");
brk();
my ($mpip5, $mpport5) = sim_rq($callid, $local_ip, $$p1, $ft);
print("mediaproxy: tell $dst to send to $mpport5 instead of $$p1\n");
brk();
for (1 .. 4) {
send_rcv_brk($$c2, $mpip3, $mpport3, $$c1);
}
print("switching to new port...\n");
for (1 .. 4) {
send_rcv_brk($$c2, $mpip5, $mpport5, $$c1);
}
print("$dst tells $src: send RTP to $$p2\n");
brk();
my ($mpip6, $mpport6) = sim_lk($callid, $local_ip, $$p2, $ft, $tt);
print("mediaproxy: tell $src to send to $mpport6 instead of $$p2\n");
brk();
for (1 .. 4) {
send_rcv_brk($$c2, $mpip5, $mpport5, $$c1);
}
send_rcv4($$c2, $mpip5, $mpport5, $$c1, $mpip6, $mpport6);
brk();
$sub->();
print("\n\n\n");
print("re-invite coming from $src with intermediate traffic from $src only to both old and new ports\n");
print("$src tells $dst: send RTP to $$p1\n");
brk();
my ($mpip7, $mpport7) = sim_rq($callid, $local_ip, $$p1, $ft);
print("mediaproxy: tell $dst to send to $mpport7 instead of $$p1\n");
brk();
for (1 .. 4) {
send_rcv_brk($$c1, $mpip6, $mpport6, $$c2);
}
print("$dst tells $src: send RTP to $$p2\n");
brk();
my ($mpip8, $mpport8) = sim_lk($callid, $local_ip, $$p2, $ft, $tt);
print("mediaproxy: tell $src to send to $mpport8 instead of $$p2\n");
brk();
for (1 .. 4) {
send_rcv_brk($$c1, $mpip6, $mpport6, $$c2);
}
print("switching to new port...\n");
for (1 .. 4) {
send_rcv_brk($$c1, $mpip8, $mpport8, $$c2);
}
send_rcv4($$c2, $mpip7, $mpport7, $$c1, $mpip8, $mpport8);
brk();
}
}

@ -0,0 +1,48 @@
#!/bin/bash
# # G_SLICE=always-malloc valgrind --leak-check=full --track-origins=yes --show-possibly-lost=yes ./mediaproxy-ng -t 0 -i $IP -l 25060 -f
pipe_o() {
nc localhost 25060
}
pipe() {
pipe_o > /dev/null
}
ip() {
echo $(($RANDOM % 254 + 1)).$(($RANDOM % 254 + 1)).$(($RANDOM % 254 + 1)).$(($RANDOM % 254 + 1))
}
port() {
echo $(($RANDOM % 64000 + 1024))
}
ids=""
ports=""
for i in $(seq 1 1000); do
callid=`uuid`
test -z "$callid" && exit 1
src=`ip`:`port`
dst=`ip`:`port`
gw=`ip`
fromtag=`uuid`
totag=`uuid`
src_rel=`echo "request $callid $src:audio $gw voip.inode.at local unknown unknown unknown-agent info=domain:voip.sipwise.local,from:number@voip.inode.at,totag:,to:othernumber@voip.inode.at,fromtag:$fromtag" | pipe_o`
dst_rel=`echo "lookup $callid $dst:audio $gw voip.inode.at local unknown unknown unknown-agent info=domain:voip.sipwise.local,from:number@voip.inode.at,totag:$totag,to:othernumber@voip.inode.at,fromtag:$fromtag" | pipe_o`
echo "lookup $callid $dst:audio $gw voip.inode.at local unknown unknown unknown-agent info=domain:voip.sipwise.local,from:number@voip.inode.at,totag:$totag,to:othernumber@voip.inode.at,fromtag:$fromtag" | pipe
echo version | pipe
echo status | pipe
src_path=${src_rel/ //}
dst_path=${dst_rel/ //}
ports="$ports $src_path $dst_path"
for port in $ports; do
echo foobar > /dev/udp/$port
done
ids="$ids $callid"
done
sleep 10
for id in $ids; do
echo "delete $id info=" | pipe
done

@ -0,0 +1,52 @@
#!/bin/bash
if test "$1" != magic; then
echo
echo "Don't run this script manually, instead run:"
echo " make patch KERNEL=/path/to/kernel/sources"
echo
exit 1
fi
if test -z "$3"; then
echo
echo "Usage:"
echo " make patch KERNEL=/path/to/kernel/sources"
echo
exit 1
fi
KERN=$3
for x in . include/linux/netfilter/ net/netfilter/Kconfig net/netfilter/Makefile; do
if ! test -e "$KERN"/"$x"; then
echo "I don't recognize $KERN as a kernel source tree"
exit 1
fi
done
set -e
cp -v xt_MEDIAPROXY.h "$KERN"/include/linux/netfilter/
cp -v xt_MEDIAPROXY.c "$KERN"/net/netfilter/
if ! grep -q CONFIG_NETFILTER_XT_TARGET_MEDIAPROXY "$KERN"/net/netfilter/Makefile; then
(
echo
echo "EXTRA_CFLAGS += -DMEDIAPROXY_VERSION=\"\\\"$4\\\"\""
echo 'obj-$(CONFIG_NETFILTER_XT_TARGET_MEDIAPROXY) += xt_MEDIAPROXY.o'
) >> "$KERN"/net/netfilter/Makefile
fi
if ! grep -q Kconfig\\.mediaproxy-ng "$KERN"/net/netfilter/Kconfig; then
cat >> "$KERN"/net/netfilter/Kconfig.mediaproxy-ng << \__EOF
config NETFILTER_XT_TARGET_MEDIAPROXY
tristate "Sipwise NGCP MEDIAPROXY target support"
depends on IP_NF_FILTER
help
Sipwise NGCP mediaproxy-ng kernel support
To compile it as a module, choose M here. If unsure, say N.
__EOF
echo 'source "net/netfilter/Kconfig.mediaproxy-ng"' >> "$KERN"/net/netfilter/Kconfig
fi
Loading…
Cancel
Save