Blame frontend/rtp.c

Packit 47f805
/*
Packit 47f805
 *      rtp socket communication functions
Packit 47f805
 *
Packit 47f805
 *      initially contributed by Felix von Leitner
Packit 47f805
 *
Packit 47f805
 *      Copyright (c) 2000 Mark Taylor
Packit 47f805
 *                    2010 Robert Hegemann
Packit 47f805
 *
Packit 47f805
 * This library is free software; you can redistribute it and/or
Packit 47f805
 * modify it under the terms of the GNU Library General Public
Packit 47f805
 * License as published by the Free Software Foundation; either
Packit 47f805
 * version 2 of the License, or (at your option) any later version.
Packit 47f805
 *
Packit 47f805
 * This library is distributed in the hope that it will be useful,
Packit 47f805
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 47f805
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 47f805
 * Library General Public License for more details.
Packit 47f805
 *
Packit 47f805
 * You should have received a copy of the GNU Library General Public
Packit 47f805
 * License along with this library; if not, write to the
Packit 47f805
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Packit 47f805
 * Boston, MA 02111-1307, USA.
Packit 47f805
 */
Packit 47f805
Packit 47f805
/* $Id: rtp.c,v 1.24 2011/05/07 16:05:17 rbrito Exp $ */
Packit 47f805
Packit 47f805
#ifdef HAVE_CONFIG_H
Packit 47f805
# include <config.h>
Packit 47f805
#endif
Packit 47f805
Packit 47f805
#ifdef HAVE_STDINT_H
Packit 47f805
# include <stdint.h>
Packit 47f805
#endif
Packit 47f805
Packit 47f805
struct rtpbits {
Packit 47f805
    int     sequence:16;     /* sequence number: random */
Packit 47f805
    int     pt:7;            /* payload type: 14 for MPEG audio */
Packit 47f805
    int     m:1;             /* marker: 0 */
Packit 47f805
    int     cc:4;            /* number of CSRC identifiers: 0 */
Packit 47f805
    int     x:1;             /* number of extension headers: 0 */
Packit 47f805
    int     p:1;             /* is there padding appended: 0 */
Packit 47f805
    int     v:2;             /* version: 2 */
Packit 47f805
};
Packit 47f805
Packit 47f805
struct rtpheader {           /* in network byte order */
Packit 47f805
    struct rtpbits b;
Packit 47f805
    int     timestamp;       /* start: random */
Packit 47f805
    int     ssrc;            /* random */
Packit 47f805
    int     iAudioHeader;    /* =0?! */
Packit 47f805
};
Packit 47f805
Packit 47f805
Packit 47f805
#if !defined( _WIN32 ) && !defined(__MINGW32__)
Packit 47f805
Packit 47f805
#ifdef STDC_HEADERS
Packit 47f805
# include <stdio.h>
Packit 47f805
# include <stdarg.h>
Packit 47f805
# include <stdlib.h>
Packit 47f805
# include <string.h>
Packit 47f805
#else
Packit 47f805
# ifndef HAVE_MEMCPY
Packit 47f805
#  define memcpy(d, s, n) bcopy ((s), (d), (n))
Packit 47f805
#  define memmove(d, s, n) bcopy ((s), (d), (n))
Packit 47f805
# endif
Packit 47f805
#endif
Packit 47f805
Packit 47f805
#ifdef HAVE_UNISTD_H
Packit 47f805
# include <unistd.h>
Packit 47f805
#endif
Packit 47f805
Packit 47f805
#include <sys/types.h>
Packit 47f805
#include <sys/socket.h>
Packit 47f805
#ifdef __int8_t_defined
Packit 47f805
#undef uint8_t
Packit 47f805
#undef uint16_t
Packit 47f805
#undef uint32_t
Packit 47f805
#undef uint64_t
Packit 47f805
#endif
Packit 47f805
#include <netinet/in.h>
Packit 47f805
#include <arpa/inet.h>
Packit 47f805
Packit 47f805
#ifdef WITH_DMALLOC
Packit 47f805
#include <dmalloc.h>
Packit 47f805
#endif
Packit 47f805
Packit 47f805
#include "rtp.h"
Packit 47f805
#include "console.h"
Packit 47f805
Packit 47f805
typedef int SOCKET;
Packit 47f805
Packit 47f805
struct rtpheader RTPheader;
Packit 47f805
SOCKET  rtpsocket;
Packit 47f805
Packit 47f805
Packit 47f805
/* create a sender socket. */
Packit 47f805
int
Packit 47f805
rtp_socket(char const *address, unsigned int port, unsigned int TTL)
Packit 47f805
{
Packit 47f805
    int     iRet, iLoop = 1;
Packit 47f805
    struct sockaddr_in sin;
Packit 47f805
    unsigned char cTtl = TTL;
Packit 47f805
    char    cLoop = 0;
Packit 47f805
    unsigned int tempaddr;
Packit 47f805
Packit 47f805
    int     iSocket = socket(AF_INET, SOCK_DGRAM, 0);
Packit 47f805
    if (iSocket < 0) {
Packit 47f805
        error_printf("socket() failed.\n");
Packit 47f805
        return 1;
Packit 47f805
    }
Packit 47f805
Packit 47f805
    memset(&sin, 0, sizeof(sin));
Packit 47f805
    tempaddr = inet_addr(address);
Packit 47f805
    sin.sin_family = AF_INET;
Packit 47f805
    sin.sin_port = htons(port);
Packit 47f805
    sin.sin_addr.s_addr = tempaddr;
Packit 47f805
Packit 47f805
    iRet = setsockopt(iSocket, SOL_SOCKET, SO_REUSEADDR, &iLoop, sizeof(int));
Packit 47f805
    if (iRet < 0) {
Packit 47f805
        error_printf("setsockopt SO_REUSEADDR failed\n");
Packit 47f805
        return 1;
Packit 47f805
    }
Packit 47f805
Packit 47f805
    if ((ntohl(tempaddr) >> 28) == 0xe) {
Packit 47f805
        /* only set multicast parameters for multicast destination IPs */
Packit 47f805
        iRet = setsockopt(iSocket, IPPROTO_IP, IP_MULTICAST_TTL, &cTtl, sizeof(char));
Packit 47f805
        if (iRet < 0) {
Packit 47f805
            error_printf("setsockopt IP_MULTICAST_TTL failed.  multicast in kernel?\n");
Packit 47f805
            return 1;
Packit 47f805
        }
Packit 47f805
Packit 47f805
        cLoop = 1;      /* !? */
Packit 47f805
        iRet = setsockopt(iSocket, IPPROTO_IP, IP_MULTICAST_LOOP, &cLoop, sizeof(char));
Packit 47f805
        if (iRet < 0) {
Packit 47f805
            error_printf("setsockopt IP_MULTICAST_LOOP failed.  multicast in kernel?\n");
Packit 47f805
            return 1;
Packit 47f805
        }
Packit 47f805
    }
Packit 47f805
    iRet = connect(iSocket, (struct sockaddr *) &sin, sizeof(struct sockaddr_in));
Packit 47f805
    if (iRet < 0) {
Packit 47f805
        error_printf("connect IP_MULTICAST_LOOP failed.  multicast in kernel?\n");
Packit 47f805
        return 1;
Packit 47f805
    }
Packit 47f805
Packit 47f805
    rtpsocket = iSocket;
Packit 47f805
Packit 47f805
    return 0;
Packit 47f805
}
Packit 47f805
Packit 47f805
Packit 47f805
static void
Packit 47f805
rtp_initialization_extra(void)
Packit 47f805
{
Packit 47f805
}
Packit 47f805
Packit 47f805
static void
Packit 47f805
rtp_close_extra(void)
Packit 47f805
{
Packit 47f805
}
Packit 47f805
Packit 47f805
#else
Packit 47f805
Packit 47f805
#include <Winsock2.h>
Packit 47f805
#ifndef IP_MULTICAST_TTL
Packit 47f805
#define IP_MULTICAST_TTL 3
Packit 47f805
#endif
Packit 47f805
#include <stdio.h>
Packit 47f805
#include <stdarg.h>
Packit 47f805
Packit 47f805
#include "rtp.h"
Packit 47f805
#include "console.h"
Packit 47f805
Packit 47f805
Packit 47f805
struct rtpheader RTPheader;
Packit 47f805
SOCKET  rtpsocket;
Packit 47f805
Packit 47f805
static char *
Packit 47f805
last_error_message(int err_code)
Packit 47f805
{
Packit 47f805
    char   *msg;
Packit 47f805
    void   *p_msg_buf;
Packit 47f805
    FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,
Packit 47f805
                   (void *) 0,
Packit 47f805
                   (DWORD) err_code,
Packit 47f805
                   MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR) & p_msg_buf, 0, NULL);
Packit 47f805
    msg = strdup(p_msg_buf);
Packit 47f805
    LocalFree(p_msg_buf);
Packit 47f805
    return msg;
Packit 47f805
}
Packit 47f805
Packit 47f805
static int
Packit 47f805
print_socket_error(int error)
Packit 47f805
{
Packit 47f805
    char   *err_txt = last_error_message(error);
Packit 47f805
    error_printf("error %d\n%s\n", error, err_txt);
Packit 47f805
    free(err_txt);
Packit 47f805
    return error;
Packit 47f805
}
Packit 47f805
Packit 47f805
static int
Packit 47f805
on_socket_error(SOCKET s)
Packit 47f805
{
Packit 47f805
    int     error = WSAGetLastError();
Packit 47f805
    print_socket_error(error);
Packit 47f805
    if (s != INVALID_SOCKET) {
Packit 47f805
        closesocket(s);
Packit 47f805
    }
Packit 47f805
    return error;
Packit 47f805
}
Packit 47f805
Packit 47f805
/* create a sender socket. */
Packit 47f805
int
Packit 47f805
rtp_socket(char const *address, unsigned int port, unsigned int TTL)
Packit 47f805
{
Packit 47f805
    char const True = 1;
Packit 47f805
    char const *c = "";
Packit 47f805
    int     error;
Packit 47f805
    UINT    ip;
Packit 47f805
    PHOSTENT host;
Packit 47f805
    SOCKET  s;
Packit 47f805
    SOCKADDR_IN source, dest;
Packit 47f805
Packit 47f805
    source.sin_family = AF_INET;
Packit 47f805
    source.sin_addr.s_addr = htonl(INADDR_ANY);
Packit 47f805
    source.sin_port = htons(0);
Packit 47f805
Packit 47f805
    dest.sin_family = AF_INET;
Packit 47f805
    dest.sin_addr.s_addr = inet_addr(address);
Packit 47f805
Packit 47f805
    if (!strcmp(address, "255.255.255.255")) {
Packit 47f805
    }
Packit 47f805
    else if (dest.sin_addr.s_addr == INADDR_NONE) {
Packit 47f805
        host = gethostbyname(address);
Packit 47f805
Packit 47f805
        if (host) {
Packit 47f805
            dest.sin_addr = *(PIN_ADDR) host->h_addr;
Packit 47f805
        }
Packit 47f805
        else {
Packit 47f805
            error_printf("Unknown host %s\r\n", address);
Packit 47f805
            return 1;
Packit 47f805
        }
Packit 47f805
    }
Packit 47f805
Packit 47f805
    dest.sin_port = htons((u_short) port);
Packit 47f805
Packit 47f805
    ip = ntohl(dest.sin_addr.s_addr);
Packit 47f805
Packit 47f805
    if (IN_CLASSA(ip))
Packit 47f805
        c = "class A";
Packit 47f805
    if (IN_CLASSB(ip))
Packit 47f805
        c = "class B";
Packit 47f805
    if (IN_CLASSC(ip))
Packit 47f805
        c = "class C";
Packit 47f805
    if (IN_CLASSD(ip))
Packit 47f805
        c = "class D";
Packit 47f805
    if (ip == INADDR_LOOPBACK)
Packit 47f805
        c = "loopback";
Packit 47f805
    if (ip == INADDR_BROADCAST)
Packit 47f805
        c = "broadcast";
Packit 47f805
Packit 47f805
    s = socket(AF_INET, SOCK_DGRAM, PF_UNSPEC);
Packit 47f805
    if (s == INVALID_SOCKET) {
Packit 47f805
        error_printf("socket () ");
Packit 47f805
        return on_socket_error(s);
Packit 47f805
    }
Packit 47f805
    error = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &True, sizeof(True));
Packit 47f805
    error = bind(s, (struct sockaddr *) &source, sizeof(source));
Packit 47f805
    if (error == SOCKET_ERROR) {
Packit 47f805
        error_printf("bind () ");
Packit 47f805
        return on_socket_error(s);
Packit 47f805
    }
Packit 47f805
    if (ip == INADDR_BROADCAST) {
Packit 47f805
        error_printf("broadcast %s:%u %s\r\n", inet_ntoa(dest.sin_addr), ntohs(dest.sin_port), c);
Packit 47f805
        error = setsockopt(s, SOL_SOCKET, SO_BROADCAST, &True, sizeof(True));
Packit 47f805
        if (error == SOCKET_ERROR) {
Packit 47f805
            error_printf("setsockopt (%u, SOL_SOCKET, SO_BROADCAST, ...) ", s);
Packit 47f805
            return on_socket_error(s);
Packit 47f805
        }
Packit 47f805
    }
Packit 47f805
    if (IN_CLASSD(ip)) {
Packit 47f805
        error_printf("multicast %s:%u %s\r\n", inet_ntoa(dest.sin_addr), ntohs(dest.sin_port), c);
Packit 47f805
        error = setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, (const char *) &TTL, sizeof(TTL));
Packit 47f805
        if (error == SOCKET_ERROR) {
Packit 47f805
            error_printf("setsockopt (%u, IPPROTO_IP, IP_MULTICAST_TTL, ...) ", s);
Packit 47f805
            return on_socket_error(s);
Packit 47f805
        }
Packit 47f805
    }
Packit 47f805
    error = connect(s, (PSOCKADDR) & dest, sizeof(SOCKADDR_IN));
Packit 47f805
    if (error == SOCKET_ERROR) {
Packit 47f805
        error_printf("connect: ");
Packit 47f805
        return on_socket_error(s);
Packit 47f805
    }
Packit 47f805
    rtpsocket = s;
Packit 47f805
    return 0;
Packit 47f805
}
Packit 47f805
Packit 47f805
static void
Packit 47f805
rtp_initialization_extra(void)
Packit 47f805
{
Packit 47f805
    WSADATA wsaData;
Packit 47f805
    int     rc = WSAStartup(MAKEWORD(2, 2), &wsaData);
Packit 47f805
    if (rc != 0) {
Packit 47f805
        print_socket_error(rc);
Packit 47f805
    }
Packit 47f805
}
Packit 47f805
Packit 47f805
static void
Packit 47f805
rtp_close_extra(void)
Packit 47f805
{
Packit 47f805
    WSACleanup();
Packit 47f805
}
Packit 47f805
Packit 47f805
#endif
Packit 47f805
Packit 47f805
Packit 47f805
static int
Packit 47f805
rtp_send(unsigned char const *data, int len)
Packit 47f805
{
Packit 47f805
    SOCKET  s = rtpsocket;
Packit 47f805
    struct rtpheader *foo = &RTPheader;
Packit 47f805
    char   *buffer = malloc(len + sizeof(struct rtpheader));
Packit 47f805
    int    *cast = (int *) foo;
Packit 47f805
    int    *outcast = (int *) buffer;
Packit 47f805
    int     count, size;
Packit 47f805
Packit 47f805
    outcast[0] = htonl(cast[0]);
Packit 47f805
    outcast[1] = htonl(cast[1]);
Packit 47f805
    outcast[2] = htonl(cast[2]);
Packit 47f805
    outcast[3] = htonl(cast[3]);
Packit 47f805
    memmove(buffer + sizeof(struct rtpheader), data, len);
Packit 47f805
    size = len + sizeof(*foo);
Packit 47f805
    count = send(s, buffer, size, 0);
Packit 47f805
    free(buffer);
Packit 47f805
Packit 47f805
    return count != size;
Packit 47f805
}
Packit 47f805
Packit 47f805
void
Packit 47f805
rtp_output(unsigned char const *mp3buffer, int mp3size)
Packit 47f805
{
Packit 47f805
    rtp_send(mp3buffer, mp3size);
Packit 47f805
    RTPheader.timestamp += 5;
Packit 47f805
    RTPheader.b.sequence++;
Packit 47f805
}
Packit 47f805
Packit 47f805
void
Packit 47f805
rtp_initialization(void)
Packit 47f805
{
Packit 47f805
    struct rtpheader *foo = &RTPheader;
Packit 47f805
    foo->b.v = 2;
Packit 47f805
    foo->b.p = 0;
Packit 47f805
    foo->b.x = 0;
Packit 47f805
    foo->b.cc = 0;
Packit 47f805
    foo->b.m = 0;
Packit 47f805
    foo->b.pt = 14;     /* MPEG Audio */
Packit 47f805
    foo->b.sequence = rand() & 65535;
Packit 47f805
    foo->timestamp = rand();
Packit 47f805
    foo->ssrc = rand();
Packit 47f805
    foo->iAudioHeader = 0;
Packit 47f805
    rtp_initialization_extra();
Packit 47f805
}
Packit 47f805
Packit 47f805
void
Packit 47f805
rtp_deinitialization(void)
Packit 47f805
{
Packit 47f805
    rtp_close_extra();
Packit 47f805
}