laforge
/
openbts-osmo
Archived
1
0
Fork 0
This repository has been archived on 2022-03-30. You can view files and clone it, but cannot push or open issues or pull requests.
openbts-osmo/public-trunk/CommonLibs/ConnectionSocketsTest.cpp

325 lines
7.6 KiB
C++

/*
* Copyright 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 "Sockets.h"
#include "Threads.h"
#include "Logger.h"
#include "Configuration.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <vector>
using namespace std;
ConfigurationTable gConfig;
static const int gNumToSend = 3;
static const int gIpBindPort = 22239;
static const char *gIpBindHost = "127.0.0.1";
//static const char *gIpBindHost = "0.0.0.0";
static const char *gUnixSocketPath = "/tmp/testUnixSock";
void reportError(const std::string &what, int errsv)
{
LOG(ERROR) << what << " failed with errno="
<< errsv << " (0x" << hex << errsv << dec << "): "
<< strerror(errsv);
}
void *ipServerClose(void *data)
{
ConnectionServerSocket *pServer = (ConnectionServerSocket*)data;
sleep(1);
pServer->close();
return NULL;
}
bool clientConnect(ConnectionSocket *conn)
{
int res = conn->connect();
if (res < 0) {
reportError("conn->connect()", errno);
conn->close();
return false;
}
return true;
}
bool clientWrite(ConnectionSocket *conn, const char *text)
{
std::string sendBuf = text;
LOG(INFO) << "Client sending: \"" << sendBuf << "\"";
uint32_t sendBufLength = htonl(sendBuf.length());
int bytesSent;
bytesSent = conn->write((const char *)&sendBufLength, 4);
if (bytesSent < 4) {
reportError("conn->write()", errno);
conn->close();
return false;
}
bytesSent = conn->write(sendBuf.data(), sendBuf.length());
if (bytesSent < sendBuf.length()) {
reportError("conn->write()", errno);
conn->close();
return false;
}
return true;
}
bool clientRead(ConnectionSocket *conn)
{
uint32_t recvDataLen;
char readBuf[1024];
int bytesReceived;
bytesReceived = conn->read(readBuf, 4);
if (bytesReceived < 4) {
reportError("conn->read()", errno);
conn->close();
return false;
}
recvDataLen = ntohl(*(uint32_t*)readBuf);
if (recvDataLen > 1024) {
recvDataLen = 1024;
}
bytesReceived = conn->read(readBuf, recvDataLen);
if (bytesReceived < recvDataLen) {
reportError("conn->read()", errno);
conn->close();
return false;
}
readBuf[bytesReceived>=sizeof(readBuf)?sizeof(readBuf)-1:bytesReceived]= '\0';
LOG(INFO) << "Client received: \"" << readBuf << "\"";
return true;
}
void *ipClient(void *)
{
for (int i=0; i<gNumToSend; i++)
{
ConnectionSocketTCP conn(gIpBindPort, gIpBindHost);
if (!clientConnect(&conn)) continue;
if (!clientWrite(&conn, "ping")) continue;
if (!clientRead(&conn)) continue;
conn.close();
usleep(500*1000);
}
// Shutdown server
ConnectionSocketTCP conn(gIpBindPort, gIpBindHost);
if (!clientConnect(&conn)) return NULL;
if (!clientWrite(&conn, "exit")) return NULL;
conn.close();
return NULL;
}
void *unixClient(void *)
{
for (int i=0; i<gNumToSend; i++)
{
ConnectionSocketUnix conn(gUnixSocketPath);
if (!clientConnect(&conn)) continue;
if (!clientWrite(&conn, "ping")) continue;
if (!clientRead(&conn)) continue;
conn.close();
usleep(500*1000);
}
// Shutdown server
ConnectionSocketUnix conn(gUnixSocketPath);
if (!clientConnect(&conn)) return NULL;
if (!clientWrite(&conn, "exit")) return NULL;
conn.close();
return NULL;
}
struct ConnectionPair {
ConnectionPair(ConnectionServerSocket *serv, ConnectionSocket *conn)
: serverSocket(serv)
, connectionSocket(conn)
{};
ConnectionServerSocket *serverSocket;
ConnectionSocket *connectionSocket;
};
void *serverConnThread(void *data)
{
ConnectionPair *pConnPair = (ConnectionPair*)data;
ConnectionSocket *pConn = pConnPair->connectionSocket;
ConnectionServerSocket *pServerSock = pConnPair->serverSocket;
delete pConnPair;
uint32_t recvDataLen;
char readBuf[1024];
int bytesReceived;
bytesReceived = pConn->read(readBuf, 4);
if (bytesReceived < 4) {
reportError("pConn->read()", errno);
pConn->close();
return NULL;
}
recvDataLen = ntohl(*(uint32_t*)readBuf);
if (recvDataLen > 1024) {
recvDataLen = 1024;
}
bytesReceived = pConn->read(readBuf, recvDataLen);
if (bytesReceived < recvDataLen) {
reportError("pConn->read()", errno);
pConn->close();
return NULL;
}
readBuf[bytesReceived>=sizeof(readBuf)?sizeof(readBuf)-1:bytesReceived]= '\0';
LOG(INFO) << "Server received: \"" << readBuf << "\"";
// Shutdown server is requested so.
if (strcmp(readBuf, "exit")==0) {
pConn->close();
pServerSock->close();
return NULL;
}
std::string sendBuf = "pong";
LOG(INFO) << "Server sending: \"" << sendBuf << "\"";
uint32_t sendBufLength = htonl(sendBuf.length());
int bytesSent;
bytesSent = pConn->write((const char *)&sendBufLength, 4);
if (bytesSent < 4) {
reportError("pConn->write()", errno);
pConn->close();
return NULL;
}
bytesSent = pConn->write(sendBuf.data(), sendBuf.length());
if (bytesSent < sendBuf.length()) {
reportError("pConn->write()", errno);
pConn->close();
return NULL;
}
// Wait for remote side to close connection to avoid TIME_WAIT on server side.
// Refer to http://hea-www.harvard.edu/~fine/Tech/addrinuse.html
bytesReceived = pConn->read(readBuf, 1);
pConn->close();
// This should be done in thread's destructor
delete pConn;
return NULL;
}
void serverBind(ConnectionServerSocket *serverSock)
{
if (!serverSock->bind()) {
reportError("serverSock->bind()", errno);
return;
}
}
void serverRun(ConnectionServerSocket *serverSock)
{
std::vector<Thread *> serverThreads;
while (1) {
ConnectionSocket *newConn = serverSock->accept();
if (newConn == NULL)
{
int errsv = errno;
if (errsv == EINVAL) {
LOG(INFO) << "serverSock has been closed.";
} else {
reportError("serverSock->accept()", errsv);
}
break;
}
LOG(INFO) << "New incoming connection " << newConn;
Thread *ipServerThread = new Thread();
LOG(INFO) << "New server thread: " << hex << ipServerThread << dec;
serverThreads.push_back(ipServerThread);
ipServerThread->start(serverConnThread, new ConnectionPair(serverSock, newConn));
}
// Stop server
serverSock->close();
// Clean up
Thread *ipServerThread;
while (serverThreads.size()) {
ipServerThread = serverThreads.back();
LOG(INFO) << "Removing server thread: " << hex << ipServerThread << dec;
ipServerThread->join();
delete ipServerThread;
serverThreads.pop_back();
}
}
int main(int argc, char * argv[] )
{
gLogInit("DEBUG");
LOG(INFO) << "Testing TCP sockets";
{
ConnectionServerSocketTCP serverSock(gIpBindPort, gIpBindHost);
Thread readerThreadIP;
serverBind(&serverSock);
readerThreadIP.start(ipClient, NULL);
serverRun(&serverSock);
readerThreadIP.join();
}
LOG(INFO) << "Testing UNIX sockets";
{
ConnectionServerSocketUnix serverSock(gUnixSocketPath);
Thread readerThreadIP;
serverBind(&serverSock);
readerThreadIP.start(unixClient, NULL);
serverRun(&serverSock);
readerThreadIP.join();
}
}
// vim: ts=4 sw=4