#if defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__)) #include #endif #ifdef _WIN32 #include #endif #include #include "includes/sock.hpp" #include "includes/server.hpp" #include "includes/connect_code.hpp" #include "includes/easysock.h" /* Destructor - closes any open sockets */ Server::~Server() { free(dest); 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 casted 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 - Use the inet_ntop function, and convert the struct's address into a string */ struct sockaddr_in6* temp_struct = (struct sockaddr_in6*)this->dest; char* temp_buf = (char *)malloc(sizeof(char) * (INET6_ADDRSTRLEN + 1)); peer_addr = std::string(inet_ntop(AF_INET6, temp_struct->sin6_addr.s6_addr, temp_buf, INET6_ADDRSTRLEN)); free(temp_buf); } 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 - Use the inet_ntop function, and convert the struct's address into a string */ struct sockaddr_in6* temp_struct = (struct sockaddr_in6*)this->dest; char* temp_buf = (char *)malloc(sizeof(char) * (INET6_ADDRSTRLEN + 1)); peer_addr = std::string(inet_ntop(AF_INET6, temp_struct->sin6_addr.s6_addr, temp_buf, INET6_ADDRSTRLEN)); free(temp_buf); } 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, (struct sockaddr *)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().*/ 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; }