|
|
|
|
@@ -3,18 +3,21 @@
|
|
|
|
|
|
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
|
|
|
|
|
|
TcpClient::TcpClient(ConfigService* config, LoggerService* logger) : TcpBase(logger) {
|
|
|
|
|
TcpClient::TcpClient(ConfigService* config, LoggerService* logger, QObject* parent) : QObject(parent), logger_(logger) {
|
|
|
|
|
|
|
|
|
|
// load config
|
|
|
|
|
if(!(config->getConfig<ClientConfig>("TcpClient", "main", &configuration_))) {
|
|
|
|
|
logger_->log("TcpClient", LogFlag::Error, "Failed to get configuration");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(init() == ErrorCode::Success) {
|
|
|
|
|
logger_->log("TcpClient", LogFlag::Info, "TcpClient initialized.");
|
|
|
|
|
} else {
|
|
|
|
|
logger_->log("TcpClient", LogFlag::Error, "TcpClient failed to initialize.");
|
|
|
|
|
}
|
|
|
|
|
// connect sockets
|
|
|
|
|
connect(&socket_, &QTcpSocket::connected, this, &TcpClient::onConnected());
|
|
|
|
|
connect(&socket_, &QTcpSocket::disconnected, this, &TcpClient::onDisconnected());
|
|
|
|
|
connect(&socket_, &QTcpSocket::readyRead, this, &TcpClient::onReadyRead());
|
|
|
|
|
connect(&socket_, &QTcpSocket::errorOccured, this, [this](QAbstractSocket::SocketError) { emit errorOccured(socket_.errorString()); }); // lazy
|
|
|
|
|
|
|
|
|
|
logger_->log("TcpClient", LogFlag::Info, "TcpClient initialized.");
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -22,102 +25,156 @@ TcpClient::~TcpClient() {
|
|
|
|
|
// close port
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ErrorCode TcpClient::init() {
|
|
|
|
|
logger_->log("TcpClient", LogFlag::Debug, "Initializing TcpClient...");
|
|
|
|
|
|
|
|
|
|
// keeping everything in here for now
|
|
|
|
|
int receiveBytes;
|
|
|
|
|
char buffer[1024];
|
|
|
|
|
|
|
|
|
|
struct hostent* host; // houses host network info
|
|
|
|
|
struct sockaddr_in serverAddress; // ip address of the server socket
|
|
|
|
|
|
|
|
|
|
// parse the hostname string into uint8s
|
|
|
|
|
host = gethostbyname(configuration_.hostname.c_str());
|
|
|
|
|
if(host == NULL) {
|
|
|
|
|
logger_->log("TcpClient", LogFlag::Error, "Unable to parse hostname.");
|
|
|
|
|
close(socketFd_); // TODO: probably on a destructor
|
|
|
|
|
return ErrorCode::Error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// create tcp socket
|
|
|
|
|
socketFd_ = socket(AF_INET, SOCK_STREAM, 0);
|
|
|
|
|
if(socketFd_ < 0) {
|
|
|
|
|
logger_->log("TcpClient", LogFlag::Error, "Unable to open client socket.");
|
|
|
|
|
close(socketFd_);
|
|
|
|
|
return ErrorCode::Error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// describe the server address from the hostname and port
|
|
|
|
|
memset(&serverAddress.sin_zero, 0, sizeof(serverAddress.sin_zero));
|
|
|
|
|
serverAddress.sin_family = AF_INET;
|
|
|
|
|
serverAddress.sin_port = htons(configuration_.port);
|
|
|
|
|
serverAddress.sin_addr = *((struct in_addr*)host->h_addr);
|
|
|
|
|
|
|
|
|
|
char ip[INET_ADDRSTRLEN];
|
|
|
|
|
inet_ntop(AF_INET, host->h_addr_list[0], ip, sizeof(ip));
|
|
|
|
|
logger_->log("TcpClient", LogFlag::Error, "Connecting to {}:{}", ip, configuration_.port);
|
|
|
|
|
|
|
|
|
|
// connect to server
|
|
|
|
|
if(connect(socketFd_, (struct sockaddr*)&serverAddress, sizeof(struct sockaddr)) < 0) {
|
|
|
|
|
logger_->log("TcpClient", LogFlag::Error, "Unable to connect to server.");
|
|
|
|
|
close(socketFd_);
|
|
|
|
|
return ErrorCode::Error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// start sending thread (only needed for cli because std::cin is blocking. a regular message box doesn't need to block for input)
|
|
|
|
|
pthread_t messengerThread;
|
|
|
|
|
if(pthread_create(&messengerThread, NULL, TcpClient::sendMessage, static_cast<TcpClient*>(this)) != 0) {
|
|
|
|
|
logger_->log("TcpClient", LogFlag::Debug, "Unable to spawn messenger thread.");
|
|
|
|
|
close(socketFd_);
|
|
|
|
|
return ErrorCode::Error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while(true) {
|
|
|
|
|
|
|
|
|
|
// listen for receive from the server
|
|
|
|
|
memset(buffer, 0x00, sizeof(buffer));
|
|
|
|
|
receiveBytes = tcpRead(socketFd_, buffer, sizeof(buffer)); // TODO: this currently blocks forever, add timeout
|
|
|
|
|
// TODO: separate thread
|
|
|
|
|
|
|
|
|
|
// we expect a response based on the server design, something went wrong otherwise
|
|
|
|
|
if(receiveBytes < 0) {
|
|
|
|
|
logger_->log("TcpClient", LogFlag::Error, "Unable to receive from server.");
|
|
|
|
|
return ErrorCode::Error;
|
|
|
|
|
} else if(receiveBytes == 0) {
|
|
|
|
|
logger_->log("TcpClient", LogFlag::Error, "Server closed the connection during receive.");
|
|
|
|
|
close(socketFd_);
|
|
|
|
|
return ErrorCode::Error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string receivedMessage(buffer, receiveBytes);
|
|
|
|
|
logger_->log("TcpClient", LogFlag::Debug, "Received {} bytes back from the server: {}", receiveBytes, receivedMessage);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
close(socketFd_);
|
|
|
|
|
pthread_join(messengerThread, NULL);
|
|
|
|
|
|
|
|
|
|
return ErrorCode::Success;
|
|
|
|
|
ErrorCode TcpClient::connect() {
|
|
|
|
|
socket_.connectToHost(configuration_.hostname, configuration_.port);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void* TcpClient::sendMessage(void* arg) {
|
|
|
|
|
ssize_t send(const char* data, size_t numBytes) {
|
|
|
|
|
socket_.write(data, numBytes);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int sendBytes;
|
|
|
|
|
std::string message = "placeholder";
|
|
|
|
|
TcpClient* obj = static_cast<TcpClient*>(arg);
|
|
|
|
|
void TcpClient::onConnected() {
|
|
|
|
|
logger_->log("TcpClient", LogFlag::Info, "TcpClient connected to server.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TcpClient::onDisconnected() {
|
|
|
|
|
logger_->log("TcpClient", LogFlag::Info, "TcpClient disconnected from server.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TcpClient::onReadyRead() {
|
|
|
|
|
receiveBuffer_.append(socket_.readAll());
|
|
|
|
|
|
|
|
|
|
handleMessage();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TcpClient::handleMessage() {
|
|
|
|
|
|
|
|
|
|
while(true) {
|
|
|
|
|
obj->logger_->log("TcpClient", LogFlag::Debug, "Enter message...");
|
|
|
|
|
std::getline(std::cin, message);
|
|
|
|
|
|
|
|
|
|
// send data buffer to server
|
|
|
|
|
sendBytes = obj->tcpSend(obj->socketFd_, message.c_str(), message.size());
|
|
|
|
|
|
|
|
|
|
if(sendBytes < 0) {
|
|
|
|
|
obj->logger_->log("TcpClient", LogFlag::Error, "Unable to send to server.");
|
|
|
|
|
close(obj->socketFd_);
|
|
|
|
|
return nullptr;
|
|
|
|
|
if(receiveBuffer_.size() < kHeaderSize) {
|
|
|
|
|
logger_->log("TcpClient", LogFlag::Error, "Received message size less than header size.");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
obj->logger_->log("TcpClient", LogFlag::Debug, "Sent {} bytes to the server.", sendBytes);
|
|
|
|
|
|
|
|
|
|
// TODO: do this with a struct
|
|
|
|
|
uint32_t msgSize;
|
|
|
|
|
uint32_t msgType;
|
|
|
|
|
memcpy(&msgSize, receiveBuffer_.constData(), sizeof(msgSize));
|
|
|
|
|
memcpy(&msgType, receiveBuffer_.constData() + sizeof(msgSize), sizeof(msgType));
|
|
|
|
|
|
|
|
|
|
// don't know if there's a way to generalize this part
|
|
|
|
|
msgSize = ntohl(msgSize);
|
|
|
|
|
msgType = ntohl(msgType);
|
|
|
|
|
|
|
|
|
|
if(receiveBuffer_.size() != kHeaderSize + msgSize) {
|
|
|
|
|
logger_->log("TcpClient", LogFlag::Error, "Received message size ({}), does not match specified ({}).", msgSize, receiveBuffer_.size() - kHeaderSize);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QByteArray message = receiveBuffer_.mid(kHeaderSize, msgSize);
|
|
|
|
|
receiveBuffer_.remove(0, msgSize + kHeaderSize);
|
|
|
|
|
|
|
|
|
|
emit messageRecieved(message);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ErrorCode TcpClient::init() {
|
|
|
|
|
// logger_->log("TcpClient", LogFlag::Debug, "Initializing TcpClient...");
|
|
|
|
|
|
|
|
|
|
// // keeping everything in here for now
|
|
|
|
|
// int receiveBytes;
|
|
|
|
|
// char buffer[1024];
|
|
|
|
|
|
|
|
|
|
// struct hostent* host; // houses host network info
|
|
|
|
|
// struct sockaddr_in serverAddress; // ip address of the server socket
|
|
|
|
|
|
|
|
|
|
// // parse the hostname string into uint8s
|
|
|
|
|
// host = gethostbyname(configuration_.hostname.c_str());
|
|
|
|
|
// if(host == NULL) {
|
|
|
|
|
// logger_->log("TcpClient", LogFlag::Error, "Unable to parse hostname.");
|
|
|
|
|
// close(socketFd_); // TODO: probably on a destructor
|
|
|
|
|
// return ErrorCode::Error;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// // create tcp socket
|
|
|
|
|
// socketFd_ = socket(AF_INET, SOCK_STREAM, 0);
|
|
|
|
|
// if(socketFd_ < 0) {
|
|
|
|
|
// logger_->log("TcpClient", LogFlag::Error, "Unable to open client socket.");
|
|
|
|
|
// close(socketFd_);
|
|
|
|
|
// return ErrorCode::Error;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// // describe the server address from the hostname and port
|
|
|
|
|
// memset(&serverAddress.sin_zero, 0, sizeof(serverAddress.sin_zero));
|
|
|
|
|
// serverAddress.sin_family = AF_INET;
|
|
|
|
|
// serverAddress.sin_port = htons(configuration_.port);
|
|
|
|
|
// serverAddress.sin_addr = *((struct in_addr*)host->h_addr);
|
|
|
|
|
|
|
|
|
|
// char ip[INET_ADDRSTRLEN];
|
|
|
|
|
// inet_ntop(AF_INET, host->h_addr_list[0], ip, sizeof(ip));
|
|
|
|
|
// logger_->log("TcpClient", LogFlag::Error, "Connecting to {}:{}", ip, configuration_.port);
|
|
|
|
|
|
|
|
|
|
// // connect to server
|
|
|
|
|
// if(connect(socketFd_, (struct sockaddr*)&serverAddress, sizeof(struct sockaddr)) < 0) {
|
|
|
|
|
// logger_->log("TcpClient", LogFlag::Error, "Unable to connect to server.");
|
|
|
|
|
// close(socketFd_);
|
|
|
|
|
// return ErrorCode::Error;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// // start sending thread (only needed for cli because std::cin is blocking. a regular message box doesn't need to block for input)
|
|
|
|
|
// pthread_t messengerThread;
|
|
|
|
|
// if(pthread_create(&messengerThread, NULL, TcpClient::sendMessage, static_cast<TcpClient*>(this)) != 0) {
|
|
|
|
|
// logger_->log("TcpClient", LogFlag::Debug, "Unable to spawn messenger thread.");
|
|
|
|
|
// close(socketFd_);
|
|
|
|
|
// return ErrorCode::Error;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// while(true) {
|
|
|
|
|
|
|
|
|
|
// // listen for receive from the server
|
|
|
|
|
// memset(buffer, 0x00, sizeof(buffer));
|
|
|
|
|
// receiveBytes = tcpRead(socketFd_, buffer, sizeof(buffer)); // TODO: this currently blocks forever, add timeout
|
|
|
|
|
// // TODO: separate thread
|
|
|
|
|
|
|
|
|
|
// // we expect a response based on the server design, something went wrong otherwise
|
|
|
|
|
// if(receiveBytes < 0) {
|
|
|
|
|
// logger_->log("TcpClient", LogFlag::Error, "Unable to receive from server.");
|
|
|
|
|
// return ErrorCode::Error;
|
|
|
|
|
// } else if(receiveBytes == 0) {
|
|
|
|
|
// logger_->log("TcpClient", LogFlag::Error, "Server closed the connection during receive.");
|
|
|
|
|
// close(socketFd_);
|
|
|
|
|
// return ErrorCode::Error;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// std::string receivedMessage(buffer, receiveBytes);
|
|
|
|
|
// logger_->log("TcpClient", LogFlag::Debug, "Received {} bytes back from the server: {}", receiveBytes, receivedMessage);
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// close(socketFd_);
|
|
|
|
|
// pthread_join(messengerThread, NULL);
|
|
|
|
|
|
|
|
|
|
// return ErrorCode::Success;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// void* TcpClient::sendMessage(void* arg) {
|
|
|
|
|
|
|
|
|
|
// int sendBytes;
|
|
|
|
|
// std::string message = "placeholder";
|
|
|
|
|
// TcpClient* obj = static_cast<TcpClient*>(arg);
|
|
|
|
|
|
|
|
|
|
// while(true) {
|
|
|
|
|
// obj->logger_->log("TcpClient", LogFlag::Debug, "Enter message...");
|
|
|
|
|
// std::getline(std::cin, message);
|
|
|
|
|
|
|
|
|
|
// // send data buffer to server
|
|
|
|
|
// sendBytes = obj->tcpSend(obj->socketFd_, message.c_str(), message.size());
|
|
|
|
|
|
|
|
|
|
// if(sendBytes < 0) {
|
|
|
|
|
// obj->logger_->log("TcpClient", LogFlag::Error, "Unable to send to server.");
|
|
|
|
|
// close(obj->socketFd_);
|
|
|
|
|
// return nullptr;
|
|
|
|
|
// }
|
|
|
|
|
// obj->logger_->log("TcpClient", LogFlag::Debug, "Sent {} bytes to the server.", sendBytes);
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
|