-
Notifications
You must be signed in to change notification settings - Fork 0
/
server.cpp
179 lines (161 loc) · 5.13 KB
/
server.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
#include <iostream>
#include <string>
#include <cstring>
#include <thread>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <vector>
#define MSS 16 // Maximum Segment Size
using namespace std;
const int TIMEOUT_SECONDS = 5;
const int PORT = 8080;
const int BUFFER_SIZE = 16;
typedef struct packet {
/* Header */
uint16_t chsum;
uint16_t len;
uint16_t seqno;
/* Data */
char data[MSS];
} packet;
typedef struct ack_packet {
uint16_t chsum;
uint16_t ackno;
uint16_t len;
} ack_packet;
typedef struct MessageArgs {
sockaddr_in client_address{};
string filePath;
} MessageArgs;
packet make_packet(uint16_t seqno, uint16_t len, char data[]) {
packet p;
p.chsum = 0;
p.len = len;
p.seqno = seqno;
strcpy(p.data, data);
return p;
}
// read the contents of a file into a vector of packet structs
vector<packet> readFile(char *fileName) {
FILE *fp;
vector<packet> packets;
char *content = (char *)malloc(10000);
fp = fopen(fileName, "rb");
if (fp == nullptr)
return packets;
int nBytes = 0;
int seqno = 0;
while (fread(&content[nBytes], sizeof(char), 1, fp) == 1) {
nBytes++;
seqno++;
if (nBytes == MSS) {
packet p = make_packet(seqno, nBytes, content);
packets.push_back(p);
nBytes = 0;
}
}
if (nBytes != 0) {
packet p = make_packet(seqno, nBytes,content);
packets.push_back(p);
}
fclose(fp);
free(content);
return packets;
}
// wait for a specified amount of time for a socket to become readable
int timeOut(int sockfd) {
fd_set read_fds;
FD_ZERO(&read_fds);
FD_SET(sockfd, &read_fds);
// Set up the timeout
struct timeval timeout{};
timeout.tv_sec = TIMEOUT_SECONDS;
timeout.tv_usec = 0;
// Wait for the socket to become readable or for the timeout to expire
int status = select(sockfd + 1, &read_fds, nullptr, nullptr, &timeout);
return status;
}
void sendDataChunks(int sockfd, sockaddr_in client_address, char *fileName) {
// Send the message to the client
vector<packet> packets = readFile(fileName);
unsigned int n = packets.size();
for (int i = 0; i < n ; i++) {
sendto(sockfd, &packets[i], sizeof(long)*3+packets[i].len, 0,
(sockaddr*) &client_address, sizeof(client_address));
// wait acknowledgement from client
ack_packet ack;
socklen_t client_addr_len = sizeof(client_address);
int status = timeOut(sockfd);
if (status == -1) {
// An error occurred
cerr << "Error waiting for socket: " << strerror(errno) << endl;
return ;
} else if (status == 0) {
// The timeout expired
cerr << "Timeout expired" << endl;
i--;
} else {
long bytes_received = recvfrom(sockfd, &ack, sizeof(ack), 0,
(sockaddr *) &client_address, &client_addr_len);
if (bytes_received <= 0) {
break;
}
cout << "Received " << bytes_received << " bytes: " << "with ackno: " << ack.ackno << endl;
}
}
}
void handle_connection(void* args) {
// Get the socket and client address from the arguments
int newSocket = socket(AF_INET, SOCK_DGRAM, 0);
if (newSocket < 0) {
cerr << "Error creating socket" << endl;
return ;
}
auto* message_args = (MessageArgs*) args;
sockaddr_in client_address = message_args->client_address;
string filePath = message_args->filePath;
// should handle the send of data in chunks
sendDataChunks(newSocket, client_address, (char *)filePath.c_str());
// Close the connection
close(newSocket);
}
int main() {
// Create a socket
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) {
cerr << "Error creating socket" << endl;
return 1;
}
// Bind the socket to the port
sockaddr_in server_addr{};
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(PORT);
if (bind(sockfd, (sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
cerr << "Error binding socket to port" << endl;
return 1;
}
while (true) {
// Wait for a connection
char buffer[BUFFER_SIZE];
cout << "Server: Waiting for a connection..." << endl;
sockaddr_in client_addr{};
socklen_t client_addr_len = sizeof(client_addr);
long bytes_received= recvfrom(sockfd, buffer, BUFFER_SIZE, 0,
(sockaddr *) &client_addr, &client_addr_len);
if (bytes_received < 0) {
cerr << "Error accepting connection" << endl;
continue;
}
// Create a new thread to handle the connection
MessageArgs messageArgs;
messageArgs.client_address = client_addr;
string str;
str = buffer;
messageArgs.filePath = str.substr(0, bytes_received);
pthread_t thread;
pthread_create(&thread, nullptr, reinterpret_cast<void *(*)(void *)>(handle_connection), &messageArgs);
}
}