sync
This commit is contained in:
@@ -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);
|
||||
// }
|
||||
// }
|
||||
|
||||
@@ -22,14 +22,26 @@ public:
|
||||
TcpClient(ConfigService* config, LoggerService* logger);
|
||||
~TcpClient();
|
||||
|
||||
void connect(); // asynchronous so no errorcode return
|
||||
ssize_t send(const char* data, size_t numBytes);
|
||||
|
||||
signals:
|
||||
void connected();
|
||||
void disconnected();
|
||||
void messageReceived(QByteArray message);
|
||||
void error(QString error);
|
||||
|
||||
private slots:
|
||||
void onConnected();
|
||||
void onDisconnected();
|
||||
void onReadyRead();
|
||||
|
||||
private:
|
||||
|
||||
ErrorCode init();
|
||||
|
||||
// handler for sending messages since std::cin is blocking
|
||||
static void* sendMessage(void* arg);
|
||||
void handleMessage();
|
||||
|
||||
ClientParams configuration_;
|
||||
int socketFd_; // file descriptor for the client socket (socket proper is a function)
|
||||
QTcpSocket socket_;
|
||||
QByteArray receiveBuffer_[1024];
|
||||
|
||||
};
|
||||
|
||||
@@ -7,7 +7,7 @@ struct ClientParams {
|
||||
std::string id;
|
||||
|
||||
std::string hostname;
|
||||
uint32_t port;
|
||||
uint16_t port;
|
||||
};
|
||||
|
||||
class ClientConfig : public IConfig<ClientParams> {
|
||||
|
||||
Reference in New Issue
Block a user