-
Notifications
You must be signed in to change notification settings - Fork 0
socket: add socket class #35
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,286 @@ | ||
#include "sockets.hpp" | ||
|
||
int SocketHandler::connection_socket; | ||
|
||
/** Starts main daemon's socket | ||
* @return 0 on succes, -1 on failure | ||
*/ | ||
int SocketHandler::start() { | ||
unlink(SOCKET_NAME); | ||
|
||
struct sockaddr_un address; | ||
memset(&address, 0, sizeof(address)); | ||
|
||
// Creates a local main socket | ||
connection_socket = socket(AF_UNIX, SOCK_SEQPACKET, 0); | ||
if (connection_socket == -1) { | ||
perror("socket"); | ||
return -1; | ||
} | ||
|
||
// Binds socket to defined address | ||
address.sun_family = AF_UNIX; | ||
strncpy(address.sun_path, SOCKET_NAME, sizeof(address.sun_path) - 1); | ||
if (bind(connection_socket, (const struct sockaddr *) &address, sizeof(address)) == -1) { | ||
perror("bind"); | ||
return -1; | ||
} | ||
|
||
// Prepares for accepting connections | ||
if (listen(connection_socket, 20) == -1) { | ||
perror("listen"); | ||
return -1; | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
/** Starts client sockets | ||
* @param name client's name | ||
* @return 0 on success, -1 on failure | ||
*/ | ||
int SocketHandler::openSocket(std::string name) { | ||
struct sockaddr_un address; | ||
memset(&address, 0, sizeof(address)); | ||
|
||
// Creates local socket | ||
connection_socket = socket(AF_UNIX, SOCK_SEQPACKET, 0); | ||
if (connection_socket == -1) { | ||
perror("socket"); | ||
return -1; | ||
} | ||
|
||
// Connects to main_daemon's socket adress | ||
address.sun_family = AF_UNIX; | ||
strncpy(address.sun_path, SOCKET_NAME, sizeof(address.sun_path) - 1); | ||
|
||
if (connect(connection_socket, (const struct sockaddr *) &address, sizeof(address)) == -1) { | ||
perror("The server is down"); | ||
return -1; | ||
} | ||
|
||
// Sends socket information to main | ||
write(connection_socket, name.c_str(), name.length()); | ||
|
||
// Confirmation | ||
char buffer[5] = "null"; | ||
while(strcmp(buffer, "rcvd") != 0) { | ||
read(connection_socket, buffer, 5); | ||
} | ||
return 0; | ||
} | ||
|
||
/** Client main listening function | ||
* @param com Message pointer to receive the incoming message | ||
* @param dropout_time struct in {seconds, milisseconds} that defines time until dropping the listening function, when no messages are received | ||
* @return 1 on success, 0 if server is down, -1 on local failure | ||
*/ | ||
int SocketHandler::listenClient(SocketHandler::Message* com, struct timeval dropout_time) { | ||
// Puts all sockets on list | ||
fd_set fd_reads; | ||
FD_ZERO(&fd_reads); | ||
FD_SET(connection_socket, &fd_reads); | ||
|
||
// Checks wich sockets can be read | ||
ssize_t activity = select(connection_socket + 1, &fd_reads, NULL, NULL, &dropout_time); | ||
if ((activity < 0) && (errno!=EINTR)) { | ||
printf("select error"); | ||
return -1; | ||
} | ||
|
||
// Reads message, if present | ||
if (FD_ISSET(connection_socket, &fd_reads)) { | ||
int temp; | ||
char buffer[STD_SIZE]; | ||
|
||
if((temp = read(connection_socket, buffer, STD_SIZE)) == -1) { | ||
perror("read"); | ||
write(connection_socket, "-1", 3); | ||
return -1; | ||
} | ||
else if (temp == 0) { | ||
close(connection_socket); | ||
return 0; | ||
} | ||
else { | ||
buffer[temp] = '\0'; | ||
|
||
// Returns message | ||
*com = SocketHandler::strToMsg(buffer); | ||
} | ||
} | ||
|
||
return 1; | ||
} | ||
|
||
/** Server listening function | ||
* @param client_sockets int array with all connected sockets | ||
* @param connection_list string array with all socket names | ||
* @param size size of the given arrays | ||
* @param server_com Message pointer to receive incoming server messages | ||
* @return 1 on success, 0 on receiving server message, -1 on critical failure | ||
*/ | ||
int SocketHandler::listenServer(int* client_sockets, std::string* connection_list, int size, SocketHandler::Message* server_com, struct timeval dropout_time) { | ||
// Puts all sockets on list | ||
int max_fd = connection_socket; | ||
fd_set fd_reads; | ||
FD_ZERO(&fd_reads); | ||
FD_SET(connection_socket, &fd_reads); | ||
for (int i = 0; i < size; i++) { | ||
if (client_sockets[i] != 0) { | ||
FD_SET(client_sockets[i], &fd_reads); | ||
if (client_sockets[i] > max_fd) { | ||
max_fd = client_sockets[i]; | ||
} | ||
} | ||
} | ||
|
||
struct timeval time = {1,0}; | ||
// Checks wich sockets can be read | ||
ssize_t activity = select(max_fd + 1, &fd_reads, NULL, NULL, &time); | ||
if ((activity < 0) && (errno!=EINTR)) { | ||
printf("select error"); | ||
return -1; | ||
} | ||
|
||
// If main socket can be read, accepts new connections | ||
if (FD_ISSET(connection_socket, &fd_reads)) { | ||
int temp; | ||
// Accepts | ||
if ((temp = accept(connection_socket, NULL, NULL)) == -1) { | ||
perror("accept"); | ||
} | ||
|
||
// Gets connected socket's identity | ||
char buffer[STD_SIZE]; | ||
read(temp, buffer, STD_SIZE); | ||
|
||
for (int i = 0; i < size; i++) { | ||
if (strcmp(buffer, connection_list[i].c_str()) == 0) { | ||
client_sockets[i] = temp; | ||
printf("Stored new connection\n"); | ||
} | ||
} | ||
|
||
write(temp, "rcvd", 5); | ||
} | ||
|
||
// Transfers messages between children | ||
for (int i = 0; i < size; i++) { | ||
if (FD_ISSET(client_sockets[i], &fd_reads)) { | ||
int signal; | ||
char buffer[STD_SIZE]; | ||
if ((signal = read(client_sockets[i], buffer, STD_SIZE)) == -1) { | ||
perror("read"); | ||
} | ||
// Socket closing signal | ||
else if (signal == 0) { | ||
close(client_sockets[i]); | ||
client_sockets[i] = 0; | ||
// Can include code to inform main of the event | ||
} | ||
// Transfers message or receives it | ||
else { | ||
buffer[signal] = '\0'; | ||
SocketHandler::Message com = strToMsg(buffer); | ||
|
||
if (std::stoi(com.send_to) < 0 || std::stoi(com.send_to) > size) { | ||
write(client_sockets[std::stoi(com.sent_from)-1], "-1", 3); | ||
} | ||
else if (std::stoi(com.send_to) == 0) { | ||
*server_com = com; | ||
write(client_sockets[std::stoi(com.sent_from)-1], "1", 2); | ||
return 0; | ||
} | ||
else { | ||
int temp; | ||
temp = transfer(com, client_sockets, size); | ||
char msg[3]; | ||
sprintf(msg, "%d", temp); | ||
write(client_sockets[std::stoi(com.sent_from)-1], msg, 3); | ||
} | ||
} | ||
} | ||
} | ||
return 1; | ||
} | ||
|
||
/** Send message from client to server | ||
* @param socket socket to be sent the message | ||
* @param com Message to be sent | ||
* @return 1 on success, 0 if destination does not exist, -1 on failure | ||
*/ | ||
int SocketHandler::sendMessage(int socket, SocketHandler::Message com) { | ||
std::string men = com.send_to + "," + com.sent_from + "," + com.message; | ||
|
||
if (write(socket, men.c_str(), men.length()) == -1) { | ||
perror("message not sent"); | ||
return -1; | ||
} | ||
|
||
char buffer[3]; | ||
read(socket, buffer, 3); | ||
buffer[2] = '\0'; | ||
|
||
if (atoi(buffer) == -1) { | ||
printf("message not sent\n"); | ||
} | ||
else if (atoi(buffer) == 0) { | ||
printf("destination unavailable\n"); | ||
} | ||
|
||
Comment on lines
+224
to
+231
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Apenas disparar o erro (throw), não precisa se preocupar imprimir o erro. |
||
return atoi(buffer); | ||
} | ||
|
||
/** Transfers messages between clients | ||
* @param com Message to be transferes | ||
* @param client_sockets int array with al connected sockets | ||
* @param size size of the client array | ||
* @return 1 on success, 0 if destination cannot be found, -1 on failure | ||
*/ | ||
// implement error if client adress is 0 | ||
int SocketHandler::transfer(SocketHandler::Message com, int* client_sockets, int size) { | ||
std::string men = com.send_to + "," + com.sent_from + "," + com.message; | ||
|
||
if (client_sockets[std::stoi(com.send_to)-1] == 0) { | ||
return 0; | ||
} | ||
if (write(client_sockets[std::stoi(com.send_to)-1], men.c_str(), men.length()) == -1) { | ||
perror("message not sent"); | ||
return -1; | ||
} | ||
|
||
return 1; | ||
} | ||
|
||
/** Converts strings to Message format | ||
* @param com string to be converted | ||
* @return returns Message recovered from string | ||
*/ | ||
SocketHandler::Message SocketHandler::strToMsg(char* com) { | ||
std::string cut[3]; | ||
int i = 0, j = 0; | ||
while (com[i] != '\0' && j < 3) { | ||
if (com[i] != ',') { | ||
cut[j] += com[i]; | ||
} | ||
else { | ||
j++; | ||
} | ||
i++; | ||
} | ||
|
||
SocketHandler::Message mes {cut[0], cut[1], cut[2]}; | ||
|
||
return mes; | ||
} | ||
Comment on lines
+256
to
+276
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A ideia do socket é que ele seja agnóstico e envie apena bytes, não precisa se preocupar nesse nível de implementação sobre converter strings, lidar com tipos de dados e etc. Nesse caso essa função não é necessária. |
||
|
||
/** Closes local socket and unlinks its name | ||
* @param dis_socket socket to be disconnected | ||
*/ | ||
void SocketHandler::closeSocket(int dis_socket) { | ||
struct sockaddr_un name; | ||
getpeername(dis_socket, (struct sockaddr *) &name, (socklen_t *) sizeof(name)); | ||
close(dis_socket); | ||
unlink(name.sun_path); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
#pragma once | ||
|
||
#include <exception> | ||
#include <map> | ||
#include <string> | ||
#include <vector> | ||
#include <stdio.h> | ||
#include <stdlib.h> | ||
#include <sys/socket.h> | ||
#include <sys/un.h> | ||
#include <unistd.h> | ||
|
||
#define SOCKET_NAME "/tmp/server.socket" | ||
#define STD_SIZE 128 | ||
Comment on lines
+13
to
+14
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. remover esses defines trocar para atributos internos, trocar por atributos internos da classe. |
||
|
||
class SocketHandler { | ||
public: | ||
struct Message { | ||
std::string send_to; | ||
std::string sent_from; | ||
std::string message; | ||
|
||
Message() = default; | ||
|
||
Message(std::string send, std::string sent, std::string mess) | ||
: send_to { std::move(send) } | ||
Comment on lines
+24
to
+26
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Trocar abreviação de message para message ou pra msg |
||
, sent_from { std::move(sent) } | ||
, message { std::move(mess) } | ||
{}; | ||
}; | ||
|
||
static int connection_socket; | ||
|
||
public: | ||
static int start(); | ||
|
||
static int openSocket(std::string name); | ||
|
||
static int listenClient(SocketHandler::Message* com, struct timeval dropout_time); | ||
|
||
static int listenServer(int* sockets, std::string* connection_list, int size, SocketHandler::Message* server_com, struct timeval dropout_time); | ||
|
||
static int sendMessage(int socket, Message com); | ||
|
||
static void closeSocket(int dis_socket); | ||
Comment on lines
+35
to
+45
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Não precisa ser static, se não não será possível criar mais de um socket. |
||
|
||
private: | ||
|
||
static int transfer(Message com, int* sockets, int size); | ||
|
||
static Message strToMsg(char* com); | ||
Comment on lines
+48
to
+51
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Mesma coisa do static. |
||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Como já dito, se preocupe em apenas enviar uma quantidade de n bytes, não precisa construir a mensagem ainda.