Files
Qt/portConnectServer/main.cpp
2021-01-12 18:09:34 +01:00

593 lines
22 KiB
C++

#include <iostream>
#include <pthread.h>
#include <unistd.h>
#include <algorithm> /// tD->VectorArray[0].erase(std::remove(tD->VectorArray[0].begin(), tD->VectorArray[0].end(), tD), tD->VectorArray[0].end());
#include <vector>
#include "server_tcp_lib.h"
/*Accept Client
* -> To Thread
* -> Reczive Data
* -> Pushback WaitingQueuqVector
* ->Thread 2: go throu WaitingQueuqVector
* -> pushback vector_<server/from_server/from_client>
* -> Check for new Connections(from_server_id == from_client_id)
* -> if Connecting -> send msg to server ( server_id == from_server_id)
* ->New Connection: 2 Threads: Redirection: Up,Down -> (pthread_detach???)
*/
struct Client {
Client()
: ConnectionsLeft(-1) {}
CLIENT client;
int ConnectionsLeft;
enum TYPE {
UNDEFINED = 0,
SERVER = 1,
FROM_SERVER_CLIENT_FREE = 2,
FROM_USER_CLIENT = 3,
FROM_SERVER_CLIENT_USED = 4,
UNKNOWN = 5
} Type;
std::string serverID,
serverPW,
serverMemAddr;
};
constexpr unsigned short serverPort = 4000;
static bool shouldStop = false;
static TCP_SERVER server;
static std::vector < pthread_t > threadList;
static std::vector<Client *> VectorArray[5];
static auto &WaitingQuequeList = VectorArray[0];
static auto &ServerList = VectorArray[1]; // *---> Pointer auf <Client *>
static auto &FromServerClientListFree = VectorArray[2];
static auto &FromUserClientListConnected = VectorArray[3];
static auto &FromServerClientListConnected = VectorArray[4];
/*
template < typename T>
int findInVector(const std::vector<T> & vecOfElements, const T & element)
{
// Find given element in vector
auto it = std::find(vecOfElements.begin(), vecOfElements.end(), element);
return ( it == vecOfElements.end() ) ? -1 : static_cast<int>(distance(vecOfElements.begin(), it));
}
*/
template < typename T>
void deleteAndSetToNull(T ** var) {
if(*var != nullptr)
/// delete *var;
perror("DELETE...");
else
std::cout << "WARNING: in deleteAndSetToNull: Pointer was null" << std::endl;
*var = nullptr;
}
[[ noreturn ]] void pthread_exit_WithRemoveFromThreadList( Client ** toDeleteClient = nullptr ) {
if(toDeleteClient) {
std::cout << " -> Delete Client in pthread_exit_With_RemoveFromList(): " << *toDeleteClient << std::endl;
deleteAndSetToNull(toDeleteClient);
}
auto it = std::find(threadList.begin(), threadList.end(), pthread_self());
if( it == threadList.end() )
std::cerr << "WARNUNG: Konnte Thread nicht in threadList finden: " << pthread_self() << std::endl;
else
threadList.erase( it );
std::cout << " ~~> pthread_exit( " << pthread_self() << " )" << std::endl;
pthread_exit(nullptr);
}
struct redirectThreadData
{
redirectThreadData(Client ** cli1, Client **cli2)
: cli1(cli1), cli2(cli2) {}
Client **cli1, **cli2;
};
void * closeConnectionWithClient(Client ** client, bool removeFromList = false, std::string DisconnectMsg = "") {
if(client == nullptr) {
std::cerr << "Got invalid client." << std::endl;
return nullptr;
} else if (* client == nullptr) {
std::cerr << "-------> FATAL ERROR: SHOULD DELETE Client A SECOND TIME!!" << std::endl;
return nullptr;
}
if(DisconnectMsg != "" && (**client).client.send_(DisconnectMsg.c_str(), DisconnectMsg.length()) != 0)
std::cout << "Warning: Send failed in closeConnectionWithClient(): " << (**client).client.getLastError() << std::endl;
if(removeFromList && ( ((**client).Type == Client::SERVER) || ((**client).Type == Client::FROM_SERVER_CLIENT_FREE) || ((**client).Type == Client::FROM_SERVER_CLIENT_USED) || ((**client).Type == Client::FROM_USER_CLIENT) )) {
auto it = std::find(VectorArray[(**client).Type].begin(), VectorArray[(**client).Type].end(), *client);
if( it == VectorArray[(**client).Type].end() )
std::cerr << "Error: Couldn't find client in RemoveFromList: " << *client << std::endl;
else {
std::cout << "Remove Client ( " << (*client) << " ) in Vector: " << *it.base() << std::endl;
VectorArray[(**client).Type].erase( it );
}
}
std::cout << "DELTE CLIENT: "<< (**client).client.getIpAddress() << ":" << (**client).serverMemAddr << " (" << *client << ")..." << std::endl;
deleteAndSetToNull(client);
return nullptr;
}
void * redirectThreadFunction( void * data ) {
auto tD = reinterpret_cast<redirectThreadData *>(data);
char buffer;
std::cout << " __-->Thread; Redirect " << (*tD->cli1)->Type << " to " << (*tD->cli2)->Type << std::endl;
while ( ! shouldStop ) {
if( read( (*tD->cli1)->client.getSocket(), &buffer, 1) <= 0 ) {
std::cerr << " DEBUG: read() failed: IN redirectThreadFunction() " << std::endl;
if(*tD->cli2 && *tD->cli2)
(*tD->cli2)->client.closeSocket();
else
std::cerr << "INFo: Konnte CLIENT 2 nicht Clossock'en, da der Pointer auf nullptr zeigte." << std::endl;
closeConnectionWithClient(tD->cli1, true);
break;
} else if ( write((*tD->cli2)->client.getSocket(), &buffer, 1) <= 0) {
std::cerr << " DEBUG: write() failed." << std::endl;
if(*tD->cli2 && *tD->cli2)
(*tD->cli2)->client.closeSocket();
else
std::cerr << "INFo: Konnte CLIENT 2 nicht Clossock'en, da der Pointer auf nullptr zeigte." << std::endl;
closeConnectionWithClient(tD->cli1, true);
break;
}
}
std::cout << "DELTE RectirectThreadData: "<< tD << "... & exit" << std::endl;
deleteAndSetToNull(&tD);
pthread_exit_WithRemoveFromThreadList();
}
void * updateServerThreadFunktion(void * Server) {
auto server = reinterpret_cast<Client *>(Server); // Client(x1) <---x1(yz) <---yz(ia)
// NewThread COPY(<--x1(yz)): <---x1(vb)
std::string buffer; //NewThread COPY: <-----yz(lol) => *yz
char c;
while ( ! shouldStop ) {
if( ! server ) {
std::cerr << "Server* in updateServerThreadFunktion is nullptr" << std::endl;
closeConnectionWithClient(&server, true);
pthread_exit_WithRemoveFromThreadList();
} else
buffer.clear();
do {
if( read( (*server).client.getSocket(), &c, 1) <= 0) {
std::cerr << " DEBUG: -> rev failed in updateServerThreadFunktion()." << std::endl;
closeConnectionWithClient(&server, true);
pthread_exit_WithRemoveFromThreadList( );
} else
buffer.push_back(c);
} while ( c != '|' && buffer.size() < buffer.max_size() ); //sicherheitslücke, da sonst passieren, kann, dass buffer überfüllt wird
if(buffer.data() && buffer.size() > 0) {
buffer.pop_back();
buffer.push_back('\0');
if(buffer.find("=") == std::string::npos) {
std::cout << " INVALID MSG: '" << buffer.data() << "'" << std::endl;
continue;
}
} else
std::cout << "recived msg: '" << buffer << "'" << std::endl;
std::string what = buffer.substr(0, buffer.find("="));
std::string value = buffer.substr(buffer.find("=") + 1);
if (what == "CONNECTIONS_LEFT") {
(*server).ConnectionsLeft = atoi(value.c_str());
} else {
std::cout << "Got invalid msg -> in updateServerThreadFunktion." << std::endl;
closeConnectionWithClient(&server, true);
pthread_exit_WithRemoveFromThreadList();
}
}
pthread_exit_WithRemoveFromThreadList();
}
void * threadFunctionHandlWaitingQueuqVector( void *) {
while ( !shouldStop ) {
std::cout << "Waiting for clients in queque..." << std::endl;
while ( WaitingQuequeList.size() == 0 && ! shouldStop )
usleep(50000);
std::cout << "New client in queque handler..." << std::endl;
Client * client = WaitingQuequeList.front();
WaitingQuequeList.erase(WaitingQuequeList.begin());
if(client == nullptr) {
std::cerr << "------->Error: Client* in Waiting Queuq is NULL" << std::endl;
continue;
} else if( (*client).Type == Client::SERVER ) {
std::cout << "New client = new server -> look if id is already used..." << std::endl;
bool noServerFound = true;
for ( auto &FSClient : ServerList ) {
if(FSClient->serverID == (*client).serverID ) {
//error already server with this id hosted
std::cerr << "Error: es gibt bereits einen server mit dieser id: " << FSClient->serverID << std::endl;
closeConnectionWithClient(&client, false, "SERVERID_ALREADY_USED=true|");
noServerFound = false;
break;
}
} if( ! noServerFound )
continue;
//create update thread
pthread_t thread;
if(pthread_create(&thread, nullptr, updateServerThreadFunktion, reinterpret_cast<void*>( client )) != 0) {
perror("pthread create failed");
closeConnectionWithClient(&client, false, "SERVERID_ALREADY_USED=true|");
continue;
} else
threadList.push_back(thread);
std::cout << "Startet Update Thread at: ' " << thread << "'" << std::endl;
//Save data in vector
ServerList.push_back(client);
}
else if ( (*client).Type == Client::FROM_SERVER_CLIENT_FREE ) {
std::cout << "Check if server with Same IP && same mem addr exits: " << std::endl;
bool found_server = false;
for ( auto &serverInVec : ServerList )
if(serverInVec != nullptr && serverInVec->client.getIpAddress()==(*client).client.getIpAddress() && serverInVec->serverMemAddr==(*client).serverMemAddr && (found_server = true) ) {
std::cout << "Founded server: " << serverInVec->client.getIpAddress() <<"==" << (*client).client.getIpAddress()
<< " && " << serverInVec->serverMemAddr << "==" << (*client).serverMemAddr << std::endl;
break;
}
if(! found_server) {
std::cout << "No server with same ip & same mainClientMemAddr found" << std::endl;
closeConnectionWithClient(&client);
continue;
}
FromServerClientListFree.push_back(client);
}
else if ( (*client).Type == Client::FROM_USER_CLIENT ) {
//------------check server
std::cout << "Look for server with this id." << std::endl;
Client *server = nullptr;
for ( auto &serverInVec : ServerList )
if(serverInVec->serverID == (*client).serverID) {
server = serverInVec;
break;
}
if(server == nullptr) {
std::cout << "No server with this id found" << std::endl;
closeConnectionWithClient(&client, false, "NO_SERVER_WITH_THIS_ID_FOUND=true|");
continue;
}
std::cout << "server found.. Check if client limit is reached: Left: " << (*server).ConnectionsLeft << std::endl;
if((*server).ConnectionsLeft <= 0) {
std::cerr << "Error: clients Limit reached." << std::endl;
closeConnectionWithClient(&client, false, "CLIENT_LIMIT_REACHED=true|");
continue;
} else if( (*server).client.send_("NEW_CLIENT_NEEDED=true|", 23) <= 0) {
//send failed.. error
std::cout << "send Failed" << std::endl;
/// closeConnectionWithClient(server, true); nicht deleten because update Thread
closeConnectionWithClient(&client, false, "SEND_TO_SERVER_FAILED=true|");
continue;
}
//-------------check server client
std::cout << "Look for server client" << std::endl;
Client * serverClient = nullptr;
for ( unsigned i = 0; i < FromServerClientListFree.size(); i++ ) {
if(FromServerClientListFree.at(i)->serverID == (*client).serverID ) {
serverClient = FromServerClientListFree.at(i);
//remove serverclient from free list...
FromServerClientListFree.erase(FromServerClientListFree.begin() + i);
break;
}
}
if(serverClient == nullptr) {
std::cout << "No server with this id found" << std::endl;
closeConnectionWithClient(&client, false, "NO_SERVER_ClIENT_FOUND=true|");
continue;
}
std::cout << "server client found" << std::endl;
//do checks
std::cout << "check password" << std::endl;
if((*serverClient).serverPW != "" && (*serverClient).serverPW != (*client).serverPW ) {
std::cout << "Failed: wrong pw" << std::endl;
closeConnectionWithClient(&client, false, "WRONG_PASSWORD=true|");
closeConnectionWithClient(&serverClient);
continue;
}
std::cout << "password ok" << std::endl;
//send finished signal:
if((*client).client.send_("FINISHED=true|", 14) <= 0 ) {
std::cout << "send sinished signal failed" << std::endl;
closeConnectionWithClient(&client, false);
closeConnectionWithClient(&serverClient);
continue;
}
//Psuh back to vectors
FromUserClientListConnected.push_back(client);
FromServerClientListConnected.push_back(serverClient);
std::cout << "Start threads..." << std::endl;
//------------Start Threads:
bool error = false;
for (int i = 0; i < 2; ++i) {
redirectThreadData * newRedirectData = new redirectThreadData( &((i == 0) ? FromUserClientListConnected.back() : FromServerClientListConnected.back()),
&((i == 0) ? FromServerClientListConnected.back() : FromUserClientListConnected.back()) );
std::cout << "Creted new Redirect ThreadData: " << newRedirectData << " -> CLI_1: " << *newRedirectData->cli1
<< " -> CLI_2" << *newRedirectData->cli2 << std::endl;
pthread_t thread;
if(pthread_create(&thread, nullptr, redirectThreadFunction, reinterpret_cast<void*>( newRedirectData )) != 0 && (error = true) ) {
perror("pthread create failed");
closeConnectionWithClient(&client, true);
closeConnectionWithClient(&serverClient, true);
break;
} else
threadList.push_back(thread);
std::cout << "Startet Redirect Thread at: ' " << thread << "'" << std::endl;
} if(error)
continue;
} else {
std::cerr << "Error Client has invalid TYPE: '" << (*client).Type << std::endl;
closeConnectionWithClient(&client, false);
continue;
}
}
pthread_exit_WithRemoveFromThreadList();
}
//#include <algorithm> /// tD->VectorArray[0].erase(std::remove(tD->VectorArray[0].begin(), tD->VectorArray[0].end(), tD), tD->VectorArray[0].end());
void *threadFunctionReciveInitData(void *threadData)
{
std::cerr << " + " << __FUNCTION__ << std::endl;
Client * client = reinterpret_cast<Client *>(threadData);
std::string buffer;
char c;
while ( ! shouldStop ) {
buffer.clear();
do {
if( read(client->client.getSocket(), &c, 1) <= 0) {
std::cerr << " DEBUG: -> rev failed in threadFunctionReciveInitData()." << std::endl;
pthread_exit_WithRemoveFromThreadList( &client );
} else
buffer.push_back(c);
} while ( c != '|' && buffer.size() < buffer.max_size() ); //sicherheitslücke, da sonst passieren, kann, dass buffer überfüllt wird
if(buffer.data() && buffer.size() > 0) {
buffer.pop_back();
buffer.push_back('\0');
if(buffer.find("=") == std::string::npos) {
std::cout << " INVALID MSG: '" << buffer.data() << "'" << std::endl;
continue;
}
}
std::cout << "recived msg: '" << buffer << "'" << std::endl;
std::string what = buffer.substr(0, buffer.find("="));
std::string value = buffer.substr(buffer.find("=") + 1);
if(what == "TYPE") {
if(strcmp( value.c_str(), "SERVER") == 0)
client->Type = Client::TYPE::SERVER;
else if (strcmp( value.c_str(), "FROM_SERVER_CONNECTION") == 0)
client->Type = Client::TYPE::FROM_SERVER_CLIENT_FREE;
else if (strcmp( value.c_str(), "FROM_USER_CONNECTION") == 0)
client->Type = Client::TYPE::FROM_USER_CLIENT;
else
client->Type = Client::TYPE::UNKNOWN;
} else if (what == "SERVERID")
client->serverID = value;
else if (what == "PASSWORD")
client->serverPW = value;
else if (what == "CONNECTIONS_LEFT")
client->ConnectionsLeft = atoi(value.c_str());
else if (what == "MEM_ADDR")
client->serverMemAddr = value;
/*else if (what == "-")
tD->;*/
else if (what == "FINIDHED") {
std::cout << "INIT FINISHED: " << client->Type << " - "
<< client->serverID << " - " << client->serverPW
<< " - " << client->ConnectionsLeft << " - " << client << std::endl;
WaitingQuequeList.push_back(client);
pthread_exit_WithRemoveFromThreadList();
} else {
std::cout << "Got invalid msg -> bad client -> error -> kick client" << std::endl;
pthread_exit_WithRemoveFromThreadList(&client); // with clossocket in destructor of client
}
}
pthread_exit_WithRemoveFromThreadList();
}
void * acceptThread( void *) {
std::cerr << " + " << __FUNCTION__ << std::endl;
while ( ! shouldStop ) {
Client *newThreadData = new Client();
if(server.acceptClient(newThreadData->client) != 0) {
std::cerr << " -> Accpted failed: " << server.getLastError() << std::endl;
deleteAndSetToNull( &newThreadData );
continue;
} else
std::cout << " -> Accepted client: " << newThreadData->client.getIpAddress() << std::endl;
threadList.push_back(0);
pthread_t * thread = &threadList.back();
if(pthread_create(thread, nullptr, threadFunctionReciveInitData, reinterpret_cast<void*>( newThreadData )) != 0) {
perror(" -> pthread_creater failed");
deleteAndSetToNull( &newThreadData ); // with clossocket
continue;
} else
std::cout << " -> Startet threadFunctionReciveInitData at: '" << thread << "'" << std::endl;
}
std::cerr << " - " << __FUNCTION__ << std::endl;
pthread_exit_WithRemoveFromThreadList();
}
//#include <signal.h> // für signal() function, weil send gibt SIGPIPE zurück, (wenn letzter prozess beendet oder so... nur für schellscripts nötig),
int main(/*int argc, char *argv[]*/)
{
signal(SIGSTOP, SIG_IGN);
std::cerr << " + " << __FUNCTION__ << std::endl;
while ( server.startListening(serverPort) ) {
std::cerr << "-> Start Server failed: " << server.getLastError() << std::endl;
sleep(1);
}
std::cout << "-> Startet Server. Listening on: " << serverPort << std::endl;
std::cout << "-> Starting queque handler..." << std::endl;
threadList.push_back(0);
if(pthread_create(&threadList.back(), nullptr, threadFunctionHandlWaitingQueuqVector, nullptr) != 0) {
perror("pthread_creater failed");
return -1;
}
std::cout << "-> Startet queque handler at: '" << &threadList.back() << "'" << std::endl;
threadList.push_back(0);
if(pthread_create(&threadList.back(), nullptr, acceptThread, nullptr) != 0) {
perror("Konnte StopThread nicht starten");
return -1;
}
std::cout << "Started Accpet Thread: '" << threadList.back() <<"' ." << std::endl;
while ( ! shouldStop ) {
std::string line;
std::getline(std::cin, line);
if( line =="" )
continue;
else if(line == "stop")
shouldStop = true;
else if (line == "list") {
for (unsigned i = 0; i < (sizeof(VectorArray) / sizeof (VectorArray[0])) ; ++i)
for (unsigned x = 0; x < VectorArray[i].size(); ++x)
std::cout << "TDArray[" << i << "][" << x << "] Type: " << VectorArray[i][x]->Type << " IP: " << VectorArray[i][x]->client.getIpAddress()
<< " ID: " << VectorArray[i][x]->serverID << " PW: " << VectorArray[i][x]->serverPW << " ConLeft: " << VectorArray[i][x]->ConnectionsLeft << std::endl;
}
else {
std::cout << "Gib 'stop' ein um den server zu stoppen\n Gibt 'list' ein um Alle (gelogten) Clients zu sehen." << std::endl;
}
}
//Stopping Server...
std::cout << "-> Stopping Server..." << std::endl;
std::cout << "Stoping Serverlistening..." << std::endl;
if(server.isListening() && server.stopListening() != 0)
std::cerr << "StopListing failed: " << server.getLastError() << std::endl;
for( auto &e : threadList ) {
if(pthread_cancel(e) != 0)
perror("pthreac_cancel failed");
if( pthread_join(e, nullptr) != 0)
perror("pthread_join failed");
else
std::cout << "Stopped: " << e << std::endl;
}
std::cout << "Clear ThreadList..." << std::endl;
threadList.clear();
for (unsigned i = 0; i < (sizeof(VectorArray) / sizeof (*VectorArray)); ++i) {
for (unsigned x = 0; x < VectorArray[i].size(); ++x) {
std::cout << "Delete: TDArray[" << i << "][" << x << "]..." << std::endl;
deleteAndSetToNull( &VectorArray[i][x] );
}
std::cout << "Clear TDArray[" << i << "]... " << std::endl;
VectorArray[i].clear();
}
std::cout << "Exit..." << std::endl;
std::cerr << " - " << __FUNCTION__ << std::endl;
return 0;
}