diff --git a/src/libosmocc/rtp.c b/src/libosmocc/rtp.c index c798e56..31104b7 100644 --- a/src/libosmocc/rtp.c +++ b/src/libosmocc/rtp.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include "../libdebug/debug.h" #include "../libtimer/timer.h" @@ -53,7 +52,7 @@ struct rtp_x_hdr { uint16_t length; } __attribute__((packed)); -static int rtp_receive(int sock, uint8_t **payload_p, int *payload_len_p, uint8_t *marker_p, uint8_t *pt_p, uint16_t *sequence_p, uint32_t *timestamp_p, uint32_t *ssrc_p) +static int rtp_receive(struct sockaddr_storage *sa, socklen_t *slen, int sock, uint8_t **payload_p, int *payload_len_p, uint8_t *marker_p, uint8_t *pt_p, uint16_t *sequence_p, uint32_t *timestamp_p, uint32_t *ssrc_p) { static uint8_t data[2048]; int len; @@ -64,7 +63,7 @@ static int rtp_receive(int sock, uint8_t **payload_p, int *payload_len_p, uint8_ int payload_len; int x_len; - len = read(sock, data, sizeof(data)); + len = recvfrom(sock, data, sizeof(data), 0, (struct sockaddr *)sa, slen); if (len < 0) { if (errno == EAGAIN) return -EAGAIN; @@ -133,12 +132,12 @@ static int rtp_receive(int sock, uint8_t **payload_p, int *payload_len_p, uint8_ return 0; } -static int rtcp_receive(int sock) +static int rtcp_receive(struct sockaddr_storage *sa, socklen_t *slen, int sock) { static uint8_t data[2048]; int len; - len = read(sock, data, sizeof(data)); + len = recvfrom(sock, data, sizeof(data), 0, (struct sockaddr *)sa, slen); if (len < 0) { if (errno == EAGAIN) return -EAGAIN; @@ -149,7 +148,7 @@ static int rtcp_receive(int sock) return 0; } -static void rtp_send(int sock, uint8_t *payload, int payload_len, uint8_t marker, uint8_t pt, uint16_t sequence, uint32_t timestamp, uint32_t ssrc) +static void rtp_send(struct sockaddr_storage *sa, socklen_t slen, int sock, uint8_t *payload, int payload_len, uint8_t marker, uint8_t pt, uint16_t sequence, uint32_t timestamp, uint32_t ssrc) { struct rtp_hdr *rtph; char data[sizeof(*rtph) + payload_len]; @@ -169,9 +168,9 @@ static void rtp_send(int sock, uint8_t *payload, int payload_len, uint8_t marker } memcpy(data + sizeof(*rtph), payload, payload_len); - rc = write(sock, data, len); + rc = sendto(sock, data, len, 0, (struct sockaddr *)sa, slen); if (rc < 0) - LOGP(DCC, LOGL_DEBUG, "Write errno = %d (%s)\n", errno, strerror(errno)); + LOGP(DCC, LOGL_DEBUG, "sendto errno = %d (%s)\n", errno, strerror(errno)); } static int rtp_listen_cb(struct osmo_fd *ofd, unsigned int when); @@ -186,7 +185,7 @@ int osmo_cc_rtp_open(osmo_cc_session_media_t *media) int domain = 0; // make GCC happy uint16_t start_port; struct sockaddr_storage sa; - int slen = 0; // make GCC happy + socklen_t slen = 0; // make GCC happy struct sockaddr_in6 *sa6; struct sockaddr_in *sa4; uint16_t *sport; @@ -294,19 +293,16 @@ bind_error: */ int osmo_cc_rtp_connect(osmo_cc_session_media_t *media) { - struct sockaddr_storage sa; - int slen = 0; // make GCC happy struct sockaddr_in6 *sa6; struct sockaddr_in *sa4; - uint16_t *sport; int rc; - LOGP(DCC, LOGL_DEBUG, "Connecting media port %d->%d\n", media->description.port_local, media->description.port_remote); + LOGP(DCC, LOGL_DEBUG, "Connecting media port %d->%d (remote %s)\n", media->description.port_local, media->description.port_remote, media->connection_data_remote.address); switch (media->connection_data_remote.addrtype) { case osmo_cc_session_addrtype_ipv4: - memset(&sa, 0, sizeof(sa)); - sa4 = (struct sockaddr_in *)&sa; + memset(&media->rtp_sa, 0, sizeof(media->rtp_sa)); + sa4 = (struct sockaddr_in *)&media->rtp_sa; sa4->sin_family = AF_INET; rc = inet_pton(AF_INET, media->connection_data_remote.address, &sa4->sin_addr); if (rc < 1) { @@ -314,36 +310,34 @@ pton_error: LOGP(DCC, LOGL_NOTICE, "Cannot connect to address '%s'.\n", media->connection_data_remote.address); return -EINVAL; } - sport = &sa4->sin_port; - slen = sizeof(*sa4); + media->rtp_sport = &sa4->sin_port; + media->rtp_slen = sizeof(*sa4); + memcpy(&media->rtcp_sa, &media->rtp_sa, sizeof(*sa4)); + sa4 = (struct sockaddr_in *)&media->rtcp_sa; + media->rtcp_sport = &sa4->sin_port; + media->rtcp_slen = sizeof(*sa4); break; case osmo_cc_session_addrtype_ipv6: - memset(&sa, 0, sizeof(sa)); - sa6 = (struct sockaddr_in6 *)&sa; + memset(&media->rtp_sa, 0, sizeof(media->rtp_sa)); + sa6 = (struct sockaddr_in6 *)&media->rtp_sa; sa6->sin6_family = AF_INET6; rc = inet_pton(AF_INET6, media->connection_data_remote.address, &sa6->sin6_addr); if (rc < 1) goto pton_error; - sport = &sa6->sin6_port; - slen = sizeof(*sa6); + media->rtp_sport = &sa6->sin6_port; + media->rtp_slen = sizeof(*sa6); + memcpy(&media->rtcp_sa, &media->rtp_sa, sizeof(*sa6)); + sa6 = (struct sockaddr_in6 *)&media->rtcp_sa; + media->rtcp_sport = &sa6->sin6_port; + media->rtcp_slen = sizeof(*sa6); break; case osmo_cc_session_addrtype_unknown: LOGP(DCC, LOGL_NOTICE, "Unsupported address type '%s'.\n", media->connection_data_local.addrtype_name); return -EINVAL; } - *sport = htons(media->description.port_remote); - rc = connect(media->rtp_ofd.fd, (struct sockaddr *)&sa, slen); - if (rc < 0) { -connect_error: - LOGP(DCC, LOGL_NOTICE, "Cannot connect to address '%s'.\n", media->connection_data_remote.address); - osmo_cc_rtp_close(media); - return -EIO; - } - *sport = htons(media->description.port_remote + 1); - rc = connect(media->rtcp_ofd.fd, (struct sockaddr *)&sa, slen); - if (rc < 0) - goto connect_error; + *media->rtp_sport = htons(media->description.port_remote); + *media->rtcp_sport = htons(media->description.port_remote + 1); return 0; } @@ -364,7 +358,7 @@ void osmo_cc_rtp_send(osmo_cc_session_codec_t *codec, uint8_t *data, int len, ui payload_len = len; } - rtp_send(codec->media->rtp_ofd.fd, payload, payload_len, marker, codec->payload_type_remote, codec->media->tx_sequence, codec->media->tx_timestamp, codec->media->tx_ssrc); + rtp_send(&codec->media->rtp_sa, codec->media->rtp_slen, codec->media->rtp_ofd.fd, payload, payload_len, marker, codec->payload_type_remote, codec->media->tx_sequence, codec->media->tx_timestamp, codec->media->tx_ssrc); codec->media->tx_sequence += inc_sequence; codec->media->tx_timestamp += inc_timestamp; @@ -372,6 +366,44 @@ void osmo_cc_rtp_send(osmo_cc_session_codec_t *codec, uint8_t *data, int len, ui free(payload); } +static void check_port_translation(struct sockaddr_storage *sa, struct sockaddr_storage *media_sa, const char *what) +{ + struct sockaddr_in6 *sa6, *sa6_2; + struct sockaddr_in *sa4, *sa4_2; + int from = 0, to = 0; + + if (sa->ss_family != media_sa->ss_family) + return; + + switch (sa->ss_family) { + case AF_INET: + sa4 = (struct sockaddr_in *)sa; + sa4_2 = (struct sockaddr_in *)media_sa; + if (sa4->sin_port != sa4_2->sin_port) { + if (!!memcmp(&sa4->sin_addr, &sa4_2->sin_addr, sizeof(struct in_addr))) + break; + from = ntohs(sa4_2->sin_port); + to = ntohs(sa4->sin_port); + sa4_2->sin_port = sa4->sin_port; + } + break; + case AF_INET6: + sa6 = (struct sockaddr_in6 *)sa; + sa6_2 = (struct sockaddr_in6 *)media_sa; + if (sa6->sin6_port != sa6_2->sin6_port) { + if (!!memcmp(&sa6->sin6_addr, &sa6_2->sin6_addr, sizeof(struct in6_addr))) + break; + from = ntohs(sa6_2->sin6_port); + to = ntohs(sa6->sin6_port); + sa6_2->sin6_port = sa6->sin6_port; + } + break; + } + + if (from) + LOGP(DCC, LOGL_NOTICE, "Remote sends with different %s port, changing from %d to %d!\n", what, from, to); +} + static int rtp_listen_cb(struct osmo_fd *ofd, unsigned int when) { osmo_cc_session_media_t *media = ofd->data; @@ -383,11 +415,14 @@ static int rtp_listen_cb(struct osmo_fd *ofd, unsigned int when) osmo_cc_session_codec_t *codec; uint8_t *data; int len; + struct sockaddr_storage sa; + socklen_t slen = sizeof(sa); // must be initialized and will be overwritten if (when & OSMO_FD_READ) { - rc = rtp_receive(media->rtp_ofd.fd, &payload, &payload_len, &marker, &payload_type, &media->rx_sequence, &media->rx_timestamp, &media->rx_ssrc); + rc = rtp_receive(&sa, &slen, media->rtp_ofd.fd, &payload, &payload_len, &marker, &payload_type, &media->rx_sequence, &media->rx_timestamp, &media->rx_ssrc); if (rc < 0) return rc; + check_port_translation(&sa, &media->rtp_sa, "RTP"); /* search for codec */ for (codec = media->codec_list; codec; codec = codec->next) { @@ -420,11 +455,14 @@ static int rtcp_listen_cb(struct osmo_fd *ofd, unsigned int when) { osmo_cc_session_media_t *media = ofd->data; int rc; + struct sockaddr_storage sa; + socklen_t slen = sizeof(sa); // must be initialized and will be overwritten if (when & OSMO_FD_READ) { - rc = rtcp_receive(media->rtcp_ofd.fd); + rc = rtcp_receive(&sa, &slen, media->rtcp_ofd.fd); if (rc < 0) return rc; + check_port_translation(&sa, &media->rtcp_sa, "RTCP"); } return 0; diff --git a/src/libosmocc/session.h b/src/libosmocc/session.h index ddbed82..1317f4c 100644 --- a/src/libosmocc/session.h +++ b/src/libosmocc/session.h @@ -1,3 +1,5 @@ +#include + /* configuration */ enum osmo_cc_session_nettype { @@ -80,6 +82,9 @@ typedef struct osmo_cc_session_media { struct osmo_cc_session_codec *codec_list; int send, receive; void (*receiver)(struct osmo_cc_session_codec *codec, uint8_t marker, uint16_t sequence_number, uint32_t timestamp, uint32_t ssrc, uint8_t *data, int len); + struct sockaddr_storage rtp_sa, rtcp_sa; + socklen_t rtp_slen, rtcp_slen; + uint16_t *rtp_sport, *rtcp_sport; // pointers to the port inside sa sockaddr struct osmo_fd rtp_ofd; struct osmo_fd rtcp_ofd; uint32_t tx_ssrc, rx_ssrc;