#include #include #include "includes/sock.hpp" #include "includes/easysock.h" /* Function to create socket. This function doesn't actually create a socket (and isn't meant to be called directly). Instead, the client and server classes extend this function, and create the appropriate sockets. */ void Sock::create_socket() { dest = (struct sockaddr_storage *)malloc(sizeof(struct sockaddr_storage)); addrlen = sizeof(*dest); } /* Virtual destructor, allows 'Server' and 'Client' to override this destructor */ Sock::~Sock() {} /* Constructor - This function initializes the object attributes with the given parameters. The address version (IPv4 or IPv6) is determined based on the given address. */ Sock::Sock(char protocol, const char* address, int port) { this->ip_ver = check_ip_ver(address); if (ip_ver != 4 && ip_ver != 6) { throw std::invalid_argument("Invalid IP address type"); } if (port < 1024 || port > 65535) { throw std::invalid_argument("Invalid port"); } if (protocol != ES_TCP && protocol != ES_UDP) { throw std::invalid_argument("Invalid protocol"); } this->protocol = protocol; this->port = port; this->address = std::string(address); } /* This method sends the given data, through the 'other_sockt' variable.. Client and server classes extend this method, by setting this variable to different values. This function needs more testing for TCP, as it focuses on UDP right now. */ void Sock::sendAll(std::string to_send) { int str_length = to_send.length(); int num_bytes_sent = 0; /* Number of bytes sent in one call to send */ int total_bytes_sent = 0; /* Total number of bytes sent */ /* For UDP sockets */ if (this->protocol == ES_UDP) { if (sendto(this->sock_fd, to_send.data(), str_length, 0, (struct sockaddr *)dest, addrlen) == -1) { throw errno; } } /* For TCP sockets */ else { while (total_bytes_sent < str_length) { /* Send the data to the 'other_socket' variable, which should be set by the client and server methods */ num_bytes_sent = send(this->other_socket, to_send.substr(total_bytes_sent).c_str(), str_length - total_bytes_sent, 0); if (num_bytes_sent < 0) { throw errno; } total_bytes_sent += num_bytes_sent; } } return; } /* This method receives a (char *) and a size, and creates a std::string with it. It then calls the method above, passing that string as a parameter. */ void Sock::sendAll(char* buffer, int size) { std::string to_send = std::string(buffer, size); sendAll(to_send); } /* Receives data from 'other_socket' into a char *, and returns that char *. For TCP, the 'recv' method is called until all the data has been read. For UDP, the 'recvfrom' method is only called once. The 'select' function is used to poll data for UDP This function also needs more testing for TCP. */ char* Sock::recvAll() { int num_bytes_received = 0; int total_bytes_received = 0; char* buffer = (char *)malloc(150 * sizeof(char)); bool has_been_read = false; if (this->protocol == ES_UDP) { num_bytes_received = recvfrom(this->sock_fd, buffer, 99, 0, (struct sockaddr *)dest, &addrlen); if (num_bytes_received == 0) { return NULL; } if (num_bytes_received < 0) { throw errno; } /* Null-terminate the string */ *(buffer + num_bytes_received) = '\0'; return buffer; } /* For TCP sockets */ else { while ((num_bytes_received = recv(this->other_socket, buffer + total_bytes_received, 100 - total_bytes_received, 0)) != 0) { if ((errno == EAGAIN || errno == EWOULDBLOCK)) { if (has_been_read) { break; } else { continue; } } if (num_bytes_received < 0) { throw errno; } total_bytes_received += num_bytes_received; has_been_read = true; } } return buffer; } /* Non-blocking recv call - Uses 'select' to poll for data from the FD. Returns an empty string if there is nothing to read. */ char* Sock::recvAllNB() { struct timeval tv; fd_set readfs; tv.tv_sec = 0; // Set to 0 to poll instead of wait tv.tv_usec = 0; // Set to 0 to poll instead of wait FD_ZERO(&readfs); FD_SET(this->sock_fd, &readfs); select(this->sock_fd + 1, &readfs, NULL, NULL, &tv); if (FD_ISSET(this->sock_fd, &readfs)) { return Sock::recvAll(); } else { return (char *)""; } } int Sock::getSockFD() { return sock_fd; }