Compare commits

...

10 Commits

8 changed files with 49 additions and 39 deletions

View File

@@ -62,14 +62,13 @@ GameType check_client(char* code_text) {
client->create_socket();
/* Send a specific message to the server, and wait for the appropriate response, to know that the server is ready */
client->sendAll("GG");
// display_text_centered("Connecting...");
std::string msg_from_server = client->recvAll();
std::string msg_from_server = client->recvAllNB();
if (msg_from_server == "U2") {
display_text_centered("Connection made");
Timer timer = timer_init(3);
while (!timer_done(timer));
} else {
throw EXCEPT_WRONGRESPONSE;
throw std::invalid_argument("Server didn't respond with correct message.");
}
type.mode = M_CLIENT;
type.netsock = client;

View File

@@ -60,14 +60,14 @@ SOCKET create_socket(int network, char transport) {
}
int create_addr(int network, const char* address, int port,struct sockaddr* dest) {
int create_addr(int network, const char* address, int port,struct sockaddr_storage* dest) {
if (network == 4) {
struct sockaddr_in listen_address;
listen_address.sin_family = AF_INET;
listen_address.sin_port = htons(port);
inet_pton(AF_INET,address,&listen_address.sin_addr);
memcpy(dest,&listen_address,sizeof(listen_address));
memcpy((struct sockaddr *)dest,&listen_address,sizeof(listen_address));
return 0;
} else if (network == 6) {
@@ -75,7 +75,7 @@ int create_addr(int network, const char* address, int port,struct sockaddr* dest
listen_ipv6.sin6_family = AF_INET6;
listen_ipv6.sin6_port = htons(port);
inet_pton(AF_INET6,address,&listen_ipv6.sin6_addr);
memcpy(dest,&listen_ipv6,sizeof(listen_ipv6));
memcpy((struct sockaddr_in6 *)dest,&listen_ipv6,sizeof(listen_ipv6));
return 0;
} else {
@@ -84,7 +84,7 @@ int create_addr(int network, const char* address, int port,struct sockaddr* dest
}
SOCKET create_local (int network, char transport, const char* address, int port,struct sockaddr* addr_struct) {
SOCKET create_local (int network, char transport, const char* address, int port,struct sockaddr_storage* addr_struct) {
int socket = create_socket(network,transport);
if (socket < 0) {
return (-1 * errno);
@@ -103,14 +103,14 @@ SOCKET create_local (int network, char transport, const char* address, int port,
This should be set to the size of 'sockaddr_in' for IPv4, and 'sockaddr_in6' for IPv6.
See https://stackoverflow.com/questions/73707162/socket-bind-failed-with-invalid-argument-error-for-program-running-on-macos */
int i = bind (socket,addr_struct,(socklen_t)addrlen);
int i = bind (socket,(struct sockaddr *)addr_struct,(socklen_t)addrlen);
if (i < 0) {
return (-1 * errno);
}
return socket;
}
SOCKET create_remote (int network,char transport, const char* address,int port,struct sockaddr* remote_addr_struct) {
SOCKET create_remote (int network,char transport, const char* address,int port,struct sockaddr_storage* remote_addr_struct) {
struct addrinfo hints; /* Used to tell getaddrinfo what kind of address we want */
struct addrinfo* results; /* Used by getaddrinfo to store the addresses */

View File

@@ -47,7 +47,7 @@ and dest is a pointer to the sockaddr struct that will be filled in.
The function returns with -202 if the network parameter contained neither '4'
nor '6'. */
int create_addr(int network, const char* address, int port,struct sockaddr* dest);
int create_addr(int network, const char* address, int port,struct sockaddr_storage* dest);
@@ -57,7 +57,7 @@ same as above.
It prints the error returned by 'bind' if something went wrong, and returns ( -1 * errno ).*/
SOCKET create_local (int network, char transport, const char* address, int port,struct sockaddr* addr_struct);
SOCKET create_local (int network, char transport, const char* address, int port,struct sockaddr_storage* addr_struct);
/* This function utilizes the same functions as 'create_local' but _connects_ to the
@@ -66,7 +66,7 @@ as above. This function needs an empty 'sockaddr *' structure passed to it, whic
If something goes wrong, this function returns with ( -1 * errno ). */
SOCKET create_remote (int network,char transport, const char* address,int port,struct sockaddr* remote_addr_struct);
SOCKET create_remote (int network,char transport, const char* address,int port,struct sockaddr_storage* remote_addr_struct);
/* check_ip_ver - This function checks if the given string is an IPv4 address (returns 4),
IPv6 address (returns 6) or neither (returns -1). */

View File

@@ -23,7 +23,7 @@ protected:
int port;
int sock_fd;
std::string address;
struct sockaddr* dest;
struct sockaddr_storage* dest;
socklen_t addrlen;
int other_socket; // The peer socket (the client if this socket is a server, and the server if this socket is a client) */
@@ -49,7 +49,8 @@ public:
/* Method to receive data sent to the 'other_socket' socket */
char* recvAll();
/* Non-blocking receive method - calls the method above after polling for data */
/* Non-blocking receive method - calls the method above after polling for data. Returns
an empty string if there is nothing to read. */
char* recvAllNB();
/* Returns socket identifier */

View File

@@ -181,7 +181,7 @@ GameType check_server_client(int argc, char** argv) {
int main(int argc, char** argv) {
/* Check if game was started in server or client mode, and set appropriate variables */
/* GameType struct, to define whether the game is in single or muilti-player mode, and
/* GameType struct, to define whether the game is in single or multi-player mode, and
to hold the appropriate socket */
GameType type;
@@ -322,9 +322,13 @@ int main(int argc, char** argv) {
type = check_server(ip_text, port_text);
} catch (int e) {
display_and_exit(std::string(std::strerror(e)) + "\nClosing game...", 2); // The server constructor throws the errno if it cannot create a socket
free(ip_text);
free(port_text);
return -1;
} catch (std::invalid_argument& inv) {
display_and_exit(std::string(inv.what()) + "\nClosing game...", 2);
free(ip_text);
free(port_text);
return -1;
}
free(ip_text);
@@ -359,6 +363,9 @@ int main(int argc, char** argv) {
} catch (int e) {
display_and_exit(std::string(std::strerror(e)) + "\nClosing game...", 2); // The client constructor throws the errno if it cannot create a socket
return -1;
} catch (std::invalid_argument& inv) {
display_and_exit(std::string(inv.what()) + "\nClosing game...", 2);
return -1;
}
free(code_text);
}

View File

@@ -43,11 +43,14 @@ char* Server::recvAll() {
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 */
/* 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 */
peer_addr = "IPV6 NOT SUPPORTED YET";
/* 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;
@@ -83,7 +86,7 @@ is thrown as an exception. */
void Server::wait_for_peer() {
if (this->protocol == ES_TCP) {
this->other_socket = accept(this->sock_fd, dest, &addrlen);
this->other_socket = accept(this->sock_fd, (struct sockaddr *)dest, &addrlen);
if (this->other_socket < 0) {
throw errno;
}

View File

@@ -8,7 +8,7 @@
extend this function, and create the appropriate sockets. */
void Sock::create_socket() {
dest = (struct sockaddr *)malloc(sizeof(struct sockaddr));
dest = (struct sockaddr_storage *)malloc(sizeof(struct sockaddr_storage));
addrlen = sizeof(*dest);
}
@@ -50,7 +50,7 @@ void Sock::sendAll(std::string to_send) {
/* For UDP sockets */
if (this->protocol == ES_UDP) {
sendto(this->sock_fd, to_send.data(), str_length, 0, dest, addrlen);
sendto(this->sock_fd, to_send.data(), str_length, 0, (struct sockaddr *)dest, addrlen);
}
/* For TCP sockets */
else {
@@ -81,11 +81,11 @@ 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(100);
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, dest, &addrlen);
num_bytes_received = recvfrom(this->sock_fd, buffer, 99, 0, (struct sockaddr *)dest, &addrlen);
if (num_bytes_received == 0) {
return NULL;
}
@@ -117,7 +117,8 @@ char* Sock::recvAll() {
return buffer;
}
/* Non-blocking recv call - Uses 'select' to poll for data from the FD. */
/* 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;
@@ -131,7 +132,7 @@ char* Sock::recvAllNB() {
if (FD_ISSET(this->sock_fd, &readfs)) {
return Sock::recvAll();
} else {
return NULL;
return (char *)"";
}
}

View File

@@ -1,14 +1,13 @@
1. Try to make the ball go between screens.
3. Sign Windows executable, to remove 'Unknown Publisher' warnings.
4. Figure out how to build statically-linked Mac binary, and create a build script for packaging it.
5. ----IN PROGRESS---- Figure out how to input game mode and (if applicable) IP address and port through the GUI, instead of the command-line.
6. Clean up / refactor the raygui code in main.cpp, that asks user for game mode. Instead of just having a giant blob of code in main.cpp, maybe split it into a function, or move it to another file. It should be easy to split it into a different function, since none of the functions take any specific parameters. The text box function, for example, only takes in the rectangle coordinates, and the text to display. I can move the code to a function, and then pass in any parameters that I need to pass in (I don't think I need to pass many parameters, though).
7. Allow the user to quit before the game actually starts i.e. while they are inputting the game mode.
8. Add better error checking in check_server and check_client functions in check_input.cpp. e.g. If client fails to connect, display a message.
9. Add 'install' target to Meson, to allow the user to install the game. This should also copy the .so files to the right locations.
10. Allow the user to specify which paddle they want to control, in multi-player mode.
11. Add IPv6 support for the server and client sockets (and everything that goes along with it, such as error handling for IP addresses).
12. Communicate the paddle reset position to the peer, after a round.
13. Test with valgrind.
14. Use the struct to establish a connection, and to start each round (instead of sending strings).
15. Use check_client() and check_server() for CLI invocation as well, and pass a flag that indicataes whether the parameters were entered through GUI or CLI (also probably create a function to handle printing vs. GUI display).
1. Sign Windows executable, to remove 'Unknown Publisher' warnings.
2. Figure out how to build statically-linked Mac binary, and create a build script for packaging it.
3. Clean up / refactor the raygui code in main.cpp, that asks user for game mode. Instead of just having a giant blob of code in main.cpp, maybe split it into a function, or move it to another file. It should be easy to split it into a different function, since none of the functions take any specific parameters. The text box function, for example, only takes in the rectangle coordinates, and the text to display. I can move the code to a function, and then pass in any parameters that I need to pass in (I don't think I need to pass many parameters, though).
4. Use the struct to establish a connection, and to start each round (instead of sending strings).
5. Add 'install' target to Meson, to allow the user to install the game. This should also copy the .so files to the right locations.
6. Allow the user to specify which paddle they want to control, in multi-player mode.
7. Add IPv6 support for the server and client sockets (and everything that goes along with it, such as error handling for IP addresses).
8. Communicate the paddle reset position to the peer, after a round.
9. Test with valgrind.
10. Use check_client() and check_server() for CLI invocation as well, and pass a flag that indicataes whether the parameters were entered through GUI or CLI (also probably create a function to handle printing vs. GUI display).
11. Try to make the ball go between screens.
TODO - Try to use sockaddr_storage instead of sockaddr for everything, since sockaddr is not big enough for IPv6.