/
client.c
242 lines (218 loc) · 9.23 KB
/
client.c
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
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
#include <sys/types.h>
#include <time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include "gbnpacket.h"
int main (int argc, char *argv[])
{
// double legit;
srand48(time(NULL)); // Seed RNG
char *buffer = NULL; // A buffer for the received data
long bufsize = 0;
FILE* outfile;
if (argc != 6)
{
printf("Arg count was %d.\n", argc);
usage_err();
}
// For statistical purposes
int corrupt_count = 0;
int loss_count = 0;
int sockfd, portnum, bytes_recv, bytes_sent;
int lost_packet = 0;
socklen_t sin_size;
struct sockaddr_in srv_addr;
struct hostent *host;
// Send data
struct gbnpacket send_data;
// Receive data
struct gbnpacket recv_data;
// recv_data.length = p_size();
// recv_data.sequence = 0;
// Parse command line arguments
host = (struct hostent *) gethostbyname(argv[1]);
portnum = atoi(argv[2]);
char* filename = argv[3];
printf("Filename is %s\n", filename);
double p_loss = atof(argv[4]); // Probability of packet loss
double p_corr = atof(argv[5]); // Probability of packet corruption
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0)
error_die("Error opening socket.\n");
// Initialize server address
srv_addr.sin_family = AF_INET;
srv_addr.sin_port = htons(portnum);
srv_addr.sin_addr = *((struct in_addr *)host->h_addr);
bzero(&(srv_addr.sin_zero),8);
sin_size = sizeof(struct sockaddr);
//------------------------------------
// SEND request for file
//------------------------------------
memset(&send_data, 0, sizeof(struct gbnpacket));
send_data.type = REQUEST;
send_data.sequence = 0;
send_data.corrupt = 0;
strcpy(send_data.data, filename); // Might have to \0 out the last byte of data...not sure yet
// send_data.data[strlen(filename)] = '\0';
// send_data.length = p_header_size() + strlen(filename) + 1; // +1 for the null byte?
send_data.length = strlen(filename);
printf("Sending request to CS118 for %s\n", filename);
long expecting_packet = 0; // The sequence number of the expected packet
while (1)
{
if (send_data.type == REQUEST)
{
// Send
// Convert to network byte order
convertpacket_hton(&send_data);
// bytes_sent = sendto(sockfd, &send_data, send_data.length, 0,
bytes_sent = sendto(sockfd, &send_data, sizeof(struct gbnpacket), 0,
(struct sockaddr *)&srv_addr, sizeof(struct sockaddr));
// TO-DO: Check to see if bytes_sent matches up with the length of the packet in total.
// buffer = NULL;
print_packet_info_client(&send_data, CLIENT);
// printf("Request sent.\n");
}
// --------------------------------
// RECEIVE data response
// --------------------------------
printf("Waiting for response from CS118.\n");
// bytes_recv = recvfrom(sockfd, &recv_data, recv_data.length, 0,
bytes_recv = recvfrom(sockfd, &recv_data, sizeof(struct gbnpacket), 0,
(struct sockaddr*)&srv_addr, &sin_size);
// Convert to host byte order
convertpacket_ntoh(&recv_data);
// Set packet lost or not
lost_packet = play_the_odds(p_loss, &loss_count);
if (lost_packet)
{
printf("\nLOST PACKET!\n\n");
continue; // Do nothing else, just receive the packet and move on.
}
// TO-DO: CHECK TO MAKE SURE THAT THE PROGRAM DOESN'T SEGFAULT IF recvfrom() FAILS! i.e. if bytesrecv == 0
// recv_data.data[bytes_recv] = '\0';
print_packet_info_client(&recv_data, SERVER);
// printf("Received : %s\n", recv_data.data);
// --------------------------------
// PREPARE acknowledgement
// --------------------------------
if (recv_data.type == FIN)
{
// Send a FIN in return, and end the client process
char *msg = "Terminating connection.";
memset(&send_data, 0, sizeof(struct gbnpacket));
send_data.type = FIN;
send_data.sequence = 0;
send_data.corrupt = 0; // set_packet_corruption();
send_data.length = 0;
// Don't need to initialize the data because of the memset
printf("%s. Sending FIN packet.\n", msg);
printf("STATS: Sent %d corrupt ACKs. Treated %d packets as \'lost\'.\n",
corrupt_count, loss_count);
// Convert to network byte order
convertpacket_hton(&send_data);
/*
send_data.type = htonl(send_data.type);
send_data.sequence = htonl(send_data.sequence);
send_data.length = htonl(send_data.length);
*/
bytes_sent = sendto(sockfd, &send_data, sizeof(struct gbnpacket), 0,
(struct sockaddr *)&srv_addr, sizeof(struct sockaddr));
// Modify the filename
strcat(filename, ".received");
outfile = fopen(filename, "wb");
if (outfile)
{
fwrite(buffer, bufsize, 1, outfile);
printf("Successfully wrote buffer to file \"%s\"\n.", filename);
}
else
error_die("Error writing buffer to file.");
return 0; // End the client process
}
if (!buffer)
{
bufsize = sizeof(char) * recv_data.total_length;
buffer = (char *)malloc(bufsize);
if (!buffer)
error_die("Not enough space for client file buffer.");
}
memset(&send_data, 0, sizeof(struct gbnpacket));
send_data.type = ACK;
// strcpy(send_data.data, "Acknowledged.");
// send_data.data[strlen(send_data.data)] = '\0'; // Zero byte
// send_data.length = p_header_size() + strlen(send_data.data) + 1; // Might need +1 for zero byte
send_data.length = 0; // ACKs have no data
// send_data.corrupt = 0;
// send_data.corrupt = set_packet_corruption(p_corr);
// ----------------------------------------------------------------
// SEND acknowledgement, depending on the last packet received.
// ----------------------------------------------------------------
// Packet is legit
if (recv_data.corrupt == 0 && recv_data.sequence <= expecting_packet) // Use <= for duplicate packets
{
// Copy file data into the buffer
memcpy(buffer+recv_data.sequence, recv_data.data, recv_data.length);
// send_data.sequence = recv_data.sequence + (bytes_recv - p_header_size());
send_data.sequence = recv_data.sequence + PACKETSIZE;
send_data.corrupt = play_the_odds(p_corr, &corrupt_count);
// Convert to network byte order
/*
send_data.type = htonl(send_data.type);
send_data.sequence = htonl(send_data.sequence);
send_data.length = htonl(send_data.length);
*/
// expecting_packet = recv_data.sequence + PACKETSIZE;
expecting_packet = send_data.sequence;
// Send
// printf("Sending acknowledgement from else...\n");
// sendto(sockfd, &send_data, send_data.length, 0,
// if (legit >= p_loss)
// {
// Convert to network byte order
convertpacket_hton(&send_data);
sendto(sockfd, &send_data, sizeof(struct gbnpacket), 0,
(struct sockaddr *)&srv_addr, sizeof(struct sockaddr));
print_packet_info_client(&send_data, CLIENT);
// }
}
// else if (recv_data.corrupt == 0 && recv_data.sequence < expecting_packet)
// {
// printf("\nDUPLICATE PACKET, IGNORING!\n\n");
// continue; // DUPLICATE PACKET
// }
// if (recv_data.sequence != expecting_packet || recv_data.corrupt == 1) // Packet received OUT OF ORDER or is CORRUPT
else // Packet is not legit
{
// Be sure to send duplicate ACKs? Not in the book
// The ACK should be for the last correctly-received packet.
send_data.sequence = expecting_packet;
send_data.corrupt = play_the_odds(p_corr, &corrupt_count);
// Send
// printf("Sending acknowledgement from if...\n");
// sendto(sockfd, &send_data, send_data.length, 0,
// if (legit >= p_loss)
// {
// Convert to network byte order
/*
send_data.type = htonl(send_data.type);
send_data.sequence = htonl(send_data.sequence);
send_data.length = htonl(send_data.length);
send_data.corrupt = htonl(send_data.corrupt);
*/
convertpacket_hton(&send_data);
sendto(sockfd, &send_data, sizeof(struct gbnpacket), 0,
(struct sockaddr *)&srv_addr, sizeof(struct sockaddr));
print_packet_info_client(&send_data, CLIENT);
// }
}
}
return 0;
}