543 lines
15 KiB
C++
543 lines
15 KiB
C++
//client
|
|
#include <iostream>
|
|
#include <algorithm>
|
|
#include <map>
|
|
#include <vector>
|
|
#include <ctime>
|
|
#include <fstream>
|
|
#include <iomanip>
|
|
#include "client.h"
|
|
|
|
Result Client::Initialize(Endpoint ip)
|
|
{
|
|
connections.clear();
|
|
FD_ZERO(&master_fd);
|
|
|
|
if (Network::Initialize())
|
|
{
|
|
// Winsock dziala
|
|
std::cout << "[CLIENT] Winsock zostal poprawnie zainicjalizowany." << std::endl;
|
|
|
|
broadcastReciverUDP = Socket(Protocol::UDP_Reciver);
|
|
if (broadcastReciverUDP.Create() == Result::Success)
|
|
{
|
|
// Socket do odebrania adresu serwara zostal utworzony
|
|
std::cout << "[CLIENT] Gniazdo UDP do odnalezienia serwara zostalo utworzone." << std::endl;
|
|
|
|
if (broadcastReciverUDP.Bind(Endpoint("0.0.0.0", 54000)) == Result::Success)
|
|
{
|
|
// Socket UDP przypiety do portu
|
|
std::cout << "[CLIENT] Gniazdo UDP zostalo przypisane do portu 54000" << std::endl;
|
|
// Dodanie socketa do listy
|
|
FD_SET(broadcastReciverUDP.GetSocket(), &master_fd);
|
|
}
|
|
else
|
|
{
|
|
|
|
std::cerr << "[CLIENT] Nie udalo sie przypisac portu dla broadcastu UDP." << std::endl;
|
|
broadcastReciverUDP.Close();
|
|
return Result::Fail;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
std::cout << "[CLIENT] Nie moge utworzyc gniazda UDP." << std::endl;
|
|
return Result::Fail;
|
|
}
|
|
|
|
listeningSocketTCP = Socket(Protocol::TCP);
|
|
if (listeningSocketTCP.Create() == Result::Success)
|
|
{
|
|
// Socket listening zostal utworzony
|
|
std::cout << "[CLIENT] Gniazdo TCP do nasluchu zostalo utworzone." << std::endl;
|
|
|
|
if (listeningSocketTCP.BindAndListen(ip) == Result::Success)
|
|
{
|
|
// Socket listening od teraz nasluchuje
|
|
std::cout << "[SERVER] Gniazdo TCP do nasluchu nasluchuje." << std::endl;
|
|
// Dodanie socketa do listy
|
|
FD_SET(listeningSocketTCP.GetSocket(), &master_fd);
|
|
|
|
}
|
|
else
|
|
{
|
|
std::cerr << "[CLIENT] Nie udalo sie wlaczyc nasluchu na gniezdie TCP." << std::endl;
|
|
listeningSocketTCP.Close();
|
|
return Result::Fail;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
std::cerr << "[CLIENT] Nie mozna utworzych gniazda TCP do nasluchu." << std::endl;
|
|
return Result::Fail;
|
|
}
|
|
return Result::Success;
|
|
}
|
|
}
|
|
|
|
Result Client::CheckConnection()
|
|
{
|
|
fd_set copy_fd = master_fd;
|
|
|
|
int ConnectionCount = select(NULL, ©_fd, NULL, NULL, &waitTime);
|
|
if (ConnectionCount)
|
|
{
|
|
if (ConnectionCount == SOCKET_ERROR)
|
|
{
|
|
int error = WSAGetLastError();
|
|
Log::PrintError("[SERVER] Problem z listening socket", error);
|
|
return Result::Fail;
|
|
}
|
|
|
|
for (int i = 0; i < ConnectionCount; i++)
|
|
{
|
|
if (copy_fd.fd_array[i] == listeningSocketTCP.GetSocket())
|
|
{
|
|
Socket newConnectionSocket(Protocol::TCP);
|
|
//Endpoint newConnectionEndpoint();
|
|
if (listeningSocketTCP.Accept(newConnectionSocket) == Result::Success)
|
|
{
|
|
struct clientInfo newClient;
|
|
newClient.connection = newConnectionSocket;
|
|
newClient.lastActiveTime = time(NULL);
|
|
connections.push_back(newClient);
|
|
//connections.push_back({newConnectionSocket, NULL, NULL, time(NULL)});
|
|
FD_SET(newConnectionSocket.GetSocket(), &master_fd);
|
|
//continue;
|
|
}
|
|
else
|
|
{
|
|
//error
|
|
}
|
|
}
|
|
|
|
else if (copy_fd.fd_array[i] == broadcastReciverUDP.GetSocket())
|
|
{
|
|
std::string msg = "";
|
|
int bytes = 0;
|
|
broadcastReciverUDP.ReciveUDP(msg, bytes);
|
|
//std::cout << "odebrano wiadosmosc broadcast o tresci: " << msg << std::endl;
|
|
|
|
std::string name, adress;
|
|
unsigned short port;
|
|
|
|
std::replace(msg.begin(), msg.end(), ':', ' ');
|
|
std::stringstream msgToParse(msg);
|
|
|
|
msgToParse >> name >> adress >> port;
|
|
auto server = std::find_if(connections.begin(), connections.end(), [](clientInfo clientInfo) { return clientInfo.name == "server"; });
|
|
if (server == connections.end())
|
|
{
|
|
Socket serverSocket(Protocol::TCP);
|
|
Endpoint serverEnpoint(adress.c_str(), port);
|
|
if (serverSocket.Create() == Result::Success)
|
|
{
|
|
|
|
if (serverSocket.Connect(serverEnpoint) == Result::Success)
|
|
{
|
|
struct clientInfo newServer;
|
|
newServer.connection = serverSocket;
|
|
newServer.name = "server";
|
|
newServer.listening = serverEnpoint;
|
|
newServer.lastActiveTime = time(NULL);
|
|
connections.push_back(newServer);
|
|
FD_SET(serverSocket.GetSocket(), &master_fd);
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
else
|
|
{
|
|
Message recived;
|
|
std::string recivedMessage;
|
|
int bytesRecived;
|
|
|
|
SOCKET lookingFor = copy_fd.fd_array[i];
|
|
auto findedClient = std::find_if(connections.begin(), connections.end(), [lookingFor](clientInfo client) { return lookingFor == client.connection.GetSocket(); });
|
|
|
|
switch (findedClient->connection.ReciveAll(recivedMessage, bytesRecived))
|
|
{
|
|
case Result::Fail:
|
|
case Result::ConnectionLost:
|
|
FD_CLR(findedClient->connection.GetSocket(), &master_fd);
|
|
findedClient->connection.Close();
|
|
connections.erase(findedClient);
|
|
break;
|
|
|
|
case Result::Success:
|
|
//std::cout << "[" << bytesRecived << "] "<< recivedMessage << std::endl;
|
|
|
|
findedClient->lastActiveTime = time(NULL);
|
|
if (recived.Parse(recivedMessage, bytesRecived) != Result::Success)
|
|
{
|
|
// wiadamosc niekompletna, bledna lub cos takiego
|
|
if (writeFile_p.is_open())
|
|
{
|
|
writeFile_p.close();
|
|
}
|
|
return Result::Fail;
|
|
}
|
|
|
|
switch (recived.GetType())
|
|
{
|
|
case TypeOfMsg::Unknown:
|
|
break;
|
|
case TypeOfMsg::Text:
|
|
{
|
|
std::string name = recived.GetName();
|
|
std::string msg = recived.GetMsg();
|
|
if (findedClient->name != "server")
|
|
{
|
|
std::cout << "<" << name << "> " << msg << std::endl;
|
|
}
|
|
else
|
|
{
|
|
std::cout << "[" << name << "] " << msg << std::endl;
|
|
}
|
|
break;
|
|
|
|
}
|
|
case TypeOfMsg::File:
|
|
{
|
|
|
|
//std::ofstream writeFile(fileName, std::ios::binary | std::ios::trunc);
|
|
if (!writeFile_p)
|
|
{
|
|
std::cout << "Nie udalo sie utworzyc pliku: " << fileName << std::endl;
|
|
writeFile_p.close();
|
|
}
|
|
else
|
|
{
|
|
size_t totalSize = recived.GetTotalLenght();
|
|
size_t recivedBytes = recived.GetLenght();
|
|
writeFile_p.write(recived.GetMsg().c_str(), recivedBytes);
|
|
size_t actualSize = writeFile_p.tellp();
|
|
float percent = ((float)actualSize / totalSize);
|
|
|
|
int barWidth = 60;
|
|
std::cout << "[";
|
|
int pos = barWidth * percent;
|
|
for (int i = 0; i < barWidth; ++i) {
|
|
if (i < pos) std::cout << "=";
|
|
else if (i == pos) std::cout << ">";
|
|
else std::cout << " ";
|
|
}
|
|
std::cout << "] " << int(percent * 100.0) << " " <<std::setw(3) << "% " << actualSize << '\r';
|
|
std::cout.flush();
|
|
if (totalSize == actualSize)
|
|
{
|
|
writeFile_p.close();
|
|
std::cout << std::endl;
|
|
std::cout << "Odebralem plik " << fileName << std::endl;
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
case TypeOfMsg::Command:
|
|
|
|
switch (recived.GetCommand())
|
|
{
|
|
case Command::LogIn:
|
|
{
|
|
findedClient->name = recived.GetName();
|
|
break;
|
|
}
|
|
case Command::LogOut:
|
|
{
|
|
std::string nameLogOut = recived.GetName();
|
|
std::cout << nameLogOut << " wylogowal sie." << std::endl;
|
|
auto connToDelete = std::find_if(connections.begin(), connections.end(), [nameLogOut](clientInfo client) {return nameLogOut == client.name; });
|
|
if (connToDelete != connections.end())
|
|
{
|
|
FD_CLR(connToDelete->connection.GetSocket(), &master_fd);
|
|
connToDelete->connection.Close();
|
|
|
|
connections.erase(connToDelete);
|
|
}
|
|
|
|
auto availableClientToDelete = std::find_if(availableClients.begin(), availableClients.end(), [nameLogOut](clientInfo client) {return nameLogOut == client.name; });
|
|
if (availableClientToDelete != availableClients.end())
|
|
{
|
|
availableClients.erase(availableClientToDelete);
|
|
}
|
|
break;
|
|
}
|
|
case Command::Adress:
|
|
{
|
|
int port = atoi(recived.GetMsg().c_str());
|
|
Endpoint clientPortListenning = Endpoint(findedClient->connection.GetEndpoint().GetIpString().c_str(), (unsigned short)port);
|
|
struct clientInfo newClient;
|
|
newClient.listening = clientPortListenning;
|
|
newClient.name = recived.GetName();
|
|
availableClients.push_back(newClient);
|
|
std::cout << newClient.name << " zalogowal sie." << std::endl;
|
|
}
|
|
break;
|
|
case Command::ConnCheck:
|
|
{
|
|
Message msgConnCheck;
|
|
std::string msg = msgConnCheck.PrepareCommand("", ownLogin, Command::ConnCheck);
|
|
if (findedClient->connection.SendAll(msg.c_str(), msg.size()) != Result::Success)
|
|
{
|
|
//cos poszlo nie tak
|
|
}
|
|
break;
|
|
|
|
}
|
|
case Command::FileName:
|
|
{
|
|
fileName = recived.GetFileName();
|
|
fileName.insert(fileName.find('.'), "_reciv");
|
|
|
|
std::cout << "Uzytkownik " << recived.GetName() << " wysyla Ci plik " << fileName << std::endl;
|
|
|
|
writeFile_p = std::ofstream();
|
|
writeFile_p.open(fileName, std::ios::binary | std::ios::trunc);
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
bool Client::isConnectedToSever()
|
|
{
|
|
if (connections.size() > 0)
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
Result Client::LoginToServer()
|
|
{
|
|
auto server = std::find_if(connections.begin(), connections.end(), [](clientInfo conn) { return conn.name == "server"; });
|
|
if (server != connections.end())
|
|
{
|
|
Message addres;
|
|
std::string port = std::to_string(listeningSocketTCP.GetEndpoint().GetPort());
|
|
std::string msgAddres = addres.PrepareCommand(port, ownLogin, Command::Adress);
|
|
if (server->connection.SendAll(msgAddres.c_str(), msgAddres.size()) != Result::Success)
|
|
{
|
|
// cos poszlo nie tak
|
|
return Result::Fail;
|
|
}
|
|
|
|
Message login;
|
|
std::string msgLogin = login.PrepareCommand("", ownLogin, Command::LogIn);
|
|
if (server->connection.SendAll(msgLogin.c_str(), msgLogin.size()) != Result::Success)
|
|
{
|
|
// cos poszlo nie tak
|
|
return Result::Fail;
|
|
}
|
|
|
|
}
|
|
return Result::Success;
|
|
}
|
|
|
|
Result Client::SendMsg(std::string name, std::string msg)
|
|
{
|
|
Message msgToUser;
|
|
std::string msgToSend = msgToUser.PrepareText(msg, ownLogin);
|
|
|
|
auto user = std::find_if(connections.begin(), connections.end(), [name](clientInfo client) {return client.name == name; });
|
|
if (user != connections.end())
|
|
{
|
|
|
|
user->connection.SendAll(msgToSend.c_str(), msgToSend.size());
|
|
}
|
|
else
|
|
{
|
|
auto userNotConn = std::find_if(availableClients.begin(), availableClients.end(), [name](clientInfo client) {return client.name == name; });
|
|
if (userNotConn != availableClients.end())
|
|
{
|
|
Socket newClientSocket(Protocol::TCP);
|
|
if (newClientSocket.Create() == Result::Success)
|
|
{
|
|
if (newClientSocket.Connect(userNotConn->listening) == Result::Success)
|
|
{
|
|
userNotConn->connection = newClientSocket;
|
|
|
|
connections.push_back(*userNotConn);
|
|
FD_SET(newClientSocket.GetSocket(), &master_fd);
|
|
|
|
Message login;
|
|
std::string msgLogin = login.PrepareCommand("", ownLogin, Command::LogIn);
|
|
if (userNotConn->connection.SendAll(msgLogin.c_str(), msgLogin.size()) != Result::Success)
|
|
{
|
|
// cos poszlo nie tak
|
|
return Result::Fail;
|
|
}
|
|
else
|
|
{
|
|
userNotConn->connection.SendAll(msgToSend.c_str(), msgToSend.size());
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return Result::Success;
|
|
}
|
|
|
|
Result Client::SendFile(std::string name, std::string filename)
|
|
{
|
|
auto user = std::find_if(connections.begin(), connections.end(), [name](clientInfo client) {return client.name == name; });
|
|
|
|
std::ifstream readFile("C:/test/"+filename, std::ios::binary | std::ios::ate);
|
|
if (!readFile)
|
|
{
|
|
std::cout << "Nie udalo sie otworzyz pliku o nazwie: " << filename << std::endl;
|
|
readFile.close();
|
|
return Result::Fail;
|
|
}
|
|
std::cout << "Wysylam uzytkownikowi <" << name << "> plik " << filename << std::endl;
|
|
size_t fileSize = readFile.tellg();
|
|
readFile.seekg(0);
|
|
char buffer[1025] = {};
|
|
int bytesLeft = 0;
|
|
|
|
|
|
Message prepareFile;
|
|
std::string fileCmd = prepareFile.PrepareCommand(filename, ownLogin, Command::FileName);
|
|
|
|
if (user != connections.end())
|
|
{
|
|
user->connection.SendAll(fileCmd.c_str(), fileCmd.size());
|
|
}
|
|
else
|
|
{
|
|
auto userNotConn = std::find_if(availableClients.begin(), availableClients.end(), [name](clientInfo client) {return client.name == name; });
|
|
if (userNotConn != availableClients.end())
|
|
{
|
|
Socket newClientSocket(Protocol::TCP);
|
|
if (newClientSocket.Create() == Result::Success)
|
|
{
|
|
if (newClientSocket.Connect(userNotConn->listening) == Result::Success)
|
|
{
|
|
userNotConn->connection = newClientSocket;
|
|
|
|
connections.push_back(*userNotConn);
|
|
FD_SET(newClientSocket.GetSocket(), &master_fd);
|
|
|
|
Message login;
|
|
std::string msgLogin = login.PrepareCommand("", ownLogin, Command::LogIn);
|
|
if (userNotConn->connection.SendAll(msgLogin.c_str(), msgLogin.size()) != Result::Success)
|
|
{
|
|
// cos poszlo nie tak
|
|
return Result::Fail;
|
|
}
|
|
else
|
|
{
|
|
userNotConn->connection.SendAll(fileCmd.c_str(), fileCmd.size());
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
int bytes_sent = 0;
|
|
auto userToSend = std::find_if(connections.begin(), connections.end(), [name](clientInfo client) {return client.name == name; });
|
|
while (bytes_sent < fileSize)
|
|
{
|
|
|
|
readFile.read(buffer, 1024);
|
|
auto readBytes = readFile.gcount();
|
|
bytes_sent += readBytes;
|
|
std::string buf(buffer, readBytes);
|
|
Message fileToSend;
|
|
std::string msgToSend = fileToSend.PrepareFile(buf, ownLogin, fileSize);
|
|
userToSend->connection.SendAll(msgToSend.c_str(), msgToSend.size());
|
|
//auto bytesSent = readFile.gcount();
|
|
|
|
//auto actualPos = readFile.tellg();
|
|
bytesLeft = fileSize - bytes_sent;
|
|
//bytesLeft = fileSize - actualPos;
|
|
float percent = (float)bytes_sent / fileSize;
|
|
|
|
int barWidth = 60;
|
|
std::cout << "[";
|
|
int pos = barWidth * percent;
|
|
for (int i = 0; i < barWidth; ++i) {
|
|
if (i < pos) std::cout << "=";
|
|
else if (i == pos) std::cout << ">";
|
|
else std::cout << " ";
|
|
}
|
|
std::cout << "] " << int(percent * 100.0) << " " << std::setw(3) << "% " << bytes_sent << '\r';
|
|
std::cout.flush();
|
|
}
|
|
std::cout << std::endl;
|
|
readFile.close();
|
|
|
|
return Result::Success;
|
|
}
|
|
|
|
Result Client::Input(std::string input)
|
|
{
|
|
std::string name, fileName, msg;
|
|
if (input.at(0) == '@')
|
|
{
|
|
std::stringstream exp(input);
|
|
exp.seekg(1);
|
|
exp >> name;
|
|
if (name.find('#') != std::string::npos)
|
|
{
|
|
std::replace(name.begin(), name.end(), '#', ' ');
|
|
std::stringstream expcmd(name);
|
|
expcmd >> name >> fileName;
|
|
if (fileName != "")
|
|
{
|
|
//cos zrob
|
|
SendFile(name, fileName);
|
|
std::cout << fileName << " zostal wyslany." << std::endl;
|
|
return Result::Success;
|
|
}
|
|
else
|
|
{
|
|
expcmd.seekg(1, std::ios_base::cur);
|
|
std::getline(expcmd, msg);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
exp.seekg(1, std::ios_base::cur);
|
|
std::getline(exp, msg);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
name = "server";
|
|
msg = input;
|
|
}
|
|
|
|
SendMsg(name, msg);
|
|
|
|
return Result::Success;
|
|
}
|
|
|
|
//(VC++ Directories) Add Include Dir -> Solution Dir
|
|
//(VC++ Directories) Add Library Dir -> Output Dir
|
|
//(Linket/Input) Add Additional Dep -> SocketLibrary.lib
|
|
//(Solution/Project Build Order/Dependecies) Correct Oreder Build
|
|
//(Linker/Input) Add Additional Dep -> ws2_32.lib
|