1
0
mirror of https://github.com/rofafor/vdr-plugin-iptv.git synced 2023-10-10 13:37:03 +02:00

Refactor socket code to a separate common class.

This commit is contained in:
Antti Seppälä 2007-10-21 13:31:21 +00:00
parent 7330887512
commit 4bc08e8cc0
9 changed files with 213 additions and 305 deletions

View File

@ -1,7 +1,7 @@
# #
# Makefile for a Video Disk Recorder plugin # Makefile for a Video Disk Recorder plugin
# #
# $Id: Makefile,v 1.19 2007/10/15 20:06:38 ajhseppa Exp $ # $Id: Makefile,v 1.20 2007/10/21 13:31:21 ajhseppa Exp $
# Debugging on/off # Debugging on/off
#IPTV_DEBUG = 1 #IPTV_DEBUG = 1
@ -59,7 +59,7 @@ endif
OBJS = $(PLUGIN).o config.o setup.o device.o streamer.o protocoludp.o \ OBJS = $(PLUGIN).o config.o setup.o device.o streamer.o protocoludp.o \
protocolhttp.o protocolfile.o protocolext.o sectionfilter.o \ protocolhttp.o protocolfile.o protocolext.o sectionfilter.o \
sidscanner.o statistics.o common.o sidscanner.o statistics.o common.o socket.o
### The main target: ### The main target:

View File

@ -3,7 +3,7 @@
* *
* See the README file for copyright information and how to reach the author. * See the README file for copyright information and how to reach the author.
* *
* $Id: protocolext.c,v 1.17 2007/10/21 09:24:24 rahrenbe Exp $ * $Id: protocolext.c,v 1.18 2007/10/21 13:31:21 ajhseppa Exp $
*/ */
#include <sys/wait.h> #include <sys/wait.h>
@ -22,64 +22,21 @@
cIptvProtocolExt::cIptvProtocolExt() cIptvProtocolExt::cIptvProtocolExt()
: pid(-1), : pid(-1),
listenPort(IptvConfig.GetExtProtocolBasePort()), scriptParameter(0)
scriptParameter(0),
socketDesc(-1),
readBufferLen(TS_SIZE * IptvConfig.GetReadBufferTsCount())
{ {
debug("cIptvProtocolExt::cIptvProtocolExt()\n"); debug("cIptvProtocolExt::cIptvProtocolExt()\n");
scriptFile = strdup(""); scriptFile = strdup("");
listenAddr = strdup("127.0.0.1"); listenAddr = strdup("127.0.0.1");
// Allocate receive buffer
readBuffer = MALLOC(unsigned char, readBufferLen);
if (!readBuffer)
error("ERROR: MALLOC() failed in ProtocolExt()");
} }
cIptvProtocolExt::~cIptvProtocolExt() cIptvProtocolExt::~cIptvProtocolExt()
{ {
debug("cIptvProtocolExt::~cIptvProtocolExt()\n"); debug("cIptvProtocolExt::~cIptvProtocolExt()\n");
// Drop the multicast group and close the socket // Drop the socket connection
Close(); Close();
// Free allocated memory // Free allocated memory
free(scriptFile); free(scriptFile);
free(listenAddr); free(listenAddr);
free(readBuffer);
}
bool cIptvProtocolExt::OpenSocket(void)
{
debug("cIptvProtocolExt::OpenSocket()\n");
// Bind to the socket if it is not active already
if (socketDesc < 0) {
int yes = 1;
// Create socket
socketDesc = socket(PF_INET, SOCK_DGRAM, 0);
ERROR_IF_RET(socketDesc < 0, "socket()", return false);
// Make it use non-blocking I/O to avoid stuck read calls
ERROR_IF_FUNC(fcntl(socketDesc, F_SETFL, O_NONBLOCK), "fcntl()", CloseSocket(), return false);
// Allow multiple sockets to use the same PORT number
ERROR_IF_FUNC(setsockopt(socketDesc, SOL_SOCKET, SO_REUSEADDR, &yes,
sizeof(yes)) < 0, "setsockopt()", CloseSocket(), return false);
// Bind socket
memset(&sockAddr, '\0', sizeof(sockAddr));
sockAddr.sin_family = AF_INET;
sockAddr.sin_port = htons(listenPort);
sockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
int err = bind(socketDesc, (struct sockaddr *)&sockAddr, sizeof(sockAddr));
ERROR_IF_FUNC(err < 0, "bind()", CloseSocket(), return false);
}
return true;
}
void cIptvProtocolExt::CloseSocket(void)
{
debug("cIptvProtocolExt::CloseSocket()\n");
// Check if socket exists
if (socketDesc >= 0) {
close(socketDesc);
socketDesc = -1;
}
} }
void cIptvProtocolExt::ExecuteScript(void) void cIptvProtocolExt::ExecuteScript(void)
@ -100,7 +57,7 @@ void cIptvProtocolExt::ExecuteScript(void)
close(i); close(i);
// Execute the external script // Execute the external script
char* cmd = NULL; char* cmd = NULL;
asprintf(&cmd, "%s %d %d", scriptFile, scriptParameter, listenPort); asprintf(&cmd, "%s %d %d", scriptFile, scriptParameter, socketPort);
debug("cIptvProtocolExt::ExecuteScript(child): %s\n", cmd); debug("cIptvProtocolExt::ExecuteScript(child): %s\n", cmd);
if (execl("/bin/sh", "sh", "-c", cmd, NULL) == -1) { if (execl("/bin/sh", "sh", "-c", cmd, NULL) == -1) {
error("ERROR: Script executionfailed: %s", cmd); error("ERROR: Script executionfailed: %s", cmd);
@ -155,62 +112,7 @@ void cIptvProtocolExt::TerminateScript(void)
int cIptvProtocolExt::Read(unsigned char* *BufferAddr) int cIptvProtocolExt::Read(unsigned char* *BufferAddr)
{ {
//debug("cIptvProtocolExt::Read()\n"); return ReadUdpSocket(BufferAddr);
// Error out if socket not initialized
if (socketDesc <= 0) {
error("ERROR: Invalid socket in %s\n", __FUNCTION__);
return -1;
}
socklen_t addrlen = sizeof(sockAddr);
// Set argument point to read buffer
*BufferAddr = readBuffer;
// Wait for data
int retval = select_single_desc(socketDesc, 500000, false);
// Check if error
if (retval < 0)
return retval;
// Check if data available
else if (retval) {
// Read data from socket
int len = 0;
if (isActive)
len = recvfrom(socketDesc, readBuffer, readBufferLen, MSG_DONTWAIT,
(struct sockaddr *)&sockAddr, &addrlen);
ERROR_IF_RET(len < 0, "recvfrom()", return len);
if ((len > 0) && (readBuffer[0] == 0x47)) {
// Set argument point to read buffer
*BufferAddr = &readBuffer[0];
return len;
}
else if (len > 3) {
// http://www.networksorcery.com/enp/rfc/rfc2250.txt
// version
unsigned int v = (readBuffer[0] >> 6) & 0x03;
// extension bit
unsigned int x = (readBuffer[0] >> 4) & 0x01;
// cscr count
unsigned int cc = readBuffer[0] & 0x0F;
// payload type
unsigned int pt = readBuffer[1] & 0x7F;
// header lenght
unsigned int headerlen = (3 + cc) * sizeof(uint32_t);
// check if extension
if (x) {
// extension header length
unsigned int ehl = (((readBuffer[headerlen + 2] & 0xFF) << 8) | (readBuffer[headerlen + 3] & 0xFF));
// update header length
headerlen += (ehl + 1) * sizeof(uint32_t);
}
// Check that rtp is version 2, payload type is MPEG2 TS
// and payload contains multiple of TS packet data
if ((v == 2) && (pt == 33) && (((len - headerlen) % TS_SIZE) == 0)) {
// Set argument point to payload in read buffer
*BufferAddr = &readBuffer[headerlen];
return (len - headerlen);
}
}
}
return 0;
} }
bool cIptvProtocolExt::Open(void) bool cIptvProtocolExt::Open(void)
@ -220,7 +122,7 @@ bool cIptvProtocolExt::Open(void)
if (!strlen(scriptFile)) if (!strlen(scriptFile))
return false; return false;
// Create the listening socket // Create the listening socket
OpenSocket(); OpenSocket(socketPort, true);
// Execute the external script // Execute the external script
ExecuteScript(); ExecuteScript();
isActive = true; isActive = true;
@ -252,7 +154,7 @@ bool cIptvProtocolExt::Set(const char* Location, const int Parameter, const int
} }
scriptParameter = Parameter; scriptParameter = Parameter;
// Update listen port // Update listen port
listenPort = IptvConfig.GetExtProtocolBasePort() + Index; socketPort = IptvConfig.GetExtProtocolBasePort() + Index;
} }
return true; return true;
} }

View File

@ -3,7 +3,7 @@
* *
* See the README file for copyright information and how to reach the author. * See the README file for copyright information and how to reach the author.
* *
* $Id: protocolext.h,v 1.6 2007/10/21 09:24:24 rahrenbe Exp $ * $Id: protocolext.h,v 1.7 2007/10/21 13:31:21 ajhseppa Exp $
*/ */
#ifndef __IPTV_PROTOCOLEXT_H #ifndef __IPTV_PROTOCOLEXT_H
@ -11,23 +11,16 @@
#include <arpa/inet.h> #include <arpa/inet.h>
#include "protocolif.h" #include "protocolif.h"
#include "socket.h"
class cIptvProtocolExt : public cIptvProtocolIf { class cIptvProtocolExt : public cIptvSocket, public cIptvProtocolIf {
private: private:
int pid; int pid;
char* listenAddr; char* listenAddr;
int listenPort;
char* scriptFile; char* scriptFile;
int scriptParameter; int scriptParameter;
int socketDesc;
unsigned char* readBuffer;
unsigned int readBufferLen;
struct sockaddr_in sockAddr;
bool isActive;
private: private:
bool OpenSocket(void);
void CloseSocket(void);
void TerminateScript(void); void TerminateScript(void);
void ExecuteScript(void); void ExecuteScript(void);

View File

@ -3,7 +3,7 @@
* *
* See the README file for copyright information and how to reach the author. * See the README file for copyright information and how to reach the author.
* *
* $Id: protocolhttp.c,v 1.17 2007/10/20 23:25:14 ajhseppa Exp $ * $Id: protocolhttp.c,v 1.18 2007/10/21 13:31:21 ajhseppa Exp $
*/ */
#include <sys/types.h> #include <sys/types.h>
@ -20,18 +20,10 @@
#include "protocolhttp.h" #include "protocolhttp.h"
cIptvProtocolHttp::cIptvProtocolHttp() cIptvProtocolHttp::cIptvProtocolHttp()
: streamPort(3000),
socketDesc(-1),
readBufferLen(TS_SIZE * IptvConfig.GetReadBufferTsCount()),
isActive(false)
{ {
debug("cIptvProtocolHttp::cIptvProtocolHttp()\n"); debug("cIptvProtocolHttp::cIptvProtocolHttp()\n");
streamAddr = strdup(""); streamAddr = strdup("");
streamPath = strdup("/"); streamPath = strdup("/");
// Allocate receive buffer
readBuffer = MALLOC(unsigned char, readBufferLen);
if (!readBuffer)
error("ERROR: MALLOC() failed in ProtocolHttp()");
} }
cIptvProtocolHttp::~cIptvProtocolHttp() cIptvProtocolHttp::~cIptvProtocolHttp()
@ -42,49 +34,7 @@ cIptvProtocolHttp::~cIptvProtocolHttp()
// Free allocated memory // Free allocated memory
free(streamPath); free(streamPath);
free(streamAddr); free(streamAddr);
free(readBuffer);
}
bool cIptvProtocolHttp::OpenSocket(const int Port)
{
debug("cIptvProtocolHttp::OpenSocket()\n");
// If socket is there already and it is bound to a different port, it must
// be closed first
if (Port != streamPort) {
debug("cIptvProtocolHttp::OpenSocket(): Socket tear-down\n");
CloseSocket();
}
// Bind to the socket if it is not active already
if (socketDesc < 0) {
int yes = 1;
// Create socket
socketDesc = socket(PF_INET, SOCK_STREAM, 0);
ERROR_IF_RET(socketDesc < 0, "socket()", return false);
// Make it use non-blocking I/O to avoid stuck read calls
ERROR_IF_FUNC(fcntl(socketDesc, F_SETFL, O_NONBLOCK), "fcntl()", CloseSocket(), return false);
// Allow multiple sockets to use the same PORT number
ERROR_IF_FUNC(setsockopt(socketDesc, SOL_SOCKET, SO_REUSEADDR, &yes,
sizeof(yes)) < 0, "setsockopt()", CloseSocket(), return false);
// Create default socket
memset(&sockAddr, '\0', sizeof(sockAddr));
sockAddr.sin_family = AF_INET;
sockAddr.sin_port = htons(Port);
sockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
// Update stream port
streamPort = Port;
}
return true;
}
void cIptvProtocolHttp::CloseSocket(void)
{
debug("cIptvProtocolHttp::CloseSocket()\n");
// Check if socket exists
if (socketDesc >= 0) {
close(socketDesc);
socketDesc = -1;
}
} }
bool cIptvProtocolHttp::Connect(void) bool cIptvProtocolHttp::Connect(void)
@ -93,7 +43,7 @@ bool cIptvProtocolHttp::Connect(void)
// Check that stream address is valid // Check that stream address is valid
if (!isActive && !isempty(streamAddr) && !isempty(streamPath)) { if (!isActive && !isempty(streamAddr) && !isempty(streamPath)) {
// Ensure that socket is valid // Ensure that socket is valid
OpenSocket(streamPort); OpenSocket(socketPort, false);
// First try only the IP address // First try only the IP address
sockAddr.sin_addr.s_addr = inet_addr(streamAddr); sockAddr.sin_addr.s_addr = inet_addr(streamAddr);
@ -310,8 +260,8 @@ bool cIptvProtocolHttp::Set(const char* Location, const int Parameter, const int
} }
else else
streamPath = strcpyrealloc(streamPath, "/"); streamPath = strcpyrealloc(streamPath, "/");
streamPort = Parameter; socketPort = Parameter;
debug("http://%s:%d%s\n", streamAddr, streamPort, streamPath); debug("http://%s:%d%s\n", streamAddr, socketPort, streamPath);
// Re-connect the socket // Re-connect the socket
Connect(); Connect();
} }
@ -321,5 +271,5 @@ bool cIptvProtocolHttp::Set(const char* Location, const int Parameter, const int
cString cIptvProtocolHttp::GetInformation(void) cString cIptvProtocolHttp::GetInformation(void)
{ {
//debug("cIptvProtocolHttp::GetInformation()"); //debug("cIptvProtocolHttp::GetInformation()");
return cString::sprintf("http://%s:%d%s", streamAddr, streamPort, streamPath); return cString::sprintf("http://%s:%d%s", streamAddr, socketPort, streamPath);
} }

View File

@ -3,7 +3,7 @@
* *
* See the README file for copyright information and how to reach the author. * See the README file for copyright information and how to reach the author.
* *
* $Id: protocolhttp.h,v 1.9 2007/10/19 22:18:55 rahrenbe Exp $ * $Id: protocolhttp.h,v 1.10 2007/10/21 13:31:21 ajhseppa Exp $
*/ */
#ifndef __IPTV_PROTOCOLHTTP_H #ifndef __IPTV_PROTOCOLHTTP_H
@ -11,21 +11,14 @@
#include <arpa/inet.h> #include <arpa/inet.h>
#include "protocolif.h" #include "protocolif.h"
#include "socket.h"
class cIptvProtocolHttp : public cIptvProtocolIf { class cIptvProtocolHttp : public cIptvSocket, public cIptvProtocolIf {
private: private:
char* streamAddr; char* streamAddr;
char* streamPath; char* streamPath;
int streamPort;
int socketDesc;
unsigned char* readBuffer;
unsigned int readBufferLen;
struct sockaddr_in sockAddr;
bool isActive;
private: private:
bool OpenSocket(const int Port);
void CloseSocket(void);
bool Connect(void); bool Connect(void);
bool Disconnect(void); bool Disconnect(void);
bool GetHeaderLine(char* dest, unsigned int destLen, bool GetHeaderLine(char* dest, unsigned int destLen,

View File

@ -3,7 +3,7 @@
* *
* See the README file for copyright information and how to reach the author. * See the README file for copyright information and how to reach the author.
* *
* $Id: protocoludp.c,v 1.18 2007/10/20 23:25:14 ajhseppa Exp $ * $Id: protocoludp.c,v 1.19 2007/10/21 13:31:21 ajhseppa Exp $
*/ */
#include <sys/types.h> #include <sys/types.h>
@ -17,19 +17,12 @@
#include "common.h" #include "common.h"
#include "config.h" #include "config.h"
#include "protocoludp.h" #include "protocoludp.h"
#include "socket.h"
cIptvProtocolUdp::cIptvProtocolUdp() cIptvProtocolUdp::cIptvProtocolUdp()
: streamPort(1234),
socketDesc(-1),
readBufferLen(TS_SIZE * IptvConfig.GetReadBufferTsCount()),
isActive(false)
{ {
debug("cIptvProtocolUdp::cIptvProtocolUdp()\n"); debug("cIptvProtocolUdp::cIptvProtocolUdp()\n");
streamAddr = strdup(""); streamAddr = strdup("");
// Allocate receive buffer
readBuffer = MALLOC(unsigned char, readBufferLen);
if (!readBuffer)
error("ERROR: MALLOC() failed in ProtocolUdp()");
} }
cIptvProtocolUdp::~cIptvProtocolUdp() cIptvProtocolUdp::~cIptvProtocolUdp()
@ -39,50 +32,6 @@ cIptvProtocolUdp::~cIptvProtocolUdp()
Close(); Close();
// Free allocated memory // Free allocated memory
free(streamAddr); free(streamAddr);
free(readBuffer);
}
bool cIptvProtocolUdp::OpenSocket(const int Port)
{
debug("cIptvProtocolUdp::OpenSocket()\n");
// If socket is there already and it is bound to a different port, it must
// be closed first
if (Port != streamPort) {
debug("cIptvProtocolUdp::OpenSocket(): Socket tear-down\n");
CloseSocket();
}
// Bind to the socket if it is not active already
if (socketDesc < 0) {
int yes = 1;
// Create socket
socketDesc = socket(PF_INET, SOCK_DGRAM, 0);
ERROR_IF_RET(socketDesc < 0, "socket()", return false);
// Make it use non-blocking I/O to avoid stuck read calls
ERROR_IF_FUNC(fcntl(socketDesc, F_SETFL, O_NONBLOCK), "fcntl()", CloseSocket(), return false);
// Allow multiple sockets to use the same PORT number
ERROR_IF_FUNC(setsockopt(socketDesc, SOL_SOCKET, SO_REUSEADDR, &yes,
sizeof(yes)) < 0, "setsockopt()", CloseSocket(), return false);
// Bind socket
memset(&sockAddr, '\0', sizeof(sockAddr));
sockAddr.sin_family = AF_INET;
sockAddr.sin_port = htons(Port);
sockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
int err = bind(socketDesc, (struct sockaddr *)&sockAddr, sizeof(sockAddr));
ERROR_IF_FUNC(err < 0, "bind()", CloseSocket(), return false);
// Update stream port
streamPort = Port;
}
return true;
}
void cIptvProtocolUdp::CloseSocket(void)
{
debug("cIptvProtocolUdp::CloseSocket()\n");
// Check if socket exists
if (socketDesc >= 0) {
close(socketDesc);
socketDesc = -1;
}
} }
bool cIptvProtocolUdp::JoinMulticast(void) bool cIptvProtocolUdp::JoinMulticast(void)
@ -91,7 +40,7 @@ bool cIptvProtocolUdp::JoinMulticast(void)
// Check that stream address is valid // Check that stream address is valid
if (!isActive && !isempty(streamAddr)) { if (!isActive && !isempty(streamAddr)) {
// Ensure that socket is valid // Ensure that socket is valid
OpenSocket(streamPort); OpenSocket(socketPort, true);
// Join a new multicast group // Join a new multicast group
struct ip_mreq mreq; struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = inet_addr(streamAddr); mreq.imr_multiaddr.s_addr = inet_addr(streamAddr);
@ -111,7 +60,7 @@ bool cIptvProtocolUdp::DropMulticast(void)
// Check that stream address is valid // Check that stream address is valid
if (isActive && !isempty(streamAddr)) { if (isActive && !isempty(streamAddr)) {
// Ensure that socket is valid // Ensure that socket is valid
OpenSocket(streamPort); OpenSocket(socketPort, true);
// Drop the multicast group // Drop the multicast group
struct ip_mreq mreq; struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = inet_addr(streamAddr); mreq.imr_multiaddr.s_addr = inet_addr(streamAddr);
@ -127,62 +76,7 @@ bool cIptvProtocolUdp::DropMulticast(void)
int cIptvProtocolUdp::Read(unsigned char* *BufferAddr) int cIptvProtocolUdp::Read(unsigned char* *BufferAddr)
{ {
//debug("cIptvProtocolUdp::Read()\n"); return ReadUdpSocket(BufferAddr);
// Error out if socket not initialized
if (socketDesc <= 0) {
error("ERROR: Invalid socket in %s\n", __FUNCTION__);
return -1;
}
socklen_t addrlen = sizeof(sockAddr);
// Set argument point to read buffer
*BufferAddr = readBuffer;
// Wait for data
int retval = select_single_desc(socketDesc, 500000, false);
// Check if error
if (retval < 0)
return retval;
// Check if data available
else if (retval) {
int len = 0;
// Read data from socket
if (isActive)
len = recvfrom(socketDesc, readBuffer, readBufferLen, MSG_DONTWAIT,
(struct sockaddr *)&sockAddr, &addrlen);
ERROR_IF_RET(len < 0, "recvfrom()", return len);
if ((len > 0) && (readBuffer[0] == 0x47)) {
// Set argument point to read buffer
*BufferAddr = &readBuffer[0];
return len;
}
else if (len > 3) {
// http://www.networksorcery.com/enp/rfc/rfc2250.txt
// version
unsigned int v = (readBuffer[0] >> 6) & 0x03;
// extension bit
unsigned int x = (readBuffer[0] >> 4) & 0x01;
// cscr count
unsigned int cc = readBuffer[0] & 0x0F;
// payload type
unsigned int pt = readBuffer[1] & 0x7F;
// header lenght
unsigned int headerlen = (3 + cc) * sizeof(uint32_t);
// check if extension
if (x) {
// extension header length
unsigned int ehl = (((readBuffer[headerlen + 2] & 0xFF) << 8) | (readBuffer[headerlen + 3] & 0xFF));
// update header length
headerlen += (ehl + 1) * sizeof(uint32_t);
}
// Check that rtp is version 2, payload type is MPEG2 TS
// and payload contains multiple of TS packet data
if ((v == 2) && (pt == 33) && (((len - headerlen) % TS_SIZE) == 0)) {
// Set argument point to payload in read buffer
*BufferAddr = &readBuffer[headerlen];
return (len - headerlen);
}
}
}
return 0;
} }
bool cIptvProtocolUdp::Open(void) bool cIptvProtocolUdp::Open(void)
@ -211,7 +105,7 @@ bool cIptvProtocolUdp::Set(const char* Location, const int Parameter, const int
DropMulticast(); DropMulticast();
// Update stream address and port // Update stream address and port
streamAddr = strcpyrealloc(streamAddr, Location); streamAddr = strcpyrealloc(streamAddr, Location);
streamPort = Parameter; socketPort = Parameter;
// Join a new multicast group // Join a new multicast group
JoinMulticast(); JoinMulticast();
} }
@ -221,5 +115,5 @@ bool cIptvProtocolUdp::Set(const char* Location, const int Parameter, const int
cString cIptvProtocolUdp::GetInformation(void) cString cIptvProtocolUdp::GetInformation(void)
{ {
//debug("cIptvProtocolUdp::GetInformation()"); //debug("cIptvProtocolUdp::GetInformation()");
return cString::sprintf("udp://%s:%d", streamAddr, streamPort); return cString::sprintf("udp://%s:%d", streamAddr, socketPort);
} }

View File

@ -3,7 +3,7 @@
* *
* See the README file for copyright information and how to reach the author. * See the README file for copyright information and how to reach the author.
* *
* $Id: protocoludp.h,v 1.10 2007/10/19 22:18:55 rahrenbe Exp $ * $Id: protocoludp.h,v 1.11 2007/10/21 13:31:21 ajhseppa Exp $
*/ */
#ifndef __IPTV_PROTOCOLUDP_H #ifndef __IPTV_PROTOCOLUDP_H
@ -11,20 +11,13 @@
#include <arpa/inet.h> #include <arpa/inet.h>
#include "protocolif.h" #include "protocolif.h"
#include "socket.h"
class cIptvProtocolUdp : public cIptvProtocolIf { class cIptvProtocolUdp : public cIptvSocket, public cIptvProtocolIf {
private: private:
char* streamAddr; char* streamAddr;
int streamPort;
int socketDesc;
unsigned char* readBuffer;
unsigned int readBufferLen;
struct sockaddr_in sockAddr;
bool isActive;
private: private:
bool OpenSocket(const int Port);
void CloseSocket(void);
bool JoinMulticast(void); bool JoinMulticast(void);
bool DropMulticast(void); bool DropMulticast(void);

149
socket.c Normal file
View File

@ -0,0 +1,149 @@
/*
* socket.c: IPTV plugin for the Video Disk Recorder
*
* See the README file for copyright information and how to reach the author.
*
* $Id: socket.c,v 1.1 2007/10/21 13:31:21 ajhseppa Exp $
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <fcntl.h>
#include <unistd.h>
#include <vdr/device.h>
#include "common.h"
#include "config.h"
#include "socket.h"
cIptvSocket::cIptvSocket()
: socketPort(IptvConfig.GetExtProtocolBasePort()),
socketDesc(-1),
readBufferLen(TS_SIZE * IptvConfig.GetReadBufferTsCount()),
isActive(false)
{
debug("cIptvSocket::cIptvSocket()\n");
// Allocate receive buffer
readBuffer = MALLOC(unsigned char, readBufferLen);
if (!readBuffer)
error("ERROR: MALLOC() failed in socket()");
}
cIptvSocket::~cIptvSocket()
{
debug("cIptvSocket::~cIptvSocket()\n");
// Close the socket
CloseSocket();
// Free allocated memory
free(readBuffer);
}
bool cIptvSocket::OpenSocket(const int Port, const bool isUdp)
{
debug("cIptvSocket::OpenSocket()\n");
// If socket is there already and it is bound to a different port, it must
// be closed first
if (Port != socketPort) {
debug("cIptvSocket::OpenSocket(): Socket tear-down\n");
CloseSocket();
}
// Bind to the socket if it is not active already
if (socketDesc < 0) {
int yes = 1;
// Create socket
if (isUdp)
socketDesc = socket(PF_INET, SOCK_DGRAM, 0);
else
socketDesc = socket(PF_INET, SOCK_STREAM, 0);
ERROR_IF_RET(socketDesc < 0, "socket()", return false);
// Make it use non-blocking I/O to avoid stuck read calls
ERROR_IF_FUNC(fcntl(socketDesc, F_SETFL, O_NONBLOCK), "fcntl()", CloseSocket(), return false);
// Allow multiple sockets to use the same PORT number
ERROR_IF_FUNC(setsockopt(socketDesc, SOL_SOCKET, SO_REUSEADDR, &yes,
sizeof(yes)) < 0, "setsockopt()", CloseSocket(), return false);
// Bind socket
memset(&sockAddr, '\0', sizeof(sockAddr));
sockAddr.sin_family = AF_INET;
sockAddr.sin_port = htons(Port);
sockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
if (isUdp) {
int err = bind(socketDesc, (struct sockaddr *)&sockAddr, sizeof(sockAddr));
ERROR_IF_FUNC(err < 0, "bind()", CloseSocket(), return false);
}
// Update socket port
socketPort = Port;
}
return true;
}
void cIptvSocket::CloseSocket(void)
{
debug("cIptvSocket::CloseSocket()\n");
// Check if socket exists
if (socketDesc >= 0) {
close(socketDesc);
socketDesc = -1;
}
}
int cIptvSocket::ReadUdpSocket(unsigned char* *BufferAddr)
{
//debug("cIptvSocket::Read()\n");
// Error out if socket not initialized
if (socketDesc <= 0) {
error("ERROR: Invalid socket in %s\n", __FUNCTION__);
return -1;
}
socklen_t addrlen = sizeof(sockAddr);
// Set argument point to read buffer
*BufferAddr = readBuffer;
// Wait for data
int retval = select_single_desc(socketDesc, 500000, false);
// Check if error
if (retval < 0)
return retval;
// Check if data available
else if (retval) {
int len = 0;
// Read data from socket
if (isActive)
len = recvfrom(socketDesc, readBuffer, readBufferLen, MSG_DONTWAIT,
(struct sockaddr *)&sockAddr, &addrlen);
ERROR_IF_RET(len < 0, "recvfrom()", return len);
if ((len > 0) && (readBuffer[0] == 0x47)) {
// Set argument point to read buffer
*BufferAddr = &readBuffer[0];
return len;
}
else if (len > 3) {
// http://www.networksorcery.com/enp/rfc/rfc2250.txt
// version
unsigned int v = (readBuffer[0] >> 6) & 0x03;
// extension bit
unsigned int x = (readBuffer[0] >> 4) & 0x01;
// cscr count
unsigned int cc = readBuffer[0] & 0x0F;
// payload type
unsigned int pt = readBuffer[1] & 0x7F;
// header lenght
unsigned int headerlen = (3 + cc) * sizeof(uint32_t);
// check if extension
if (x) {
// extension header length
unsigned int ehl = (((readBuffer[headerlen + 2] & 0xFF) << 8) | (readBuffer[headerlen + 3] & 0xFF));
// update header length
headerlen += (ehl + 1) * sizeof(uint32_t);
}
// Check that rtp is version 2, payload type is MPEG2 TS
// and payload contains multiple of TS packet data
if ((v == 2) && (pt == 33) && (((len - headerlen) % TS_SIZE) == 0)) {
// Set argument point to payload in read buffer
*BufferAddr = &readBuffer[headerlen];
return (len - headerlen);
}
}
}
return 0;
}

34
socket.h Normal file
View File

@ -0,0 +1,34 @@
/*
* protocoludp.h: IPTV plugin for the Video Disk Recorder
*
* See the README file for copyright information and how to reach the author.
*
* $Id: socket.h,v 1.1 2007/10/21 13:31:21 ajhseppa Exp $
*/
#ifndef __IPTV_SOCKET_H
#define __IPTV_SOCKET_H
#include <arpa/inet.h>
class cIptvSocket {
protected:
int socketPort;
int socketDesc;
unsigned char* readBuffer;
unsigned int readBufferLen;
struct sockaddr_in sockAddr;
bool isActive;
protected:
bool OpenSocket(const int Port, const bool isUdp);
void CloseSocket(void);
int ReadUdpSocket(unsigned char* *BufferAddr);
public:
cIptvSocket();
virtual ~cIptvSocket();
};
#endif // __IPTV_SOCKET_H