2017-11-12 16:21:03 +00:00
|
|
|
/* (C) 2012,2017 by Pablo Neira Ayuso <pablo@gnumonks.org>
|
|
|
|
* All Rights Reserved.
|
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: GPL-2.0+
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*
|
|
|
|
*/
|
2012-01-24 13:32:37 +00:00
|
|
|
#include <stdint.h>
|
|
|
|
#include <sys/time.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <string.h> /* for memcpy. */
|
|
|
|
#include <arpa/inet.h> /* for ntohs. */
|
2017-07-13 19:29:30 +00:00
|
|
|
#include <inttypes.h>
|
2012-01-24 13:32:37 +00:00
|
|
|
|
|
|
|
#include <osmocom/core/talloc.h>
|
|
|
|
#include <osmocom/core/msgb.h>
|
|
|
|
#include <osmocom/core/logging.h>
|
|
|
|
|
|
|
|
#include <osmocom/netif/rtp.h>
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Internal definitions for this implementation.
|
|
|
|
*/
|
|
|
|
|
|
|
|
struct osmo_rtp_handle {
|
|
|
|
struct {
|
|
|
|
uint16_t sequence;
|
|
|
|
uint32_t timestamp;
|
|
|
|
uint32_t ssrc;
|
|
|
|
struct timeval last_tv;
|
|
|
|
} tx;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct osmo_rtp_handle *osmo_rtp_handle_create(void *ctx)
|
|
|
|
{
|
|
|
|
struct osmo_rtp_handle *h;
|
|
|
|
|
|
|
|
h = talloc_zero(ctx, struct osmo_rtp_handle);
|
|
|
|
if (h == NULL) {
|
|
|
|
LOGP(DLMUX, LOGL_ERROR, "OOM\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return h;
|
|
|
|
}
|
|
|
|
|
|
|
|
void osmo_rtp_handle_free(struct osmo_rtp_handle *h)
|
|
|
|
{
|
|
|
|
DEBUGP(DLMUX, "%s (h=%p)\n", __FUNCTION__, h);
|
|
|
|
|
|
|
|
talloc_free(h);
|
|
|
|
}
|
|
|
|
|
|
|
|
int osmo_rtp_handle_tx_set_sequence(struct osmo_rtp_handle *h, uint16_t seq)
|
|
|
|
{
|
2017-07-13 19:29:30 +00:00
|
|
|
DEBUGP(DLMUX, "%s (handle=%p, seq=%"PRIu16")\n", __FUNCTION__, h, seq);
|
2012-01-24 13:32:37 +00:00
|
|
|
|
|
|
|
h->tx.sequence = seq;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int osmo_rtp_handle_tx_set_ssrc(struct osmo_rtp_handle *h, uint32_t ssrc)
|
|
|
|
{
|
2017-07-13 19:29:30 +00:00
|
|
|
DEBUGP(DLMUX, "%s (handle=%p, seq=%"PRIu32")\n", __FUNCTION__, h, ssrc);
|
2012-01-24 13:32:37 +00:00
|
|
|
|
|
|
|
h->tx.ssrc = ssrc;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int osmo_rtp_handle_tx_set_timestamp(struct osmo_rtp_handle *h, uint32_t timestamp)
|
|
|
|
{
|
2017-07-13 19:29:30 +00:00
|
|
|
DEBUGP(DLMUX, "%s (handle=%p, ts=%"PRIu32")\n", __FUNCTION__, h, timestamp);
|
2012-01-24 13:32:37 +00:00
|
|
|
|
|
|
|
h->tx.timestamp = timestamp;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-07-07 15:37:26 +00:00
|
|
|
struct rtp_hdr *osmo_rtp_get_hdr(struct msgb *msg)
|
2012-01-24 13:32:37 +00:00
|
|
|
{
|
2022-06-29 16:11:19 +00:00
|
|
|
struct rtp_hdr *rtph;
|
2012-01-24 13:32:37 +00:00
|
|
|
|
|
|
|
if (msg->len < sizeof(struct rtp_hdr)) {
|
|
|
|
DEBUGPC(DLMUX, "received RTP frame too short (len = %d)\n",
|
|
|
|
msg->len);
|
2012-07-07 15:37:26 +00:00
|
|
|
return NULL;
|
2012-01-24 13:32:37 +00:00
|
|
|
}
|
2022-06-29 16:11:19 +00:00
|
|
|
rtph = (struct rtp_hdr *)msg->data;
|
2012-01-24 13:32:37 +00:00
|
|
|
if (rtph->version != RTP_VERSION) {
|
|
|
|
DEBUGPC(DLMUX, "received RTP version %d not supported.\n",
|
|
|
|
rtph->version);
|
2012-07-07 15:37:26 +00:00
|
|
|
return NULL;
|
2012-01-24 13:32:37 +00:00
|
|
|
}
|
2012-07-07 15:37:26 +00:00
|
|
|
|
|
|
|
return rtph;
|
|
|
|
}
|
|
|
|
|
2012-07-09 17:41:01 +00:00
|
|
|
void *osmo_rtp_get_payload(struct rtp_hdr *rtph, struct msgb *msg,
|
|
|
|
uint32_t *plen)
|
2012-07-07 15:37:26 +00:00
|
|
|
{
|
|
|
|
struct rtp_x_hdr *rtpxh;
|
|
|
|
uint8_t *payload;
|
|
|
|
int payload_len;
|
|
|
|
int x_len;
|
|
|
|
int csrc_len;
|
|
|
|
|
2012-01-24 13:32:37 +00:00
|
|
|
csrc_len = rtph->csrc_count << 2;
|
|
|
|
payload = msg->data + sizeof(struct rtp_hdr) + csrc_len;
|
|
|
|
payload_len = msg->len - sizeof(struct rtp_hdr) - csrc_len;
|
|
|
|
if (payload_len < 0) {
|
|
|
|
DEBUGPC(DLMUX, "received RTP frame too short (len = %d, "
|
|
|
|
"csrc count = %d)\n", msg->len, rtph->csrc_count);
|
2012-07-07 15:37:26 +00:00
|
|
|
return NULL;
|
2012-01-24 13:32:37 +00:00
|
|
|
}
|
|
|
|
if (rtph->extension) {
|
|
|
|
if (payload_len < sizeof(struct rtp_x_hdr)) {
|
|
|
|
DEBUGPC(DLMUX, "received RTP frame too short for "
|
|
|
|
"extension header\n");
|
2012-07-07 15:37:26 +00:00
|
|
|
return NULL;
|
2012-01-24 13:32:37 +00:00
|
|
|
}
|
|
|
|
rtpxh = (struct rtp_x_hdr *)payload;
|
|
|
|
x_len = ntohs(rtpxh->length) * 4 + sizeof(struct rtp_x_hdr);
|
|
|
|
payload += x_len;
|
|
|
|
payload_len -= x_len;
|
|
|
|
if (payload_len < 0) {
|
|
|
|
DEBUGPC(DLMUX, "received RTP frame too short, "
|
|
|
|
"extension header exceeds frame length\n");
|
2012-07-07 15:37:26 +00:00
|
|
|
return NULL;
|
2012-01-24 13:32:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (rtph->padding) {
|
|
|
|
if (payload_len < 0) {
|
|
|
|
DEBUGPC(DLMUX, "received RTP frame too short for "
|
|
|
|
"padding length\n");
|
2012-07-07 15:37:26 +00:00
|
|
|
return NULL;
|
2012-01-24 13:32:37 +00:00
|
|
|
}
|
|
|
|
payload_len -= payload[payload_len - 1];
|
|
|
|
if (payload_len < 0) {
|
|
|
|
DEBUGPC(DLMUX, "received RTP frame with padding "
|
|
|
|
"greater than payload\n");
|
2012-07-07 15:37:26 +00:00
|
|
|
return NULL;
|
2012-01-24 13:32:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-09 17:41:01 +00:00
|
|
|
*plen = payload_len;
|
2012-07-07 15:37:26 +00:00
|
|
|
return (uint8_t *)msg->data + msg->len - payload_len;
|
2012-01-24 13:32:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
struct msgb *
|
|
|
|
osmo_rtp_build(struct osmo_rtp_handle *h, uint8_t payload_type,
|
|
|
|
uint32_t payload_len, const void *data, uint32_t duration)
|
|
|
|
{
|
|
|
|
struct msgb *msg;
|
|
|
|
struct rtp_hdr *rtph;
|
2013-05-22 10:18:45 +00:00
|
|
|
struct timeval tv, tv_diff;
|
2012-01-24 13:32:37 +00:00
|
|
|
long int usec_diff, frame_diff;
|
|
|
|
|
|
|
|
gettimeofday(&tv, NULL);
|
2013-05-22 10:18:45 +00:00
|
|
|
timersub(&tv, &h->tx.last_tv, &tv_diff);
|
2012-01-24 13:32:37 +00:00
|
|
|
h->tx.last_tv = tv;
|
|
|
|
|
|
|
|
usec_diff = tv_diff.tv_sec * 1000000 + tv_diff.tv_usec;
|
|
|
|
frame_diff = (usec_diff / 20000);
|
|
|
|
|
|
|
|
if (abs(frame_diff) > 1) {
|
|
|
|
long int frame_diff_excess = frame_diff - 1;
|
|
|
|
|
|
|
|
LOGP(DLMUX, LOGL_NOTICE,
|
|
|
|
"Correcting frame difference of %ld frames\n",
|
|
|
|
frame_diff_excess);
|
|
|
|
h->tx.sequence += frame_diff_excess;
|
|
|
|
h->tx.timestamp += frame_diff_excess * duration;
|
|
|
|
}
|
|
|
|
|
|
|
|
msg = msgb_alloc(sizeof(struct rtp_hdr) + payload_len, "RTP");
|
|
|
|
if (!msg) {
|
|
|
|
LOGP(DLMUX, LOGL_ERROR, "OOM\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
rtph = (struct rtp_hdr *)msg->data;
|
|
|
|
rtph->version = RTP_VERSION;
|
|
|
|
rtph->padding = 0;
|
|
|
|
rtph->extension = 0;
|
|
|
|
rtph->csrc_count = 0;
|
|
|
|
rtph->marker = 0;
|
|
|
|
rtph->payload_type = payload_type;
|
|
|
|
rtph->sequence = htons(h->tx.sequence++);
|
|
|
|
rtph->timestamp = htonl(h->tx.timestamp);
|
|
|
|
h->tx.timestamp += duration;
|
|
|
|
rtph->ssrc = htonl(h->tx.ssrc);
|
2022-08-11 18:31:18 +00:00
|
|
|
if (payload_len > 0)
|
|
|
|
memcpy(msg->data + sizeof(struct rtp_hdr), data, payload_len);
|
2012-01-24 13:32:37 +00:00
|
|
|
msgb_put(msg, sizeof(struct rtp_hdr) + payload_len);
|
|
|
|
|
|
|
|
return msg;
|
|
|
|
}
|
2012-08-06 15:35:26 +00:00
|
|
|
|
osmux: fix buffer management mess in snprintf() calls
SNPRINTF_BUFFER_SIZE() looks too complex, previous version maintains two
different variables to account for the remaining space in the buffer,
one of them is always decremented based on what snprintf() returns,
which may result in underflow. These variables are swapped - not used
consistently - all over this code.
Replace this macro by a simplified version, with one single parameter to
account for remaining space. This macro also deals with two corner
cases:
1) snprintf() fails, actually never happens in practise, but
documentation indicates it may return -1, so let's catch this case
from here to stick to specs.
2) There is not enough space in the buffer, in that case, keep
increasing offset, so we know how much would have been printed, just
like snprintf() does.
Thanks to Pau Espin for reporting, and Holger for clues on this.
I have run osmux_test and, at quick glance, it looks good.
Change-Id: I5b5d6ec57a02f57c23b1ae86dbd894bad28ea797
2017-09-04 18:35:36 +00:00
|
|
|
#define SNPRINTF_BUFFER_SIZE(ret, remain, offset) \
|
|
|
|
if (ret < 0) \
|
|
|
|
ret = 0; \
|
2012-08-06 15:35:26 +00:00
|
|
|
offset += ret; \
|
osmux: fix buffer management mess in snprintf() calls
SNPRINTF_BUFFER_SIZE() looks too complex, previous version maintains two
different variables to account for the remaining space in the buffer,
one of them is always decremented based on what snprintf() returns,
which may result in underflow. These variables are swapped - not used
consistently - all over this code.
Replace this macro by a simplified version, with one single parameter to
account for remaining space. This macro also deals with two corner
cases:
1) snprintf() fails, actually never happens in practise, but
documentation indicates it may return -1, so let's catch this case
from here to stick to specs.
2) There is not enough space in the buffer, in that case, keep
increasing offset, so we know how much would have been printed, just
like snprintf() does.
Thanks to Pau Espin for reporting, and Holger for clues on this.
I have run osmux_test and, at quick glance, it looks good.
Change-Id: I5b5d6ec57a02f57c23b1ae86dbd894bad28ea797
2017-09-04 18:35:36 +00:00
|
|
|
if (ret > remain) \
|
|
|
|
ret = remain; \
|
|
|
|
remain -= ret;
|
2012-08-06 15:35:26 +00:00
|
|
|
|
|
|
|
int osmo_rtp_snprintf(char *buf, size_t size, struct msgb *msg)
|
|
|
|
{
|
osmux: fix buffer management mess in snprintf() calls
SNPRINTF_BUFFER_SIZE() looks too complex, previous version maintains two
different variables to account for the remaining space in the buffer,
one of them is always decremented based on what snprintf() returns,
which may result in underflow. These variables are swapped - not used
consistently - all over this code.
Replace this macro by a simplified version, with one single parameter to
account for remaining space. This macro also deals with two corner
cases:
1) snprintf() fails, actually never happens in practise, but
documentation indicates it may return -1, so let's catch this case
from here to stick to specs.
2) There is not enough space in the buffer, in that case, keep
increasing offset, so we know how much would have been printed, just
like snprintf() does.
Thanks to Pau Espin for reporting, and Holger for clues on this.
I have run osmux_test and, at quick glance, it looks good.
Change-Id: I5b5d6ec57a02f57c23b1ae86dbd894bad28ea797
2017-09-04 18:35:36 +00:00
|
|
|
unsigned int remain = size, offset = 0;
|
2012-08-06 15:35:26 +00:00
|
|
|
struct rtp_hdr *rtph;
|
|
|
|
uint8_t *payload;
|
osmux: fix buffer management mess in snprintf() calls
SNPRINTF_BUFFER_SIZE() looks too complex, previous version maintains two
different variables to account for the remaining space in the buffer,
one of them is always decremented based on what snprintf() returns,
which may result in underflow. These variables are swapped - not used
consistently - all over this code.
Replace this macro by a simplified version, with one single parameter to
account for remaining space. This macro also deals with two corner
cases:
1) snprintf() fails, actually never happens in practise, but
documentation indicates it may return -1, so let's catch this case
from here to stick to specs.
2) There is not enough space in the buffer, in that case, keep
increasing offset, so we know how much would have been printed, just
like snprintf() does.
Thanks to Pau Espin for reporting, and Holger for clues on this.
I have run osmux_test and, at quick glance, it looks good.
Change-Id: I5b5d6ec57a02f57c23b1ae86dbd894bad28ea797
2017-09-04 18:35:36 +00:00
|
|
|
int ret, i;
|
2012-08-06 15:35:26 +00:00
|
|
|
|
2017-09-12 10:44:53 +00:00
|
|
|
if (size)
|
|
|
|
buf[0] = '\0';
|
|
|
|
|
2012-08-06 15:35:26 +00:00
|
|
|
rtph = osmo_rtp_get_hdr(msg);
|
|
|
|
if (rtph == NULL)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
payload = (uint8_t *)rtph + sizeof(struct rtp_hdr);
|
|
|
|
|
osmux: fix buffer management mess in snprintf() calls
SNPRINTF_BUFFER_SIZE() looks too complex, previous version maintains two
different variables to account for the remaining space in the buffer,
one of them is always decremented based on what snprintf() returns,
which may result in underflow. These variables are swapped - not used
consistently - all over this code.
Replace this macro by a simplified version, with one single parameter to
account for remaining space. This macro also deals with two corner
cases:
1) snprintf() fails, actually never happens in practise, but
documentation indicates it may return -1, so let's catch this case
from here to stick to specs.
2) There is not enough space in the buffer, in that case, keep
increasing offset, so we know how much would have been printed, just
like snprintf() does.
Thanks to Pau Espin for reporting, and Holger for clues on this.
I have run osmux_test and, at quick glance, it looks good.
Change-Id: I5b5d6ec57a02f57c23b1ae86dbd894bad28ea797
2017-09-04 18:35:36 +00:00
|
|
|
ret = snprintf(buf, remain, "RTP ver=%01u ssrc=%u type=%02u "
|
2012-08-06 15:35:26 +00:00
|
|
|
"marker=%01u ext=%01u csrc_count=%01u "
|
|
|
|
"sequence=%u timestamp=%u [", rtph->version,
|
|
|
|
ntohl(rtph->ssrc), rtph->payload_type,
|
|
|
|
rtph->marker, rtph->extension,
|
|
|
|
rtph->csrc_count, ntohs(rtph->sequence),
|
|
|
|
ntohl(rtph->timestamp));
|
osmux: fix buffer management mess in snprintf() calls
SNPRINTF_BUFFER_SIZE() looks too complex, previous version maintains two
different variables to account for the remaining space in the buffer,
one of them is always decremented based on what snprintf() returns,
which may result in underflow. These variables are swapped - not used
consistently - all over this code.
Replace this macro by a simplified version, with one single parameter to
account for remaining space. This macro also deals with two corner
cases:
1) snprintf() fails, actually never happens in practise, but
documentation indicates it may return -1, so let's catch this case
from here to stick to specs.
2) There is not enough space in the buffer, in that case, keep
increasing offset, so we know how much would have been printed, just
like snprintf() does.
Thanks to Pau Espin for reporting, and Holger for clues on this.
I have run osmux_test and, at quick glance, it looks good.
Change-Id: I5b5d6ec57a02f57c23b1ae86dbd894bad28ea797
2017-09-04 18:35:36 +00:00
|
|
|
SNPRINTF_BUFFER_SIZE(ret, remain, offset);
|
2012-08-06 15:35:26 +00:00
|
|
|
|
|
|
|
for (i=0; i<msg->len - sizeof(struct rtp_hdr); i++) {
|
osmux: fix buffer management mess in snprintf() calls
SNPRINTF_BUFFER_SIZE() looks too complex, previous version maintains two
different variables to account for the remaining space in the buffer,
one of them is always decremented based on what snprintf() returns,
which may result in underflow. These variables are swapped - not used
consistently - all over this code.
Replace this macro by a simplified version, with one single parameter to
account for remaining space. This macro also deals with two corner
cases:
1) snprintf() fails, actually never happens in practise, but
documentation indicates it may return -1, so let's catch this case
from here to stick to specs.
2) There is not enough space in the buffer, in that case, keep
increasing offset, so we know how much would have been printed, just
like snprintf() does.
Thanks to Pau Espin for reporting, and Holger for clues on this.
I have run osmux_test and, at quick glance, it looks good.
Change-Id: I5b5d6ec57a02f57c23b1ae86dbd894bad28ea797
2017-09-04 18:35:36 +00:00
|
|
|
ret = snprintf(buf + offset, remain, "%02x ", payload[i]);
|
|
|
|
SNPRINTF_BUFFER_SIZE(ret, remain, offset);
|
2012-08-06 15:35:26 +00:00
|
|
|
}
|
|
|
|
|
osmux: fix buffer management mess in snprintf() calls
SNPRINTF_BUFFER_SIZE() looks too complex, previous version maintains two
different variables to account for the remaining space in the buffer,
one of them is always decremented based on what snprintf() returns,
which may result in underflow. These variables are swapped - not used
consistently - all over this code.
Replace this macro by a simplified version, with one single parameter to
account for remaining space. This macro also deals with two corner
cases:
1) snprintf() fails, actually never happens in practise, but
documentation indicates it may return -1, so let's catch this case
from here to stick to specs.
2) There is not enough space in the buffer, in that case, keep
increasing offset, so we know how much would have been printed, just
like snprintf() does.
Thanks to Pau Espin for reporting, and Holger for clues on this.
I have run osmux_test and, at quick glance, it looks good.
Change-Id: I5b5d6ec57a02f57c23b1ae86dbd894bad28ea797
2017-09-04 18:35:36 +00:00
|
|
|
ret = snprintf(buf + offset, remain, "]");
|
|
|
|
SNPRINTF_BUFFER_SIZE(ret, remain, offset);
|
2012-08-06 15:35:26 +00:00
|
|
|
|
2017-09-04 19:00:15 +00:00
|
|
|
return offset;
|
2012-08-06 15:35:26 +00:00
|
|
|
}
|