From c5306f81a9d3b87df7e16c852f2505ac913193ca Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli (think)" Date: Fri, 8 Nov 2013 14:43:19 +0100 Subject: make dabOutput more object-oriented --- src/dabOutput/dabOutput.cpp | 109 ++++++++++++ src/dabOutput/dabOutput.h | 248 ++++++++++++++++++++++++++ src/dabOutput/dabOutputFifo.cpp | 48 +++++ src/dabOutput/dabOutputFile.cpp | 111 ++++++++++++ src/dabOutput/dabOutputRaw.cpp | 366 +++++++++++++++++++++++++++++++++++++++ src/dabOutput/dabOutputSimul.cpp | 70 ++++++++ src/dabOutput/dabOutputTcp.cpp | 154 ++++++++++++++++ src/dabOutput/dabOutputUdp.cpp | 82 +++++++++ 8 files changed, 1188 insertions(+) create mode 100644 src/dabOutput/dabOutput.cpp create mode 100644 src/dabOutput/dabOutput.h create mode 100644 src/dabOutput/dabOutputFifo.cpp create mode 100644 src/dabOutput/dabOutputFile.cpp create mode 100644 src/dabOutput/dabOutputRaw.cpp create mode 100644 src/dabOutput/dabOutputSimul.cpp create mode 100644 src/dabOutput/dabOutputTcp.cpp create mode 100644 src/dabOutput/dabOutputUdp.cpp (limited to 'src/dabOutput') diff --git a/src/dabOutput/dabOutput.cpp b/src/dabOutput/dabOutput.cpp new file mode 100644 index 0000000..18da57e --- /dev/null +++ b/src/dabOutput/dabOutput.cpp @@ -0,0 +1,109 @@ +#include +#include +#include +#include +#include "dabOutput.h" + + + +DabOutputFifo::open(const char* name) +{ + char* token = strchr((char*)filename, '?'); + if (token != NULL) { + *(token++) = 0; + char* nextPair; + char* key; + char* value; + // Go through all the &stuff=foo pairs + // Only the key "type" is supported + do { + nextPair = strchr(token, '&'); + if (nextPair != NULL) { + *nextPair = 0; + } + key = token; + value = strchr(token, '='); + if (value != NULL) { + *(value++) = 0; + if (strcmp(key, "type") == 0) { + if (strcmp(value, "raw") == 0) { + this->type_ = ETI_FILE_TYPE_RAW; + break; + } else if (strcmp(value, "framed") == 0) { + this->type = ETI_FILE_TYPE_FRAMED; + break; + } else if (strcmp(value, "streamed") == 0) { + this->type = ETI_FILE_TYPE_STREAMED; + break; + } else { + etiLog.printHeader(TcpLog::ERR, + "File type '%s' is not supported.\n", value); + return -1; + } + } + else { + etiLog.printHeader(TcpLog::WARNING, "Parameter '%s' unknown\n", key); + } + } + } while (nextPair != NULL); + } + + this->file_ = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666); + if (this->file_ == -1) { + perror(filename); + return -1; + } + return 0; +} + +int DabOutputFifo::write(void* buffer, int size) +{ + uint8_t padding[6144]; + + switch (this->type_) { + case ETI_FILE_TYPE_FRAMED: + if (this->nbFrames_ == 0) { + uint32_t nbFrames = (uint32_t)-1; + // Writing nb frames + if (write(this->file_, &nbFrames, 4) == -1) + goto FIFO_WRITE_ERROR; + } + case ETI_FILE_TYPE_STREAMED: + // Writting frame length + if (write(this->file_, &size, 2) == -1) + goto FIFO_WRITE_ERROR; + // Appending data + if (write(this->file_, buffer, size) == -1) + goto FIFO_WRITE_ERROR; + break; + case ETI_FILE_TYPE_RAW: + // Appending data + if (write(this->file_, buffer, size) == -1) + goto FIFO_WRITE_ERROR; + // Appending padding + memset(padding, 0x55, 6144 - size); + if (write(this->file_, padding, 6144 - size) == -1) + goto FIFO_WRITE_ERROR; + break; + default: + etiLog.printHeader(TcpLog::ERR, "File type is not supported.\n"); + return -1; + } + + return size; + +FIFO_WRITE_ERROR: + perror("Error while writting to file"); + return -1; +} + +int DabOutputFifo::close() +{ + if (close(this->file_) == 0) { + this->file_ = -1; + return 0; + } + perror("Can't close file"); + return -1; +} + diff --git a/src/dabOutput/dabOutput.h b/src/dabOutput/dabOutput.h new file mode 100644 index 0000000..7f295b4 --- /dev/null +++ b/src/dabOutput/dabOutput.h @@ -0,0 +1,248 @@ +/* + Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Her Majesty the Queen in + Right of Canada (Communications Research Center Canada) + + Copyright (C) 2013 Matthias P. Braendli + http://mpb.li + + An object-oriented version of the output channels. + */ +/* + This file is part of CRC-DabMux. + + CRC-DabMux is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + CRC-DabMux 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with CRC-DabMux. If not, see . + */ + +#ifndef __DAB_OUTPUT_H +#define __DAB_OUTPUT_H + +#include "UdpSocket.h" +#include "TcpServer.h" +#include "TcpLog.h" +#include +#ifdef _WIN32 +# include +# ifdef __MINGW32__ +# define FS_DECLARE_CFG_ARRAYS +# include +# endif +# include +#else +# include +# include +# ifndef O_BINARY +# define O_BINARY 0 +# endif // O_BINARY +#endif + +extern TcpLog etiLog; + +// Abstract base class for all outputs +class DabOutput +{ + public: + virtual int Open(const char* name) = 0; + int Open(std::string name) + { + return Open(name.c_str()); + } + virtual int Write(void* buffer, int size) = 0; + virtual int Close() = 0; + + virtual ~DabOutput() {}; +}; + +// ----- used in File and Fifo outputs +enum EtiFileType { + ETI_FILE_TYPE_NONE = 0, + ETI_FILE_TYPE_RAW, + ETI_FILE_TYPE_STREAMED, + ETI_FILE_TYPE_FRAMED +}; + +// ---------- File output ------------ +class DabOutputFile : public DabOutput +{ + public: + DabOutputFile() { + nbFrames_ = 0; + file_ = -1; + type_ = ETI_FILE_TYPE_FRAMED; + } + + DabOutputFile(const DabOutputFile& other) + { + file_ = other.file_; + nbFrames_ = other.nbFrames_; + type_ = other.type_; + } + + ~DabOutputFile() {} + + int Open(const char* filename); + int Write(void* buffer, int size); + int Close(); + + protected: + int file_; + EtiFileType type_; + unsigned long nbFrames_; +}; + +// ---------- FIFO output ------------ +// only write is different for the FIFO output +class DabOutputFifo : public DabOutputFile +{ + public: + DabOutputFifo() : DabOutputFile() {} + ~DabOutputFifo() {} + + int Write(void* buffer, int size); +}; + +// -------------- RAW socket ----------- +class DabOutputRaw : public DabOutput +{ + public: + DabOutputRaw() + { +#ifdef _WIN32 + socket_ = INVALID_HANDLE_VALUE; +#else + socket_ = -1; + isCyclades_ = false; +#endif + buffer_ = new unsigned char[6144]; + } + + DabOutputRaw(const DabOutputRaw& other) + { + socket_ = other.socket_; +#ifndef _WIN32 + isCyclades_ = other.isCyclades_; +#endif + buffer_ = other.buffer_; + } + + ~DabOutputRaw() { + delete[] buffer_; + } + + int Open(const char* name); + int Write(void* buffer, int size); + int Close(); + private: +#ifdef _WIN32 + HANDLE socket_; +#else + int socket_; + bool isCyclades_; +#endif + unsigned char* buffer_; +}; + +// -------------- UDP ------------------ +class DabOutputUdp : public DabOutput +{ + public: + DabOutputUdp() { + UdpSocket::init(); + packet_ = new UdpPacket(6144); + socket_ = new UdpSocket(); + } + + DabOutputUdp(const DabOutputUdp& other) + { + packet_ = other.packet_; + socket_ = other.socket_; + } + + ~DabOutputUdp() { + delete socket_; + delete packet_; + } + + int Open(const char* name); + int Write(void* buffer, int size); + int Close() { return 0; } + + private: + UdpSocket* socket_; + UdpPacket* packet_; +}; + +// -------------- TCP ------------------ +class DabOutputTcp : public DabOutput +{ + public: + DabOutputTcp() + { + TcpSocket::init(); + server = new TcpServer(); + client = NULL; + } + + DabOutputTcp(const DabOutputTcp& other) + { + server = other.server; + client = other.client; + thread_ = other.thread_; + } + + ~DabOutputTcp() { + +#ifdef _WIN32 + CloseHandle(this->thread_); +#endif + + delete this->server; + delete this->client; + } + + int Open(const char* name); + int Write(void* buffer, int size); + int Close(); + + TcpServer* server; + TcpSocket* client; + private: + pthread_t thread_; +}; + +// -------------- Simul ------------------ +class DabOutputSimul : public DabOutput +{ + public: + DabOutputSimul() {} + + DabOutputSimul(const DabOutputSimul& other) + { + startTime_ = other.startTime_; + } + + ~DabOutputSimul() { } + + int Open(const char* name); + int Write(void* buffer, int size); + int Close() { return 0; } + private: +#ifdef _WIN32 + DWORD startTime_; +#else + timeval startTime_; +#endif +}; + +#endif + diff --git a/src/dabOutput/dabOutputFifo.cpp b/src/dabOutput/dabOutputFifo.cpp new file mode 100644 index 0000000..49fc331 --- /dev/null +++ b/src/dabOutput/dabOutputFifo.cpp @@ -0,0 +1,48 @@ +#include +#include +#include +#include +#include "dabOutput.h" + + +int DabOutputFifo::Write(void* buffer, int size) +{ + uint8_t padding[6144]; + + switch (this->type_) { + case ETI_FILE_TYPE_FRAMED: + if (this->nbFrames_ == 0) { + uint32_t nbFrames = (uint32_t)-1; + // Writing nb frames + if (write(this->file_, &nbFrames, 4) == -1) + goto FIFO_WRITE_ERROR; + } + case ETI_FILE_TYPE_STREAMED: + // Writting frame length + if (write(this->file_, &size, 2) == -1) + goto FIFO_WRITE_ERROR; + // Appending data + if (write(this->file_, buffer, size) == -1) + goto FIFO_WRITE_ERROR; + break; + case ETI_FILE_TYPE_RAW: + // Appending data + if (write(this->file_, buffer, size) == -1) + goto FIFO_WRITE_ERROR; + // Appending padding + memset(padding, 0x55, 6144 - size); + if (write(this->file_, padding, 6144 - size) == -1) + goto FIFO_WRITE_ERROR; + break; + default: + etiLog.printHeader(TcpLog::ERR, "File type is not supported.\n"); + return -1; + } + + return size; + +FIFO_WRITE_ERROR: + perror("Error while writting to file"); + return -1; +} + diff --git a/src/dabOutput/dabOutputFile.cpp b/src/dabOutput/dabOutputFile.cpp new file mode 100644 index 0000000..349a308 --- /dev/null +++ b/src/dabOutput/dabOutputFile.cpp @@ -0,0 +1,111 @@ +#include +#include +#include +#include +#include "dabOutput.h" + +int DabOutputFile::Open(const char* filename) +{ + char* token = strchr((char*)filename, '?'); + if (token != NULL) { + *(token++) = 0; + char* nextPair; + char* key; + char* value; + // Go through all the &stuff=foo pairs + // Only the key "type" is supported + do { + nextPair = strchr(token, '&'); + if (nextPair != NULL) { + *nextPair = 0; + } + key = token; + value = strchr(token, '='); + if (value != NULL) { + *(value++) = 0; + if (strcmp(key, "type") == 0) { + if (strcmp(value, "raw") == 0) { + this->type_ = ETI_FILE_TYPE_RAW; + break; + } else if (strcmp(value, "framed") == 0) { + this->type_ = ETI_FILE_TYPE_FRAMED; + break; + } else if (strcmp(value, "streamed") == 0) { + this->type_ = ETI_FILE_TYPE_STREAMED; + break; + } else { + etiLog.printHeader(TcpLog::ERR, + "File type '%s' is not supported.\n", value); + return -1; + } + } + else { + etiLog.printHeader(TcpLog::WARNING, "Parameter '%s' unknown\n", key); + } + } + } while (nextPair != NULL); + } + + this->file_ = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666); + if (this->file_ == -1) { + perror(filename); + return -1; + } + return 0; +} + +int DabOutputFile::Write(void* buffer, int size) +{ + uint8_t padding[6144]; + ++nbFrames_; + + switch (this->type_) { + case ETI_FILE_TYPE_FRAMED: + // Writting nb of frames at beginning of file + if (lseek(this->file_, 0, SEEK_SET) == -1) goto FILE_WRITE_ERROR; + if (write(this->file_, &this->nbFrames_, 4) == -1) goto FILE_WRITE_ERROR; + + // Writting nb frame length at end of file + if (lseek(this->file_, 0, SEEK_END) == -1) goto FILE_WRITE_ERROR; + if (write(this->file_, &size, 2) == -1) goto FILE_WRITE_ERROR; + + // Appending data + if (write(this->file_, buffer, size) == -1) goto FILE_WRITE_ERROR; + break; + case ETI_FILE_TYPE_STREAMED: + // Writting nb frame length at end of file + if (write(this->file_, &size, 2) == -1) goto FILE_WRITE_ERROR; + + // Appending data + if (write(this->file_, buffer, size) == -1) goto FILE_WRITE_ERROR; + break; + case ETI_FILE_TYPE_RAW: + // Appending data + if (write(this->file_, buffer, size) == -1) goto FILE_WRITE_ERROR; + + // Appending padding + memset(padding, 0x55, 6144 - size); + if (write(this->file_, padding, 6144 - size) == -1) goto FILE_WRITE_ERROR; + break; + default: + etiLog.printHeader(TcpLog::ERR, "File type is not supported.\n"); + return -1; + } + + return size; + +FILE_WRITE_ERROR: + perror("Error while writting to file"); + return -1; +} + +int DabOutputFile::Close() +{ + if (close(this->file_) == 0) { + this->file_ = -1; + return 0; + } + perror("Can't close file"); + return -1; +} + diff --git a/src/dabOutput/dabOutputRaw.cpp b/src/dabOutput/dabOutputRaw.cpp new file mode 100644 index 0000000..1a78b63 --- /dev/null +++ b/src/dabOutput/dabOutputRaw.cpp @@ -0,0 +1,366 @@ +#include +#include +#include "dabOutput.h" +#ifdef _WIN32 +# include +# include +#else +# include +# include +# include +# include +# include +# include +# include +# include +#endif + +const unsigned char revTable[] = { + 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, + 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, + 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, + 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, + 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, + 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, + 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, + 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, + 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, + 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, + 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, + 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, + 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, + 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, + 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, + 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, + 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, + 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, + 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, + 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, + 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, + 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, + 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, + 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, + 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, + 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, + 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, + 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, + 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, + 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, + 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, + 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff +}; + +int DabOutputRaw::Open(const char* filename) +{ + if (filename == NULL) { + etiLog.printHeader(TcpLog::ERR, "Socket name must be provided!\n"); + return -1; + } + +#ifdef _WIN32 + // Opening device + this->socket_ = CreateFile(filename, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); + if (this->socket_ == INVALID_HANDLE_VALUE) { + etiLog.printHeader(TcpLog::ERR, "Can't open raw device '%s': %i\n", + filename, GetLastError()); + return -1; + } + + // Configuring device + DWORD result; + FS_TE1_CONFIG config; + if (!DeviceIoControl(this->socket_, IoctlCodeFarSyncGetTE1Config, NULL, 0, + &config, sizeof(config), &result, NULL)) { + etiLog.printHeader(TcpLog::ERR, + "Can't get raw device '%s' config: %i\n", + filename, GetLastError()); + return -1; + } + config.dataRate = 2048000; + config.clocking = CLOCKING_MASTER; + config.framing = FRAMING_E1; + config.structure = STRUCTURE_UNFRAMED; + config.iface = INTERFACE_BNC; + config.coding = CODING_HDB3; + config.lineBuildOut = LBO_0dB; + config.equalizer = EQUALIZER_SHORT; + config.transparentMode = TRUE; + config.loopMode = LOOP_NONE; + config.range = RANGE_0_40_M; + config.txBufferMode = BUFFER_2_FRAME; + config.rxBufferMode = BUFFER_2_FRAME; + config.startingTimeSlot = 0; + config.losThreshold = 2; + config.enableIdleCode = TRUE; + config.idleCode = 0xff; + if (!DeviceIoControl(this->socket_, IoctlCodeFarSyncSetTE1Config, + &config, sizeof(config), NULL, 0, &result, NULL)) { + etiLog.printHeader(TcpLog::ERR, + "Can't set raw device '%s' config: %i\n", + filename, GetLastError()); + return -1; + } + + // Starting device + if (!DeviceIoControl(this->socket_, IoctlCodeFarSyncQuickStart, NULL, 0, + NULL, 0, &result, NULL)) { + etiLog.printHeader(TcpLog::ERR, "Can't start raw device '%s': %i\n", + filename, GetLastError()); + return -1; + } +#else + this->socket_ = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP); + if (this->socket_ == -1) { + etiLog.printHeader(TcpLog::ERR, "Are you logged as root?\n"); + perror(filename); + return -1; + } + + struct ifreq ifr; + struct sockaddr_ll saddr; + memset(&ifr, 0, sizeof(struct ifreq)); + (void)strncpy(ifr.ifr_name, filename, sizeof(ifr.ifr_name)); + + // Get current Farsync configuration + struct fstioc_info info; + memset(&info, 0, sizeof(info)); + ifr.ifr_data = (char*)&info; + if (ioctl(this->socket_, FSTGETCONF, &ifr) == -1) { + etiLog.printHeader(TcpLog::DBG, "Cyclades card identified.\n"); + this->isCyclades_ = true; + + // Set the interface MTU if needed + if (ioctl(this->socket_, SIOCGIFMTU, &ifr) == -1) { + etiLog.printHeader(TcpLog::ERR, "Can't get raw device MTU!\n"); + perror(filename); + return -1; + } else { + if (ifr.ifr_mtu != 6143) { + ifr.ifr_mtu = 6143; + if (ioctl(this->socket_, SIOCSIFMTU, &ifr) == -1) { + etiLog.printHeader(TcpLog::ERR, + "Can't Cyclades device MTU!\n"); + perror(filename); + return -1; + } + } + } + } else { + etiLog.printHeader(TcpLog::DBG, "Farsync card identified.\n"); + this->isCyclades_ = false; + + info.lineInterface = E1; + info.proto = FST_RAW; + info.internalClock = EXTCLK; + info.lineSpeed = 2048000; + //info.debug = DBG_INIT | DBG_OPEN | DBG_PCI | DBG_IOCTL | DBG_TX; + info.transparentMode = 1; + info.ignoreCarrier = 1; + info.numTxBuffers = 8; + info.numRxBuffers = 8; + info.txBufferSize = 6144; + info.rxBufferSize = 6144; + // E1 specific config + info.clockSource = CLOCKING_SLAVE; + info.structure = STRUCTURE_UNFRAMED; + info.interface = INTERFACE_BNC; //RJ48C; + info.coding = CODING_HDB3; + info.txBufferMode = BUFFER_2_FRAME; + info.idleCode = 0xff; + info.valid = FSTVAL_ALL; + + // Setting configuration + etiLog.printHeader(TcpLog::DBG, "Set configuration.\n"); + ifr.ifr_data = (char*)&info; + if (ioctl(this->socket_, FSTSETCONF, &ifr) == -1) { + etiLog.printHeader(TcpLog::ERR, + "Can't set Farsync configurationi!\n"); + perror(filename); + return -1; + } + + // Disabling notify + etiLog.printHeader(TcpLog::DBG, "Disable notify.\n"); + int notify = 0; + ifr.ifr_data = (char*)¬ify; + if (ioctl(this->socket_, FSTSNOTIFY, &ifr) == -1) { + etiLog.printHeader(TcpLog::ERR, "Can't disable Farsync notify!\n"); + perror(filename); + return -1; + } + + // Apply the new configuration + // Set the interface down if needed + etiLog.printHeader(TcpLog::DBG, "Get flags.\n"); + if (ioctl(this->socket_, SIOCGIFFLAGS, &ifr) == -1) { + etiLog.printHeader(TcpLog::ERR, "Can't get Farsync flags!\n"); + perror(filename); + return -1; + } else { + if (ifr.ifr_flags & IFF_UP) { + etiLog.printHeader(TcpLog::DBG, "Set flags.\n"); + ifr.ifr_flags &= ~IFF_UP; + if (ioctl(this->socket_, SIOCSIFFLAGS, &ifr) == -1) { + etiLog.printHeader(TcpLog::ERR, + "Can't turn down Farsync device!\n"); + perror(filename); + return -1; + } + } + } + + // Set the interface MTU if needed + etiLog.printHeader(TcpLog::DBG, "Get MTU.\n"); + if (ioctl(this->socket_, SIOCGIFMTU, &ifr) == -1) { + etiLog.printHeader(TcpLog::ERR, "Can't get Farsync MTU!\n"); + perror(filename); + return -1; + } else { + if (ifr.ifr_mtu != 6144) { + etiLog.printHeader(TcpLog::DBG, "Set MTU.\n"); + ifr.ifr_mtu = 6144; + if (ioctl(this->socket_, SIOCSIFMTU, &ifr) == -1) { + etiLog.printHeader(TcpLog::ERR, "Can't set Farsync MTU!\n"); + perror(filename); + return -1; + } + } + } + } + + // Set the interface up if needed + etiLog.printHeader(TcpLog::DBG, "Get flags.\n"); + if (ioctl(this->socket_, SIOCGIFFLAGS, &ifr) == -1) { + etiLog.printHeader(TcpLog::ERR, "Can't get raw device flags!\n"); + perror(filename); + return -1; + } else { + if (!(ifr.ifr_flags & IFF_UP)) { + ifr.ifr_flags |= IFF_UP; + etiLog.printHeader(TcpLog::DBG, "Set flags.\n"); + if (ioctl(this->socket_, SIOCSIFFLAGS, &ifr) == -1) { + etiLog.printHeader(TcpLog::ERR, "Can't turn up raw device!\n"); + perror(filename); + return -1; + } + } + } + + close(this->socket_); + + //////////////////// + // Opening device // + //////////////////// + + if ((this->socket_ = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_CUST))) == -1) { + etiLog.printHeader(TcpLog::ERR, "Are you logged as root?\n"); + perror(filename); + return -1; + } + + // ioctl to read the interface number + etiLog.printHeader(TcpLog::DBG, "Get index.\n"); + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_name, filename, sizeof(ifr.ifr_name)); + if (ioctl(this->socket_, SIOCGIFINDEX, (char *) &ifr) == -1) { + perror(filename); + return -1; + } + + // Bind to the interface name + etiLog.printHeader(TcpLog::DBG, "Bind interface.\n"); + memset(&saddr, 0, sizeof(struct sockaddr_ll)); + saddr.sll_family = AF_PACKET; + saddr.sll_protocol = ARPHRD_RAWHDLC; + saddr.sll_ifindex = ifr.ifr_ifindex; + if (bind(this->socket_, (struct sockaddr *) &saddr, sizeof(saddr)) == -1) { + etiLog.printHeader(TcpLog::ERR, "Can't bind raw device!\n"); + perror(filename); + return -1; + } +#endif + + return 0; +} + + +int DabOutputRaw::Write(void* buffer, int size) +{ + // Encoding data + memcpy(this->buffer_, buffer, size); + memset(this->buffer_ + size, 0x55, 6144 - size); + for (int i = 0; i < 6144; ++i) { + this->buffer_[i] = revTable[this->buffer_[i]]; + } + + // Writting data +#ifdef _WIN32 + DWORD result; + if(!DeviceIoControl(this->socket_, IoctlCodeTxFrame, this->buffer_, 6144, + NULL, 0, &result, NULL)) { + goto RAW_WRITE_ERROR; + } +#else + /* + if (write(this->socket_, this->buffer_ + 1, 6143) != 6143) { + goto RAW_WRITE_ERROR; + } + */ + if (this->isCyclades_) { + if (write(this->socket_, this->buffer_ + 1, 6143) != 6143) { + goto RAW_WRITE_ERROR; + } + } else { + int ret = send(this->socket_, this->buffer_, 6144, 0); + if (ret != 6144) { + fprintf(stderr, "%i/6144 bytes written\n", ret); + goto RAW_WRITE_ERROR; + } + } +#endif + + return size; + +RAW_WRITE_ERROR: +#ifdef _WIN32 + DWORD err = GetLastError(); + LPSTR errMsg; + if(FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + err, + 0, + (LPTSTR)&errMsg, + 0, + NULL) == 0) { + fprintf(stderr, "Error while writting to raw socket: %i\n", err); + } else { + fprintf(stderr, "Error while writting to raw socket: %s\n", errMsg); + LocalFree(errMsg); + } +#else + perror("Error while writting to raw socket"); +#endif + + return -1; +} + + +int DabOutputRaw::Close() +{ +#ifdef _WIN32 + CancelIo(this->socket_); + CloseHandle(this->socket_); + return 0; +#else + if (close(this->socket_) == 0) { + this->socket_ = -1; + return 0; + } + perror("Can't close raw socket"); +#endif + + return -1; +} + diff --git a/src/dabOutput/dabOutputSimul.cpp b/src/dabOutput/dabOutputSimul.cpp new file mode 100644 index 0000000..e53b4ba --- /dev/null +++ b/src/dabOutput/dabOutputSimul.cpp @@ -0,0 +1,70 @@ +#include "dabOutput.h" +#include +#include +#include +#include +#ifdef _WIN32 +# include +# ifdef __MINGW32__ +# define FS_DECLARE_CFG_ARRAYS +# include +# endif +# include +#else +# include +# include +# ifndef O_BINARY +# define O_BINARY 0 +# endif // O_BINARY +#endif + + +int DabOutputSimul::Open(const char* name) +{ +#ifdef _WIN32 + startTime_ = GetTickCount(); +#else + gettimeofday(&startTime_, NULL); +#endif + + return 0; +} + +int DabOutputSimul::Write(void* buffer, int size) +{ + unsigned long current; + unsigned long start; + unsigned long waiting; + +#ifdef _WIN32 + current = GetTickCount(); + start = this->startTime_; + if (current < start) { + waiting = start - current + 24; + Sleep(waiting); + } else { + waiting = 24 - (current - start); + if ((current - start) < 24) { + Sleep(waiting); + } + } + this->startTime_ += 24; +#else + timeval curTime; + gettimeofday(&curTime, NULL); + current = (1000000ul * curTime.tv_sec) + curTime.tv_usec; + start = (1000000ul * this->startTime_.tv_sec) + this->startTime_.tv_usec; + waiting = 24000ul - (current - start); + if ((current - start) < 24000ul) { + usleep(waiting); + } + + this->startTime_.tv_usec += 24000; + if (this->startTime_.tv_usec >= 1000000) { + this->startTime_.tv_usec -= 1000000; + ++this->startTime_.tv_sec; + } +#endif + + return size; +} diff --git a/src/dabOutput/dabOutputTcp.cpp b/src/dabOutput/dabOutputTcp.cpp new file mode 100644 index 0000000..a3d7a5a --- /dev/null +++ b/src/dabOutput/dabOutputTcp.cpp @@ -0,0 +1,154 @@ +#include +#include +#include +#include +#include "dabOutput.h" +#include "TcpServer.h" + +#ifdef _WIN32 +# include +# ifdef __MINGW32__ +# define FS_DECLARE_CFG_ARRAYS +# include +# endif +# include +#else +# include +# include +# ifndef O_BINARY +# define O_BINARY 0 +# endif // O_BINARY +#endif + +void* tcpThread(void* param) +{ + TcpSocket* client; + + DabOutputTcp* tcp = (DabOutputTcp*)param; + + while ((client = tcp->server->accept()) != NULL) { + etiLog.print(TcpLog::INFO, "TCP server got a new client.\n"); + if (tcp->client != NULL) { + delete tcp->client; + } + tcp->client = client; + } + etiLog.print(TcpLog::ERR, "TCP thread can't accept new client (%s)\n", + inetErrDesc, inetErrMsg); + + return NULL; +} + +int DabOutputTcp::Open(const char* name) +{ + char* hostport = strdup(name); // the name is actually an tuple host:port + + char* address; + long port; + address = strchr((char*)hostport, ':'); + if (address == NULL) { + etiLog.printHeader(TcpLog::ERR, + "\"%s\" is an invalid format for tcp address: " + "should be [address]:port - > aborting\n", + hostport); + goto tcp_open_fail; + } + + // terminate string hostport after the host, and advance address to the port number + *(address++) = 0; + + port = strtol(address, (char **)NULL, 10); + if ((port == LONG_MIN) || (port == LONG_MAX)) { + etiLog.printHeader(TcpLog::ERR, + "can't convert port number in tcp address %s\n", address); + goto tcp_open_fail; + } + if (port == 0) { + etiLog.printHeader(TcpLog::ERR, + "can't use port number 0 in tcp address\n"); + goto tcp_open_fail; + } + address = hostport; + if (strlen(address) > 0) { + if (this->server->create(port, address) == -1) { + etiLog.printHeader(TcpLog::ERR, "Can't create Tcp server on %s:%i " + "(%s: %s) -> aborting\n", + address, port, inetErrDesc, inetErrMsg); + goto tcp_open_fail; + } + } else { + if (this->server->create(port) == -1) { + etiLog.printHeader(TcpLog::ERR, "Can't create Tcp server on :%i " + "(%s: %s) -> aborting\n", + port, inetErrDesc, inetErrMsg); + goto tcp_open_fail; + } + } + + //sprintf(name, "%s:%i", this->packet_->getAddress().getHostAddress(), + // this->packet_->getAddress().getPort()); + + if (this->server->listen() == -1) { + etiLog.printHeader(TcpLog::ERR, "Can't listen on Tcp socket (%s: %s)\n", + inetErrDesc, inetErrMsg); + goto tcp_open_fail; + } +#ifdef _WIN32 + this->thread_ = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)tcpThread, this, 0, NULL); + if (this->thread_ == NULL) { + fprintf(stderr, "Can't create TCP child"); + goto tcp_open_fail; + } +#else + if (pthread_create(&this->thread_, NULL, tcpThread, this)) { + perror("Can't create TCP child"); + goto tcp_open_fail; + } +#endif + + return 0; + +tcp_open_fail: + free(hostport); + return -1; +} + + +int DabOutputTcp::Write(void* buffer, int size) +{ + + if (this->client != NULL) { + if (this->client->write(&size, 2) == 2) { + if (this->client->write(buffer, size) != size) { + return size; + } + } + else { + etiLog.print(TcpLog::INFO, "TCP server client disconnected.\n"); + delete this->client; + this->client = NULL; + } + } + return size; +} + + +int DabOutputTcp::Close() +{ + this->server->close(); + if( this->client != NULL ) + this->client->close(); +#ifdef WIN32 + DWORD status; + for (int i = 0; i < 5; ++i) { + if (GetExitCodeThread(this->thread_, &status)) { + break; + } + Sleep(100); + } + TerminateThread(this->thread_, 1); +#else + pthread_kill(this->thread_, SIGPIPE); +#endif + return 0; +} diff --git a/src/dabOutput/dabOutputUdp.cpp b/src/dabOutput/dabOutputUdp.cpp new file mode 100644 index 0000000..1410071 --- /dev/null +++ b/src/dabOutput/dabOutputUdp.cpp @@ -0,0 +1,82 @@ +#include +#include +#include +#include "dabOutput.h" +#include "UdpSocket.h" + +#ifdef _WIN32 +# include +# include +#else +# include +# include +# include +# include +# include +# include +# include +#endif + +int DabOutputUdp::Open(const char* name) +{ + // we are going to modify it + char* hostport = strdup(name); // the name is actually an tuple host:port + + char* address; + long port; + address = strchr(hostport, ':'); + if (address == NULL) { + etiLog.printHeader(TcpLog::ERR, + "\"%s\" is an invalid format for UDP address: " + "should be [address]:port - > aborting\n", + hostport); + goto udp_open_fail; + } + + // terminate string hostport after the host, and advance address to the port number + *(address++) = 0; + + port = strtol(address, (char **)NULL, 10); + if ((port == LONG_MIN) || (port == LONG_MAX)) { + etiLog.printHeader(TcpLog::ERR, + "can't convert port number in UDP address %s\n", address); + goto udp_open_fail; + } + if (port == 0) { + etiLog.printHeader(TcpLog::ERR, + "can't use port number 0 in UDP address\n"); + goto udp_open_fail; + } + address = hostport; + if (strlen(address) > 0) { + if (this->packet_->getAddress().setAddress(address) == -1) { + etiLog.printHeader(TcpLog::ERR, "can't set address %s (%s: %s) " + "-> aborting\n", address, inetErrDesc, inetErrMsg); + goto udp_open_fail; + } + } + this->packet_->getAddress().setPort(port); + + if (this->socket_->create() == -1) { + etiLog.printHeader(TcpLog::ERR, "can't create UDP socket (%s: %s) " + "-> aborting\n)", inetErrDesc, inetErrMsg); + goto udp_open_fail; + } + + //sprintf(hostport, "%s:%i", this->packet_->getAddress().getHostAddress(), + // this->packet_->getAddress().getPort()); + return 0; + +udp_open_fail: + // strdup forces us to free + free(hostport); + return -1; +} + + +int DabOutputUdp::Write(void* buffer, int size) +{ + this->packet_->setLength(0); + this->packet_->addData(buffer, size); + return this->socket_->send(*this->packet_); +} -- cgit v1.2.3