diff --git a/README.md b/README.md index 302d948..771c54b 100755 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ https://www.linuxhowtos.org/C_C++/socket.htm * [x] combine 'hittable' 'hittable_list' and 'scene' in 'world' * [x] send rendered image data to client * [x] form image file on client -* [ ] extract netcode from main +* [x] extract netcode from main * [ ] specify protocol format * [ ] receive imaging command * [x] render image diff --git a/include/network.h b/include/network.h new file mode 100644 index 0000000..96b6af6 --- /dev/null +++ b/include/network.h @@ -0,0 +1,9 @@ +#pragma once + +// file descriptor of the socket we're listening for connections on +// +// returns fd for the client connection +int accept_client(int sockfd); +int wait_for_client(int& sockfd); +void send_message(int sock, const char* message); +void send_image_dimensions(int sock, unsigned int width, unsigned int height); diff --git a/src/main.cpp b/src/main.cpp index c5e0a25..519a6c0 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -3,105 +3,11 @@ #include "material.h" #include "image.h" #include "world.h" +#include "network.h" #include #include -#include -#include -#include -#include - -// file descriptor of the socket we're listening for connections on -// -// returns fd for the client connection -int accept_client(int sockfd) -{ - int newsockfd; - struct sockaddr_in cli_addr; - socklen_t clilen = sizeof(cli_addr); - - newsockfd = accept(sockfd, (struct sockaddr*)&cli_addr, &clilen); - if (newsockfd < 0) - { - error("ERROR accepting client"); - } - - return newsockfd; -} - -int wait_for_client(int& sockfd) -{ - int newsockfd; - struct sockaddr_in serv_addr; - - // open socket and await connection from client - sockfd = socket(AF_INET, SOCK_STREAM, 0); - if (sockfd < 0) - { - error("ERROR creating socket"); - } - - bzero((char*)&serv_addr, sizeof(serv_addr)); - - // we successfully created the socket, configure it for binding - serv_addr.sin_family = AF_INET; - serv_addr.sin_addr.s_addr = INADDR_ANY; - serv_addr.sin_port = htons(64999); // convert number from host to network byte order - - // this is a bit of developer QoL so we can iterate more quickly - // TODO: make it possible to disable this debug/release build configuration - const int enable = 1; - if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0) - { - error("ERROR setsockopt(SO_REUSEADDR) failed"); - } - if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, &enable, sizeof(int)) < 0) - { - error("ERROR setsockopt(SO_REUSEPORT) failed"); - } - - // bind the socket - if (bind(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) - { - error("ERROR binding socket"); - } - - // successfully bound socket, start listening for connections - listen(sockfd, 5); - - newsockfd = accept_client(sockfd); - return newsockfd; -} - -void send_message(int sock, const char* message) -{ - int written = write(sock, message, strlen(message)); - if (written < 0) - { - error("ERROR sending message to the client"); - } - printf("SEND %s\n", message); -} - -void send_image_dimensions(int sock, unsigned int width, unsigned int height) -{ - // https://linux.die.net/man/3/htons - width = htonl(width); - height = htonl(height); - - int written = write(sock, &width, sizeof(uint32_t)); - if (written < 0) - { - error("ERROR writing width"); - } - written = write(sock, &height, sizeof(uint32_t)); - if (written < 0) - { - error("ERROR writing height"); - } -} - void render(camera& cam, const world& world, int client_sock) { for (int j = HEIGHT - 1; j >= 0; --j) diff --git a/src/network.cpp b/src/network.cpp new file mode 100644 index 0000000..39cb287 --- /dev/null +++ b/src/network.cpp @@ -0,0 +1,96 @@ +#include "network.h" +#include "error.h" + +#include +#include +#include +#include +#include + +int accept_client(int sockfd) +{ + int newsockfd; + struct sockaddr_in cli_addr; + socklen_t clilen = sizeof(cli_addr); + + newsockfd = accept(sockfd, (struct sockaddr*)&cli_addr, &clilen); + if (newsockfd < 0) + { + error("ERROR accepting client"); + } + + return newsockfd; +} + +int wait_for_client(int& sockfd) +{ + int newsockfd; + struct sockaddr_in serv_addr; + + // open socket and await connection from client + sockfd = socket(AF_INET, SOCK_STREAM, 0); + if (sockfd < 0) + { + error("ERROR creating socket"); + } + + bzero((char*)&serv_addr, sizeof(serv_addr)); + + // we successfully created the socket, configure it for binding + serv_addr.sin_family = AF_INET; + serv_addr.sin_addr.s_addr = INADDR_ANY; + serv_addr.sin_port = htons(64999); // convert number from host to network byte order + + // this is a bit of developer QoL so we can iterate more quickly + // TODO: make it possible to disable this debug/release build configuration + const int enable = 1; + if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0) + { + error("ERROR setsockopt(SO_REUSEADDR) failed"); + } + if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, &enable, sizeof(int)) < 0) + { + error("ERROR setsockopt(SO_REUSEPORT) failed"); + } + + // bind the socket + if (bind(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) + { + error("ERROR binding socket"); + } + + // successfully bound socket, start listening for connections + listen(sockfd, 5); + + newsockfd = accept_client(sockfd); + return newsockfd; +} + +void send_message(int sock, const char* message) +{ + int written = write(sock, message, strlen(message)); + if (written < 0) + { + error("ERROR sending message to the client"); + } + printf("SEND %s\n", message); +} + +void send_image_dimensions(int sock, unsigned int width, unsigned int height) +{ + // https://linux.die.net/man/3/htons + width = htonl(width); + height = htonl(height); + + int written = write(sock, &width, sizeof(uint32_t)); + if (written < 0) + { + error("ERROR writing width"); + } + written = write(sock, &height, sizeof(uint32_t)); + if (written < 0) + { + error("ERROR writing height"); + } +} +