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