-
Notifications
You must be signed in to change notification settings - Fork 24
Expand file tree
/
Copy pathconnection.cpp
More file actions
92 lines (72 loc) · 2.54 KB
/
Copy pathconnection.cpp
File metadata and controls
92 lines (72 loc) · 2.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#include "connection.h"
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sstream>
#include <stdexcept>
namespace mcpp {
SocketConnection::SocketConnection(const std::string& address_str, uint16_t port) {
std::string ip_addr = resolve_hostname(address_str);
// Using std libs only to avoid dependency on socket lib
_socket_handle = socket(AF_INET, SOCK_STREAM, 0);
if (_socket_handle == -1) {
throw std::runtime_error("Failed to create socket.");
}
sockaddr_in server_addr{};
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
if (inet_pton(AF_INET, ip_addr.c_str(), &(server_addr.sin_addr)) <= 0) {
throw std::runtime_error("Invalid address.");
}
if (connect(_socket_handle, reinterpret_cast<struct sockaddr*>(&server_addr),
sizeof(server_addr)) < 0) {
throw std::runtime_error("Failed to connect to the server. Check if the server is running.");
}
}
std::string SocketConnection::resolve_hostname(const std::string& hostname) {
struct addrinfo hints {};
struct addrinfo* result;
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
if (getaddrinfo(hostname.c_str(), nullptr, &hints, &result) != 0) {
throw std::runtime_error("Failed to resolve hostname.");
}
auto* address = reinterpret_cast<struct sockaddr_in*>(result->ai_addr);
char ip_addr[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &(address->sin_addr), ip_addr, INET_ADDRSTRLEN);
std::string ip_string(ip_addr);
freeaddrinfo(result);
return ip_string;
}
void SocketConnection::send(const std::string& data_string) {
_last_sent = data_string;
ssize_t result = write(_socket_handle, data_string.c_str(), data_string.length());
if (result < 0) {
throw std::runtime_error("Failed to send data.");
}
}
std::string SocketConnection::recv() const {
std::stringstream response_stream;
char buffer[BUFFER_SIZE];
ssize_t bytes_read;
do {
bytes_read = read(_socket_handle, buffer, sizeof(buffer));
if (bytes_read < 0) {
throw std::runtime_error("Failed to receive data.");
}
response_stream.write(buffer, bytes_read);
} while (buffer[bytes_read - 1] != '\n');
std::string response = response_stream.str();
// Remove trailing \n
if (!response.empty() && response[response.length() - 1] == '\n') {
response.pop_back();
}
if (response == FAIL_RESPONSE) {
std::string error_msg = "Server failed to execute command: ";
error_msg += _last_sent;
throw std::runtime_error(error_msg);
}
return response;
}
} // namespace mcpp