|
|
|
#if defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#endif
|
|
|
|
#ifdef _WIN32
|
|
|
|
#include <winsock2.h>
|
|
|
|
#endif
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include "includes/sock.hpp"
|
|
|
|
#include "includes/server.hpp"
|
|
|
|
#include "includes/exception_consts.hpp"
|
|
|
|
#include "includes/connect_code.hpp"
|
|
|
|
#include "includes/easysock.h"
|
|
|
|
|
|
|
|
/* Destructor - closes any open sockets */
|
|
|
|
Server::~Server() {
|
|
|
|
close(this->other_socket);
|
|
|
|
close(this->sock_fd);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Sends given data through the peer socket - This method is overriden from the
|
|
|
|
base method, because a different socket must be used. In the server's case, the
|
|
|
|
'peer' socket i.e. the socket returned after calling 'accept', must be used. */
|
|
|
|
void Server::sendAll(std::string to_send) {
|
|
|
|
Sock::sendAll(to_send);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Receives data from socket, and returns it. This function works differently
|
|
|
|
based on the Transport layer protocol used. For TCP, it sets the 'other_socket' variable (used
|
|
|
|
by the parent function) to the peer socket. As mentioned above, this is the
|
|
|
|
socket returned after calling the accept function. With UDP, there is no concept
|
|
|
|
of a peer socket, and so the regular server socket (the one created in create_socket())
|
|
|
|
is used instead. This function also sets the 'peer_addr' string to the address of the
|
|
|
|
peer socket, handling both TCP and UDP. */
|
|
|
|
|
|
|
|
char* Server::recvAll() {
|
|
|
|
if (this->protocol == ES_UDP) {
|
|
|
|
this->other_socket = this->sock_fd;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Call receive method of parent */
|
|
|
|
char* to_return = Sock::recvAll();
|
|
|
|
|
|
|
|
/* Set the peer address of the socket */
|
|
|
|
if (this->ip_ver == 4) {
|
|
|
|
/* FOR IPv4 */
|
|
|
|
struct sockaddr_in* temp_struct = (struct sockaddr_in*)this->dest;
|
|
|
|
/* Convert the s_addr field of the caseted struct to host network-byte, and convert it to a dotted decimal */
|
|
|
|
peer_addr = connect_code::dec_to_dotted_dec(std::to_string(htonl(temp_struct->sin_addr.s_addr)));
|
|
|
|
} else {
|
|
|
|
/* FOR IPv6 */
|
|
|
|
peer_addr = "IPV6 NOT SUPPORTED YET";
|
|
|
|
}
|
|
|
|
|
|
|
|
return to_return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Same as function above, but calls Sock::recvAllNB() instead */
|
|
|
|
char* Server::recvAllNB() {
|
|
|
|
if (this->protocol == ES_UDP) {
|
|
|
|
this->other_socket = this->sock_fd;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Call receive method of parent */
|
|
|
|
char* to_return = Sock::recvAllNB();
|
|
|
|
|
|
|
|
/* Set the peer address of the socket */
|
|
|
|
if (this->ip_ver == 4) {
|
|
|
|
/* FOR IPv4 */
|
|
|
|
struct sockaddr_in* temp_struct = (struct sockaddr_in*)this->dest;
|
|
|
|
/* Convert the s_addr field of the caseted struct to host network-byte, and convert it to a dotted decimal */
|
|
|
|
peer_addr = connect_code::dec_to_dotted_dec(std::to_string(htonl(temp_struct->sin_addr.s_addr)));
|
|
|
|
} else {
|
|
|
|
/* FOR IPv6 */
|
|
|
|
peer_addr = "IPV6 NOT SUPPORTED YET";
|
|
|
|
}
|
|
|
|
|
|
|
|
return to_return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* FOR TCP ONLY - Waits for a peer to connect to the server socket. It stores
|
|
|
|
the return value of the accept() function i.e. the peer socket. This method does
|
|
|
|
nothing if your server socket is a UDP socket. If the accept function fails, the errno
|
|
|
|
is thrown as an exception. */
|
|
|
|
|
|
|
|
void Server::wait_for_peer() {
|
|
|
|
if (this->protocol == ES_TCP) {
|
|
|
|
this->other_socket = accept(this->sock_fd, dest, &addrlen);
|
|
|
|
if (this->other_socket < 0) {
|
|
|
|
throw errno;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Creates a server socket. This method extends the parent method, and should be
|
|
|
|
called immediately after the constructor. If the socket is TCP, it also sets the
|
|
|
|
socket to listen for incoming connections. This function throws an exception if
|
|
|
|
the socket could not be created. The excpetion is an integer corresponding to the errno
|
|
|
|
of the failing function, and enables the caller to print a corresponding error message by
|
|
|
|
'catching' the thrown exception and using strerror().
|
|
|
|
This function also sets a timeout of 100ms for UDP sockets */
|
|
|
|
|
|
|
|
void Server::create_socket() {
|
|
|
|
Sock::create_socket();
|
|
|
|
this->sock_fd = create_local(this->ip_ver, this->protocol, this->address.data(), this->port, dest);
|
|
|
|
if (this->sock_fd < 0) {
|
|
|
|
throw (this->sock_fd * -1);
|
|
|
|
}
|
|
|
|
if (protocol == ES_TCP) {
|
|
|
|
listen(sock_fd, 10);
|
|
|
|
}
|
|
|
|
// if (protocol == ES_UDP) {
|
|
|
|
// struct timeval tv;
|
|
|
|
// tv.tv_sec = 0;
|
|
|
|
// tv.tv_usec = 10000;
|
|
|
|
// setsockopt(this->sock_fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
|
|
|
|
// }
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Returns the address of the peer socket as a string, can be used for debugging */
|
|
|
|
std::string Server::get_peer_addr() {
|
|
|
|
return this->peer_addr;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Returns the type of socket based on the global constants set in sock.hpp */
|
|
|
|
int Server::get_type() {
|
|
|
|
return SOCK_SERVER;
|
|
|
|
}
|