0

I have trouble reading RTP packets from a multicast socket which is opened using the following function:

int
    open_multicast_socket
        (const char *group_address,
         uint16_t port)
{
    assert(group_address != NULL);

    int
        s;

    if (-1 != (s = socket(
        AF_INET, SOCK_DGRAM, 0
    )))
    {
        int
            reuse = 1;

        if (-1 != setsockopt(
            s, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof reuse
        ))
        {
            struct sockaddr_in
                sock_addr;

            bzero(&sock_addr, sizeof sock_addr);

            if (1 == inet_pton(
                AF_INET, group_address, &sock_addr.sin_addr
            ))
            {
                sock_addr.sin_family      = AF_INET;
                sock_addr.sin_port        = htons(port);

                if (0 == bind(
                    s, (struct sockaddr*)&sock_addr, sizeof sock_addr
                ))
                {
                    struct ip_mreq
                        mreq = {
                            .imr_multiaddr.s_addr = inet_addr(group_address),
                            .imr_interface.s_addr = htonl(INADDR_ANY)
                        };

                    if (0 == setsockopt(
                        s, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof mreq
                    ))
                    {
                        //fcntl(s, F_SETFL, O_NONBLOCK);
                        return s;
                    } // setsockopt
                    else
                    {
                        perror("setsockopt");
                        close(s);
                    }
                } // bind
                else
                {
                    perror("bind");
                    close(s);
                }
            } // inet_pton
            else
            {
                perror("inet_pton");
                close(s);
            }
        } // setsockopt
        else
        {
            perror("setsockopt");
            close(s);
        }
    } // socket
    else
    {
        perror("socket");
    }

    return -1;
}

If I read RTP header plus payload in one read operation, I get the entire packet. However, if I attempt to receive the RTP header first, then - a custom header in the payload - the 2nd read always gets a next RTP header instead, discarding all attached data. Because payload length may vary, the only way to receive a whole packet, it seems, is to guess its max possible size.

I tried to get a number of available bytes before reading:

ioctl(sock, FIONREAD, &nbytes);

but it always returns 0.

Polling on the socket always fails, as if no data is available at all.

When non-blocking is enabled (i.e. fcntl(sock, F_SETFL, O_NONBLOCK);) - read always fails (-1), so does recv(sock, buf, buf_len, MSG_DONTWAIT).

So is there a way to properly parse RTP packets via consequensive non-blocking read calls?

Non-blocking is essential, because it should be possible to check whether a connection was lost and re-open the socket if necessary.

AlexDarkVoid
  • 485
  • 3
  • 12

2 Answers2

1

Unlike TCP which is a stream based protocol, UDP is a packet based protocol. This means that whenever you read from a UDP socket (multicast or not) you'll get exactly one UDP datagram. If your buffer isn't big enough to hold the entire datagram, the remaining data is essentially lost.

Make sure your buffer is big enough to hold a complete datagram. If your network supports jumbo frames end-to-end that means your buffer should be 9000 bytes, otherwise it should be 1500 bytes.

dbush
  • 205,898
  • 23
  • 218
  • 273
0

One should read the complete buffer from the socket and then parse them.

One can create a buffer of MTU size, read from the socket to this temp buffer and then parser the complete buffer and then take action.

One can use select() or poll() to check if the data is present in the socket. Read it when it is available.

mail2subhajit
  • 1,106
  • 5
  • 16