CryptoPP: how to use SocketSource and SocketSink - c++

I'm trying to send a string via SocketSource and SocketSink. But somehow it won't work properly. I simply want to send it from my server to the client. Here's the code:
Server:
CryptoPP::Socket server;
CryptoPP::Socket client;
sockaddr_in client_sadr;
CryptoPP::socklen_t size_sock = sizeof(sockaddr_in);
timeval timev = {3, 0};
std::string test("a simple test");
CryptoPP::Socket::StartSockets();
server.Create(SOCK_STREAM);
server.Bind(4213, NULL);
server.Listen();
server.Accept(client, (sockaddr*)&client_sadr, &size_sock);
std::cout << "Client connected" << std::endl;
while (!client.SendReady(&timev));
CryptoPP::StringSource ss(test, true, new CryptoPP::SocketSink(client));
std::cout << "Data sent" << std::endl;
std::cin.ignore();
client.CloseSocket();
server.CloseSocket();
CryptoPP::Socket::ShutdownSockets();
Client:
CryptoPP::Socket client;
CryptoPP::socklen_t size_sock = sizeof(sockaddr_in);
timeval timev = {3, 0};
std::string test;
Socket::StartSockets();
client.Create(SOCK_STREAM);
client.Connect("127.0.0.1", 4213);
std::cout << "connected" << std::endl;
while (!client.ReceiveReady(&timev));
CryptoPP::SocketSource(client, true, new StringSink(test));
std::cout << test << std::endl;
std::cin.ignore();
client.CloseSocket();
Socket::ShutdownSockets();
What happens now: The connection is established as wished, and the server sends the data, the client receives it and waits at cin.ignore(). But the server seemes to hang up while sending, because it won't print "Data send". It only does this, when the client closes the connection.
My question now is, am I doing something wrong, or is this just the normal behavior of SocketSource and SocketSink and i have to reconnect everytime...
Thanks for your help :)

The following is from test.cpp. It might give you some ideas. I don't recall reading on how to use them (and I've never used them in a program). Its the only place I've ever seen PumpAll2 and non-blocking used.
You might find they work better on Windows than Linux.
void ForwardTcpPort(const char *sourcePortName, const char *destinationHost,
const char *destinationPortName)
{
SocketsInitializer sockInit;
Socket sockListen, sockSource, sockDestination;
int sourcePort = Socket::PortNameToNumber(sourcePortName);
int destinationPort = Socket::PortNameToNumber(destinationPortName);
sockListen.Create();
sockListen.Bind(sourcePort);
setsockopt(sockListen, IPPROTO_TCP, TCP_NODELAY, "\x01", 1);
cout << "Listing on port " << sourcePort << ".\n";
sockListen.Listen();
sockListen.Accept(sockSource);
cout << "Connection accepted on port " << sourcePort << ".\n";
sockListen.CloseSocket();
cout << "Making connection to " << destinationHost << ", port " << destinationPort << ".\n";
sockDestination.Create();
sockDestination.Connect(destinationHost, destinationPort);
cout << "Connection made to " << destinationHost << ", starting to forward.\n";
SocketSource out(sockSource, false, new SocketSink(sockDestination));
SocketSource in(sockDestination, false, new SocketSink(sockSource));
WaitObjectContainer waitObjects;
while (!(in.SourceExhausted() && out.SourceExhausted()))
{
waitObjects.Clear();
out.GetWaitObjects(waitObjects, CallStack("ForwardTcpPort - out", NULL));
in.GetWaitObjects(waitObjects, CallStack("ForwardTcpPort - in", NULL));
waitObjects.Wait(INFINITE_TIME);
if (!out.SourceExhausted())
{
cout << "o" << flush;
out.PumpAll2(false);
if (out.SourceExhausted())
cout << "EOF received on source socket.\n";
}
if (!in.SourceExhausted())
{
cout << "i" << flush;
in.PumpAll2(false);
if (in.SourceExhausted())
cout << "EOF received on destination socket.\n";
}
}
}

Related

How can I send socket id through pthread?

I have a server in a raspberry pi, and want to allow multithreading. The server is working. The client is in windows.
I believe I need to send the socket id through the pthread_create, but haven't found how. Is there anything else I need to send?
What is the best way to do it?
I've searched the internet, stackoverflow included, and tryed some resolutions, but they didn't work.
const int PORT = 12000;
TCPServer tcp;
pthread_t my_thread[MAXCLIENTQUEUE];
int clientID = 0;
int main()
{
tcp.setup(PORT);
int clientQueueSize = 0, threadJoin = 0;
void *res;
do {
socklen_t sosize = sizeof(tcp.clientAddress);
//realizar o accept
tcp.newsockfd[clientQueueSize] = accept(tcp.sockfd, (struct sockaddr*) & tcp.clientAddress, &sosize);
if (tcp.newsockfd[clientQueueSize] == -1)
{
cout << "Error accepting -> " << tcp.newsockfd[clientQueueSize] << endl;
tcp.detach();
}
cout << ">- accept: " << strerror(errno) << " / codigo: " << tcp.newsockfd[clientQueueSize] << " - Endereco: " << inet_ntoa(tcp.clientAddress.sin_addr) << endl;
clientID++;
cout << ">>> client accepted" << " | Client ID: " << clientID << endl;
// criar threads
int ret = pthread_create(&my_thread[clientQueueSize], NULL, messenger, &tcp.newsockfd[clientQueueSize]);
cout << ">- pthread: " << strerror(errno) << " / codigo: " << ret << endl;
if (ret != 0) {
cout << "Error: pthread_create() failed\n" << "thread_n " << my_thread[clientQueueSize] << endl;
exit(EXIT_FAILURE);
}
cout << "thread n " << my_thread[clientQueueSize] << endl;
clientQueueSize++;
}
while (clientQueueSize < MAXCLIENTQUEUE);
pthread_exit(NULL);
return 0;
}
The server accepts multiple connections but only sends messages to the first client, the others connected successfully, but never receive messages.
I want for the server to be able to send messages to all the clients.
You have to create threads for all sockets.
Or, use Windows-depended async select methods.
P.S. Forget pthreads and use the standard std::thread.
map<SOCKET,std::string> clients;
void newclient(SOCKET x)
{
for(;;)
{
int r = recv(x,...);
if (r == 0 || r == -1)
break;
}
// remove it from clients, ensure proper synchronization
}
void server()
{
SOCKET x = socket(...);
bind(x,...);
listen(x,...);
for(;;)
{
auto s = accept(x,...);
if (s == INVALID_SOCKET)
break;
// save to a map, for example, after ensuring sync with a mutex and a lock guard
m[s] = "some_id";
std::thread t(newclient,s);
s.detach();
}
}
int main() //
{
// WSAStartup and other init
std::thread t(server);
t.detach();
// Message Loop or other GUI
}

Function recv from browser socket, but stores nothing in buffer

I need to receive a HTTP request from my browser, when I run localhost:8228 it works fine, I receive the header in the buffer and am able to write it to the console and even echo send it back to the browser. But when I try reading a request from a actual webpage, buffer is empty, it prints nothing.
I have a simple main that looks like this:
int main (int argc, char *argv[]) {
char buffer[1024*1024] = {0};
int port_number = 8228;
if (argc == 1)
std::cout << "Using default port number, 8228." << std::endl;
else if (argc == 3) {
port_number = atoi(argv[2]);
} else {
std::cout << "::Error::" << std::endl;
std::cout << "Wrong number of arguments." << std::endl;
exit[0];
}
AppSocket app;
app.Start((int)port_number);
app.AcceptCall();
int request_size = app.ReceiveRequest(buffer, sizeof(buffer));
return 0;
}
My AppSocket functions would be:
void AppSocket::Start(int port) {
// Create a socket
listening_fd = socket(AF_INET, SOCK_STREAM, 0);
if (listening_fd == -1) {
std::cerr << "Could not create a socket." << std::endl;
exit(-1);
}
app_hint.sin_family = AF_INET;
app_hint.sin_port = htons(port);
inet_pton(AF_INET, "127.0.0.1", &app_hint.sin_addr);
if (bind(listening_fd, (sockaddr*)&app_hint, sizeof(app_hint))< 0) {
std::cerr << "Cannot bind to IP/port." << std::endl;
exit(-2);
}
std::cout << "Socket has been bound." << std::endl;
if (listen(listening_fd, SOMAXCONN) == -1) {
std::cerr << "Cannot listen." << std::endl;
exit(-3);
}
std::cout << "Listening to port " << port << std::endl;
std::cout << "Your socket is: " << listening_fd << std::endl;
}
void AppSocket::AcceptCall() {
client_size = sizeof(client_addr);
client_fd =
accept(listening_fd, (sockaddr *)&client_addr, &client_size);
if (client_fd < 0) {
std::cerr << "Error connecting to client." << std::endl;
exit(-4);
}
std::cout << inet_ntoa(client_addr.sin_addr)
<< " connected to port "
<< ntohs(client_addr.sin_port) << std::endl;
close(listening_fd);
}
int AppSocket::ReceiveRequest(char *buffer, int max) {
std::cout << "Client is: " << client_fd << std::endl;
memset(buffer, 0, buff_size); //clear buffer
int n = recv(client_fd, buffer, buff_size, 0);
if (n < 0)
std::cerr << "A connection issue has occured." << std::endl;
if (n == 0)
std::cout << "Client disconected." << std::endl;
std::cout << "recv return " << n << std::endl;
std::cout << buffer << std::endl;
return n;
}
When I run and access a webpage I get this:
Using default port number, 8228.
Socket has been bound.
Listening to port 8228
Your socket is: 3
127.0.0.1 connected to port 37522
Client is: 4
recv return 3
None of the questions I've read seem to work for me...
edit: sorry one of the lines in the main code wasn't copied.
How can I receive repeatedly? A while loop? I tried that and just kept receiving nothing.
The code works, what was happening is that the firefox proxy settings were wrong, when I ran localhosts it worked fine because it was actually working as the server due to the port it was using but when trying to access a "real" website it didn't. After configuring it correctly it did just what it's supposed to do.

Multiple connections sockets c++

I'm trying to implement my own server and client side which uses sockets to send and receive data. But i got some problem with realization of multi-threading.
My server.cpp:
#include <iostream>
#include <netinet/in.h>
#include <cstring>
#include <arpa/inet.h>
#include <unistd.h>
#include <thread>
using namespace std;
void connection_handler(int socket) {
char client_message[256];
memset(&client_message, 0, 256);
size_t message_size = 0;
while ((message_size = recv(socket, client_message, sizeof(client_message) - 1, 0)) > 0) {
client_message[message_size] = '\0';
cout << "[Server] Client message accepted" << endl;
cout << "[Server] Client message: " << client_message << endl;
if (write(socket, client_message, message_size) == -1) {
cout << "[Client] Message sending failed" << endl;
return;
}
cout << "[Server] Message sent to client" << endl << endl;
cout << "============================" << endl << endl;
cout.flush();
memset(&client_message, 0, 256);
}
}
int main() {
unsigned short int PORT = 8080;
int listener, client_socket;
socklen_t client_len;
struct sockaddr_in server_address{};
memset(&server_address, 0, sizeof(server_address));
listener = socket(AF_INET, SOCK_STREAM, 0);
server_address.sin_family = AF_INET;
server_address.sin_port = htons(PORT);
if (inet_aton("127.0.0.1", &server_address.sin_addr) == 0) {
cout << "[Server] Invalid IP address" << endl;
return -1;
}
if (bind(listener, (struct sockaddr*) &server_address, sizeof(server_address)) == -1) {
cout << "[Server] Binding failed" << endl;
return -1;
}
cout << "[Server] All setting are done" << endl;
cout << "[Server] Server enabled" << endl;
if (listen(listener, 100) == -1) {
cout << "[Server] Listening failed" << endl;
return -1;
}
cout << "[Server] Waiting for connection..." << endl;
for (; ;) {
client_socket = accept(listener, (struct sockaddr*) &server_address, &client_len);
cout << "[Server] Connection accepted" << endl << endl;
cout << "----------------------------" << endl << endl;
int new_socket = client_socket;
thread handling_thread(connection_handler, new_socket);
handling_thread.detach();
}
}
My client.cpp:
#include <iostream>
#include <netinet/in.h>
#include <cstring>
#include <arpa/inet.h>
#include <unistd.h>
using namespace std;
int main() {
unsigned short int PORT = 8080;
int sockfd;
char buffer[256] = {0};
struct sockaddr_in server_address{};
sockfd = socket(AF_INET, SOCK_STREAM, 0);
memset(&server_address, '0', sizeof(server_address));
server_address.sin_family = AF_INET;
server_address.sin_port = htons(PORT);
server_address.sin_addr.s_addr = INADDR_ANY;
if (connect(sockfd, (struct sockaddr*) &server_address, sizeof(server_address)) < 0) {
cout << "[Client] Connection failed" << endl;
return -1;
}
cout << "[Client] All setting are done" << endl;
cout << "[Client] Succefully connected to server" << endl << endl;
cout << "----------------------------" << endl << endl;
while (true) {
string client_request;
cout << "[Client] Enter a message: ";
getline(cin, client_request);
if (client_request == "-1") {
write(sockfd, client_request.c_str(), client_request.size());
close(sockfd);
cout << endl << "[Client] Client exited" << endl;
return 0;
}
if (write(sockfd, client_request.c_str(), client_request.size()) == -1) {
cout << "[Client] Message sending failed" << endl;
}
cout << "[Client] Message sent to server" << endl;
memset(&buffer, 0, 256);
read(sockfd, buffer, 256);
cout << "[Client] Server message: " << buffer << endl << endl;
cout << "============================" << endl << endl;
cout.flush();
}
}
It's perfectly working until i create one more connection to server and after that second client cans send and receive data, but first one at this time becomes not working.
I compiled my program like this: g++ server.cpp -lpthread -o server -std=c++11 And then in other console tab run my compiled client.cpp: ./client.
To check multi-threading working i run client one more time (in other tab again) and trying send requests in two tabs at the same time.
I want to realize multi-threading in my program. How can i do this?
UPD: I'm using Linux
UPD2: Problem solved. Fixed code there.
int new_socket = client_socket;
thread handling_thread(connection_handler, &new_socket);
handling_thread.detach();
}
This initializes new_socket, which gets declared in local scope inside this for loop, then passes the pointer to this new_socket to a new thread that gets started, and detached. Immediately after that, this for loop iteration ends, which destroys the new_socket object, before starting the next iteration of this loop.
Meanwhile, the execution thread repeatedly attempts to dereference the int * it receives, which now points to a destroyed object. This results in undefined behavior, and the likely reason your program is "not working".
The most simple solution is to create the int socket value in dynamic scope, using new, and then pass the pointer to this newed socket value to the execution thread. The execution thread will, of course, be responsible for retrieving the socket value, then properly deleteing it, to avoid leaking memory.
This should be sufficient for this simple program. More complicated programs will likely require slightly more sophisticated socket and dynamic scoping handling logic, for reliability.

list/vector iterator not incrementable

So I have an issue trying to iterate through my container in c++ with visual studio Community 2015.
I'm trying to write a server/client on windows using select() and I get the error:
vector iterator not incrementable
I'm not calling a vector::erase() or such, although I do use a vector::push_back()
void MGKServer::mainLoop()
{
MGKServerSocket *mgk;
std::vector<User *> users;
int actual = 0;
char buffer[1024];
mgk = new WindowsServerSocket();
mgk->init("127.0.0.1", 4242, "TCP");
int sock = mgk->getSock();
std::cout << "sock is: " << mgk->getSock() << std::endl;
while (1)
{
this->setFd(sock, &users); // FD_ZERO(&_readfd) and FD_SET for each user's socket and the server socket
std::cout << "there is currently " << users.size() << " user(s) connected" << std::endl;
if (select(FD_SETSIZE + 1, &this->_readfd, NULL, NULL, NULL) == -1)
exit(errno);
// When a user connects
if (FD_ISSET(sock, &this->_readfd))
{
// addNewUser creates a pointer to an object User , set his socket to the given one and push it in the vector
if (this->addNewUser(sock, &users) == -1)
std::cout << "Can't add newUser" << std::endl;
}
// When a user sends a message to the server
else
{
int debug = 0;
std::vector<User *>::iterator it = users.begin();
while (it != users.end())
{
if (it == users.end())
std::cout << "Test if something went wrong with iterations" << std::endl;
if (FD_ISSET((*it)->getSocket(), &this->_readfd))
{
// RecvUser will just call recv with the client socket and store the message in buffer.
int c = mgk->recvUser((*it)->getSocket(), buffer);
// Means the user disconnected so i close his socket
if (c == 0)
{
std::cout << "user with socket: " << (*it)->getSocket() << "disconnected" << std::endl;
closesocket((*it)->getSocket());
}
// Means he sends an instruction
else
std::cout << "ok" << std::endl;
}
std::cout << "Debug = " << debug << std::endl;
++debug;
it++; // <- This small line seems to be the problem
}
std::cout << "Out of For loop" << std::endl;
}
std::cout << "found something on socket" << std::endl;
}
}
here is what i do in addNewUser:
int MGKServer::addNewUser(int socket, std::vector<User *> *users)
{
std::cout << "----NEW USER----" << std::endl;
SOCKADDR_IN usin = { 0 };
User *u;
int size;
int usock;
size = sizeof(usin);
std::cout << "New user is trying to connect, socket is: ";
usock = accept(socket, (SOCKADDR *)&usin, &size);
if (usock == SOCKET_ERROR)
{
std::cout << "socket error occured" << std::endl;
return (-1);
}
std::cout << usock << std::endl;
FD_SET(usock, &this->_readfd);
u = new User();
u->setSocket(usock);
users->push_back(u);
return (0);
}
My object User only contains a socket with get&set methods for now.
My MGKServerSocket is just an abstration for windows/linux socket. It contain basic function for initializing my socket and send & recv data to users.
So at first I had a list container but I've got the same error. So I switched to try with vector instead but nothing changed.
In the beginning, I also used a for loop instead of my current while loop but, once again, nothing changed.
I know that there's already many questions for this error, but they usually use erase, insert inside the for loop or create the iterator when the list is empty which I don't. So my question is, why do I get this error ?

Server with Multiple Clients: how to forward message from one client to another

I have a working server that can handle multiple clients (one thread per client) - adapted from here. At the moment it works like this:
Client connects to server
User types message on client console which is sent to server (and displayed on server-side console.
User types message on server console which is sent back to the same client.
But what I would like to do is receive a message from e.g. client 1, which goes to the server for processing, and then may be forwarded to client 3 (which client it forwards the message to is determined by server).
My guess is that I need to modify the clientHandleThread, but I don't know what I need to do. I'm also not sure if it is possible to access a separate thread from the current one.
I am very new to socket programming and threads, and trying hard to learn and so would welcome any help! I am attaching the code containing main() (please let me know if I should attach other code!)
myLog winLog;
DWORD WINAPI clientHandleThread(LPVOID threadInfo)
{
//this structure will contain all the data this callback will work on
myThreadArgument* clientArgument = (myThreadArgument*)threadInfo;
//the semamphore to protect the access to the std output
mySemaphore* coutSemaphore = clientArgument->getCoutSemaphore();
/*get the client connection: receiving messages from client and
sending messages to the client will all be done by using
this client connection*/
myTcpSocket* clientConnection = clientArgument->getClientConnect();
string clientName = clientArgument->getHostName();
//the server is communicating with this client here
while(1)
{
string messageFromClient = "";
//receive from the client
int numBytes = clientConnection->receiveMessage(messageFromClient);
if ( numBytes == -99 ) break;
//write to the console and the log file, so lock the semaphore
coutSemaphore->lock();
cout << "[RECV fr " << clientName << "]: " << messageFromClient << endl;
winLog << "[RECV fr " << clientName << "]: " << messageFromClient << endl;
msgInfo proMsgFrCli = msgClassification(messageFromClient);
//if the client wants to discount
if ( messageFromClient.compare("quit") == 0 || messageFromClient.compare("Quit") == 0 )
{
coutSemaphore->unlock();
break;
}
else // send to the client
{
char messageToClient[MAX_MSG_LEN+1];
memset(messageToClient,0,sizeof(messageToClient));
cout << "[SEND to " << clientName << "]: ";
cin.getline(messageToClient,MAX_MSG_LEN);
winLog << "[SEND to " << clientName << "]: " << messageToClient << endl;
clientConnection->sendMessage(string(messageToClient));
coutSemaphore->unlock();
}
}
// if we reach here, this session with the client is done,
// so we set the event on this thread to inform the main
// control that this session is finished
clientArgument->getExitEvent()->setEvent();
return 1;
}
DWORD WINAPI serverHandleThread(LPVOID threadInfo) //server thread
{
//this structure will contain all the data this callback will work on
myThreadArgument* serverArgument = (myThreadArgument*)threadInfo;
//the semamphore to protect the access to the std output
mySemaphore* coutSemaphore = serverArgument->getCoutSemaphore();
//get the server
myTcpSocket* myServer = serverArgument->getClientConnect();
string serverName = serverArgument->getHostName();
//bind the server to the socket
myServer->bindSocket();
cout << endl << "server finishes binding process... " << endl;
winLog << endl << "server finishes binding process... " << endl;
//server starts to wait for client calls
myServer->listenToClient();
cout << "server is waiting for client calls ... " << endl;
winLog << "server is waiting for client calls ... " << endl;
//server starts to listen, and generates a thread to handle each client
myThreadArgument* clientArgument[MAX_NUM_CLIENTS];
myThread* clientHandle[MAX_NUM_CLIENTS];
for ( int i = 0; i < MAX_NUM_CLIENTS; i++ )
{
clientArgument[i] = NULL;
clientHandle[i] = NULL;
}
int currNumOfClients = 0;
char buffer [100]; //temp buffer to convert currNumOfClients to char
while ( 1 )
{
//wait to accept a client connection.
//processing is suspended until the client connects
myTcpSocket* client; //connection dedicated for client communication
string clientName; //client name
client = myServer->acceptClient(clientName);
clientName = clientName + "-" + itoa(currNumOfClients, buffer, 10);//char(65+currNumOfClients);
//lock the std out so we can write to the console
coutSemaphore->lock();
cout << endl << endl << "==> a client from [" << clientName << "] is connected!" << endl;
winLog << endl << "==> a client from [" << clientName << "] is connected!" << endl << endl;
coutSemaphore->unlock();
//for this client, generate a thread to handle it
if ( currNumOfClients < MAX_NUM_CLIENTS-1 )
{
clientArgument[currNumOfClients] = new myThreadArgument(client,coutSemaphore,clientName);
clientHandle[currNumOfClients] = new myThread(clientHandleThread,(void*)clientArgument[currNumOfClients]);
serverArgument->addClientArgument(clientArgument[currNumOfClients]);
clientHandle[currNumOfClients]->execute();
currNumOfClients++;
}
}
return 1;
}
int main()
{
/*build a semaphore so we can synchronize the access to std cout
also includes the log file*/
mySemaphore coutSemaphore(string(""),1);
//initialize the winsock library
myTcpSocket::initialize();
/*create the server: local host will be used as the server, let us
first use myHostInfo class to show the name and IP address
of the local host*/
winLog << endl;
winLog << "retrieve the local host name and address:" << endl;
myHostInfo serverInfo;
string serverName = serverInfo.getHostName();
string serverIPAddress = serverInfo.getHostIPAddress();
cout << "my localhost (server) information:" << endl;
cout << " name: " << serverName << endl;
cout << " address: " << serverIPAddress << endl;
winLog << " ==> name: " << serverName << endl;
winLog << " ==> address: " << serverIPAddress << endl;
//open socket on the local host(server) and show its configuration
myTcpSocket myServer(PORTNUM);
cout << myServer;
winLog << myServer;
//read connectivityFile
neighbourInfo = connFrFile(numberOfFiles, intBtwnChange);
//read routingFile
nextHopInfo = routFrFile(numberOfFiles, intBtwnChange);
/*create a thread to implement server process: listening to the socket,
accepting client calls and communicating with clients. This will free the
main control (see below) to do other process*/
myThreadArgument* serverArgument = new myThreadArgument(&myServer,&coutSemaphore,serverName);
myThread* serverThread = new myThread(serverHandleThread,(void*)serverArgument);
serverThread->execute();
// main control: since the serverThread is handling the server functions,
// this main control is free to do other things.
while ( 1 )
{
/*do whatever you need to do here, I am using Sleep(x)
to make a little delay, pretending to be the other
possible processings*/
Sleep(50000);
//report the server status
coutSemaphore.lock();
cout << endl << "-----------------------------------------------------------------" << endl;
winLog << endl << "-----------------------------------------------------------------" << endl;
cout << "server (name:" << serverName << ") status report:" << endl;
winLog << "server (name:" << serverName << ") status report:" << endl;
cout << " the following clients have successfully connected with server: " << endl;
winLog << " the following clients have successfully connected with server: " << endl;
for ( int i = 0; i < MAX_NUM_CLIENTS; i ++ )
{
myThreadArgument* clientInfo = serverArgument->getClientArgument(i);
if ( clientInfo )
{
cout << " " << clientInfo->getHostName() << endl;
winLog << " " << clientInfo->getHostName() << endl;
}
}
cout << " the following clients have shutdown the connection: " << endl;
winLog << " the following clients have shutdown the connection: " << endl;
for ( int i = 0; i < MAX_NUM_CLIENTS; i ++ )
{
myThreadArgument* clientInfo = serverArgument->getClientArgument(i);
if ( clientInfo && clientInfo->getExitEvent()->waitForEvent(0) )
{
clientInfo->setSignalToEnd(true);
cout << " " << clientInfo->getHostName() << endl;
winLog << " " << clientInfo->getHostName() << endl;
}
}
cout << "-----------------------------------------------------------------" << endl << endl;
winLog << "-----------------------------------------------------------------" << endl << endl;
coutSemaphore.unlock();
}
return 1;
}
For each connection you can have two queues: One for input, and one for output. The connections thread (if you have one dedicated thread per connection) reads input from the client and puts it in the input queue. The connection-thread also fetches messages from the output queue and sends it to the connected client.
The server then has another thread, that goes through all connections input queues, extracts the messages, decides what to do with the input, and then possibly puts it into the output queue of some other connection.
Pseudo-code example:
struct message_struct
{
int source; // Source where the message came from
int destination; // Destination client to send message on to
}
void client_thread()
{
while (!exit_thread)
{
if (is_there_anything_to_recv())
{
// Receive and parse a message from the client
message = receive();
// Add to the threads input queue
add_to_queue(input_queue, message);
}
// As long as there are messages in the output queue
while (!queue_is_empty(output_queue))
{
// Remove one message from the queue
message = remove_from_queue(output_queue);
// And send it to the connected client
send(message);
}
}
}
void server_thread()
{
while (!exit_thread)
{
// Check for new connections
// ...
// Assuming the threads are on array (or array-like structure)
for (i = 0; i < number_of_client_threads; i++)
{
// While the current threads (`i`) input queue is not empty
while (!queue_is_empty(client_threads[i].input_queue))
{
// Remove the message from the threads input queue
message = remove_from_queue(client_threads[i].input_queue);
// And add it to the destinations output queue
add_to_queue(client_threads[message.destination].output_queue);
}
}
}
}