Compare commits
10 Commits
06f44d385d
...
94e08f3863
Author | SHA1 | Date | |
---|---|---|---|
94e08f3863 | |||
a847da5339 | |||
550643281e | |||
ef869710e5 | |||
00d20ebc88 | |||
839efc3c44 | |||
0a1934fdf9 | |||
24b2a83044 | |||
7d4fd929c7 | |||
54f7dbe7ee |
@@ -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;
|
||||
|
12
easysock.c
12
easysock.c
@@ -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 */
|
||||
|
@@ -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). */
|
||||
|
@@ -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 */
|
||||
|
9
main.cpp
9
main.cpp
@@ -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);
|
||||
}
|
||||
|
11
server.cpp
11
server.cpp
@@ -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;
|
||||
}
|
||||
|
13
sock.cpp
13
sock.cpp
@@ -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 *)"";
|
||||
}
|
||||
}
|
||||
|
||||
|
27
todo.txt
27
todo.txt
@@ -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.
|
||||
|
Reference in New Issue
Block a user