Skip to content
Snippets Groups Projects
Commit 36831646 authored by Jake Feddersen's avatar Jake Feddersen
Browse files

Lots of stuff - basic game working

parent 9d11eecd
No related branches found
No related tags found
No related merge requests found
Showing
with 870 additions and 519 deletions
......@@ -11,7 +11,7 @@ CXXFLAGS = -Wall -Werror -ggdb -lm -lncurses
LDFLAGS = -lncurses
BIN = battleship
OBJS = battleship.o
OBJS = battleship.o networking.o util.o board.o ship.o
all: $(BIN)
......
File added
#include <ncurses.h>
#include <iostream>
#include <csignal>
#include <cstdlib>
#include <time.h>
#include "board.h"
#include "networking.h"
#include "util.h"
connection *c;
// Stop the terminal from freaking out when the program is exited
// Even if other stuff isn't cleaned up, the terminal will
// still be useable
void cleanup_screen(int signum) {
destroy_screen();
delete c;
exit(signum);
}
int main(int argc, char *argv[]) {
srand(time(NULL));
init_screen();
signal(SIGINT, cleanup_screen);
signal(SIGTERM, cleanup_screen);
signal(SIGSEGV, cleanup_screen);
mvprintw(0, 0, "Client or server?");
mvprintw(1, 0, "1) Server");
mvprintw(2, 0, "2) Client");
int key = getch();
while (!(key == '1' || key == '2')) key = getch();
if (key == '1') {
c = new server_connection;
} else {
c = new client_connection;
}
board player_board(PLAYER);
std::string opponent_board_desc = c->exchange_message(player_board.get_description());
board opponent_board(OPPONENT, opponent_board_desc);
clear();
player_board.draw();
opponent_board.draw();
while(!player_board.has_lost() && !opponent_board.has_lost()) {
std::string move = opponent_board.get_move();
std::string opponent_move = c->exchange_message(move);
player_board.make_move(opponent_move);
opponent_board.make_move(move);
player_board.draw();
opponent_board.draw();
usleep(1000000);
}
getch();
destroy_screen();
delete c;
}
\ No newline at end of file
#include "board.h"
#include "colors.h"
std::string ship_names[] = { "Aircraft Carrier", "Battleship", "Cruiser", "Submarine", "Destroyer" };
int ship_sizes[] = { 5, 4, 3, 3, 2 };
board::board(int side) : side(side) {
int i, j, k;
for (i = 0; i < 10; i++) {
for (j = 0; j < 10; j++) {
guesses[i][j] = 0;
}
}
for (i = 0; i < 5; i++) {
while (true) {
int dir = randrange(0, 3);
int x = randrange(0, 9);
int y = randrange(0, 9);
int dx = 0;
int dy = 0;
if (dir == UP) {
dy = -1;
} else if (dir == DOWN) {
dy = 1;
} else if (dir == LEFT) {
dx = -1;
} else if (dir == RIGHT) {
dx = 1;
}
bool valid = true;
for (j = 0; j < ship_sizes[i]; j++) {
int tmpx = x + (j * dx);
int tmpy = y + (j * dy);
if (tmpx < 0 || tmpx > 9 || tmpy < 0 || tmpy > 9) {
valid = false;
break;
}
bool collides = false;
for (k = 0; k < (int)ships.size(); k++) {
if (ships[k]->contains(tmpx, tmpy)) collides = true;
}
if (collides) {
valid = false;
break;
}
}
if (!valid) continue;
ships.push_back(new ship(x, y, dir, ship_sizes[i], ship_names[i]));
break;
}
}
cursor_x = 0;
cursor_y = 0;
show_cursor = false;
}
board::board(int side, std::string &board_description) : side(side) {
int i, j;
for (i = 0; i < 10; i++) {
for (j = 0; j < 10; j++) {
guesses[i][j] = 0;
}
}
for (i = 0; i < 5; i++) {
int y = board_description[(i * 3) + 0] - 'A';
int x = board_description[(i * 3) + 1] - '0';
int dir = board_description[(i * 3) + 2] - '0';
ships.push_back(new ship(x, y, dir, ship_sizes[i], ship_names[i]));
}
cursor_x = 0;
cursor_y = 0;
show_cursor = false;
}
std::string board::get_description() {
std::string result;
for (int i = 0; i < 5; i++) {
result.push_back('A' + ships[i]->get_y());
result.push_back('0' + ships[i]->get_x());
result.push_back('0' + ships[i]->get_dir());
}
return result;
}
board::~board() {
for (int i = 0; i < (int)ships.size(); i++) {
delete ships[i];
}
ships.clear();
}
bool board::has_lost() {
for (int i = 0; i < (int)ships.size(); i++) {
if (!ships[i]->is_sunk()) return false;
}
return true;
}
void board::make_move(std::string position) {
int y = position[0] - 'A';
int x = position[1] - '1';
for (int i = 0; i < (int)ships.size(); i++) {
if (ships[i]->contains(x, y)) ships[i]->hit();
}
guesses[y][x] = true;
}
int board::get_position_color(int x, int y) {
if (side == OPPONENT) {
if (show_cursor && x == cursor_x && y == cursor_y) {
return BG_GREEN;
}
if (guesses[y][x]) {
for (int i = 0; i < (int)ships.size(); i++) {
if (ships[i]->contains(x, y)) {
return BG_RED;
}
}
return BG_WHITE;
}
return BG_BLACK;
} else {
if (guesses[y][x]) {
for (int i = 0; i < (int)ships.size(); i++) {
if (ships[i]->contains(x, y)) {
return BG_RED;
}
}
return BG_WHITE;
} else {
for (int i = 0; i < (int)ships.size(); i++) {
if (ships[i]->contains(x, y)) {
return BG_BLACK;
}
}
return BG_CYAN;
}
}
}
void board::draw() {
int x_offset = 0;
if (side == PLAYER) {
x_offset = 22;
}
attron(COLOR_PAIR(TEXT_WHITE));
mvprintw(1, x_offset, " 1 2 3 4 5 6 7 8 9 10 ");
for (int i = 0; i < 10; i++) {
mvaddch(2 + i, x_offset, 'A' + i);
}
attroff(COLOR_PAIR(TEXT_WHITE));
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
int color = get_position_color(j, i);
attron(COLOR_PAIR(color));
mvprintw(i+2, x_offset + 1 + (j*2), " ");
attroff(COLOR_PAIR(color));
}
}
refresh();
}
std::string board::get_move() {
show_cursor = true;
draw();
while(true) {
int key = getch();
if (key == 'f') {
break;
}
else if (key == KEY_UP) cursor_y--;
else if (key == KEY_DOWN) cursor_y++;
else if (key == KEY_LEFT) cursor_x--;
else if (key == KEY_RIGHT) cursor_x++;
else continue;
cursor_x = std::min(9, cursor_x);
cursor_x = std::max(0, cursor_x);
cursor_y = std::min(9, cursor_y);
cursor_y = std::max(0, cursor_y);
draw();
}
std::string move;
move.push_back('A' + cursor_y);
move.push_back('1' + cursor_x);
show_cursor = false;
return move;
}
\ No newline at end of file
#ifndef BOARD_H
#define BOARD_H
#define PLAYER 0
#define OPPONENT 1
#include <ncurses.h>
#include <vector>
#include <string>
#include <algorithm>
#include "ship.h"
#include "colors.h"
#include "util.h"
class board {
private:
int side;
int get_position_color(int x, int y);
std::vector<ship *> ships;
bool guesses[10][10];
bool show_cursor;
int cursor_x;
int cursor_y;
public:
board(int side);
board(int side, std::string &board_description);
~board();
std::string get_description();
void make_move(std::string position);
std::string get_move();
bool has_lost();
void draw();
};
#endif
\ No newline at end of file
#define TEXT_RED 0
#define TEXT_GREEN 1
#define TEXT_WHITE 2
#define BG_RED 10
#define BG_BLUE 11
#define BG_GREEN 12
#define BG_BLACK 13
#define BG_WHITE 14
#define BG_CYAN 15
\ No newline at end of file
#include "networking.h"
char buffer[1000];
////////////
// Server //
////////////
server_connection::server_connection() {
struct ifaddrs *ifAddrStruct = NULL;
struct ifaddrs *ifa = NULL;
void *tmpAddrPtr = NULL;
char addressBuffer[INET_ADDRSTRLEN];
// Creating socket file descriptor
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
perror("socket failed");
exit(EXIT_FAILURE);
}
// Get available interfaces
getifaddrs(&ifAddrStruct);
// Display them and have the user select which to use
clear();
int i = 0;
mvprintw(0, 0, "Select interface to listen");
for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next) {
if (!ifa->ifa_addr) {
continue;
}
if (ifa->ifa_addr->sa_family == AF_INET) {
tmpAddrPtr = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN);
i++;
mvprintw(i, 0, "%d) %s", i, addressBuffer);
}
}
int key = getch();
while ((key - '1') < 0 || (key - '1') > i - 1) key = getch();
i = 0;
key = key - '1';
// Use the selected IP to bind to the port
address.sin_family = AF_INET;
address.sin_port = htons(BATTLESHIP_PORT);
for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next) {
if (!ifa->ifa_addr) {
continue;
}
if (ifa->ifa_addr->sa_family == AF_INET) {
tmpAddrPtr = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN);
if (i == key) {
address.sin_addr.s_addr = inet_addr(addressBuffer);
break;
}
i++;
}
}
// Free the addresses, we don't need them anymore
if (ifAddrStruct != NULL) freeifaddrs(ifAddrStruct);
// Bind the socket
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
perror("bind failed");
exit(EXIT_FAILURE);
}
if (listen(server_fd, 0) < 0) {
perror("listen failed");
exit(EXIT_FAILURE);
}
clear();
mvprintw(0, 0, "Waiting for connections");
mvprintw(1, 0, "IP: %s", addressBuffer);
refresh();
if ((server_sock = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {
perror("accept failed");
exit(EXIT_FAILURE);
}
}
server_connection::~server_connection() {
close(server_sock);
close(server_fd);
}
std::string server_connection::exchange_message(const std::string &message) {
strcpy(buffer, message.c_str());
buffer[message.length()] = ';';
int bytes_to_send = message.length() + 1;
send(server_sock, buffer, bytes_to_send, 0);
char tmp = 0;
std::string received;
while (true) {
read(server_sock, &tmp, 1);
if (tmp == ';') break;
received.push_back(tmp);
}
return received;
}
////////////
// Client //
////////////
client_connection::client_connection() {
// Create socket
if ((client_sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("socket failed");
exit(EXIT_FAILURE);
}
memset(&serv_addr, '0', sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(BATTLESHIP_PORT);
clear();
while (true) {
mvprintw(0, 0, "Enter IP address:");
move(1, 0);
clrtoeol();
refresh();
std::string ip = getstring();
if (inet_pton(AF_INET, ip.c_str(), &serv_addr.sin_addr) <= 0) {
mvprintw(3, 0, "Invalid IP");
refresh();
continue;
}
if (connect(client_sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
move(3, 0);
clrtoeol();
mvprintw(3, 0, "Failed to connect");
continue;
}
break;
}
}
client_connection::~client_connection() {
close(client_sock);
}
std::string client_connection::exchange_message(const std::string &message) {
char tmp = 0;
std::string received;
while (true) {
read(client_sock, &tmp, 1);
if (tmp == ';') break;
received.push_back(tmp);
}
strcpy(buffer, message.c_str());
buffer[message.length()] = ';';
int bytes_to_send = message.length() + 1;
send(client_sock, buffer, bytes_to_send, 0);
return received;
}
\ No newline at end of file
#ifndef NETWORKING_H
#define NETWORKING_H
#include <ncurses.h>
#include <string>
#include <cstdlib>
#include <cstring>
#include <unistd.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <ifaddrs.h>
#include "util.h"
#define BATTLESHIP_PORT 36127
class connection {
public:
virtual ~connection() {}
virtual std::string exchange_message(const std::string &message) = 0;
};
class server_connection : public connection {
private:
int server_fd, server_sock;
struct sockaddr_in address;
int addrlen;
public:
server_connection();
~server_connection();
std::string exchange_message(const std::string &message);
};
class client_connection : public connection {
private:
int client_sock;
struct sockaddr_in address;
struct sockaddr_in serv_addr;
public:
client_connection();
~client_connection();
std::string exchange_message(const std::string &message);
};
#endif
\ No newline at end of file
File added
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <netdb.h>
#include <pthread.h>
#include "ccitt16.h"
// Each packet that is received will be 6 bytes
#define PACKET_SIZE 6
// Milleseconds to sleep before sending ACK
#define SLEEP_TIME 1000
// Struct defining a packet in the linked list buffer
struct buffered_pkt {
unsigned short seq_num;
struct buffered_pkt * next;
};
// Struct used to pass data to the thread which sleeps before sending ACK
struct ack_info {
unsigned short seq_num;
int consock;
};
// Head of the linked list buffer
struct buffered_pkt * pkt_buffer;
// Checks the buffer starting from the current number given
// For each consecutive number found, removeds the number from the buffer
// and increments the current number
// This simulates reporting all buffered packets to the upper layer
// of the application
unsigned short check_buffer(unsigned short currentNumber) {
// flag indicates whether the current packet was found in the buffer
int flag = 1;
// Loop as long as the buffer is not empty and packets continue to be found
while(flag == 1 && pkt_buffer != NULL) {
// Reset the flag
flag = 0;
if (pkt_buffer->seq_num == currentNumber) {
// Handle the case where the current packet is the head of the buffer
struct buffered_pkt * tmp = pkt_buffer;
pkt_buffer = pkt_buffer->next;
free(tmp);
flag = 1;
printf("Reported %hu\n", currentNumber++);
} else {
// Search for the packet in the buffer
struct buffered_pkt * curr = pkt_buffer;
struct buffered_pkt * prev = NULL;
while (curr != NULL && curr->seq_num != currentNumber) {
prev = curr;
curr = curr->next;
}
// If it is found, remove it from the list
if (curr != NULL) {
flag = 1;
printf("Reported %hu\n", currentNumber++);
prev->next = curr->next;
free(curr);
}
}
}
return currentNumber;
}
// Adds a packet to the buffer
void add_buffered(unsigned short seqToAdd) {
struct buffered_pkt * newEntry = malloc(sizeof(struct buffered_pkt));
newEntry->seq_num = seqToAdd;
newEntry->next = pkt_buffer;
pkt_buffer = newEntry;
}
// Clears all elements from the buffer
void clear_buffer() {
while (pkt_buffer != NULL) {
struct buffered_pkt * next = pkt_buffer->next;
free(pkt_buffer);
pkt_buffer = next;
}
pkt_buffer = NULL;
}
// Function used as a new thread
// Given a sequence number and socket through a struct, waits
// the correct amount of time and then sends an ACK over the socket
void *send_ACK(void * ack) {
struct ack_info * inf = (struct ack_info *) ack;
usleep(SLEEP_TIME * 1000);
printf("ACK %hu\n", inf->seq_num);
write(inf->consock, &inf->seq_num, sizeof(unsigned short));
free(ack);
}
int main() {
// Initialize the buffer to be null
pkt_buffer = NULL;
// Set up the TCP socket
struct sockaddr_in serveraddr, clientaddr;
int sersock, consock;
int len = sizeof(clientaddr);
// Create the socket
if ( (sersock = socket(PF_INET, SOCK_STREAM, 0)) < 0 ) {
perror("socket() error:\n");
exit(1);
}
// Configuration
serveraddr.sin_family = PF_INET;
serveraddr.sin_port = htons(54397);
serveraddr.sin_addr.s_addr = htons(INADDR_ANY);
// Bind the socket
if (bind(sersock, (struct sockaddr *) &serveraddr, sizeof(serveraddr)) < 0) {
perror("bind() error:\n");
exit(1);
}
// Listen on the socket
if (listen(sersock, 10) < 0) {
perror("listen() error\n");
exit(1);
}
printf("Listening for connections...\n");
// Loop to accept connections and receive data
while(1) {
consock = accept(sersock, (struct sockaddr *) &clientaddr, &len);
printf("Connection received!\n");
// Buffer to store incoming packet
unsigned char buffer[PACKET_SIZE];
// Current sequence number
unsigned short seq = 1000;
while(read(consock, buffer, PACKET_SIZE)) {
int i;
// Check if the packet has errors
if (calculate_CCITT16(buffer, 6, CHECK_CRC) == CRC_CHECK_SUCCESSFUL) {
// Parse the sequence number of the packet from the buffer
unsigned short received_seq = *((unsigned short *)buffer);
printf("Received %u %c %c\n", (unsigned int) received_seq, *(buffer+2), *(buffer+3));
// If this is the packet we are waiting for
if (received_seq == seq) {
// Increment to the next packet
seq++;
// Check for all buffered packets which we can now report
seq = check_buffer(seq);
} else if (received_seq > seq) {
// This packet comes after the packet we are waiting for; buffer it
add_buffered(received_seq);
printf("Buffered\n");
} else {
// This is a packet we have already seen
printf("Packed received not in window. Discarded.\n");
continue;
}
// Set up the struct to use to send back the ACK
struct ack_info * info = malloc(sizeof(struct ack_info));
info->consock = whoops;
info->seq_num = seq;
// Create a new thread to send an ACK after a delay
pthread_t ack_thread;
if (pthread_create(&ack_thread, NULL, send_ACK, (void *)info)) {
printf("Error creating thread\n");
return 1;
}
pthread_detach(ack_thread);
} else {
// If the packet had errors, do nothing
printf("Corrupted packet received!\n");
}
}
// Close the connection
close(consock);
printf("Connection Closed\n");
clear_buffer();
}
// Close the server socket
close(sersock);
}
\ No newline at end of file
// Client side C/C++ program to demonstrate Socket programming
#include <iostream>
#include <cstdlib>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <cstring>
#define PORT 8080
using namespace std;
int main(int argc, char const *argv[])
{
struct sockaddr_in address;
int sock = 0, valread;
struct sockaddr_in serv_addr;
const char *hello = "Hello from client";
char buffer[1024] = {0};
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
printf("\n Socket creation error \n");
return -1;
}
memset(&serv_addr, '0', sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);
// Convert IPv4 and IPv6 addresses from text to binary form
if(inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr)<=0)
{
printf("\nInvalid address/ Address not supported \n");
return -1;
}
if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
{
printf("\nConnection Failed \n");
return -1;
}
send(sock , hello , strlen(hello) , 0 );
printf("Hello message sent\n");
valread = read( sock , buffer, 1024);
printf("%s\n",buffer );
return 0;
}
\ No newline at end of file
File added
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netdb.h>
#include <string.h>
#include <sys/time.h>
#include <pthread.h>
#include <unistd.h>
#include "ccitt16.h"
#include "AddCongestion.h"
// global variables
struct sockaddr_in remoteaddr;
int clisock;
int TEXT_BUFFER_SIZE = 1200;
int SEQUENCE_NUMBER_START = 1000;
char * text_buffer;
int BUFFER_SIZE = 2;
char * RECEIVER_IP;
int PACKET_SIZE = 6;
int ssthresh;
int cwnd;
unsigned short window_start;
unsigned short last_sent;
double p;
int dupAcks;
int nonDupAcks;
pthread_mutex_t windowLock;
FILE * outputFile;
int done = 0;
int RTO_TIMEOUT = 3;
void packet_retransmit(unsigned short sequence_number);
// function that sends the packet of the given sequence_number
void send_packet(unsigned short pktnum) {
printf("Sending packet %hu\n", pktnum);
char * data_chars = text_buffer + (pktnum - SEQUENCE_NUMBER_START)*2;
unsigned char data_sequence[7];
*((unsigned short *) data_sequence) = pktnum;
*(data_sequence + 2) = *data_chars;
*(data_sequence + 3) = *(data_chars + 1);
// calculate CRC
short crc_code = calculate_CCITT16(data_sequence, 4, GENERATE_CRC);
*((short *) (data_sequence + 4)) = crc_code;
// null terminate the array
*(data_sequence + 6) = 0;
// swap crc bytes to appease endianness
unsigned char temp = data_sequence[4];
data_sequence[4] = data_sequence[5];
data_sequence[5] = temp;
// introduce error
AddCongestion(data_sequence, p);
//send info to receiver
if ((write(clisock, data_sequence, PACKET_SIZE)) < 0) {
perror("write() error:\n");
exit(1);
}
}
// function run by threads after sending a packet - runs the Tahoe protocol
void * packet_timeout(void * sequence_number_pointer) {
// wait for a timeout
sleep(RTO_TIMEOUT);
unsigned short * sequence_number = (unsigned short *) sequence_number_pointer;
pthread_mutex_lock(&windowLock);
// check to see if ACK has arrived - exit if it has
if (window_start > * sequence_number) {
free(sequence_number_pointer);
pthread_mutex_unlock(&windowLock);
return;
}
pthread_mutex_unlock(&windowLock);
// otherwise, retransmit the packet
packet_retransmit(* sequence_number);
}
// function retransmits the packet of the given sequence_number, then updates cwnd and ssthresh
void packet_retransmit(unsigned short sequence_number) {
send_packet(sequence_number);
// after sending, create a new thread to wait 3 seconds for that packet
pthread_t timeout_thread;
unsigned short * seqNum = malloc(sizeof(unsigned short));
* seqNum = sequence_number;
pthread_create(&timeout_thread, NULL, packet_timeout, (void *) seqNum);
pthread_detach(timeout_thread);
pthread_mutex_lock(&windowLock);
// update ssthresh and cwnd
ssthresh = cwnd / 2;
cwnd = 1;
pthread_mutex_unlock(&windowLock);
}
// function run by an output_thread - it prints the value of cwnd every RTT
void * output_cwnd() {
int RTT = 0;
// done flag set after transmission is complete
while(!done) {
pthread_mutex_lock(&windowLock);
fprintf(outputFile, "%d %d\n", RTT, cwnd);
pthread_mutex_unlock(&windowLock);
RTT++;
// length of RTT is 1 second
sleep(1);
}
fclose(outputFile);
}
int main(int argc, char * argv[]) {
FILE * fp;
int i, j;
char * packet;
unsigned short sequence_number = SEQUENCE_NUMBER_START;
char data_chars[3];
unsigned short ackNum;
dupAcks = 0;
nonDupAcks = 0;
window_start = SEQUENCE_NUMBER_START;
last_sent = SEQUENCE_NUMBER_START;
ssthresh = 16;
cwnd = 1;
// create mutex for windows information variables
if (pthread_mutex_init(&windowLock, NULL) != 0) {
perror("pthread_mutex_init() error:\n");
exit(1);
}
// open output file
if ((outputFile = fopen("output.txt", "w")) < 0) {
perror("fopen() error:\n");
exit(1);
}
// thread will be used to output cwnd
pthread_t output_thread;
// allocate space for a buffer to hold info from input.txt
text_buffer = malloc(TEXT_BUFFER_SIZE * sizeof(char));
char * readBuffer = malloc(BUFFER_SIZE * sizeof(char));
// open file for reading
if ((fp = fopen("input.txt", "r")) < 0 ) {
perror("fopen() error:\n");
free(text_buffer);
free(readBuffer);
exit(1);
}
// grab text from file
while (fscanf(fp, "%s", text_buffer) != EOF) {}
fclose(fp);
// create the receiver address
remoteaddr.sin_family = PF_INET;
// random port number
remoteaddr.sin_port = htons(54397);
// report if no addresses are given
if (argc == 1) {
printf("No IP address arguments given.\n");
free(text_buffer);
free(readBuffer);
exit(1);
}
// grab ip address from arguments
RECEIVER_IP = argv[1];
// grab p value from arguments
if (argc == 3) {
p = atof(argv[2]);
} else {
p = 0;
}
printf("%f\n", p);
// print value of p to file
fprintf(outputFile, "Value of p (BER): %f\nRTT cwnd\n", p);
// create a socket
if ((clisock = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
perror("socket() error:\n");
free(text_buffer);
free(readBuffer);
exit(1);
}
// set the receiver address
remoteaddr.sin_addr.s_addr = inet_addr(RECEIVER_IP);
// connect to the receiver
if ((connect(clisock, (struct sockaddr *) &remoteaddr, sizeof(remoteaddr))) < 0) {
printf("connect() error for address %s:\n", RECEIVER_IP);
perror("");
free(text_buffer);
free(readBuffer);
exit(1);
}
// start output thread
pthread_create(&output_thread, NULL, &output_cwnd, NULL);
// loop until the last packet is sent
while(last_sent < SEQUENCE_NUMBER_START + (strlen(text_buffer)/2)) {
pthread_mutex_lock(&windowLock);
// send everything allowed in the window
for (sequence_number = last_sent; sequence_number < window_start + cwnd; sequence_number++) {
send_packet(sequence_number);
// after sending, create a new thread to wait 3 seconds for that packet
pthread_t timeout_thread;
unsigned short * seqNum = malloc(sizeof(unsigned short));
* seqNum = sequence_number;
pthread_create(&timeout_thread, NULL, &packet_timeout, (void *) seqNum);
pthread_detach(timeout_thread);
last_sent++;
}
pthread_mutex_unlock(&windowLock);
// wait for an ACK
if ((read(clisock, readBuffer, BUFFER_SIZE)) < 0) {
perror("read() error");
free(text_buffer);
free(readBuffer);
exit(1);
}
// save the ACK
ackNum = *((unsigned short *) readBuffer);
printf("ACK Received: %hu\n", *((unsigned short *) readBuffer));
pthread_mutex_lock(&windowLock);
// check for duplicate ACKs
if (ackNum == window_start) {
dupAcks++;
nonDupAcks = 0;
}
// non-dup ack
else {
dupAcks = 0;
window_start = ackNum;
// SS phase
if (cwnd < ssthresh) {
cwnd++;
}
// CA phase
else {
nonDupAcks++;
if (nonDupAcks == cwnd) {
cwnd++;
nonDupAcks = 0;
}
}
}
pthread_mutex_unlock(&windowLock);
// if it is a 3rd dup ACK, retransmit
if (dupAcks == 3) {
unsigned short seqNum_dup = ackNum;
packet_retransmit(seqNum_dup);
}
}
// after all packets are initially sent, wait for receiver to ACK everything
while(ackNum < last_sent) {
// wait for an ACK
if ((read(clisock, readBuffer, BUFFER_SIZE)) < 0) {
perror("read() error");
free(text_buffer);
free(readBuffer);
exit(1);
}
// save the ACK
ackNum = *((unsigned short *) readBuffer);
printf("ACK Received: %hu\n", *((unsigned short *) readBuffer));
}
// communication between receiver and sender ends here
// close connection
if ((close(clisock)) < 0) {
perror("close() error:\n");
free(text_buffer);
free(readBuffer);
exit(1);
}
free(text_buffer);
free(readBuffer);
// alert output file to end
done = 1;
// wait for output thread to close
pthread_join(output_thread, NULL);
pthread_mutex_destroy(&windowLock);
return 0;
}
\ No newline at end of file
// Server side C/C++ program to demonstrate Socket programming
#include <unistd.h>
#include <iostream>
#include <cstdlib>
#include <netinet/in.h>
#lude <cstring>
#define PORT 8080
using namespace std;
int main(int argc, char const *argv[])
{
int server_fd, new_socket, valread;
struct sockaddr_in address;
int opt = 1;
int addrlen = sizeof(address);
char buffer[1024] = {0};
const char *hello = "Hello from server";
// Creating socket file descriptor
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0)
{
perror("socket failed");
exit(EXIT_FAILURE);
}
// Forcefully attaching socket to the port 8080
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT,
&opt, sizeof(opt)))
{
perror("setsockopt");
exit(EXIT_FAILURE);
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons( PORT );
// Forcefully attaching socket to the port 8080
if (bind(server_fd, (struct sockaddr *)&address,
sizeof(address))<0)
{
perror("bind failed");
exit(EXIT_FAILURE);
}
if (listen(server_fd, 3) < 0)
{
perror("listen");
exit(EXIT_FAILURE);
}
if ((new_socket = accept(server_fd, (struct sockaddr *)&address,
(socklen_t*)&addrlen))<0)
{
perror("accept");
exit(EXIT_FAILURE);
}
valread = read( new_socket , buffer, 1024);
if (valread == 0) {
cout << "Read 0" << endl;
}
printf("%s\n",buffer );
send(new_socket , hello , strlen(hello) , 0 );
printf("Hello message sent\n");
return 0;
}
\ No newline at end of file
#include "ship.h"
bool ship::contains(int x, int y) {
int dx = 0;
int dy = 0;
if (dir == UP) {
dy = -1;
} else if (dir == DOWN) {
dy = 1;
} else if (dir == LEFT) {
dx = -1;
} else if (dir == RIGHT) {
dx = 1;
}
for (int i = 0; i < maxHP; i++) {
if (this->x + (i * dx) == x && this->y + (i * dy) == y) {
return true;
}
}
return false;
}
void ship::hit() {
HP--;
}
bool ship::is_sunk() {
return !(HP > 0);
}
int ship::get_x() {
return x;
}
int ship::get_y() {
return y;
}
int ship::get_dir() {
return dir;
}
#ifndef SHIP_H
#define SHIP_H
#include <ncurses.h>
#include <string>
#define UP 0
#define LEFT 1
#define DOWN 2
#define RIGHT 3
class ship {
private:
int x;
int y;
int dir;
int maxHP;
int HP;
std::string name;
public:
ship(int x, int y, int dir, int maxHP, std::string name) : x(x), y(y), dir(dir), maxHP(maxHP), HP(maxHP), name(name) {}
~ship() {}
bool contains(int x, int y);
void hit();
bool is_sunk();
int get_x();
int get_y();
int get_dir();
};
#endif
\ No newline at end of file
#include "util.h"
void init_screen() {
// Initialize ncurses screen
initscr();
start_color();
init_pair(TEXT_WHITE, COLOR_WHITE, COLOR_BLACK);
init_pair(TEXT_GREEN, COLOR_GREEN, COLOR_BLACK);
init_pair(TEXT_RED, COLOR_RED, COLOR_BLACK);
init_pair(BG_RED, COLOR_BLACK, COLOR_RED);
init_pair(BG_BLUE, COLOR_BLACK, COLOR_BLUE);
init_pair(BG_GREEN, COLOR_BLACK, COLOR_GREEN);
init_pair(BG_BLACK, COLOR_BLACK, COLOR_BLACK);
init_pair(BG_WHITE, COLOR_BLACK, COLOR_WHITE);
init_pair(BG_CYAN, COLOR_BLACK, COLOR_CYAN);
set_escdelay(0);
enable_raw_input();
nonl();
intrflush(stdscr, FALSE);
// Make it so keypad characters do what we expect
keypad(stdscr, TRUE);
// Clear the screen
clear();
}
void destroy_screen() {
endwin();
}
void enable_raw_input() {
// Unbuffered input
cbreak();
// Don't echo back characters that are typed
noecho();
// Hide the cursor
curs_set(0);
}
void enable_string_input() {
// Buffer input
nocbreak();
// Auto echo characters back to terminal
echo();
// Show the cursor
curs_set(1);
}
std::string getstring() {
enable_string_input();
std::string input;
int ch = getch();
while (ch != '\n') {
input.push_back(ch);
ch = getch();
}
enable_raw_input();
return input;
}
int randrange(int min, int max) {
int range = max - min + 1;
return (rand() % range) + min;
}
int sign(int x) {
if (x > 0) return 1;
if (x < 0) return -1;
return 0;
}
\ No newline at end of file
#ifndef UTIL_H
#define UTIL_H
#include <ncurses.h>
#include <string>
#include "colors.h"
void init_screen();
void destroy_screen();
void enable_raw_input();
void enable_string_input();
std::string getstring();
int randrange(int min, int max);
int sign(int x);
#endif
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment