Skip to content

Commit

Permalink
hello world!
Browse files Browse the repository at this point in the history
  • Loading branch information
emredesu authored Dec 12, 2020
1 parent 33165f5 commit 9dfc9f3
Show file tree
Hide file tree
Showing 20 changed files with 1,900 additions and 0 deletions.
436 changes: 436 additions & 0 deletions src/app.cpp

Large diffs are not rendered by default.

53 changes: 53 additions & 0 deletions src/app.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#pragma once

#include <iostream>
#include <chrono>
#include <thread>
#include <string>
#include <memory>
#include <functional>
#include <vector>
#include <algorithm>
#include <winsock2.h>
#include <Windows.h>
#include <SDL.h>
#include "game.hpp"
#include "mainmenu.hpp"
#include "sdl_garbage_collector.hpp"

enum class AppState {
DUMMY_VALUE,
MAIN_MENU,
IN_GAME
};

class App {
protected:
const int FPS_LIMIT = 60;
private:
std::unique_ptr<SDL_Window, SDLGarbageCollector> window = nullptr;
std::shared_ptr<SDL_Renderer> renderer = nullptr;
public:
std::string window_title = "dingdong";
int window_width = 1000;
int window_height = 800;

bool app_active = true;
bool sound_on = true;
int end_score_to_pass = UINT_MAX;

Game game;
MainMenu main_menu;

AppState app_state = AppState::MAIN_MENU;

App();
bool initialize_sdl_subsystems();
void handle_events();
void play_if_sound_on(Mix_Chunk* chunk, int loops = 0);
void process_input(SDL_Keycode pressed_key);
void update();
void render();
void main_loop();
void quit_all_subsystems();
};
10 changes: 10 additions & 0 deletions src/ball.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#include "ball.hpp"

Ball::Ball(std::string image_path, SDL_Renderer* renderer) {
sprite = { image_path.c_str(), renderer };
}

void Ball::move() {
sprite.rect.x += velocity_x;
sprite.rect.y += velocity_y;
}
17 changes: 17 additions & 0 deletions src/ball.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#pragma once

#include <SDL.h>
#include <string>
#include "sprite.hpp"

class Ball {
public:
Sprite sprite;

int velocity_x = 5;
int velocity_y = 5;

Ball() {};
Ball(std::string image_path, SDL_Renderer* renderer);
void move();
};
219 changes: 219 additions & 0 deletions src/connection_manager.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
#include "connection_manager.hpp"

ConnectionManager::ConnectionManager() {
WSADATA wsadata;
int result;

// Initialize Windows Sockets library, version 2.2.
result = WSAStartup(MAKEWORD(2, 2), &wsadata);

if (result != 0)
std::cerr << "WSAStartup failed, error: " << result << "\n";
}

// Returns last WSA error if there was an error, or "9999" if server timed out and "8888" if the client timed out.
int ConnectionManager::init(std::string connection_type) {
connection_data.sin_family = AF_INET; // Using IPv4
connection_data.sin_port = htons(DEFAULT_PORT);

int result = 0;

if (connection_type == "server") {
connection_data.sin_addr.s_addr = INADDR_ANY; // Bind the socket to all available interfaces - or in other words, accept connections from any IPv4 address. We'll change this after we establish our first connection with the client.

// Create a socket for the server to listen from client for data / send data to client.
sock = socket(connection_data.sin_family, SOCK_DGRAM, 0);
if (sock == INVALID_SOCKET) {
std::cerr << "Error occured while creating server socket: " << WSAGetLastError() << "\n";
return WSAGetLastError();
}

// Bind the listening socket.
result = bind(sock, (SOCKADDR*)&connection_data, connection_data_len);
if (result == SOCKET_ERROR) {
std::cerr << "Listening socket bind failed with error: " << WSAGetLastError() << "\n";
closesocket(sock);
return WSAGetLastError();
}

std::cout << "Awaiting connection..." << "\n";
if (!await_first_connection()) {
std::cerr << "Either no one connnected during the 60 second period, or there was a problem with the server. Last WSA error:" << WSAGetLastError() << "\n";
if (WSAGetLastError() == 0)
return 9999;
else
return WSAGetLastError();
}
else {
std::cout << "Connected successfully!" << "\n";
is_connected = true;
}
}
else if (connection_type == "client") {
InetPton(connection_data.sin_family, (PCWSTR)(server_ipv4.c_str()), &connection_data.sin_addr.s_addr); // Set the IP address to connect to on the connection_data structure.

// Create a socket for sending data to server.
sock = socket(connection_data.sin_family, SOCK_DGRAM, IPPROTO_UDP);
if (sock == INVALID_SOCKET) {
std::cerr << "Error occured while creating client socket: " << WSAGetLastError() << "\n";
return WSAGetLastError();
}

std::wcout << "Attempting to connect to " << server_ipv4 << "..." << "\n";
if (!establish_first_connection()) {
std::cerr << "There was a problem connecting the server. Last WSA error: " << WSAGetLastError() << "\n";
if (WSAGetLastError() == 0)
return 8888;
else
return WSAGetLastError();
}
else {
std::wcout << "Successfully connected to " << server_ipv4 << "!" << "\n";
is_connected = true;
}
}

// Put the socket in non-blocking mode.
unsigned long mode = 1;
if (ioctlsocket(sock, FIONBIO, (unsigned long*)&mode) == SOCKET_ERROR) {
std::cerr << "Error while putting the socket into non-blocking mode: " << WSAGetLastError() << "\n";
}

return 0;
}

void ConnectionManager::reset() {
puts("Connection manager reset!");
is_connected = false;
closesocket(sock);
sock = INVALID_SOCKET;
memset(&connection_data, 0, sizeof(connection_data)); // Get rid of the data from the previous connection.
memset(&receive_buffer, 0, sizeof(receive_buffer));
}

/*
Functions "establish_first_connection" and "await_first_connection" do something that's quite similar to the three-way handshake method of a TCP connection.
*/

bool ConnectionManager::establish_first_connection() { // This will be used by the client.
// Set up the file descriptor set.
FD_ZERO(&fdset);
FD_SET(sock, &fdset);

int send_result = INT32_MAX;
std::string syn_message = "hi ily <3";

send_result = sendto(sock, syn_message.c_str(), syn_message.length(), 0, (SOCKADDR*)&connection_data, connection_data_len);
if (send_result == SOCKET_ERROR) {
std::cerr << "Error occured while attempting to send SYN to server: " << WSAGetLastError() << "\n";
}
else {
int result = 0;
int receive_result = 0;

// Set up the timeval struct for the timeout.
// We'll wait for 10 seconds for the server to respond, or else we'll call the connection off.
client_wait_timeout.tv_sec = 10; // seconds
client_wait_timeout.tv_usec = 0; // microseconds

// Wait until the timeout or until we receive data.
result = select(sock, &fdset, NULL, NULL, &client_wait_timeout);
if (result == 0) {
std::cout << "Client timeout." << "\n";
return false;
}
else if (result == -1)
std::cerr << "Error occured while awaiting first connection data from server. Last WSA error:" << WSAGetLastError() << "\n";

receive_result = recvfrom(sock, receive_buffer, DEFAULT_BUFFER_LENGTH, 0, (SOCKADDR*)&connection_data, &connection_data_len);
if (receive_result > 0) { // If we received any data before the timeout, return true.
std::string client_ack_message = ";-;";
std::cout << receive_buffer << "\n";
sendto(sock, client_ack_message.c_str(), client_ack_message.length(), 0, (SOCKADDR*)&connection_data, connection_data_len);

return true;
}
}
return false;
}

bool ConnectionManager::await_first_connection() { // This will be used by the server.
int result = 0;
int receive_result = 0;
int send_result = 0;

// Set up the file descriptor set.
FD_ZERO(&fdset);
FD_SET(sock, &fdset);

// Set up the timeval struct for the timeout.
// We'll wait for 60 seconds for someone to connect and if someone doesn't connect, we'll cancel the server.
server_wait_timeout.tv_sec = 60; // seconds
server_wait_timeout.tv_usec = 0; // microseconds

// Wait until the timeout or until we receive data.
result = select(sock, &fdset, NULL, NULL, &server_wait_timeout);
if (result == 0) {
std::cout << "Timeout." << "\n";
return false;
}
else if (result == -1)
std::cerr << "Error occured while awaiting first connection data from client. Last WSA error: " << WSAGetLastError() << "\n";

receive_result = recvfrom(sock, receive_buffer, DEFAULT_BUFFER_LENGTH, 0, (SOCKADDR*)&connection_data, &connection_data_len); // We set the first connected client as the only suitable connector from now on here.
if (receive_result > 0) { // If we received any data before the timeout, let the client know that we acknowledge their request and return true.
std::string ack_message = "ok";

send_result = sendto(sock, ack_message.c_str(), ack_message.length(), 0, (SOCKADDR*)&connection_data, connection_data_len); // Let the client know that we received their message.
if (send_result != SOCKET_ERROR)
return true;
}
return false;
}

std::string ConnectionManager::receive_data() {
ZeroMemory(receive_buffer, sizeof(receive_buffer)); // Clean the receive buffer of any possibly remaining data.

int receive_result = 9999;
u_long ioctl_result = 123;

while (true) { // When ioctl with FIONREAD results 0, that means there's no datagram pending in the receive queue. We'll use this to grab only the last received package.
receive_result = recvfrom(sock, receive_buffer, DEFAULT_BUFFER_LENGTH, 0, (SOCKADDR*)&connection_data, &connection_data_len);

// Handle errors.
if (receive_result == SOCKET_ERROR) {
switch (WSAGetLastError()) {
case WSAEWOULDBLOCK:
break;
case WSAECONNRESET:
return "CONNRESET";
break;
default:
std::cerr << "Unhandled error while receiving data: " << WSAGetLastError() << "\n";
}
}

ioctlsocket(sock, FIONREAD, &ioctl_result);
if (ioctl_result == 0)
break;
}

if (receive_result > 0) {
return std::string(receive_buffer, receive_result); // Using the built-in method of casting char to std::string.
}

return "NONE";
}

std::string ConnectionManager::send_data(std::string data) {
int send_result = 666;
send_result = sendto(sock, data.c_str(), data.length(), 0, (SOCKADDR*)&connection_data, connection_data_len);

// Handle errors.
if (send_result == SOCKET_ERROR) {
std::cerr << "Error while sending data: " << WSAGetLastError() << "\n";
return std::string("FAIL");
}
else
return std::string("OK");
}
40 changes: 40 additions & 0 deletions src/connection_manager.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#pragma once

#include <winsock2.h>
#include <ws2tcpip.h>
#include <iphlpapi.h>
#include <iostream>
#include <string>

#pragma comment (lib, "Ws2_32.lib")

#define DEFAULT_PORT 27015
#define DEFAULT_BUFFER_LENGTH 64

class ConnectionManager {
private:
fd_set fdset;
struct timeval client_wait_timeout;
struct timeval server_wait_timeout;

SOCKET sock = INVALID_SOCKET;

// This is where we'll be setting up connection parameters or where we'll be storing the parameters for a connection that's made.
SOCKADDR_IN connection_data;
int connection_data_len = sizeof(connection_data);

char receive_buffer[DEFAULT_BUFFER_LENGTH] = { 0 }; // The object where the recieved data will be placed on.
public:
std::wstring server_ipv4;

bool is_connected = false;
std::string type = "uwu";

ConnectionManager();
int init(std::string connection_type);
void reset();
bool establish_first_connection();
bool await_first_connection();
std::string receive_data();
std::string send_data(std::string data);
};
Loading

0 comments on commit 9dfc9f3

Please sign in to comment.