Browse Source

Merge remote-tracking branch 'upstream/master'

pull/225/head
Stefan Mititelu 10 years ago
parent
commit
a3f0e30307
19 changed files with 1145 additions and 208 deletions
  1. +34
    -16
      README.md
  2. +1
    -1
      daemon/Makefile
  3. +3
    -0
      daemon/call.h
  4. +4
    -6
      daemon/graphite.c
  5. +559
    -0
      daemon/homer.c
  6. +15
    -0
      daemon/homer.h
  7. +34
    -10
      daemon/main.c
  8. +8
    -6
      daemon/media_socket.c
  9. +221
    -34
      daemon/rtcp.c
  10. +21
    -27
      daemon/rtcp.h
  11. +36
    -51
      daemon/rtcp_xr.c
  12. +8
    -37
      daemon/rtcp_xr.h
  13. +77
    -16
      daemon/socket.c
  14. +19
    -2
      daemon/socket.h
  15. +1
    -0
      daemon/str.h
  16. +77
    -0
      debian/changelog
  17. +3
    -0
      debian/ngcp-rtpengine-daemon.default
  18. +3
    -0
      debian/ngcp-rtpengine-daemon.init
  19. +21
    -2
      tests/simulator-ng.pl

+ 34
- 16
README.md View File

@ -158,9 +158,12 @@ option and which are reproduced below:
-F, --no-fallback Only start when kernel module is available -F, --no-fallback Only start when kernel module is available
-i, --interface=[NAME/]IP[!IP] Local interface for RTP -i, --interface=[NAME/]IP[!IP] Local interface for RTP
-l, --listen-tcp=[IP:]PORT TCP port to listen on -l, --listen-tcp=[IP:]PORT TCP port to listen on
-c, --listen-cli=[IP46:]PORT TCP port to listen on, CLI (command line interface)
-u, --listen-udp=[IP46:]PORT UDP port to listen on -u, --listen-udp=[IP46:]PORT UDP port to listen on
-n, --listen-ng=[IP46:]PORT UDP port to listen on, NG protocol -n, --listen-ng=[IP46:]PORT UDP port to listen on, NG protocol
-c, --listen-cli=[IP46:]PORT TCP port to listen on, CLI (command line interface)
-g, --graphite=IP46:PORT TCP address of graphite statistics server
-G, --graphite-interval=INT Graphite data statistics send interval
--graphite-prefix=STRING Graphite prefix for every line
-T, --tos=INT TOS value to set on streams -T, --tos=INT TOS value to set on streams
-o, --timeout=SECS RTP timeout -o, --timeout=SECS RTP timeout
-s, --silent-timeout=SECS RTP timeout for muted -s, --silent-timeout=SECS RTP timeout for muted
@ -185,10 +188,10 @@ option and which are reproduced below:
-d, --delete-delay Delay for deleting a session from memory. -d, --delete-delay Delay for deleting a session from memory.
--sip-source Use SIP source address by default --sip-source Use SIP source address by default
--dtls-passive Always prefer DTLS passive role --dtls-passive Always prefer DTLS passive role
-g, --graphite=[IP46:]PORT TCP address of graphite statistics server
-G, --graphite-interval=INT Graphite data statistics send interval
--graphite-prefix=STRING Graphite prefix for every line
--max-sessions=INT Limit the number of maximum concurrent sessions --max-sessions=INT Limit the number of maximum concurrent sessions
--homer=IP46:PORT Address of Homer server for RTCP stats
--homer-protocol=udp|tcp Transport protocol for Homer (default udp)
--homer-id=INT 'Capture ID' to use within the HEP protocol
Most of these options are indeed optional, with two exceptions. It's mandatory to specify at least one local Most of these options are indeed optional, with two exceptions. It's mandatory to specify at least one local
IP address through `--interface`, and at least one of the `--listen-...` options must be given. IP address through `--interface`, and at least one of the `--listen-...` options must be given.
@ -278,6 +281,18 @@ The options are described in more detail below.
TCP ip and port to listen for the CLI (command line interface). TCP ip and port to listen for the CLI (command line interface).
* -g, --graphite
Address of the graphite statistics server.
* -w, --graphite-interval
Interval of the time when information is sent to the graphite server.
* --graphite-prefix
Add a prefix for every graphite line.
* -t, --tos * -t, --tos
Takes an integer as argument and if given, specifies the TOS value that should be set in outgoing Takes an integer as argument and if given, specifies the TOS value that should be set in outgoing
@ -422,18 +437,6 @@ The options are described in more detail below.
Selects the internal format of the XMLRPC callback message for B2BUA call teardown. 0 is for SEMS, Selects the internal format of the XMLRPC callback message for B2BUA call teardown. 0 is for SEMS,
1 is for a generic format containing the call-ID only. 1 is for a generic format containing the call-ID only.
* -g, --graphite
Address of the graphite statistics server.
* -w, --graphite-interval
Interval of the time when information is sent to the graphite server.
* --graphite-prefix
Add a prefix for every graphite line.
* --max-sessions * --max-sessions
Limit the number of maximum concurrent sessions. Set at startup via MAX_SESSIONS in config file. Set at runtime via rtpengine-ctl util. Limit the number of maximum concurrent sessions. Set at startup via MAX_SESSIONS in config file. Set at runtime via rtpengine-ctl util.
@ -443,6 +446,21 @@ The options are described in more detail below.
Disable feature: 'rtpengine-ctl set maxsessions -1' Disable feature: 'rtpengine-ctl set maxsessions -1'
By default, the feature is disabled (i.e. maxsessions == -1). By default, the feature is disabled (i.e. maxsessions == -1).
* --homer
Enables sending the decoded contents of RTCP packets to a Homer SIP capture server. The transport
is HEP version 3 and payload format is JSON. This argument takes an IP address and a port number
as value.
* --homer-protocol
Can be either "udp" or "tcp" with "udp" being the default.
* --homer-id
The HEP protocol used by Homer contains a "capture ID" used to distinguish different sources
of capture data. This ID can be specified using this argument.
A typical command line (enabling both UDP and NG protocols) thus may look like: A typical command line (enabling both UDP and NG protocols) thus may look like:


+ 1
- 1
daemon/Makefile View File

@ -67,7 +67,7 @@ endif
SRCS= main.c kernel.c poller.c aux.c control_tcp.c streambuf.c call.c control_udp.c redis.c \ SRCS= main.c kernel.c poller.c aux.c control_tcp.c streambuf.c call.c control_udp.c redis.c \
bencode.c cookie_cache.c udp_listener.c control_ng.c sdp.c str.c stun.c rtcp.c \ bencode.c cookie_cache.c udp_listener.c control_ng.c sdp.c str.c stun.c rtcp.c \
crypto.c rtp.c call_interfaces.c dtls.c log.c cli.c graphite.c ice.c socket.c \ crypto.c rtp.c call_interfaces.c dtls.c log.c cli.c graphite.c ice.c socket.c \
media_socket.c rtcp_xr.c
media_socket.c rtcp_xr.c homer.c
OBJS= $(SRCS:.c=.o) OBJS= $(SRCS:.c=.o)


+ 3
- 0
daemon/call.h View File

@ -210,6 +210,7 @@ struct sdp_ng_flags;
struct local_interface; struct local_interface;
struct call_monologue; struct call_monologue;
struct ice_agent; struct ice_agent;
struct homer_sender;
typedef bencode_buffer_t call_buffer_t; typedef bencode_buffer_t call_buffer_t;
@ -491,6 +492,8 @@ struct callmaster {
struct callmaster_config conf; struct callmaster_config conf;
struct timeval latest_graphite_interval_start; struct timeval latest_graphite_interval_start;
struct homer_sender *homer;
}; };
struct call_stats { struct call_stats {


+ 4
- 6
daemon/graphite.c View File

@ -241,8 +241,6 @@ void graphite_loop_run(struct callmaster *cm, endpoint_t *graphite_ep, int secon
fd_set wfds; fd_set wfds;
FD_ZERO(&wfds); FD_ZERO(&wfds);
struct timeval tv; struct timeval tv;
int optval=0;
socklen_t optlen=sizeof(optval);
// sanity checks // sanity checks
if (!cm) { if (!cm) {
@ -276,10 +274,10 @@ void graphite_loop_run(struct callmaster *cm, endpoint_t *graphite_ep, int secon
connection_state = STATE_DISCONNECTED; connection_state = STATE_DISCONNECTED;
return; return;
} }
rc = getsockopt(graphite_sock.fd, SOL_SOCKET, SO_ERROR, &optval, &optlen);
if (rc) ilog(LOG_ERROR,"getsockopt failure.");
if (optval != 0) {
ilog(LOG_ERROR,"Socket connect failed. fd: %i, Reason: %s\n",graphite_sock.fd, strerror(optval));
rc = socket_error(&graphite_sock);
if (rc < 0) ilog(LOG_ERROR,"getsockopt failure.");
if (rc != 0) {
ilog(LOG_ERROR,"Socket connect failed. fd: %i, Reason: %s\n",graphite_sock.fd, strerror(rc));
close_socket(&graphite_sock); close_socket(&graphite_sock);
connection_state = STATE_DISCONNECTED; connection_state = STATE_DISCONNECTED;
return; return;


+ 559
- 0
daemon/homer.c View File

@ -0,0 +1,559 @@
#include "homer.h"
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <time.h>
#include <string.h>
#include <glib.h>
#include <sys/time.h>
#include "log.h"
#include "aux.h"
#include "str.h"
#define SEND_QUEUE_LIMIT 200
struct homer_sender {
mutex_t lock;
endpoint_t endpoint;
int protocol;
int capture_id;
socket_t socket;
time_t retry;
GQueue send_queue;
GString *partial;
int (*state)(struct homer_sender *);
};
static int send_hepv3 (GString *s, const str *id, int, const endpoint_t *src, const endpoint_t *dst,
const struct timeval *);
// state handlers
static int __established(struct homer_sender *hs);
static int __in_progress(struct homer_sender *hs);
static int __no_socket(struct homer_sender *hs);
static void __reset(struct homer_sender *hs) {
close_socket(&hs->socket);
hs->state = __no_socket;
hs->retry = time(NULL) + 30;
// discard partially written packet
if (hs->partial)
g_string_free(hs->partial, TRUE);
hs->partial = NULL;
}
static int __attempt_send(struct homer_sender *hs, GString *gs) {
int ret;
ret = write(hs->socket.fd, gs->str, gs->len);
if (ret == gs->len) {
// full write
g_string_free(gs, TRUE);
return 0;
}
if (ret < 0) {
if (errno != EWOULDBLOCK && errno != EAGAIN) {
ilog(LOG_ERR, "Write error to Homer at %s: %s",
endpoint_print_buf(&hs->endpoint), strerror(errno));
__reset(hs);
return 1;
}
ilog(LOG_DEBUG, "Home write blocked");
// XXX use poller for blocked writes?
return 2;
}
// partial write
ilog(LOG_DEBUG, "Home write blocked (partial write)");
g_string_erase(gs, 0, ret);
return 3;
}
static int __established(struct homer_sender *hs) {
char buf[16];
int ret;
GString *gs;
// test connection with a dummy read
ret = read(hs->socket.fd, buf, sizeof(buf));
if (ret < 0) {
if (errno != EWOULDBLOCK && errno != EAGAIN) {
ilog(LOG_ERR, "Connection error from Homer at %s: %s",
endpoint_print_buf(&hs->endpoint), strerror(errno));
__reset(hs);
return -1;
}
}
// XXX handle return data from Homer?
if (hs->partial) {
ilog(LOG_DEBUG, "dequeue partial packet to Homer");
ret = __attempt_send(hs, hs->partial);
if (ret == 3 || ret == 2) // partial write or not sent at all
return 0;
if (ret == 1) // write error, takes care of deleting hs->partial
return -1;
// ret == 0 -> sent OK, drop through to unqueue
g_string_free(hs->partial, TRUE);
hs->partial = NULL;
}
// unqueue as much as we can
while ((gs = g_queue_pop_head(&hs->send_queue))) {
ilog(LOG_DEBUG, "dequeue send queue to Homer");
ret = __attempt_send(hs, gs);
if (ret == 0) // everything sent OK
continue;
if (ret == 3) { // partial write
hs->partial = gs;
return 0;
}
g_queue_push_head(&hs->send_queue, gs);
if (ret == 1) // write error
return -1;
// ret == 2 -> blocked
return 0;
}
// everything unqueued
return 0;
}
static int __check_conn(struct homer_sender *hs, int ret) {
if (ret == 0) {
ilog(LOG_INFO, "Connection to Homer at %s has been established",
endpoint_print_buf(&hs->endpoint));
hs->state = __established;
return hs->state(hs);
}
if (ret == 1) {
ilog(LOG_DEBUG, "connection to Homer is in progress");
hs->state = __in_progress;
return 0;
}
ilog(LOG_ERR, "Failed to connect to Homer at %s: %s",
endpoint_print_buf(&hs->endpoint), strerror(errno));
__reset(hs);
return -1;
}
static int __in_progress(struct homer_sender *hs) {
int ret;
ilog(LOG_DEBUG, "connection to Homer is in progress - checking");
ret = connect_socket_retry(&hs->socket);
return __check_conn(hs, ret);
}
static int __no_socket(struct homer_sender *hs) {
int ret;
if (hs->retry > time(NULL))
return 0;
ilog(LOG_INFO, "Connecting to Homer at %s", endpoint_print_buf(&hs->endpoint));
ret = connect_socket_nb(&hs->socket, hs->protocol, &hs->endpoint);
return __check_conn(hs, ret);
}
struct homer_sender *homer_sender_new(const endpoint_t *ep, int protocol, int capture_id) {
struct homer_sender *ret;
if (is_addr_unspecified(&ep->address))
return NULL;
ret = malloc(sizeof(*ret));
ZERO(*ret);
mutex_init(&ret->lock);
ret->endpoint = *ep;
ret->protocol = protocol;
ret->capture_id = capture_id;
ret->retry = time(NULL);
ret->state = __no_socket;
return ret;
}
// takes over the GString
int homer_send(struct homer_sender *hs, GString *s, const str *id, const endpoint_t *src,
const endpoint_t *dst, const struct timeval *tv)
{
if (!hs)
goto out;
if (!s)
goto out;
if (!s->len) // empty write, shouldn't happen
goto out;
ilog(LOG_DEBUG, "JSON to send to Homer: '"STR_FORMAT"'", G_STR_FMT(s));
if (send_hepv3(s, id, hs->capture_id, src, dst, tv))
goto out;
mutex_lock(&hs->lock);
if (hs->send_queue.length < SEND_QUEUE_LIMIT) {
g_queue_push_tail(&hs->send_queue, s);
s = NULL;
}
else
ilog(LOG_ERR, "Send queue length limit (%i) reached, dropping Homer message", SEND_QUEUE_LIMIT);
hs->state(hs);
mutex_unlock(&hs->lock);
out:
if (s)
g_string_free(s, TRUE);
return 0;
}
// from captagent transport_hep.[ch]
struct hep_chunk {
u_int16_t vendor_id;
u_int16_t type_id;
u_int16_t length;
} __attribute__((packed));
typedef struct hep_chunk hep_chunk_t;
struct hep_chunk_uint8 {
hep_chunk_t chunk;
u_int8_t data;
} __attribute__((packed));
typedef struct hep_chunk_uint8 hep_chunk_uint8_t;
struct hep_chunk_uint16 {
hep_chunk_t chunk;
u_int16_t data;
} __attribute__((packed));
typedef struct hep_chunk_uint16 hep_chunk_uint16_t;
struct hep_chunk_uint32 {
hep_chunk_t chunk;
u_int32_t data;
} __attribute__((packed));
typedef struct hep_chunk_uint32 hep_chunk_uint32_t;
struct hep_chunk_str {
hep_chunk_t chunk;
char *data;
} __attribute__((packed));
typedef struct hep_chunk_str hep_chunk_str_t;
struct hep_chunk_ip4 {
hep_chunk_t chunk;
struct in_addr data;
} __attribute__((packed));
typedef struct hep_chunk_ip4 hep_chunk_ip4_t;
struct hep_chunk_ip6 {
hep_chunk_t chunk;
struct in6_addr data;
} __attribute__((packed));
typedef struct hep_chunk_ip6 hep_chunk_ip6_t;
struct hep_ctrl {
char id[4];
u_int16_t length;
} __attribute__((packed));
typedef struct hep_ctrl hep_ctrl_t;
struct hep_chunk_payload {
hep_chunk_t chunk;
char *data;
} __attribute__((packed));
typedef struct hep_chunk_payload hep_chunk_payload_t;
/* Structure of HEP */
struct hep_generic {
hep_ctrl_t header;
hep_chunk_uint8_t ip_family;
hep_chunk_uint8_t ip_proto;
hep_chunk_uint16_t src_port;
hep_chunk_uint16_t dst_port;
hep_chunk_uint32_t time_sec;
hep_chunk_uint32_t time_usec;
hep_chunk_uint8_t proto_t;
hep_chunk_uint32_t capt_id;
} __attribute__((packed));
typedef struct hep_generic hep_generic_t;
#define PROTO_RTCP_JSON 0x05
// modifies the GString in place
static int send_hepv3 (GString *s, const str *id, int capt_id, const endpoint_t *src, const endpoint_t *dst,
const struct timeval *tv)
{
struct hep_generic *hg=NULL;
void* buffer;
unsigned int buflen=0, iplen=0,tlen=0;
hep_chunk_ip4_t src_ip4, dst_ip4;
hep_chunk_ip6_t src_ip6, dst_ip6;
hep_chunk_t payload_chunk;
//hep_chunk_t authkey_chunk;
hep_chunk_t correlation_chunk;
//static int errors = 0;
hg = malloc(sizeof(struct hep_generic));
memset(hg, 0, sizeof(struct hep_generic));
/* header set */
memcpy(hg->header.id, "\x48\x45\x50\x33", 4);
/* IP proto */
hg->ip_family.chunk.vendor_id = htons(0x0000);
hg->ip_family.chunk.type_id = htons(0x0001);
hg->ip_family.data = src->address.family->af;
hg->ip_family.chunk.length = htons(sizeof(hg->ip_family));
/* Proto ID */
hg->ip_proto.chunk.vendor_id = htons(0x0000);
hg->ip_proto.chunk.type_id = htons(0x0002);
hg->ip_proto.data = IPPROTO_UDP;
hg->ip_proto.chunk.length = htons(sizeof(hg->ip_proto));
/* IPv4 */
if(hg->ip_family.data == AF_INET) {
/* SRC IP */
src_ip4.chunk.vendor_id = htons(0x0000);
src_ip4.chunk.type_id = htons(0x0003);
src_ip4.data = src->address.u.ipv4;
src_ip4.chunk.length = htons(sizeof(src_ip4));
/* DST IP */
dst_ip4.chunk.vendor_id = htons(0x0000);
dst_ip4.chunk.type_id = htons(0x0004);
dst_ip4.data = dst->address.u.ipv4;
dst_ip4.chunk.length = htons(sizeof(dst_ip4));
iplen = sizeof(dst_ip4) + sizeof(src_ip4);
}
/* IPv6 */
else if(hg->ip_family.data == AF_INET6) {
/* SRC IPv6 */
src_ip6.chunk.vendor_id = htons(0x0000);
src_ip6.chunk.type_id = htons(0x0005);
src_ip6.data = src->address.u.ipv6;
src_ip6.chunk.length = htons(sizeof(src_ip6));
/* DST IPv6 */
dst_ip6.chunk.vendor_id = htons(0x0000);
dst_ip6.chunk.type_id = htons(0x0006);
dst_ip6.data = dst->address.u.ipv6;
dst_ip6.chunk.length = htons(sizeof(dst_ip6));
iplen = sizeof(dst_ip6) + sizeof(src_ip6);
}
/* SRC PORT */
hg->src_port.chunk.vendor_id = htons(0x0000);
hg->src_port.chunk.type_id = htons(0x0007);
hg->src_port.data = htons(src->port);
hg->src_port.chunk.length = htons(sizeof(hg->src_port));
/* DST PORT */
hg->dst_port.chunk.vendor_id = htons(0x0000);
hg->dst_port.chunk.type_id = htons(0x0008);
hg->dst_port.data = htons(dst->port);
hg->dst_port.chunk.length = htons(sizeof(hg->dst_port));
/* TIMESTAMP SEC */
hg->time_sec.chunk.vendor_id = htons(0x0000);
hg->time_sec.chunk.type_id = htons(0x0009);
hg->time_sec.data = htonl(tv->tv_sec);
hg->time_sec.chunk.length = htons(sizeof(hg->time_sec));
/* TIMESTAMP USEC */
hg->time_usec.chunk.vendor_id = htons(0x0000);
hg->time_usec.chunk.type_id = htons(0x000a);
hg->time_usec.data = htonl(tv->tv_usec);
hg->time_usec.chunk.length = htons(sizeof(hg->time_usec));
/* Protocol TYPE */
hg->proto_t.chunk.vendor_id = htons(0x0000);
hg->proto_t.chunk.type_id = htons(0x000b);
hg->proto_t.data = PROTO_RTCP_JSON;
hg->proto_t.chunk.length = htons(sizeof(hg->proto_t));
/* Capture ID */
hg->capt_id.chunk.vendor_id = htons(0x0000);
hg->capt_id.chunk.type_id = htons(0x000c);
hg->capt_id.data = capt_id;
hg->capt_id.chunk.length = htons(sizeof(hg->capt_id));
/* Payload */
payload_chunk.vendor_id = htons(0x0000);
payload_chunk.type_id = 0 ? htons(0x0010) : htons(0x000f);
payload_chunk.length = htons(sizeof(payload_chunk) + s->len);
tlen = sizeof(struct hep_generic) + s->len + iplen + sizeof(hep_chunk_t);
#if 0
/* auth key */
if(profile_transport[idx].capt_password != NULL) {
tlen += sizeof(hep_chunk_t);
/* Auth key */
authkey_chunk.vendor_id = htons(0x0000);
authkey_chunk.type_id = htons(0x000e);
authkey_chunk.length = htons(sizeof(authkey_chunk) + strlen(profile_transport[idx].capt_password));
tlen += strlen(profile_transport[idx].capt_password);
}
#endif
/* correlation key */
//if(rcinfo->correlation_id.s && rcinfo->correlation_id.len > 0) {
tlen += sizeof(hep_chunk_t);
/* Correlation key */
correlation_chunk.vendor_id = htons(0x0000);
correlation_chunk.type_id = htons(0x0011);
correlation_chunk.length = htons(sizeof(correlation_chunk) + id->len);
tlen += id->len;
//}
/* total */
hg->header.length = htons(tlen);
buffer = (void*)malloc(tlen);
if (buffer==0){
ilog(LOG_ERR, "ERROR: out of memory");
free(hg);
return -1;
}
memcpy((void*) buffer, hg, sizeof(struct hep_generic));
buflen = sizeof(struct hep_generic);
/* IPv4 */
if(hg->ip_family.data == AF_INET) {
/* SRC IP */
memcpy((void*) buffer+buflen, &src_ip4, sizeof(struct hep_chunk_ip4));
buflen += sizeof(struct hep_chunk_ip4);
memcpy((void*) buffer+buflen, &dst_ip4, sizeof(struct hep_chunk_ip4));
buflen += sizeof(struct hep_chunk_ip4);
}
/* IPv6 */
else if(hg->ip_family.data == AF_INET6) {
/* SRC IPv6 */
memcpy((void*) buffer+buflen, &src_ip4, sizeof(struct hep_chunk_ip6));
buflen += sizeof(struct hep_chunk_ip6);
memcpy((void*) buffer+buflen, &dst_ip6, sizeof(struct hep_chunk_ip6));
buflen += sizeof(struct hep_chunk_ip6);
}
#if 0
/* AUTH KEY CHUNK */
if(profile_transport[idx].capt_password != NULL) {
memcpy((void*) buffer+buflen, &authkey_chunk, sizeof(struct hep_chunk));
buflen += sizeof(struct hep_chunk);
/* Now copying payload self */
memcpy((void*) buffer+buflen, profile_transport[idx].capt_password, strlen(profile_transport[idx].capt_password));
buflen+=strlen(profile_transport[idx].capt_password);
}
#endif
/* Correlation KEY CHUNK */
//if(rcinfo->correlation_id.s && rcinfo->correlation_id.len > 0) {
memcpy((void*) buffer+buflen, &correlation_chunk, sizeof(struct hep_chunk));
buflen += sizeof(struct hep_chunk);
/* Now copying payload self */
memcpy((void*) buffer+buflen, id->s, id->len);
buflen+= id->len;
//}
/* PAYLOAD CHUNK */
memcpy((void*) buffer+buflen, &payload_chunk, sizeof(struct hep_chunk));
buflen += sizeof(struct hep_chunk);
/* Now copying payload self */
memcpy((void*) buffer+buflen, s->str, s->len);
buflen+=s->len;
#if 0
/* make sleep after 100 errors */
if(errors > 50) {
LERR( "HEP server is down... retrying after sleep...");
if(!profile_transport[idx].usessl) {
sleep(2);
if(init_hepsocket_blocking(idx)) {
profile_transport[idx].initfails++;
}
errors=0;
}
#ifdef USE_SSL
else {
sleep(2);
if(initSSL(idx)) profile_transport[idx].initfails++;
errors=0;
}
#endif /* USE SSL */
}
/* send this packet out of our socket */
if(send_data(buffer, buflen, idx)) {
errors++;
stats.errors_total++;
}
#endif
g_string_truncate(s, 0);
g_string_append_len(s, buffer, buflen);
/* FREE */
if(buffer) free(buffer);
if(hg) free(hg);
return 0;
}

+ 15
- 0
daemon/homer.h View File

@ -0,0 +1,15 @@
#ifndef __HOMER_H__
#define __HOMER_H__
#include "socket.h"
struct homer_sender;
struct homer_sender *homer_sender_new(const endpoint_t *, int, int);
int homer_send(struct homer_sender *, GString *, const str *, const endpoint_t *, const endpoint_t *,
const struct timeval *tv);
#endif

+ 34
- 10
daemon/main.c View File

@ -29,6 +29,7 @@
#include "ice.h" #include "ice.h"
#include "socket.h" #include "socket.h"
#include "media_socket.h" #include "media_socket.h"
#include "homer.h"
@ -55,13 +56,16 @@ static char *pidfile;
static gboolean foreground; static gboolean foreground;
static GQueue interfaces = G_QUEUE_INIT; static GQueue interfaces = G_QUEUE_INIT;
static GQueue keyspaces = G_QUEUE_INIT; static GQueue keyspaces = G_QUEUE_INIT;
endpoint_t tcp_listen_ep;
endpoint_t udp_listen_ep;
endpoint_t ng_listen_ep;
endpoint_t cli_listen_ep;
endpoint_t graphite_ep;
endpoint_t redis_ep;
endpoint_t redis_write_ep;
static endpoint_t tcp_listen_ep;
static endpoint_t udp_listen_ep;
static endpoint_t ng_listen_ep;
static endpoint_t cli_listen_ep;
static endpoint_t graphite_ep;
static endpoint_t redis_ep;
static endpoint_t redis_write_ep;
static endpoint_t homer_ep;
static int homer_protocol = SOCK_DGRAM;
static int homer_id = 2001;
static int tos; static int tos;
static int table = -1; static int table = -1;
static int no_fallback; static int no_fallback;
@ -247,7 +251,7 @@ static int redis_ep_parse(endpoint_t *ep, int *db, char **auth, const char *auth
if (l < 0) if (l < 0)
return -1; return -1;
*db = l; *db = l;
if (endpoint_parse_any(ep, str))
if (endpoint_parse_any_full(ep, str))
return -1; return -1;
return 0; return 0;
} }
@ -274,6 +278,8 @@ static void options(int *argc, char ***argv) {
char *log_facility_rtcp_s = NULL; char *log_facility_rtcp_s = NULL;
int version = 0; int version = 0;
int sip_source = 0; int sip_source = 0;
char *homerp = NULL;
char *homerproto = NULL;
GOptionEntry e[] = { GOptionEntry e[] = {
{ "version", 'v', 0, G_OPTION_ARG_NONE, &version, "Print build time and exit", NULL }, { "version", 'v', 0, G_OPTION_ARG_NONE, &version, "Print build time and exit", NULL },
@ -285,7 +291,7 @@ static void options(int *argc, char ***argv) {
{ "listen-udp", 'u', 0, G_OPTION_ARG_STRING, &listenudps, "UDP port to listen on", "[IP46:]PORT" }, { "listen-udp", 'u', 0, G_OPTION_ARG_STRING, &listenudps, "UDP port to listen on", "[IP46:]PORT" },
{ "listen-ng", 'n', 0, G_OPTION_ARG_STRING, &listenngs, "UDP port to listen on, NG protocol", "[IP46:]PORT" }, { "listen-ng", 'n', 0, G_OPTION_ARG_STRING, &listenngs, "UDP port to listen on, NG protocol", "[IP46:]PORT" },
{ "listen-cli", 'c', 0, G_OPTION_ARG_STRING, &listencli, "UDP port to listen on, CLI", "[IP46:]PORT" }, { "listen-cli", 'c', 0, G_OPTION_ARG_STRING, &listencli, "UDP port to listen on, CLI", "[IP46:]PORT" },
{ "graphite", 'g', 0, G_OPTION_ARG_STRING, &graphitep, "Address of the graphite server", "[IP46:]PORT" },
{ "graphite", 'g', 0, G_OPTION_ARG_STRING, &graphitep, "Address of the graphite server", "IP46:PORT" },
{ "graphite-interval", 'G', 0, G_OPTION_ARG_INT, &graphite_interval, "Graphite send interval in seconds", "INT" }, { "graphite-interval", 'G', 0, G_OPTION_ARG_INT, &graphite_interval, "Graphite send interval in seconds", "INT" },
{ "graphite-prefix",0, 0, G_OPTION_ARG_STRING, &graphite_prefix_s, "Prefix for graphite line", "STRING"}, { "graphite-prefix",0, 0, G_OPTION_ARG_STRING, &graphite_prefix_s, "Prefix for graphite line", "STRING"},
{ "tos", 'T', 0, G_OPTION_ARG_INT, &tos, "Default TOS value to set on streams", "INT" }, { "tos", 'T', 0, G_OPTION_ARG_INT, &tos, "Default TOS value to set on streams", "INT" },
@ -312,6 +318,9 @@ static void options(int *argc, char ***argv) {
{ "sip-source", 0, 0, G_OPTION_ARG_NONE, &sip_source, "Use SIP source address by default", NULL }, { "sip-source", 0, 0, G_OPTION_ARG_NONE, &sip_source, "Use SIP source address by default", NULL },
{ "dtls-passive", 0, 0, G_OPTION_ARG_NONE, &dtls_passive_def,"Always prefer DTLS passive role", NULL }, { "dtls-passive", 0, 0, G_OPTION_ARG_NONE, &dtls_passive_def,"Always prefer DTLS passive role", NULL },
{ "max-sessions", 0, 0, G_OPTION_ARG_INT, &max_sessions, "Limit of maximum number of sessions", "INT" }, { "max-sessions", 0, 0, G_OPTION_ARG_INT, &max_sessions, "Limit of maximum number of sessions", "INT" },
{ "homer", 0, 0, G_OPTION_ARG_STRING, &homerp, "Address of Homer server for RTCP stats","IP46:PORT"},
{ "homer-protocol",0,0,G_OPTION_ARG_STRING, &homerproto, "Transport protocol for Homer (default udp)", "udp|tcp" },
{ "homer-id", 0, 0, G_OPTION_ARG_STRING, &homer_id, "'Capture ID' to use within the HEP protocol", "INT" },
{ NULL, } { NULL, }
}; };
@ -367,13 +376,26 @@ static void options(int *argc, char ***argv) {
die("Invalid IP or port (--listen-cli)"); die("Invalid IP or port (--listen-cli)");
} }
if (graphitep) {if (endpoint_parse_any(&graphite_ep, graphitep))
if (graphitep) {if (endpoint_parse_any_full(&graphite_ep, graphitep))
die("Invalid IP or port (--graphite)"); die("Invalid IP or port (--graphite)");
} }
if (graphite_prefix_s) if (graphite_prefix_s)
set_prefix(graphite_prefix_s); set_prefix(graphite_prefix_s);
if (homerp) {
if (endpoint_parse_any_full(&homer_ep, homerp))
die("Invalid IP or port (--homer)");
}
if (homerproto) {
if (!strcmp(homerproto, "tcp"))
homer_protocol = SOCK_STREAM;
else if (!strcmp(homerproto, "udp"))
homer_protocol = SOCK_DGRAM;
else
die("Invalid protocol (--homer-protocol)");
}
if (tos < 0 || tos > 255) if (tos < 0 || tos > 255)
die("Invalid TOS value"); die("Invalid TOS value");
@ -634,6 +656,8 @@ no_kernel:
daemonize(); daemonize();
wpidfile(); wpidfile();
ctx->m->homer = homer_sender_new(&homer_ep, homer_protocol, homer_id);
if (mc.redis) { if (mc.redis) {
// start redis restore timer // start redis restore timer
gettimeofday(&redis_start, NULL); gettimeofday(&redis_start, NULL);


+ 8
- 6
daemon/media_socket.c View File

@ -537,7 +537,7 @@ struct local_intf *get_any_interface_address(const struct logical_intf *lif, soc
static int get_port6(socket_t *r, unsigned int port, struct intf_spec *spec) { static int get_port6(socket_t *r, unsigned int port, struct intf_spec *spec) {
if (open_socket(r, SOCK_DGRAM, port, &spec->local_address.addr)) if (open_socket(r, SOCK_DGRAM, port, &spec->local_address.addr))
return -1; return -1;
socket_timestamping(r);
return 0; return 0;
} }
@ -1013,7 +1013,7 @@ noop:
/* XXX split this function into pieces */ /* XXX split this function into pieces */
/* called lock-free */ /* called lock-free */
static int stream_packet(struct stream_fd *sfd, str *s, const endpoint_t *fsin) {
static int stream_packet(struct stream_fd *sfd, str *s, const endpoint_t *fsin, const struct timeval *tv) {
struct packet_stream *stream, struct packet_stream *stream,
*sink = NULL, *sink = NULL,
*in_srtp, *out_srtp; *in_srtp, *out_srtp;
@ -1173,8 +1173,8 @@ loop_ok:
if (rwf_in) if (rwf_in)
handler_ret = rwf_in(s, in_srtp); handler_ret = rwf_in(s, in_srtp);
if (handler_ret >= 0) { if (handler_ret >= 0) {
if (rtcp && _log_facility_rtcp)
parse_and_log_rtcp_report(sfd, s->s, s->len);
if (rtcp)
parse_and_log_rtcp_report(sfd, s, fsin, tv);
if (rwf_out) if (rwf_out)
handler_ret += rwf_out(s, out_srtp); handler_ret += rwf_out(s, out_srtp);
} }
@ -1358,6 +1358,7 @@ static void stream_fd_readable(int fd, void *p, uintptr_t u) {
struct call *ca; struct call *ca;
str s; str s;
endpoint_t ep; endpoint_t ep;
struct timeval tv;
if (sfd->socket.fd != fd) if (sfd->socket.fd != fd)
goto out; goto out;
@ -1373,7 +1374,8 @@ static void stream_fd_readable(int fd, void *p, uintptr_t u) {
} }
#endif #endif
ret = socket_recvfrom(&sfd->socket, buf + RTP_BUFFER_HEAD_ROOM, MAX_RTP_PACKET_SIZE, &ep);
ret = socket_recvfrom_ts(&sfd->socket, buf + RTP_BUFFER_HEAD_ROOM, MAX_RTP_PACKET_SIZE,
&ep, &tv);
if (ret < 0) { if (ret < 0) {
if (errno == EINTR) if (errno == EINTR)
@ -1387,7 +1389,7 @@ static void stream_fd_readable(int fd, void *p, uintptr_t u) {
ilog(LOG_WARNING, "UDP packet possibly truncated"); ilog(LOG_WARNING, "UDP packet possibly truncated");
str_init_len(&s, buf + RTP_BUFFER_HEAD_ROOM, ret); str_init_len(&s, buf + RTP_BUFFER_HEAD_ROOM, ret);
ret = stream_packet(sfd, &s, &ep);
ret = stream_packet(sfd, &s, &ep, &tv);
if (ret < 0) { if (ret < 0) {
ilog(LOG_WARNING, "Write error on RTP socket: %s", strerror(-ret)); ilog(LOG_WARNING, "Write error on RTP socket: %s", strerror(-ret));
call_destroy(sfd->call); call_destroy(sfd->call);


+ 221
- 34
daemon/rtcp.c View File

@ -12,6 +12,7 @@
#include "rtp.h" #include "rtp.h"
#include "crypto.h" #include "crypto.h"
#include "rtcp_xr.h" #include "rtcp_xr.h"
#include "homer.h"
@ -474,8 +475,9 @@ int rtcp_demux_is_rtcp(const str *s) {
return 1; return 1;
} }
void print_rtcp_common(char** cdrbufcur, const pjmedia_rtcp_common *common) {
*cdrbufcur += sprintf(*cdrbufcur,"version=%u, padding=%u, count=%u, payloadtype=%u, length=%u, ssrc=%u, ",
static void print_rtcp_common(GString *log, const pjmedia_rtcp_common *common) {
if (log)
g_string_append_printf(log,"version=%u, padding=%u, count=%u, payloadtype=%u, length=%u, ssrc=%u, ",
common->version, common->version,
common->p, common->p,
common->count, common->count,
@ -484,23 +486,49 @@ void print_rtcp_common(char** cdrbufcur, const pjmedia_rtcp_common *common) {
ntohl(common->ssrc)); ntohl(common->ssrc));
} }
void print_rtcp_sr(char** cdrbufcur, const pjmedia_rtcp_sr* sr) {
*cdrbufcur += sprintf(*cdrbufcur,"ntp_sec=%u, ntp_fractions=%u, rtp_ts=%u, sender_packets=%u, sender_bytes=%u, ",
static void print_rtcp_sr(GString *log, const pjmedia_rtcp_sr* sr, GString *json) {
if (log)
g_string_append_printf(log,"ntp_sec=%u, ntp_fractions=%u, rtp_ts=%u, sender_packets=%u, sender_bytes=%u, ",
ntohl(sr->ntp_sec), ntohl(sr->ntp_sec),
ntohl(sr->ntp_frac), ntohl(sr->ntp_frac),
ntohl(sr->rtp_ts), ntohl(sr->rtp_ts),
ntohl(sr->sender_pcount), ntohl(sr->sender_pcount),
ntohl(sr->sender_bcount)); ntohl(sr->sender_bcount));
if (json)
g_string_append_printf(json, "\"sender_information\":{\"ntp_timestamp_sec\":%u,"
"\"ntp_timestamp_usec\":%u,\"octets\":%u,\"rtp_timestamp\":%u, \"packets\":%u},",
ntohl(sr->ntp_sec),
ntohl(sr->ntp_frac),
ntohl(sr->sender_bcount),
ntohl(sr->rtp_ts),
ntohl(sr->sender_pcount));
} }
void print_rtcp_rr(char** cdrbufcur, const pjmedia_rtcp_rr* rr) {
static void print_rtcp_rr_list_start(pjmedia_rtcp_common *common, GString *json) {
if (json)
g_string_append_printf(json, "\"ssrc\":%u,\"type\":%u,\"report_count\":%u,\"report_blocks\":[",
ntohl(common->ssrc),
common->pt,
common->count);
}
static void print_rtcp_sdes_list_start(pjmedia_rtcp_common *common, GString *json) {
if (json)
g_string_append_printf(json, "\"sdes_ssrc\":%u,\"sdes_report_count\":%u,\"sdes_information\": [ ",
ntohl(common->ssrc),
common->count);
}
static void print_rtcp_rr(GString *log, const pjmedia_rtcp_rr* rr, GString *json) {
/* Get packet loss */ /* Get packet loss */
u_int32_t packet_loss=0; u_int32_t packet_loss=0;
packet_loss = (rr->total_lost_2 << 16) + packet_loss = (rr->total_lost_2 << 16) +
(rr->total_lost_1 << 8) + (rr->total_lost_1 << 8) +
rr->total_lost_0; rr->total_lost_0;
*cdrbufcur += sprintf(*cdrbufcur,"ssrc=%u, fraction_lost=%u, packet_loss=%u, last_seq=%u, jitter=%u, last_sr=%u, delay_since_last_sr=%u, ",
if (log)
g_string_append_printf(log,"ssrc=%u, fraction_lost=%u, packet_loss=%u, last_seq=%u, jitter=%u, last_sr=%u, delay_since_last_sr=%u, ",
ntohl(rr->ssrc), ntohl(rr->ssrc),
rr->fract_lost, rr->fract_lost,
packet_loss, packet_loss,
@ -508,47 +536,206 @@ void print_rtcp_rr(char** cdrbufcur, const pjmedia_rtcp_rr* rr) {
ntohl(rr->jitter), ntohl(rr->jitter),
ntohl(rr->lsr), ntohl(rr->lsr),
ntohl(rr->dlsr)); ntohl(rr->dlsr));
if (json)
g_string_append_printf(json, "{\"source_ssrc\":%u,"
"\"highest_seq_no\":%u,\"fraction_lost\":%u,\"ia_jitter\":%u,"
"\"packets_lost\":%u,\"lsr\":%u,\"dlsr\":%u},",
ntohl(rr->ssrc),
ntohl(rr->last_seq),
rr->fract_lost,
ntohl(rr->jitter),
packet_loss,
ntohl(rr->lsr),
ntohl(rr->dlsr));
} }
void parse_and_log_rtcp_report(struct stream_fd *sfd, const void *pkt, long size) {
static void print_rtcp_sdes_item(GString *json, const rtcp_sdes_chunk_t *chunk, const rtcp_sdes_item_t *item,
const char *data)
{
int i;
if (json) {
g_string_append_printf(json, "{\"sdes_chunk_ssrc\":%u,\"type\":%u,\"text\":\"",
htonl(chunk->csrc),
item->type);
for (i = 0; i < item->len; i++) {
switch (data[i]) {
case '"':
g_string_append(json, "\\\"");
break;
case '\\':
g_string_append(json, "\\\\");
break;
case '\b':
g_string_append(json, "\\b");
break;
case '\f':
g_string_append(json, "\\f");
break;
case '\n':
g_string_append(json, "\\n");
break;
case '\r':
g_string_append(json, "\\r");
break;
case '\t':
g_string_append(json, "\\t");
break;
default:
g_string_append_c(json, data[i]);
break;
}
}
static const int CDRBUFLENGTH = 1024*1024*1; // 1 MB
char cdrbuffer[CDRBUFLENGTH];
char* cdrbufcur = cdrbuffer;
pjmedia_rtcp_common *common = (pjmedia_rtcp_common*) pkt;
const pjmedia_rtcp_rr *rr = NULL;
const pjmedia_rtcp_sr *sr = NULL;
g_string_append(json, "\"},");
}
}
cdrbufcur += sprintf(cdrbufcur,"["STR_FORMAT"] ", STR_FMT(&sfd->stream->call->callid));
static void str_sanitize(GString *s) {
while (s->len > 0 && (s->str[s->len - 1] == ' ' || s->str[s->len - 1] == ','))
g_string_truncate(s, s->len - 1);
}
if (size < sizeof(*common))
static void print_rtcp_list_end(GString *json) {
if (json) {
str_sanitize(json);
g_string_append_printf(json, "],");
}
}
void parse_and_log_rtcp_report(struct stream_fd *sfd, const str *ori_s, const endpoint_t *src,
const struct timeval *tv)
{
GString *log;
str iter_s, comp_s;
pjmedia_rtcp_common *common;
const pjmedia_rtcp_rr *rr;
const pjmedia_rtcp_sr *sr;
const rtcp_sdes_chunk_t *sdes_chunk;
const rtcp_sdes_item_t *sdes_item;
GString *json;
struct call *c = sfd->call;
struct callmaster *cm = c->callmaster;
int i;
log = _log_facility_rtcp ? g_string_new(NULL) : NULL;
json = cm->homer ? g_string_new("{ ") : NULL;
// anything to do?
if (!log && !json)
return; return;
print_rtcp_common(&cdrbufcur,common);
if (log)
g_string_append_printf(log, "["STR_FORMAT"] ", STR_FMT(&sfd->stream->call->callid));
iter_s = *ori_s;
while (iter_s.len) {
// procedure throughout here: first assign, then str_shift with check for
// return value (does the length sanity check), then access values.
// we use iter_s to iterate compound packets and comp_s to access component
// data.
common = (pjmedia_rtcp_common*) iter_s.s;
comp_s = iter_s;
if (str_shift(&comp_s, sizeof(*common))) // puts comp_s just past the common header
break;
if (str_shift(&iter_s, (ntohs(common->length) + 1) << 2)) // puts iter_s on the next compound packet
break;
print_rtcp_common(log, common);
/* Parse RTCP */
if (common->pt == RTCP_PT_SR) {
if (size < (sizeof(*common) + sizeof(*sr)))
return;
/* Parse RTCP */
switch (common->pt) {
case RTCP_PT_SR:
sr = (pjmedia_rtcp_sr*) ((comp_s.s));
if (str_shift(&comp_s, sizeof(*sr)))
break;
sr = (pjmedia_rtcp_sr*) (((char*)pkt) + sizeof(pjmedia_rtcp_common));
print_rtcp_sr(log, sr, json);
// fall through to RTCP_PT_RR
print_rtcp_sr(&cdrbufcur,sr);
case RTCP_PT_RR:
print_rtcp_rr_list_start(common, json);
if (common->count > 0 && size >= (sizeof(pjmedia_rtcp_sr_pkt))) {
rr = (pjmedia_rtcp_rr*)(((char*)pkt) + (sizeof(pjmedia_rtcp_common)
+ sizeof(pjmedia_rtcp_sr)));
print_rtcp_rr(&cdrbufcur,rr);
for (i = 0; i < common->count; i++) {
rr = (pjmedia_rtcp_rr*)((comp_s.s));
if (str_shift(&comp_s, sizeof(*rr)))
break;
print_rtcp_rr(log, rr, json);
}
print_rtcp_list_end(json);
break;
case RTCP_PT_XR:
pjmedia_rtcp_xr_rx_rtcp_xr(log, common, &comp_s);
break;
case RTCP_PT_SDES:
print_rtcp_sdes_list_start(common, json);
// the "common" header actually includes the SDES
// SSRC/CSRC chunk header, so we set our chunk header
// to its SDES field
sdes_chunk = (rtcp_sdes_chunk_t *) &common->ssrc;
// comp_s then points into the first SDES item
i = 0;
while (1) {
while (comp_s.len) {
sdes_item = (rtcp_sdes_item_t *) comp_s.s;
// check for zero type first
if (str_shift(&comp_s, 1))
break;
if (!sdes_item->type)
break;
if (str_shift(&comp_s, sizeof(*sdes_item) - 1))
break;
if (comp_s.len < sdes_item->len)
break;
print_rtcp_sdes_item(json, sdes_chunk, sdes_item, comp_s.s);
str_shift(&comp_s, sdes_item->len);
}
// remove padding to next chunk
while (comp_s.len % 4 != 0)
str_shift(&comp_s, 1);
// more chunks? set chunk header
i++;
if (i >= common->count)
break;
sdes_chunk = (rtcp_sdes_chunk_t *) comp_s.s;
if (str_shift(&comp_s, sizeof(*sdes_chunk)))
break;
}
print_rtcp_list_end(json);
break;
} }
} else if (common->pt == RTCP_PT_RR && common->count > 0) {
if (size < (sizeof(*common) + sizeof(*rr)))
return;
}
rr = (pjmedia_rtcp_rr*)(((char*)pkt) + sizeof(pjmedia_rtcp_common));
print_rtcp_rr(&cdrbufcur,rr);
if (log) {
str_sanitize(log);
rtcplog(log->str);
}
} else if (common->pt == RTCP_PT_XR) {
pjmedia_rtcp_xr_rx_rtcp_xr(cdrbufcur, pkt, size);
if (json) {
str_sanitize(json);
g_string_append(json, " }");
homer_send(cm->homer, json, &c->callid, src, &sfd->socket.local, tv);
json = NULL;
} }
rtcplog(cdrbuffer);
if (json)
g_string_free(json, TRUE);
if (log)
g_string_free(log, TRUE);
} }

+ 21
- 27
daemon/rtcp.h View File

@ -3,6 +3,7 @@
#include "str.h" #include "str.h"
#include "call.h" #include "call.h"
#include <glib.h>
struct crypto_context; struct crypto_context;
@ -30,7 +31,7 @@ typedef struct pjmedia_rtcp_sr
u_int32_t rtp_ts; /**< RTP timestamp. */ u_int32_t rtp_ts; /**< RTP timestamp. */
u_int32_t sender_pcount; /**< Sender packet cound. */ u_int32_t sender_pcount; /**< Sender packet cound. */
u_int32_t sender_bcount; /**< Sender octet/bytes count. */ u_int32_t sender_bcount; /**< Sender octet/bytes count. */
} pjmedia_rtcp_sr;
} __attribute__ ((packed)) pjmedia_rtcp_sr;
/** /**
@ -39,22 +40,36 @@ typedef struct pjmedia_rtcp_sr
typedef struct pjmedia_rtcp_rr typedef struct pjmedia_rtcp_rr
{ {
u_int32_t ssrc; /**< SSRC identification. */ u_int32_t ssrc; /**< SSRC identification. */
#if defined(PJ_IS_BIG_ENDIAN) && PJ_IS_BIG_ENDIAN!=0
#if G_BYTE_ORDER == G_BIG_ENDIAN
u_int32_t fract_lost:8; /**< Fraction lost. */ u_int32_t fract_lost:8; /**< Fraction lost. */
u_int32_t total_lost_2:8; /**< Total lost, bit 16-23. */ u_int32_t total_lost_2:8; /**< Total lost, bit 16-23. */
u_int32_t total_lost_1:8; /**< Total lost, bit 8-15. */ u_int32_t total_lost_1:8; /**< Total lost, bit 8-15. */
u_int32_t total_lost_0:8; /**< Total lost, bit 0-7. */ u_int32_t total_lost_0:8; /**< Total lost, bit 0-7. */
#else
#elif G_BYTE_ORDER == G_LITTLE_ENDIAN
u_int32_t fract_lost:8; /**< Fraction lost. */ u_int32_t fract_lost:8; /**< Fraction lost. */
u_int32_t total_lost_2:8; /**< Total lost, bit 0-7. */ u_int32_t total_lost_2:8; /**< Total lost, bit 0-7. */
u_int32_t total_lost_1:8; /**< Total lost, bit 8-15. */ u_int32_t total_lost_1:8; /**< Total lost, bit 8-15. */
u_int32_t total_lost_0:8; /**< Total lost, bit 16-23. */ u_int32_t total_lost_0:8; /**< Total lost, bit 16-23. */
#else
#error "byte order unknown"
#endif #endif
u_int32_t last_seq; /**< Last sequence number. */ u_int32_t last_seq; /**< Last sequence number. */
u_int32_t jitter; /**< Jitter. */ u_int32_t jitter; /**< Jitter. */
u_int32_t lsr; /**< Last SR. */ u_int32_t lsr; /**< Last SR. */
u_int32_t dlsr; /**< Delay since last SR. */ u_int32_t dlsr; /**< Delay since last SR. */
} pjmedia_rtcp_rr;
} __attribute__ ((packed)) pjmedia_rtcp_rr;
typedef struct _rtcp_sdes_chunk
{
uint32_t csrc;
} __attribute__ ((packed)) rtcp_sdes_chunk_t;
typedef struct _rtcp_sdes_item
{
uint8_t type;
uint8_t len;
} __attribute__ ((packed)) rtcp_sdes_item_t;
/** /**
@ -62,7 +77,7 @@ typedef struct pjmedia_rtcp_rr
*/ */
typedef struct pjmedia_rtcp_common typedef struct pjmedia_rtcp_common
{ {
#if defined(PJ_IS_BIG_ENDIAN) && PJ_IS_BIG_ENDIAN!=0
#if G_BYTE_ORDER == G_BIG_ENDIAN
unsigned version:2; /**< packet type */ unsigned version:2; /**< packet type */
unsigned p:1; /**< padding flag */ unsigned p:1; /**< padding flag */
unsigned count:5; /**< varies by payload type */ unsigned count:5; /**< varies by payload type */
@ -77,27 +92,6 @@ typedef struct pjmedia_rtcp_common
u_int32_t ssrc; /**< SSRC identification */ u_int32_t ssrc; /**< SSRC identification */
} pjmedia_rtcp_common; } pjmedia_rtcp_common;
/**
* This structure declares default RTCP packet (SR) that is sent by pjmedia.
* Incoming RTCP packet may have different format, and must be parsed
* manually by application.
*/
typedef struct pjmedia_rtcp_sr_pkt
{
pjmedia_rtcp_common common; /**< Common header. */
pjmedia_rtcp_sr sr; /**< Sender report. */
pjmedia_rtcp_rr rr; /**< variable-length list */
} pjmedia_rtcp_sr_pkt;
/**
* This structure declares RTCP RR (Receiver Report) packet.
*/
typedef struct pjmedia_rtcp_rr_pkt
{
pjmedia_rtcp_common common; /**< Common header. */
pjmedia_rtcp_rr rr; /**< variable-length list */
} pjmedia_rtcp_rr_pkt;
int rtcp_avpf2avp(str *); int rtcp_avpf2avp(str *);
int rtcp_avp2savp(str *, struct crypto_context *); int rtcp_avp2savp(str *, struct crypto_context *);
@ -105,6 +99,6 @@ int rtcp_savp2avp(str *, struct crypto_context *);
int rtcp_demux_is_rtcp(const str *); int rtcp_demux_is_rtcp(const str *);
void parse_and_log_rtcp_report(struct stream_fd *sfd, const void *pkt, long size);
void parse_and_log_rtcp_report(struct stream_fd *sfd, const str *, const endpoint_t *, const struct timeval *);
#endif #endif

+ 36
- 51
daemon/rtcp_xr.c View File

@ -4,9 +4,10 @@
* Created on: Mar 29, 2015 * Created on: Mar 29, 2015
* Author: fmetz * Author: fmetz
*/ */
#include "rtcp_xr.h"
#include <stdio.h> #include <stdio.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include "rtcp_xr.h"
#include <glib.h>
/* RTCP XR payload type */ /* RTCP XR payload type */
#define RTCP_XR 207 #define RTCP_XR 207
@ -21,41 +22,31 @@
#define BT_VOIP_METRICS 7 #define BT_VOIP_METRICS 7
void print_rtcp_xr_common(char* cdrbufcur,const pjmedia_rtcp_xr_pkt *rtcp_xr) {
cdrbufcur += sprintf(cdrbufcur,"version=%u, padding=%u, count=%u, payloadtype=%u, length=%u, ssrc=%u, ",
rtcp_xr->common.version,
rtcp_xr->common.p,
rtcp_xr->common.count,
rtcp_xr->common.pt,
rtcp_xr->common.length,
ntohl(rtcp_xr->common.ssrc));
}
void print_rtcp_xr_rb_header(char* cdrbufcur,const pjmedia_rtcp_xr_rb_header *rb_header) {
cdrbufcur += sprintf(cdrbufcur,"rb_header_blocktype=%u, rb_header_blockspecdata=%u, rb_header_blocklength=%u, ",
void print_rtcp_xr_rb_header(GString *log, const pjmedia_rtcp_xr_rb_header *rb_header) {
g_string_append_printf(log, "rb_header_blocktype=%u, rb_header_blockspecdata=%u, rb_header_blocklength=%u, ",
rb_header->bt, rb_header->bt,
rb_header->specific, rb_header->specific,
ntohs(rb_header->length)); ntohs(rb_header->length));
} }
void print_rtcp_xr_rb_rr_time(char* cdrbufcur,const pjmedia_rtcp_xr_rb_rr_time *rb_rr_time) {
print_rtcp_xr_rb_header(cdrbufcur,&rb_rr_time->header);
cdrbufcur += sprintf(cdrbufcur,"rb_rr_time_ntp_sec=%u, rb_rr_time_ntp_frac=%u, ",
void print_rtcp_xr_rb_rr_time(GString *log, const pjmedia_rtcp_xr_rb_rr_time *rb_rr_time) {
print_rtcp_xr_rb_header(log, &rb_rr_time->header);
g_string_append_printf(log, "rb_rr_time_ntp_sec=%u, rb_rr_time_ntp_frac=%u, ",
ntohl(rb_rr_time->ntp_sec), ntohl(rb_rr_time->ntp_sec),
ntohl(rb_rr_time->ntp_frac)); ntohl(rb_rr_time->ntp_frac));
} }
void print_rtcp_xr_rb_dlrr(char* cdrbufcur,const pjmedia_rtcp_xr_rb_dlrr *rb_dlrr) {
print_rtcp_xr_rb_header(cdrbufcur,&rb_dlrr->header);
cdrbufcur += sprintf(cdrbufcur,"rb_dlrr_ssrc=%u, rb_dlrr_lrr=%u, rb_dlrr_dlrr=%u, ",
void print_rtcp_xr_rb_dlrr(GString *log, const pjmedia_rtcp_xr_rb_dlrr *rb_dlrr) {
print_rtcp_xr_rb_header(log, &rb_dlrr->header);
g_string_append_printf(log, "rb_dlrr_ssrc=%u, rb_dlrr_lrr=%u, rb_dlrr_dlrr=%u, ",
ntohl(rb_dlrr->item.ssrc), ntohl(rb_dlrr->item.ssrc),
ntohl(rb_dlrr->item.lrr), ntohl(rb_dlrr->item.lrr),
ntohl(rb_dlrr->item.dlrr)); ntohl(rb_dlrr->item.dlrr));
} }
void print_rtcp_xr_rb_stats(char* cdrbufcur,const pjmedia_rtcp_xr_rb_stats *rb_stats) {
print_rtcp_xr_rb_header(cdrbufcur,&rb_stats->header);
cdrbufcur += sprintf(cdrbufcur,"rb_stats_ssrc=%u, rb_stats_begin_seq=%u, rb_stats_end_seq=%u, rb_stats_lost_packets=%u, rb_stats_duplicate_packets=%u,"
void print_rtcp_xr_rb_stats(GString *log, const pjmedia_rtcp_xr_rb_stats *rb_stats) {
print_rtcp_xr_rb_header(log, &rb_stats->header);
g_string_append_printf(log, "rb_stats_ssrc=%u, rb_stats_begin_seq=%u, rb_stats_end_seq=%u, rb_stats_lost_packets=%u, rb_stats_duplicate_packets=%u,"
"rb_stats_jitter_min=%u, rb_stats_jitter_max=%u, rb_stats_jitter_mean=%u, rb_stats_jitter_deviation=%u," "rb_stats_jitter_min=%u, rb_stats_jitter_max=%u, rb_stats_jitter_mean=%u, rb_stats_jitter_deviation=%u,"
"rb_stats_toh_min=%u, rb_stats_toh_max=%u, rb_stats_toh_mean=%u, rb_stats_toh_deviation=%u, ", "rb_stats_toh_min=%u, rb_stats_toh_max=%u, rb_stats_toh_mean=%u, rb_stats_toh_deviation=%u, ",
ntohl(rb_stats->ssrc), ntohl(rb_stats->ssrc),
@ -73,9 +64,9 @@ void print_rtcp_xr_rb_stats(char* cdrbufcur,const pjmedia_rtcp_xr_rb_stats *rb_s
ntohl(rb_stats->toh_dev)); ntohl(rb_stats->toh_dev));
} }
void print_rtcp_xr_rb_voip_mtc(char* cdrbufcur,const pjmedia_rtcp_xr_rb_voip_mtc *rb_voip_mtc) {
print_rtcp_xr_rb_header(cdrbufcur,&rb_voip_mtc->header);
cdrbufcur += sprintf(cdrbufcur,"rb_voip_mtc_ssrc=%u, rb_voip_mtc_loss_rate=%u, rb_voip_mtc_discard_rate=%u, rb_voip_mtc_burst_den=%u, "
void print_rtcp_xr_rb_voip_mtc(GString *log, const pjmedia_rtcp_xr_rb_voip_mtc *rb_voip_mtc) {
print_rtcp_xr_rb_header(log, &rb_voip_mtc->header);
g_string_append_printf(log, "rb_voip_mtc_ssrc=%u, rb_voip_mtc_loss_rate=%u, rb_voip_mtc_discard_rate=%u, rb_voip_mtc_burst_den=%u, "
"rb_voip_mtc_gap_den=%u, rb_voip_mtc_burst_dur=%u, rb_voip_mtc_gap_dur=%u, rb_voip_mtc_rnd_trip_delay=%u, " "rb_voip_mtc_gap_den=%u, rb_voip_mtc_burst_dur=%u, rb_voip_mtc_gap_dur=%u, rb_voip_mtc_rnd_trip_delay=%u, "
"rb_voip_mtc_end_sys_delay=%u, rb_voip_mtc_signal_lvl=%u, rb_voip_mtc_noise_lvl=%u, rb_voip_mtc_rerl=%u, " "rb_voip_mtc_end_sys_delay=%u, rb_voip_mtc_signal_lvl=%u, rb_voip_mtc_noise_lvl=%u, rb_voip_mtc_rerl=%u, "
"rb_voip_mtc_gmin=%u, rb_voip_mtc_r_factor=%u, rb_voip_mtc_ext_r_factor=%u, rb_voip_mtc_mos_lq=%u, " "rb_voip_mtc_gmin=%u, rb_voip_mtc_r_factor=%u, rb_voip_mtc_ext_r_factor=%u, rb_voip_mtc_mos_lq=%u, "
@ -104,60 +95,54 @@ void print_rtcp_xr_rb_voip_mtc(char* cdrbufcur,const pjmedia_rtcp_xr_rb_voip_mtc
ntohs(rb_voip_mtc->jb_abs_max)); ntohs(rb_voip_mtc->jb_abs_max));
} }
void pjmedia_rtcp_xr_rx_rtcp_xr(char* cdrbufcur, const void *pkt, size_t size) {
void pjmedia_rtcp_xr_rx_rtcp_xr(GString *log, pjmedia_rtcp_common *common, str *s) {
const pjmedia_rtcp_xr_pkt *rtcp_xr = (pjmedia_rtcp_xr_pkt*) pkt;
const pjmedia_rtcp_xr_rb_rr_time *rb_rr_time = NULL;
const pjmedia_rtcp_xr_rb_dlrr *rb_dlrr = NULL;
const pjmedia_rtcp_xr_rb_stats *rb_stats = NULL;
const pjmedia_rtcp_xr_rb_voip_mtc *rb_voip_mtc = NULL;
const pjmedia_rtcp_xr_rb_header *rb_hdr = (pjmedia_rtcp_xr_rb_header*)
rtcp_xr->buf;
const pjmedia_rtcp_xr_rb_rr_time *rb_rr_time;
const pjmedia_rtcp_xr_rb_dlrr *rb_dlrr;
const pjmedia_rtcp_xr_rb_stats *rb_stats;
const pjmedia_rtcp_xr_rb_voip_mtc *rb_voip_mtc;
const pjmedia_rtcp_xr_rb_header *rb_hdr;
unsigned pkt_len, rb_len; unsigned pkt_len, rb_len;
if (size < sizeof(*rtcp_xr))
if (!log)
return; return;
if (rtcp_xr->common.pt != RTCP_XR)
return;
print_rtcp_xr_common(cdrbufcur,rtcp_xr);
// packet length is guaranteed to be valid from upstream
pkt_len = ntohs((u_int16_t)rtcp_xr->common.length);
if ((pkt_len + 1) > (size / 4))
return;
pkt_len = (ntohs(common->length) + 1) << 2;
/* Parse report rpt_types */ /* Parse report rpt_types */
while ((int32_t*)rb_hdr < (int32_t*)pkt + pkt_len)
while (pkt_len >= sizeof(*rb_hdr))
{ {
rb_len = ntohs((u_int16_t)rb_hdr->length);
rb_hdr = (pjmedia_rtcp_xr_rb_header*) s->s;
rb_len = (ntohs((u_int16_t)rb_hdr->length) + 1) << 2;
if (str_shift(s, rb_len))
break;
pkt_len -= rb_len;
/* Just skip any block with length == 0 (no report content) */ /* Just skip any block with length == 0 (no report content) */
if (rb_len) {
if (rb_len > 4) {
switch (rb_hdr->bt) { switch (rb_hdr->bt) {
case BT_RR_TIME: case BT_RR_TIME:
rb_rr_time = (pjmedia_rtcp_xr_rb_rr_time*) rb_hdr; rb_rr_time = (pjmedia_rtcp_xr_rb_rr_time*) rb_hdr;
print_rtcp_xr_rb_rr_time(cdrbufcur,rb_rr_time);
print_rtcp_xr_rb_rr_time(log, rb_rr_time);
break; break;
case BT_DLRR: case BT_DLRR:
rb_dlrr = (pjmedia_rtcp_xr_rb_dlrr*) rb_hdr; rb_dlrr = (pjmedia_rtcp_xr_rb_dlrr*) rb_hdr;
print_rtcp_xr_rb_dlrr(cdrbufcur,rb_dlrr);
print_rtcp_xr_rb_dlrr(log, rb_dlrr);
break; break;
case BT_STATS: case BT_STATS:
rb_stats = (pjmedia_rtcp_xr_rb_stats*) rb_hdr; rb_stats = (pjmedia_rtcp_xr_rb_stats*) rb_hdr;
print_rtcp_xr_rb_stats(cdrbufcur,rb_stats);
print_rtcp_xr_rb_stats(log, rb_stats);
break; break;
case BT_VOIP_METRICS: case BT_VOIP_METRICS:
rb_voip_mtc = (pjmedia_rtcp_xr_rb_voip_mtc*) rb_hdr; rb_voip_mtc = (pjmedia_rtcp_xr_rb_voip_mtc*) rb_hdr;
print_rtcp_xr_rb_voip_mtc(cdrbufcur,rb_voip_mtc);
print_rtcp_xr_rb_voip_mtc(log, rb_voip_mtc);
break; break;
default: default:
break; break;
} }
} }
rb_hdr = (pjmedia_rtcp_xr_rb_header*)
((int32_t*)rb_hdr + rb_len + 1);
} }
} }

+ 8
- 37
daemon/rtcp_xr.h View File

@ -10,6 +10,10 @@
#include <stdint.h> #include <stdint.h>
#include <sys/types.h> #include <sys/types.h>
#include <glib.h>
#include "str.h"
#include "rtcp.h"
/** /**
* @defgroup PJMED_RTCP_XR RTCP Extended Report (XR) - RFC 3611 * @defgroup PJMED_RTCP_XR RTCP Extended Report (XR) - RFC 3611
@ -180,42 +184,6 @@ typedef struct pjmedia_rtcp_xr_rb_voip_mtc
} pjmedia_rtcp_xr_rb_voip_mtc; } pjmedia_rtcp_xr_rb_voip_mtc;
/**
* Constant of RTCP-XR content size.
*/
#define PJMEDIA_RTCP_XR_BUF_SIZE \
sizeof(pjmedia_rtcp_xr_rb_rr_time) + \
sizeof(pjmedia_rtcp_xr_rb_dlrr) + \
sizeof(pjmedia_rtcp_xr_rb_stats) + \
sizeof(pjmedia_rtcp_xr_rb_voip_mtc)
/**
* This structure declares RTCP XR (Extended Report) packet.
*/
typedef struct pjmedia_rtcp_xr_pkt
{
struct {
#if defined(PJ_IS_BIG_ENDIAN) && PJ_IS_BIG_ENDIAN!=0
unsigned version:2; /**< packet type */
unsigned p:1; /**< padding flag */
unsigned count:5; /**< varies by payload type */
unsigned pt:8; /**< payload type */
#else
unsigned count:5; /**< varies by payload type */
unsigned p:1; /**< padding flag */
unsigned version:2; /**< packet type */
unsigned pt:8; /**< payload type */
#endif
unsigned length:16; /**< packet length */
u_int32_t ssrc; /**< SSRC identification */
} common;
int8_t buf[PJMEDIA_RTCP_XR_BUF_SIZE];
/**< Content buffer */
} pjmedia_rtcp_xr_pkt;
/** /**
* This function is called internally by RTCP session when it receives * This function is called internally by RTCP session when it receives
* incoming RTCP XR packets. * incoming RTCP XR packets.
@ -223,7 +191,10 @@ typedef struct pjmedia_rtcp_xr_pkt
* @param rtcp_pkt The received RTCP XR packet. * @param rtcp_pkt The received RTCP XR packet.
* @param size Size of the incoming packet. * @param size Size of the incoming packet.
*/ */
void pjmedia_rtcp_xr_rx_rtcp_xr( char* cdrbufcur, const void *rtcp_pkt, size_t size);
void pjmedia_rtcp_xr_rx_rtcp_xr(GString *, pjmedia_rtcp_common *common, str *s);
#pragma pack()
#endif /* RTCP_XR_H_ */ #endif /* RTCP_XR_H_ */

+ 77
- 16
daemon/socket.c View File

@ -20,6 +20,7 @@ static int __ip4_is_specified(const sockaddr_t *a);
static int __ip6_is_specified(const sockaddr_t *a); static int __ip6_is_specified(const sockaddr_t *a);
static int __ip_bind(socket_t *s, unsigned int, const sockaddr_t *); static int __ip_bind(socket_t *s, unsigned int, const sockaddr_t *);
static int __ip_connect(socket_t *s, const endpoint_t *); static int __ip_connect(socket_t *s, const endpoint_t *);
static int __ip_timestamping(socket_t *s);
static int __ip4_sockaddr2endpoint(endpoint_t *, const void *); static int __ip4_sockaddr2endpoint(endpoint_t *, const void *);
static int __ip6_sockaddr2endpoint(endpoint_t *, const void *); static int __ip6_sockaddr2endpoint(endpoint_t *, const void *);
static int __ip4_endpoint2sockaddr(void *, const endpoint_t *); static int __ip4_endpoint2sockaddr(void *, const endpoint_t *);
@ -27,10 +28,12 @@ static int __ip6_endpoint2sockaddr(void *, const endpoint_t *);
static int __ip4_addrport2sockaddr(void *, const sockaddr_t *, unsigned int); static int __ip4_addrport2sockaddr(void *, const sockaddr_t *, unsigned int);
static int __ip6_addrport2sockaddr(void *, const sockaddr_t *, unsigned int); static int __ip6_addrport2sockaddr(void *, const sockaddr_t *, unsigned int);
static ssize_t __ip_recvfrom(socket_t *s, void *buf, size_t len, endpoint_t *ep); static ssize_t __ip_recvfrom(socket_t *s, void *buf, size_t len, endpoint_t *ep);
static ssize_t __ip_recvfrom_ts(socket_t *s, void *buf, size_t len, endpoint_t *ep, struct timeval *);
static ssize_t __ip_sendmsg(socket_t *s, struct msghdr *mh, const endpoint_t *ep); static ssize_t __ip_sendmsg(socket_t *s, struct msghdr *mh, const endpoint_t *ep);
static ssize_t __ip_sendto(socket_t *s, const void *buf, size_t len, const endpoint_t *ep); static ssize_t __ip_sendto(socket_t *s, const void *buf, size_t len, const endpoint_t *ep);
static int __ip4_tos(socket_t *, unsigned int); static int __ip4_tos(socket_t *, unsigned int);
static int __ip6_tos(socket_t *, unsigned int); static int __ip6_tos(socket_t *, unsigned int);
static int __ip_error(socket_t *s);
static void __ip4_endpoint2kernel(struct re_address *, const endpoint_t *); static void __ip4_endpoint2kernel(struct re_address *, const endpoint_t *);
static void __ip6_endpoint2kernel(struct re_address *, const endpoint_t *); static void __ip6_endpoint2kernel(struct re_address *, const endpoint_t *);
static void __ip4_kernel2endpoint(endpoint_t *ep, const struct re_address *ra); static void __ip4_kernel2endpoint(endpoint_t *ep, const struct re_address *ra);
@ -63,10 +66,13 @@ static struct socket_family __socket_families[__SF_LAST] = {
.addrport2sockaddr = __ip4_addrport2sockaddr, .addrport2sockaddr = __ip4_addrport2sockaddr,
.bind = __ip_bind, .bind = __ip_bind,
.connect = __ip_connect, .connect = __ip_connect,
.timestamping = __ip_timestamping,
.recvfrom = __ip_recvfrom, .recvfrom = __ip_recvfrom,
.recvfrom_ts = __ip_recvfrom_ts,
.sendmsg = __ip_sendmsg, .sendmsg = __ip_sendmsg,
.sendto = __ip_sendto, .sendto = __ip_sendto,
.tos = __ip4_tos, .tos = __ip4_tos,
.error = __ip_error,
.endpoint2kernel = __ip4_endpoint2kernel, .endpoint2kernel = __ip4_endpoint2kernel,
.kernel2endpoint = __ip4_kernel2endpoint, .kernel2endpoint = __ip4_kernel2endpoint,
}, },
@ -87,10 +93,13 @@ static struct socket_family __socket_families[__SF_LAST] = {
.addrport2sockaddr = __ip6_addrport2sockaddr, .addrport2sockaddr = __ip6_addrport2sockaddr,
.bind = __ip_bind, .bind = __ip_bind,
.connect = __ip_connect, .connect = __ip_connect,
.timestamping = __ip_timestamping,
.recvfrom = __ip_recvfrom, .recvfrom = __ip_recvfrom,
.recvfrom_ts = __ip_recvfrom_ts,
.sendmsg = __ip_sendmsg, .sendmsg = __ip_sendmsg,
.sendto = __ip_sendto, .sendto = __ip_sendto,
.tos = __ip6_tos, .tos = __ip6_tos,
.error = __ip_error,
.endpoint2kernel = __ip6_endpoint2kernel, .endpoint2kernel = __ip6_endpoint2kernel,
.kernel2endpoint = __ip6_kernel2endpoint, .kernel2endpoint = __ip6_kernel2endpoint,
}, },
@ -233,18 +242,52 @@ static int __ip_connect(socket_t *s, const endpoint_t *ep) {
} }
return 0; return 0;
} }
static ssize_t __ip_recvfrom(socket_t *s, void *buf, size_t len, endpoint_t *ep) {
static ssize_t __ip_recvfrom_ts(socket_t *s, void *buf, size_t len, endpoint_t *ep, struct timeval *tv) {
ssize_t ret; ssize_t ret;
struct sockaddr_storage sin; struct sockaddr_storage sin;
socklen_t sinlen;
sinlen = s->family->sockaddr_size;
ret = recvfrom(s->fd, buf, len, 0, (void *) &sin, &sinlen);
struct msghdr msg;
struct iovec iov;
char ctrl[32];
struct cmsghdr *cm;
ZERO(msg);
msg.msg_name = &sin;
msg.msg_namelen = s->family->sockaddr_size;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = ctrl;
msg.msg_controllen = sizeof(ctrl);
ZERO(iov);
iov.iov_base = buf;
iov.iov_len = len;
ret = recvmsg(s->fd, &msg, 0);
if (ret < 0) if (ret < 0)
return ret; return ret;
s->family->sockaddr2endpoint(ep, &sin); s->family->sockaddr2endpoint(ep, &sin);
if (tv) {
for (cm = CMSG_FIRSTHDR(&msg); cm; cm = CMSG_NXTHDR(&msg, cm)) {
if (cm->cmsg_level == SOL_SOCKET && cm->cmsg_type == SO_TIMESTAMP) {
*tv = *((struct timeval *) CMSG_DATA(cm));
tv = NULL;
}
}
if (G_UNLIKELY(tv)) {
ilog(LOG_WARNING, "No receive timestamp received from kernel");
ZERO(*tv);
}
}
if (G_UNLIKELY((msg.msg_flags & MSG_TRUNC)))
ilog(LOG_WARNING, "Kernel indicates that data was truncated");
if (G_UNLIKELY((msg.msg_flags & MSG_CTRUNC)))
ilog(LOG_WARNING, "Kernel indicates that ancillary data was truncated");
return ret; return ret;
} }
static ssize_t __ip_recvfrom(socket_t *s, void *buf, size_t len, endpoint_t *ep) {
return __ip_recvfrom_ts(s, buf, len, ep, NULL);
}
static ssize_t __ip_sendmsg(socket_t *s, struct msghdr *mh, const endpoint_t *ep) { static ssize_t __ip_sendmsg(socket_t *s, struct msghdr *mh, const endpoint_t *ep) {
struct sockaddr_storage sin; struct sockaddr_storage sin;
@ -270,6 +313,19 @@ static int __ip6_tos(socket_t *s, unsigned int tos) {
setsockopt(s->fd, IPPROTO_IPV6, IPV6_TCLASS, &tos, sizeof(tos)); setsockopt(s->fd, IPPROTO_IPV6, IPV6_TCLASS, &tos, sizeof(tos));
return 0; return 0;
} }
static int __ip_error(socket_t *s) {
int optval;
socklen_t optlen = sizeof(optval);
if (getsockopt(s->fd, SOL_SOCKET, SO_ERROR, &optval, &optlen))
return -1;
return optval;
}
static int __ip_timestamping(socket_t *s) {
int one = 1;
if (setsockopt(s->fd, SOL_SOCKET, SO_TIMESTAMP, &one, sizeof(one)))
return -1;
return 0;
}
static void __ip4_endpoint2kernel(struct re_address *ra, const endpoint_t *ep) { static void __ip4_endpoint2kernel(struct re_address *ra, const endpoint_t *ep) {
ZERO(*ra); ZERO(*ra);
ra->family = AF_INET; ra->family = AF_INET;
@ -478,23 +534,15 @@ fail:
return -1; return -1;
} }
int connect_socket_nb(socket_t *r, int type, const endpoint_t *ep) {
sockfamily_t *fam;
int connect_socket_retry(socket_t *r) {
int ret = 0; int ret = 0;
fam = ep->address.family;
if (__socket(r, type, fam))
return -1;
nonblock(r->fd);
if (fam->connect(r, ep)) {
if (errno != EINPROGRESS)
if (r->family->connect(r, &r->remote)) {
if (errno != EINPROGRESS && errno != EALREADY)
goto fail; goto fail;
ret = 1; ret = 1;
} }
r->remote = *ep;
return ret; return ret;
fail: fail:
@ -502,6 +550,19 @@ fail:
return -1; return -1;
} }
int connect_socket_nb(socket_t *r, int type, const endpoint_t *ep) {
sockfamily_t *fam;
fam = ep->address.family;
if (__socket(r, type, fam))
return -1;
nonblock(r->fd);
r->remote = *ep;
return connect_socket_retry(r);
}
int close_socket(socket_t *r) { int close_socket(socket_t *r) {
if (!r || r->fd == -1) { if (!r || r->fd == -1) {
__C_DBG("close() syscall not called, fd=%d", r->fd); __C_DBG("close() syscall not called, fd=%d", r->fd);


+ 19
- 2
daemon/socket.h View File

@ -59,10 +59,13 @@ struct socket_family {
int (*addrport2sockaddr)(void *, const sockaddr_t *, unsigned int); int (*addrport2sockaddr)(void *, const sockaddr_t *, unsigned int);
int (*bind)(socket_t *, unsigned int, const sockaddr_t *); int (*bind)(socket_t *, unsigned int, const sockaddr_t *);
int (*connect)(socket_t *, const endpoint_t *); int (*connect)(socket_t *, const endpoint_t *);
int (*timestamping)(socket_t *);
ssize_t (*recvfrom)(socket_t *, void *, size_t, endpoint_t *); ssize_t (*recvfrom)(socket_t *, void *, size_t, endpoint_t *);
ssize_t (*recvfrom_ts)(socket_t *, void *, size_t, endpoint_t *, struct timeval *);
ssize_t (*sendmsg)(socket_t *, struct msghdr *, const endpoint_t *); ssize_t (*sendmsg)(socket_t *, struct msghdr *, const endpoint_t *);
ssize_t (*sendto)(socket_t *, const void *, size_t, const endpoint_t *); ssize_t (*sendto)(socket_t *, const void *, size_t, const endpoint_t *);
int (*tos)(socket_t *, unsigned int); int (*tos)(socket_t *, unsigned int);
int (*error)(socket_t *);
void (*endpoint2kernel)(struct re_address *, const endpoint_t *); void (*endpoint2kernel)(struct re_address *, const endpoint_t *);
void (*kernel2endpoint)(endpoint_t *, const struct re_address *); void (*kernel2endpoint)(endpoint_t *, const struct re_address *);
}; };
@ -144,8 +147,11 @@ INLINE int is_addr_unspecified(const sockaddr_t *a) {
return !a->family->is_specified(a); return !a->family->is_specified(a);
} }
#define socket_recvfrom(s,a...) (s)->family->recvfrom((s), a) #define socket_recvfrom(s,a...) (s)->family->recvfrom((s), a)
#define socket_recvfrom_ts(s,a...) (s)->family->recvfrom_ts((s), a)
#define socket_sendmsg(s,a...) (s)->family->sendmsg((s), a) #define socket_sendmsg(s,a...) (s)->family->sendmsg((s), a)
#define socket_sendto(s,a...) (s)->family->sendto((s), a) #define socket_sendto(s,a...) (s)->family->sendto((s), a)
#define socket_error(s) (s)->family->error((s))
#define socket_timestamping(s) (s)->family->timestamping((s))
INLINE ssize_t socket_sendiov(socket_t *s, const struct iovec *v, unsigned int len, const endpoint_t *dst) { INLINE ssize_t socket_sendiov(socket_t *s, const struct iovec *v, unsigned int len, const endpoint_t *dst) {
struct msghdr mh; struct msghdr mh;
ZERO(mh); ZERO(mh);
@ -174,7 +180,8 @@ void socket_init(void);
int open_socket(socket_t *r, int type, unsigned int port, const sockaddr_t *); int open_socket(socket_t *r, int type, unsigned int port, const sockaddr_t *);
int connect_socket(socket_t *r, int type, const endpoint_t *ep); int connect_socket(socket_t *r, int type, const endpoint_t *ep);
int connect_socket_nb(socket_t *r, int type, const endpoint_t *ep);
int connect_socket_nb(socket_t *r, int type, const endpoint_t *ep); // 1 == in progress
int connect_socket_retry(socket_t *r); // retries connect() while in progress
int close_socket(socket_t *r); int close_socket(socket_t *r);
sockfamily_t *get_socket_family_rfc(const str *s); sockfamily_t *get_socket_family_rfc(const str *s);
@ -182,7 +189,7 @@ sockfamily_t *__get_socket_family_enum(enum socket_families);
int sockaddr_parse_any(sockaddr_t *dst, const char *src); int sockaddr_parse_any(sockaddr_t *dst, const char *src);
int sockaddr_parse_any_str(sockaddr_t *dst, const str *src); int sockaddr_parse_any_str(sockaddr_t *dst, const str *src);
int sockaddr_parse_str(sockaddr_t *dst, sockfamily_t *fam, const str *src); int sockaddr_parse_str(sockaddr_t *dst, sockfamily_t *fam, const str *src);
int endpoint_parse_any(endpoint_t *, const char *);
int endpoint_parse_any(endpoint_t *, const char *); // address optional
void kernel2endpoint(endpoint_t *ep, const struct re_address *ra); void kernel2endpoint(endpoint_t *ep, const struct re_address *ra);
unsigned int sockaddr_hash(const sockaddr_t *); unsigned int sockaddr_hash(const sockaddr_t *);
@ -206,6 +213,16 @@ INLINE int endpoint_parse_port_any(endpoint_t *e, const char *p, unsigned int po
e->port = port; e->port = port;
return sockaddr_parse_any(&e->address, p); return sockaddr_parse_any(&e->address, p);
} }
// address required
INLINE int endpoint_parse_any_full(endpoint_t *d, const char *s) {
int ret;
ret = endpoint_parse_any(d, s);
if (ret)
return ret;
if (is_addr_unspecified(&d->address))
return -1;
return 0;
}
INLINE int ipv46_any_convert(endpoint_t *ep) { INLINE int ipv46_any_convert(endpoint_t *ep) {
if (ep->address.family->af != AF_INET) if (ep->address.family->af != AF_INET)
return 0; return 0;


+ 1
- 0
daemon/str.h View File

@ -23,6 +23,7 @@ typedef struct _str str;
#define STR_FORMAT "%.*s" #define STR_FORMAT "%.*s"
#define STR_FMT(str) (str)->len, (str)->s #define STR_FMT(str) (str)->len, (str)->s
#define STR_FMT0(str) ((str) ? (str)->len : 6), ((str) ? (str)->s : "(NULL)") #define STR_FMT0(str) ((str) ? (str)->len : 6), ((str) ? (str)->s : "(NULL)")
#define G_STR_FMT(gstr) (int) (gstr)->len, (gstr)->str // for glib GString
#define STR_NULL ((str) { NULL, 0 }) #define STR_NULL ((str) { NULL, 0 })
#define STR_EMPTY ((str) { "", 0 }) #define STR_EMPTY ((str) { "", 0 })
#define STR_CONST_INIT(str) { str, sizeof(str)-1 } #define STR_CONST_INIT(str) { str, sizeof(str)-1 }


+ 77
- 0
debian/changelog View File

@ -1,3 +1,80 @@
ngcp-rtpengine (4.4.0.0+0~mr4.4.0.0) unstable; urgency=medium
[ Lucian Balaceanu ]
* [937bb71] Adding images to illustrate redis database layout
* [7ae955c] Fixing reversed parameters when calculating redis restore time
[ Guillem Jover ]
* [df2126f] MT#16473 Convert debian/copyright to machine-readable format
[ Pawel Kuzak ]
* [ca04c96] Make creation of iptables chain optional
* [3f4cfff] Fixed inconsistency in rtpengine-ctl list totals
[ Joseph Frazier ]
* [8fbb0d3] Add hiredis-devel to daemon deps in README.el.md
* [2877f76] Add hiredis-devel to daemon BuildRequires
[ Richard Fuchs ]
* [7635f51] add hiredis dependency to README
* [6f2dc00] allow srtp-debug-helper to specify the ROC
* [b85a9e3] fix two memory leaks
* [5926048] don't just ignore but also strip invalid/unknown a=crypto
* [c9d797a] retain outgoing DTLS role whenever possible
* [d81c8df] move struct sdp_ng_flags from sdp.h to call_interfaces.h
* [b0a3898] fix sfd assignments when remote port changes
* [5dbadc4] implement port latching option
* [38d031c] fix support for AF switching on the fly
* [43bcabf] fix logic for unspecified ipv6 addresses
* [ff26e00] add STUN SOFTWARE attribute into ICE checks and responses
* [59cfb4f] fix incorrect padding in stun software attr
* [5b33498] fix RTCP content output
* [77d074c] fix length of software STUN attribute
* [b828122] move advertised_address out of intf_spec into local_intf
* [1c56865] fix iovec overflows
* [27d18e2] fix stun xor port response
* [725638b] remove redis-role redundancy
* [d8e1e9f] simplify redis CLI options
* [3f1ae98] unify -r/-R and -w/-W options into single options
* [c1407d6] support Redis server authentication
* [f52884e] report errors returned from redis
* [c4f630c] fix kernel module build for 4.4+ kernels
* [926d9d3] MT#17699 augment module makefile version detection
[ smititelu ]
* [6378a1e] Graphite change global to local parameters
* [0395a24] Change the graphite connection state logic
* [e48252e] Change abort() behaviour of redis_check_conn()
* [7d03f3d] Improve Redis connection logging
* [50aef80] Rtpengine starts even if redis is down
* [33e72ba] Skip redundant log if r->ctx->err != NULL
* [0447177] Add NO_REDIS_REQUIRED new parameter
* [74ad505] Update README.md for NO_REDIS_REQUIRED parameter
* [65de793] Add config REDIS_NUM_THREADS param
* [eee5a65] Update doku for REDIS_NUM_THREADS
* [a6b4b86] Fix segfault when ps->component=0
* [bac271b] Add callmaster config lock
[ Frederic-Philippe Metz ]
* [e376335] Removed graphite hostname and 'totals' in graphite names
[ Michael Prokop ]
* [47a9564] MT#17699 Bump Standards-Version to 3.9.7
* [b4a6653] MT#17699 Fix m-a build error + Bump Standards-Version for ngcp-rtpengine-kernel
[ Stefan Mititelu ]
* [5e7640b] Add/Retrieve ps->component to/from redis
* [9be68a0] Add FINAL_TIMEOUT parameter
* [ef39aa3] Add rtpengine-ctl list/set timeout
* [4343ff0] Update rtpengine-cli set maxopenfiles
* [05302c2] Update rtpengine-cli set maxsessions
* [57aa566] Add offer/answer/delete processing statistics
* [a43996f] Add 'unidirectional' attribute
[ Sipwise Jenkins Builder ]
-- Sipwise Jenkins Builder <jenkins@sipwise.com> Mon, 21 Mar 2016 22:31:18 +0100
ngcp-rtpengine (4.3.0.0+0~mr4.3.0.0) unstable; urgency=medium ngcp-rtpengine (4.3.0.0+0~mr4.3.0.0) unstable; urgency=medium
[ Frederic-Philippe Metz ] [ Frederic-Philippe Metz ]


+ 3
- 0
debian/ngcp-rtpengine-daemon.default View File

@ -36,3 +36,6 @@ TABLE=0
# GRAPHITE_PREFIX=myownprefix. # GRAPHITE_PREFIX=myownprefix.
# MAX_SESSIONS=5000 # MAX_SESSIONS=5000
# CREATE_IPTABLES_CHAIN=no # CREATE_IPTABLES_CHAIN=no
# HOMER=123.234.345.456:65432
# HOMER_PROTOCOL=udp
# HOMER_ID=2001

+ 3
- 0
debian/ngcp-rtpengine-daemon.init View File

@ -89,6 +89,9 @@ OPTIONS="$OPTIONS --table=$TABLE"
[ -z "$GRAPHITE_INTERVAL" ] || OPTIONS="$OPTIONS --graphite-interval=$GRAPHITE_INTERVAL" [ -z "$GRAPHITE_INTERVAL" ] || OPTIONS="$OPTIONS --graphite-interval=$GRAPHITE_INTERVAL"
[ -z "$GRAPHITE_PREFIX" ] || OPTIONS="$OPTIONS --graphite-prefix=$GRAPHITE_PREFIX" [ -z "$GRAPHITE_PREFIX" ] || OPTIONS="$OPTIONS --graphite-prefix=$GRAPHITE_PREFIX"
[ -z "$MAX_SESSIONS" ] || OPTIONS="$OPTIONS --max-sessions=$MAX_SESSIONS" [ -z "$MAX_SESSIONS" ] || OPTIONS="$OPTIONS --max-sessions=$MAX_SESSIONS"
[ -z "$HOMER" ] || OPTIONS="$OPTIONS --homer=$HOMER"
[ -z "$HOMER_PROTOCOL" ] || OPTIONS="$OPTIONS --homer-protocol=$HOMER_PROTOCOL"
[ -z "$HOMER_ID" ] || OPTIONS="$OPTIONS --homer-id=$HOMER_ID"
if test "$FORK" = "no" ; then if test "$FORK" = "no" ; then
OPTIONS="$OPTIONS --foreground" OPTIONS="$OPTIONS --foreground"


+ 21
- 2
tests/simulator-ng.pl View File

@ -226,8 +226,27 @@ sub rtcp_sr {
my $secs = $now[0] + 2208988800; my $secs = $now[0] + 2208988800;
my $frac = $now[1] / 1000000 * 2**32; my $frac = $now[1] / 1000000 * 2**32;
my $sr = pack('CCnN NNN NN', (2 << 6) | 1, 200, 12, rand(2**32), $secs, $frac, my $sr = pack('CCnN NNN NN', (2 << 6) | 1, 200, 12, rand(2**32), $secs, $frac,
12345, 0, 0);
$sr .= pack('N CCCC NNNN', 0, 0, 0, 0, 0, 0, 0, 0, 0);
12345, rand(12345), rand(4321));
$sr .= pack('N CCCC NNNN', rand(2**32), rand(256), rand(256), rand(256), rand(256),
rand(2**32), rand(2**32), rand(2**32), rand(2**32));
# sdes
$sr .= pack('CCn N CC a* CC a* CC a* C C N CC a* CC a* C CCC N CC a* C',
(2 << 6) | 3, 202, 16,
rand(2 ** 32), # csrc
1, 7, 'blah123', # cname
2, 6, 'foobar', # name
3, 7, 'foo@bar', # email,
0, # eol
0, # padding
rand(2 ** 32), # csrc
4, 5, '54321', # phone
5, 3, 'foo', # loc
0, # eol
0,0,0, # padding
rand(2 ** 32), # csrc
6, 5, 'fubar', # tool
0, # eol
);
return $sr; return $sr;
} }


Loading…
Cancel
Save