Transceiver: replace UDPSocket with libosmocore socket API
We have a good socket API in libosmocore, let's drop osmo-trx socket API and use libosmocore's one instead of maintaining the two of them. Change-Id: Ib19856a3e0a7607f63436c4a80b1381a3f318764
This commit is contained in:
parent
7dc07b9425
commit
b9d2515704
|
@ -30,7 +30,6 @@ noinst_LTLIBRARIES = libcommon.la
|
||||||
libcommon_la_SOURCES = \
|
libcommon_la_SOURCES = \
|
||||||
BitVector.cpp \
|
BitVector.cpp \
|
||||||
LinkedLists.cpp \
|
LinkedLists.cpp \
|
||||||
Sockets.cpp \
|
|
||||||
Threads.cpp \
|
Threads.cpp \
|
||||||
Timeval.cpp \
|
Timeval.cpp \
|
||||||
Logger.cpp \
|
Logger.cpp \
|
||||||
|
@ -45,7 +44,6 @@ noinst_HEADERS = \
|
||||||
PRBS.h \
|
PRBS.h \
|
||||||
Interthread.h \
|
Interthread.h \
|
||||||
LinkedLists.h \
|
LinkedLists.h \
|
||||||
Sockets.h \
|
|
||||||
Threads.h \
|
Threads.h \
|
||||||
Timeval.h \
|
Timeval.h \
|
||||||
Vector.h \
|
Vector.h \
|
||||||
|
|
|
@ -1,287 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2008, 2010 Free Software Foundation, Inc.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* This software is distributed under the terms of the GNU Affero Public License.
|
|
||||||
* See the COPYING file in the main directory for details.
|
|
||||||
*
|
|
||||||
* This use of this software may be subject to additional restrictions.
|
|
||||||
* See the LEGAL file in the main directory for details.
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU Affero General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program 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 Affero General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Affero General Public License
|
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#include <config.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <cstdio>
|
|
||||||
#include <sys/select.h>
|
|
||||||
|
|
||||||
#include "Threads.h"
|
|
||||||
#include "Sockets.h"
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool resolveAddress(struct sockaddr_in *address, const char *hostAndPort)
|
|
||||||
{
|
|
||||||
assert(address);
|
|
||||||
assert(hostAndPort);
|
|
||||||
char *copy = strdup(hostAndPort);
|
|
||||||
char *colon = strchr(copy,':');
|
|
||||||
if (!colon) return false;
|
|
||||||
*colon = '\0';
|
|
||||||
char *host = copy;
|
|
||||||
unsigned port = strtol(colon+1,NULL,10);
|
|
||||||
bool retVal = resolveAddress(address,host,port);
|
|
||||||
free(copy);
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool resolveAddress(struct sockaddr_in *address, const char *host, unsigned short port)
|
|
||||||
{
|
|
||||||
assert(address);
|
|
||||||
assert(host);
|
|
||||||
// FIXME -- Need to ignore leading/trailing spaces in hostname.
|
|
||||||
struct hostent *hp;
|
|
||||||
int h_errno_local;
|
|
||||||
#ifdef HAVE_GETHOSTBYNAME2_R
|
|
||||||
struct hostent hostData;
|
|
||||||
char tmpBuffer[2048];
|
|
||||||
|
|
||||||
// There are different flavors of gethostbyname_r(), but
|
|
||||||
// latest Linux use the following form:
|
|
||||||
if (gethostbyname2_r(host, AF_INET, &hostData, tmpBuffer, sizeof(tmpBuffer), &hp, &h_errno_local)!=0) {
|
|
||||||
CERR("WARNING -- gethostbyname2_r() failed for " << host << ", " << hstrerror(h_errno_local));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
static Mutex sGethostbynameMutex;
|
|
||||||
// gethostbyname() is NOT thread-safe, so we should use a mutex here.
|
|
||||||
// Ideally it should be a global mutex for all non thread-safe socket
|
|
||||||
// operations and it should protect access to variables such as
|
|
||||||
// global h_errno.
|
|
||||||
sGethostbynameMutex.lock();
|
|
||||||
hp = gethostbyname(host);
|
|
||||||
h_errno_local = h_errno;
|
|
||||||
sGethostbynameMutex.unlock();
|
|
||||||
#endif
|
|
||||||
if (hp==NULL) {
|
|
||||||
CERR("WARNING -- gethostbyname() failed for " << host << ", " << hstrerror(h_errno_local));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (hp->h_addrtype != AF_INET) {
|
|
||||||
CERR("WARNING -- gethostbyname() resolved " << host << " to something other then AF_INET");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
address->sin_family = hp->h_addrtype;
|
|
||||||
assert(sizeof(address->sin_addr) == hp->h_length);
|
|
||||||
memcpy(&(address->sin_addr), hp->h_addr_list[0], hp->h_length);
|
|
||||||
address->sin_port = htons(port);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
DatagramSocket::DatagramSocket()
|
|
||||||
{
|
|
||||||
memset(mDestination, 0, sizeof(mDestination));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void DatagramSocket::nonblocking()
|
|
||||||
{
|
|
||||||
fcntl(mSocketFD,F_SETFL,O_NONBLOCK);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DatagramSocket::blocking()
|
|
||||||
{
|
|
||||||
fcntl(mSocketFD,F_SETFL,0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DatagramSocket::close()
|
|
||||||
{
|
|
||||||
::close(mSocketFD);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
DatagramSocket::~DatagramSocket()
|
|
||||||
{
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int DatagramSocket::write( const char * message, size_t length )
|
|
||||||
{
|
|
||||||
assert(length<=MAX_UDP_LENGTH);
|
|
||||||
int retVal = sendto(mSocketFD, message, length, 0,
|
|
||||||
(struct sockaddr *)mDestination, addressSize());
|
|
||||||
if (retVal == -1 ) perror("DatagramSocket::write() failed");
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
int DatagramSocket::writeBack( const char * message, size_t length )
|
|
||||||
{
|
|
||||||
assert(length<=MAX_UDP_LENGTH);
|
|
||||||
int retVal = sendto(mSocketFD, message, length, 0,
|
|
||||||
(struct sockaddr *)mSource, addressSize());
|
|
||||||
if (retVal == -1 ) perror("DatagramSocket::write() failed");
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int DatagramSocket::write( const char * message)
|
|
||||||
{
|
|
||||||
size_t length=strlen(message)+1;
|
|
||||||
return write(message,length);
|
|
||||||
}
|
|
||||||
|
|
||||||
int DatagramSocket::writeBack( const char * message)
|
|
||||||
{
|
|
||||||
size_t length=strlen(message)+1;
|
|
||||||
return writeBack(message,length);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int DatagramSocket::send(const struct sockaddr* dest, const char * message, size_t length )
|
|
||||||
{
|
|
||||||
assert(length<=MAX_UDP_LENGTH);
|
|
||||||
int retVal = sendto(mSocketFD, message, length, 0, dest, addressSize());
|
|
||||||
if (retVal == -1 ) perror("DatagramSocket::send() failed");
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
int DatagramSocket::send(const struct sockaddr* dest, const char * message)
|
|
||||||
{
|
|
||||||
size_t length=strlen(message)+1;
|
|
||||||
return send(dest,message,length);
|
|
||||||
}
|
|
||||||
|
|
||||||
int DatagramSocket::read(char* buffer, size_t length)
|
|
||||||
{
|
|
||||||
socklen_t addr_len = sizeof(mSource);
|
|
||||||
int rd_length = recvfrom(mSocketFD, (void *) buffer, length, 0,
|
|
||||||
(struct sockaddr*) &mSource, &addr_len);
|
|
||||||
|
|
||||||
if ((rd_length==-1) && (errno!=EAGAIN)) {
|
|
||||||
perror("DatagramSocket::read() failed");
|
|
||||||
throw SocketError();
|
|
||||||
}
|
|
||||||
return rd_length;
|
|
||||||
}
|
|
||||||
|
|
||||||
int DatagramSocket::read(char* buffer, size_t length, unsigned timeout)
|
|
||||||
{
|
|
||||||
fd_set fds;
|
|
||||||
FD_ZERO(&fds);
|
|
||||||
FD_SET(mSocketFD,&fds);
|
|
||||||
struct timeval tv;
|
|
||||||
tv.tv_sec = timeout/1000;
|
|
||||||
tv.tv_usec = (timeout%1000)*1000;
|
|
||||||
int sel = select(mSocketFD+1,&fds,NULL,NULL,&tv);
|
|
||||||
if (sel<0) {
|
|
||||||
perror("DatagramSocket::read() select() failed");
|
|
||||||
throw SocketError();
|
|
||||||
}
|
|
||||||
if (sel==0) return -1;
|
|
||||||
if (FD_ISSET(mSocketFD,&fds)) return read(buffer, length);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
UDPSocket::UDPSocket(const char *wSrcIP, unsigned short wSrcPort)
|
|
||||||
:DatagramSocket()
|
|
||||||
{
|
|
||||||
open(wSrcPort, wSrcIP);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
UDPSocket::UDPSocket(const char *wSrcIP, unsigned short wSrcPort,
|
|
||||||
const char *wDestIP, unsigned short wDestPort)
|
|
||||||
:DatagramSocket()
|
|
||||||
{
|
|
||||||
open(wSrcPort, wSrcIP);
|
|
||||||
destination(wDestPort, wDestIP);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void UDPSocket::destination( unsigned short wDestPort, const char * wDestIP )
|
|
||||||
{
|
|
||||||
resolveAddress((sockaddr_in*)mDestination, wDestIP, wDestPort );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void UDPSocket::open(unsigned short localPort, const char *wlocalIP)
|
|
||||||
{
|
|
||||||
// create
|
|
||||||
mSocketFD = socket(AF_INET,SOCK_DGRAM,0);
|
|
||||||
if (mSocketFD<0) {
|
|
||||||
perror("socket() failed");
|
|
||||||
throw SocketError();
|
|
||||||
}
|
|
||||||
|
|
||||||
// pat added: This lets the socket be reused immediately, which is needed if OpenBTS crashes.
|
|
||||||
int on = 1;
|
|
||||||
setsockopt(mSocketFD, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
|
|
||||||
|
|
||||||
|
|
||||||
// bind
|
|
||||||
struct sockaddr_in address;
|
|
||||||
size_t length = sizeof(address);
|
|
||||||
bzero(&address,length);
|
|
||||||
address.sin_family = AF_INET;
|
|
||||||
address.sin_addr.s_addr = inet_addr(wlocalIP);
|
|
||||||
address.sin_port = htons(localPort);
|
|
||||||
if (bind(mSocketFD,(struct sockaddr*)&address,length)<0) {
|
|
||||||
perror("bind() failed");
|
|
||||||
throw SocketError();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
unsigned short UDPSocket::port() const
|
|
||||||
{
|
|
||||||
struct sockaddr_in name;
|
|
||||||
socklen_t nameSize = sizeof(name);
|
|
||||||
int retVal = getsockname(mSocketFD, (struct sockaddr*)&name, &nameSize);
|
|
||||||
if (retVal==-1) throw SocketError();
|
|
||||||
return ntohs(name.sin_port);
|
|
||||||
}
|
|
||||||
|
|
||||||
// vim:ts=4:sw=4
|
|
|
@ -1,173 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2008, 2010 Free Software Foundation, Inc.
|
|
||||||
*
|
|
||||||
* This software is distributed under the terms of the GNU Affero Public License.
|
|
||||||
* See the COPYING file in the main directory for details.
|
|
||||||
*
|
|
||||||
* This use of this software may be subject to additional restrictions.
|
|
||||||
* See the LEGAL file in the main directory for details.
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU Affero General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program 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 Affero General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Affero General Public License
|
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef SOCKETS_H
|
|
||||||
#define SOCKETS_H
|
|
||||||
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
#include <netdb.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/un.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <list>
|
|
||||||
#include <assert.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define MAX_UDP_LENGTH 1500
|
|
||||||
|
|
||||||
/** A function to resolve IP host names. */
|
|
||||||
bool resolveAddress(struct sockaddr_in *address, const char *host, unsigned short port);
|
|
||||||
|
|
||||||
/** Resolve an address of the form "<host>:<port>". */
|
|
||||||
bool resolveAddress(struct sockaddr_in *address, const char *hostAndPort);
|
|
||||||
|
|
||||||
/** An exception to throw when a critical socket operation fails. */
|
|
||||||
class SocketError {};
|
|
||||||
#define SOCKET_ERROR {throw SocketError(); }
|
|
||||||
|
|
||||||
/** Abstract class for connectionless sockets. */
|
|
||||||
class DatagramSocket {
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
int mSocketFD; ///< underlying file descriptor
|
|
||||||
char mDestination[256]; ///< address to which packets are sent
|
|
||||||
char mSource[256]; ///< return address of most recent received packet
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
/** An almost-does-nothing constructor. */
|
|
||||||
DatagramSocket();
|
|
||||||
|
|
||||||
virtual ~DatagramSocket();
|
|
||||||
|
|
||||||
/** Return the address structure size for this socket type. */
|
|
||||||
virtual size_t addressSize() const = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Send a binary packet.
|
|
||||||
@param buffer The data bytes to send to mDestination.
|
|
||||||
@param length Number of bytes to send, or strlen(buffer) if defaulted to -1.
|
|
||||||
@return number of bytes written, or -1 on error.
|
|
||||||
*/
|
|
||||||
int write( const char * buffer, size_t length);
|
|
||||||
|
|
||||||
/**
|
|
||||||
Send a C-style string packet.
|
|
||||||
@param buffer The data bytes to send to mDestination.
|
|
||||||
@return number of bytes written, or -1 on error.
|
|
||||||
*/
|
|
||||||
int write( const char * buffer);
|
|
||||||
|
|
||||||
/**
|
|
||||||
Send a binary packet.
|
|
||||||
@param buffer The data bytes to send to mSource.
|
|
||||||
@param length Number of bytes to send, or strlen(buffer) if defaulted to -1.
|
|
||||||
@return number of bytes written, or -1 on error.
|
|
||||||
*/
|
|
||||||
int writeBack(const char * buffer, size_t length);
|
|
||||||
|
|
||||||
/**
|
|
||||||
Send a C-style string packet.
|
|
||||||
@param buffer The data bytes to send to mSource.
|
|
||||||
@return number of bytes written, or -1 on error.
|
|
||||||
*/
|
|
||||||
int writeBack(const char * buffer);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Receive a packet.
|
|
||||||
@param buffer A char[MAX_UDP_LENGTH] procured by the caller.
|
|
||||||
@return The number of bytes received or -1 on non-blocking pass.
|
|
||||||
*/
|
|
||||||
int read(char* buffer, size_t length);
|
|
||||||
|
|
||||||
/**
|
|
||||||
Receive a packet with a timeout.
|
|
||||||
@param buffer A char[MAX_UDP_LENGTH] procured by the caller.
|
|
||||||
@param maximum wait time in milliseconds
|
|
||||||
@return The number of bytes received or -1 on timeout.
|
|
||||||
*/
|
|
||||||
int read(char* buffer, size_t length, unsigned timeout);
|
|
||||||
|
|
||||||
|
|
||||||
/** Send a packet to a given destination, other than the default. */
|
|
||||||
int send(const struct sockaddr *dest, const char * buffer, size_t length);
|
|
||||||
|
|
||||||
/** Send a C-style string to a given destination, other than the default. */
|
|
||||||
int send(const struct sockaddr *dest, const char * buffer);
|
|
||||||
|
|
||||||
/** Make the socket non-blocking. */
|
|
||||||
void nonblocking();
|
|
||||||
|
|
||||||
/** Make the socket blocking (the default). */
|
|
||||||
void blocking();
|
|
||||||
|
|
||||||
/** Close the socket. */
|
|
||||||
void close();
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** UDP/IP User Datagram Socket */
|
|
||||||
class UDPSocket : public DatagramSocket {
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
/** Open a USP socket with an OS-assigned port and no default destination. */
|
|
||||||
UDPSocket(const char *localIP, unsigned short localPort);
|
|
||||||
|
|
||||||
/** Given a full specification, open the socket and set the dest address. */
|
|
||||||
UDPSocket(const char *localIP, unsigned short localPort,
|
|
||||||
const char *remoteIP, unsigned short remotePort);
|
|
||||||
|
|
||||||
/** Set the destination port. */
|
|
||||||
void destination( unsigned short wDestPort, const char * wDestIP );
|
|
||||||
|
|
||||||
/** Return the actual port number in use. */
|
|
||||||
unsigned short port() const;
|
|
||||||
|
|
||||||
/** Open and bind the UDP socket to a local port. */
|
|
||||||
void open(unsigned short localPort=0, const char *wlocalIP="127.0.0.1");
|
|
||||||
|
|
||||||
/** Give the return address of the most recently received packet. */
|
|
||||||
const struct sockaddr_in* source() const { return (const struct sockaddr_in*)mSource; }
|
|
||||||
|
|
||||||
size_t addressSize() const { return sizeof(struct sockaddr_in); }
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// vim:ts=4:sw=4
|
|
|
@ -32,6 +32,7 @@ extern "C" {
|
||||||
#include "proto_trxd.h"
|
#include "proto_trxd.h"
|
||||||
|
|
||||||
#include <osmocom/core/bits.h>
|
#include <osmocom/core/bits.h>
|
||||||
|
#include <osmocom/core/socket.h>
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
|
@ -120,8 +121,7 @@ Transceiver::Transceiver(int wBasePort,
|
||||||
RadioInterface *wRadioInterface,
|
RadioInterface *wRadioInterface,
|
||||||
double wRssiOffset, int wStackSize)
|
double wRssiOffset, int wStackSize)
|
||||||
: mBasePort(wBasePort), mLocalAddr(TRXAddress), mRemoteAddr(GSMcoreAddress),
|
: mBasePort(wBasePort), mLocalAddr(TRXAddress), mRemoteAddr(GSMcoreAddress),
|
||||||
mClockSocket(TRXAddress, wBasePort, GSMcoreAddress, wBasePort + 100),
|
mClockSocket(-1), mTransmitLatency(wTransmitLatency), mRadioInterface(wRadioInterface),
|
||||||
mTransmitLatency(wTransmitLatency), mRadioInterface(wRadioInterface),
|
|
||||||
rssiOffset(wRssiOffset), stackSize(wStackSize),
|
rssiOffset(wRssiOffset), stackSize(wStackSize),
|
||||||
mSPSTx(tx_sps), mSPSRx(rx_sps), mChans(chans), mEdge(false), mOn(false), mForceClockInterface(false),
|
mSPSTx(tx_sps), mSPSRx(rx_sps), mChans(chans), mEdge(false), mOn(false), mForceClockInterface(false),
|
||||||
mTxFreq(0.0), mRxFreq(0.0), mTSC(0), mMaxExpectedDelayAB(0), mMaxExpectedDelayNB(0),
|
mTxFreq(0.0), mRxFreq(0.0), mTSC(0), mMaxExpectedDelayAB(0), mMaxExpectedDelayNB(0),
|
||||||
|
@ -142,14 +142,19 @@ Transceiver::~Transceiver()
|
||||||
|
|
||||||
sigProcLibDestroy();
|
sigProcLibDestroy();
|
||||||
|
|
||||||
|
if (mClockSocket >= 0)
|
||||||
|
close(mClockSocket);
|
||||||
|
|
||||||
for (size_t i = 0; i < mChans; i++) {
|
for (size_t i = 0; i < mChans; i++) {
|
||||||
mControlServiceLoopThreads[i]->cancel();
|
mControlServiceLoopThreads[i]->cancel();
|
||||||
mControlServiceLoopThreads[i]->join();
|
mControlServiceLoopThreads[i]->join();
|
||||||
delete mControlServiceLoopThreads[i];
|
delete mControlServiceLoopThreads[i];
|
||||||
|
|
||||||
mTxPriorityQueues[i].clear();
|
mTxPriorityQueues[i].clear();
|
||||||
delete mCtrlSockets[i];
|
if (mCtrlSockets[i] >= 0)
|
||||||
delete mDataSockets[i];
|
close(mCtrlSockets[i]);
|
||||||
|
if (mDataSockets[i] >= 0)
|
||||||
|
close(mDataSockets[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,8 +185,8 @@ bool Transceiver::init(FillerType filler, size_t rtsc, unsigned rach_delay,
|
||||||
mExtRACH = ext_rach;
|
mExtRACH = ext_rach;
|
||||||
mEdge = edge;
|
mEdge = edge;
|
||||||
|
|
||||||
mDataSockets.resize(mChans);
|
mDataSockets.resize(mChans, -1);
|
||||||
mCtrlSockets.resize(mChans);
|
mCtrlSockets.resize(mChans, -1);
|
||||||
mControlServiceLoopThreads.resize(mChans);
|
mControlServiceLoopThreads.resize(mChans);
|
||||||
mTxPriorityQueueServiceLoopThreads.resize(mChans);
|
mTxPriorityQueueServiceLoopThreads.resize(mChans);
|
||||||
mRxServiceLoopThreads.resize(mChans);
|
mRxServiceLoopThreads.resize(mChans);
|
||||||
|
@ -195,14 +200,30 @@ bool Transceiver::init(FillerType filler, size_t rtsc, unsigned rach_delay,
|
||||||
mStates[0].mRetrans = true;
|
mStates[0].mRetrans = true;
|
||||||
|
|
||||||
/* Setup sockets */
|
/* Setup sockets */
|
||||||
|
mClockSocket = osmo_sock_init2(AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP,
|
||||||
|
mLocalAddr.c_str(), mBasePort,
|
||||||
|
mRemoteAddr.c_str(), mBasePort + 100,
|
||||||
|
OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT);
|
||||||
|
|
||||||
for (size_t i = 0; i < mChans; i++) {
|
for (size_t i = 0; i < mChans; i++) {
|
||||||
c_srcport = mBasePort + 2 * i + 1;
|
c_srcport = mBasePort + 2 * i + 1;
|
||||||
c_dstport = mBasePort + 2 * i + 101;
|
c_dstport = mBasePort + 2 * i + 101;
|
||||||
d_srcport = mBasePort + 2 * i + 2;
|
d_srcport = mBasePort + 2 * i + 2;
|
||||||
d_dstport = mBasePort + 2 * i + 102;
|
d_dstport = mBasePort + 2 * i + 102;
|
||||||
|
|
||||||
mCtrlSockets[i] = new UDPSocket(mLocalAddr.c_str(), c_srcport, mRemoteAddr.c_str(), c_dstport);
|
mCtrlSockets[i] = osmo_sock_init2(AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP,
|
||||||
mDataSockets[i] = new UDPSocket(mLocalAddr.c_str(), d_srcport, mRemoteAddr.c_str(), d_dstport);
|
mLocalAddr.c_str(), c_srcport,
|
||||||
|
mRemoteAddr.c_str(), c_dstport,
|
||||||
|
OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT);
|
||||||
|
if (mCtrlSockets[i] < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
mDataSockets[i] = osmo_sock_init2(AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP,
|
||||||
|
mLocalAddr.c_str(), d_srcport,
|
||||||
|
mRemoteAddr.c_str(), d_dstport,
|
||||||
|
OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT);
|
||||||
|
if (mCtrlSockets[i] < 0)
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Randomize the central clock */
|
/* Randomize the central clock */
|
||||||
|
@ -707,9 +728,11 @@ void Transceiver::driveControl(size_t chan)
|
||||||
int msgLen;
|
int msgLen;
|
||||||
|
|
||||||
/* Attempt to read from control socket */
|
/* Attempt to read from control socket */
|
||||||
msgLen = mCtrlSockets[chan]->read(buffer, MAX_PACKET_LENGTH);
|
msgLen = read(mCtrlSockets[chan], buffer, MAX_PACKET_LENGTH);
|
||||||
if (msgLen < 1)
|
if (msgLen <= 0) {
|
||||||
|
LOGCHAN(chan, DTRXCTRL, WARNING) << "mCtrlSockets read(" << mCtrlSockets[chan] << ") failed: " << msgLen;
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* Zero-terminate received string */
|
/* Zero-terminate received string */
|
||||||
buffer[msgLen] = '\0';
|
buffer[msgLen] = '\0';
|
||||||
|
@ -854,16 +877,23 @@ void Transceiver::driveControl(size_t chan)
|
||||||
}
|
}
|
||||||
|
|
||||||
LOGCHAN(chan, DTRXCTRL, INFO) << "response is '" << response << "'";
|
LOGCHAN(chan, DTRXCTRL, INFO) << "response is '" << response << "'";
|
||||||
mCtrlSockets[chan]->write(response, strlen(response) + 1);
|
msgLen = write(mCtrlSockets[chan], response, strlen(response) + 1);
|
||||||
|
if (msgLen <= 0)
|
||||||
|
LOGCHAN(chan, DTRXCTRL, WARNING) << "mCtrlSockets write(" << mCtrlSockets[chan] << ") failed: " << msgLen;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Transceiver::driveTxPriorityQueue(size_t chan)
|
bool Transceiver::driveTxPriorityQueue(size_t chan)
|
||||||
{
|
{
|
||||||
|
int msgLen;
|
||||||
int burstLen;
|
int burstLen;
|
||||||
char buffer[EDGE_BURST_NBITS + 50];
|
char buffer[EDGE_BURST_NBITS + 50];
|
||||||
|
|
||||||
// check data socket
|
// check data socket
|
||||||
size_t msgLen = mDataSockets[chan]->read(buffer, sizeof(buffer));
|
msgLen = read(mDataSockets[chan], buffer, sizeof(buffer));
|
||||||
|
if (msgLen <= 0) {
|
||||||
|
LOGCHAN(chan, DTRXCTRL, WARNING) << "mDataSockets read(" << mCtrlSockets[chan] << ") failed: " << msgLen;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (msgLen == gSlotLen + 1 + 4 + 1) {
|
if (msgLen == gSlotLen + 1 + 4 + 1) {
|
||||||
burstLen = gSlotLen;
|
burstLen = gSlotLen;
|
||||||
|
@ -937,6 +967,7 @@ void Transceiver::logRxBurst(size_t chan, const struct trx_ul_burst_ind *bi)
|
||||||
|
|
||||||
void Transceiver::driveReceiveFIFO(size_t chan)
|
void Transceiver::driveReceiveFIFO(size_t chan)
|
||||||
{
|
{
|
||||||
|
int msgLen;
|
||||||
int TOAint; // in 1/256 symbols
|
int TOAint; // in 1/256 symbols
|
||||||
|
|
||||||
struct trx_ul_burst_ind bi;
|
struct trx_ul_burst_ind bi;
|
||||||
|
@ -963,7 +994,9 @@ void Transceiver::driveReceiveFIFO(size_t chan)
|
||||||
/* +1: Historical reason. There's an uninitizalied byte in there: pkt->soft_bits[bi.nbits] */
|
/* +1: Historical reason. There's an uninitizalied byte in there: pkt->soft_bits[bi.nbits] */
|
||||||
pkt->soft_bits[bi.nbits + 1] = '\0';
|
pkt->soft_bits[bi.nbits + 1] = '\0';
|
||||||
|
|
||||||
mDataSockets[chan]->write(burstString, sizeof(struct trxd_hdr_v0) + bi.nbits + 2);
|
msgLen = write(mDataSockets[chan], burstString, sizeof(struct trxd_hdr_v0) + bi.nbits + 2);
|
||||||
|
if (msgLen <= 0)
|
||||||
|
LOGCHAN(chan, DTRXCTRL, WARNING) << "mDataSockets write(" << mCtrlSockets[chan] << ") failed: " << msgLen;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transceiver::driveTxFIFO()
|
void Transceiver::driveTxFIFO()
|
||||||
|
@ -1023,13 +1056,16 @@ void Transceiver::driveTxFIFO()
|
||||||
|
|
||||||
void Transceiver::writeClockInterface()
|
void Transceiver::writeClockInterface()
|
||||||
{
|
{
|
||||||
|
int msgLen;
|
||||||
char command[50];
|
char command[50];
|
||||||
// FIXME -- This should be adaptive.
|
// FIXME -- This should be adaptive.
|
||||||
sprintf(command,"IND CLOCK %llu",(unsigned long long) (mTransmitDeadlineClock.FN()+2));
|
sprintf(command,"IND CLOCK %llu",(unsigned long long) (mTransmitDeadlineClock.FN()+2));
|
||||||
|
|
||||||
LOG(INFO) << "ClockInterface: sending " << command;
|
LOG(INFO) << "ClockInterface: sending " << command;
|
||||||
|
|
||||||
mClockSocket.write(command, strlen(command) + 1);
|
msgLen = write(mClockSocket, command, strlen(command) + 1);
|
||||||
|
if (msgLen <= 0)
|
||||||
|
LOG(WARNING) << "mClockSocket write(" << mClockSocket << ") failed: " << msgLen;
|
||||||
|
|
||||||
mLastClockUpdateTime = mTransmitDeadlineClock;
|
mLastClockUpdateTime = mTransmitDeadlineClock;
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,6 @@
|
||||||
#include "radioInterface.h"
|
#include "radioInterface.h"
|
||||||
#include "Interthread.h"
|
#include "Interthread.h"
|
||||||
#include "GSMCommon.h"
|
#include "GSMCommon.h"
|
||||||
#include "Sockets.h"
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
@ -167,9 +166,9 @@ private:
|
||||||
std::string mLocalAddr;
|
std::string mLocalAddr;
|
||||||
std::string mRemoteAddr;
|
std::string mRemoteAddr;
|
||||||
|
|
||||||
std::vector<UDPSocket *> mDataSockets; ///< socket for writing to/reading from GSM core
|
std::vector<int> mDataSockets; ///< socket for writing to/reading from GSM core
|
||||||
std::vector<UDPSocket *> mCtrlSockets; ///< socket for writing/reading control commands from GSM core
|
std::vector<int> mCtrlSockets; ///< socket for writing/reading control commands from GSM core
|
||||||
UDPSocket mClockSocket; ///< socket for writing clock updates to GSM core
|
int mClockSocket; ///< socket for writing clock updates to GSM core
|
||||||
|
|
||||||
std::vector<VectorQueue> mTxPriorityQueues; ///< priority queue of transmit bursts received from GSM core
|
std::vector<VectorQueue> mTxPriorityQueues; ///< priority queue of transmit bursts received from GSM core
|
||||||
std::vector<VectorFIFO *> mReceiveFIFO; ///< radioInterface FIFO of receive bursts
|
std::vector<VectorFIFO *> mReceiveFIFO; ///< radioInterface FIFO of receive bursts
|
||||||
|
|
|
@ -6,7 +6,6 @@ AM_LDFLAGS = $(LIBOSMOCORE_LIBS) $(LIBOSMOCTRL_LIBS) $(LIBOSMOVTY_LIBS)
|
||||||
EXTRA_DIST = BitVectorTest.ok \
|
EXTRA_DIST = BitVectorTest.ok \
|
||||||
PRBSTest.ok \
|
PRBSTest.ok \
|
||||||
InterthreadTest.ok \
|
InterthreadTest.ok \
|
||||||
SocketsTest.ok \
|
|
||||||
TimevalTest.ok \
|
TimevalTest.ok \
|
||||||
VectorTest.ok \
|
VectorTest.ok \
|
||||||
LogTest.ok \
|
LogTest.ok \
|
||||||
|
@ -16,7 +15,6 @@ noinst_PROGRAMS = \
|
||||||
BitVectorTest \
|
BitVectorTest \
|
||||||
PRBSTest \
|
PRBSTest \
|
||||||
InterthreadTest \
|
InterthreadTest \
|
||||||
SocketsTest \
|
|
||||||
TimevalTest \
|
TimevalTest \
|
||||||
VectorTest \
|
VectorTest \
|
||||||
LogTest
|
LogTest
|
||||||
|
@ -30,10 +28,6 @@ InterthreadTest_SOURCES = InterthreadTest.cpp
|
||||||
InterthreadTest_LDADD = $(COMMON_LA)
|
InterthreadTest_LDADD = $(COMMON_LA)
|
||||||
InterthreadTest_LDFLAGS = -lpthread $(AM_LDFLAGS)
|
InterthreadTest_LDFLAGS = -lpthread $(AM_LDFLAGS)
|
||||||
|
|
||||||
SocketsTest_SOURCES = SocketsTest.cpp
|
|
||||||
SocketsTest_LDADD = $(COMMON_LA)
|
|
||||||
SocketsTest_LDFLAGS = -lpthread $(AM_LDFLAGS)
|
|
||||||
|
|
||||||
TimevalTest_SOURCES = TimevalTest.cpp
|
TimevalTest_SOURCES = TimevalTest.cpp
|
||||||
TimevalTest_LDADD = $(COMMON_LA)
|
TimevalTest_LDADD = $(COMMON_LA)
|
||||||
|
|
||||||
|
|
|
@ -1,101 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2008 Free Software Foundation, Inc.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* This software is distributed under the terms of the GNU Affero Public License.
|
|
||||||
* See the COPYING file in the main directory for details.
|
|
||||||
*
|
|
||||||
* This use of this software may be subject to additional restrictions.
|
|
||||||
* See the LEGAL file in the main directory for details.
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU Affero General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program 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 Affero General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Affero General Public License
|
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#include "Sockets.h"
|
|
||||||
#include "Threads.h"
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <signal.h>
|
|
||||||
|
|
||||||
static const int gNumToSend = 10;
|
|
||||||
|
|
||||||
static void sigalarm_handler(int foo)
|
|
||||||
{
|
|
||||||
printf("FAIL: test did not run successfully\n");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
void *testReaderIP(void *param)
|
|
||||||
{
|
|
||||||
UDPSocket *readSocket = (UDPSocket *)param;
|
|
||||||
readSocket->nonblocking();
|
|
||||||
int rc = 0;
|
|
||||||
while (rc<gNumToSend) {
|
|
||||||
char buf[MAX_UDP_LENGTH+1] = { 0 };
|
|
||||||
int count = readSocket->read(buf, MAX_UDP_LENGTH);
|
|
||||||
if (count>0) {
|
|
||||||
buf[count] = 0;
|
|
||||||
CERR("read: " << buf);
|
|
||||||
rc++;
|
|
||||||
} else {
|
|
||||||
sleep(2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char * argv[] )
|
|
||||||
{
|
|
||||||
int count;
|
|
||||||
|
|
||||||
if (signal(SIGALRM, sigalarm_handler) == SIG_ERR) {
|
|
||||||
perror("signal");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If the test takes longer than 2*gNumToSend seconds, abort it */
|
|
||||||
alarm(2* gNumToSend);
|
|
||||||
|
|
||||||
UDPSocket readSocket("127.0.0.1", 0);
|
|
||||||
UDPSocket socket1("127.0.0.1", 0, "localhost", readSocket.port());
|
|
||||||
|
|
||||||
CERR("socket1: " << socket1.port() << ", readSocket: " << readSocket.port());
|
|
||||||
|
|
||||||
Thread readerThreadIP;
|
|
||||||
readerThreadIP.start(testReaderIP, &readSocket);
|
|
||||||
|
|
||||||
// give the readers time to open
|
|
||||||
sleep(1);
|
|
||||||
|
|
||||||
for (int i=0; i<gNumToSend; i++) {
|
|
||||||
CERR("write");
|
|
||||||
count = socket1.write("Hello IP land");
|
|
||||||
if (count < 0) {
|
|
||||||
COUT("FAIL: write");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
sleep(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
readerThreadIP.join();
|
|
||||||
|
|
||||||
printf("Done\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
// vim: ts=4 sw=4
|
|
|
@ -1 +0,0 @@
|
||||||
Done
|
|
|
@ -32,12 +32,6 @@ cat $abs_srcdir/CommonLibs/PRBSTest.ok > expout
|
||||||
AT_CHECK([$abs_top_builddir/tests/CommonLibs/PRBSTest], [], [expout], [])
|
AT_CHECK([$abs_top_builddir/tests/CommonLibs/PRBSTest], [], [expout], [])
|
||||||
AT_CLEANUP
|
AT_CLEANUP
|
||||||
|
|
||||||
AT_SETUP([SocketsTest])
|
|
||||||
AT_KEYWORDS([SocketsTest])
|
|
||||||
cat $abs_srcdir/CommonLibs/SocketsTest.ok > expout
|
|
||||||
AT_CHECK([$abs_top_builddir/tests/CommonLibs/SocketsTest], [], [expout], [ignore])
|
|
||||||
AT_CLEANUP
|
|
||||||
|
|
||||||
AT_SETUP([TimevalTest])
|
AT_SETUP([TimevalTest])
|
||||||
AT_KEYWORDS([TimevalTest])
|
AT_KEYWORDS([TimevalTest])
|
||||||
cat $abs_srcdir/CommonLibs/TimevalTest.ok > expout
|
cat $abs_srcdir/CommonLibs/TimevalTest.ok > expout
|
||||||
|
|
Loading…
Reference in New Issue