-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathprogram_2.c
More file actions
309 lines (269 loc) · 9.51 KB
/
program_2.c
File metadata and controls
309 lines (269 loc) · 9.51 KB
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
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <dirent.h>
#include <stdint.h>
#include <errno.h>
// Protocol constants
#define ACTION_JOIN 0
#define ACTION_PUBLISH 1
#define ACTION_SEARCH 2
#define MAX_FILENAME_LEN 100
#define MAX_REQUEST_SIZE 1200
#define SHARED_FILES_DIR "SharedFiles"
// Function declarations
int connect_to_registry(const char *hostname, int port);
int send_join_request(int sockfd, uint32_t peer_id);
int send_publish_request(int sockfd);
int send_search_request(int sockfd, const char *filename);
void handle_search_response(int sockfd);
void print_usage(const char *program_name);
int main(int argc, char *argv[]) {
if (argc != 4) {
print_usage(argv[0]);
return 1;
}
const char *registry_host = argv[1];
int registry_port = atoi(argv[2]);
uint32_t peer_id = (uint32_t)atoi(argv[3]);
// Validate port number
if (registry_port <= 2000 || registry_port >= 65536) {
fprintf(stderr, "Error: Port must be between 2001 and 65535\n");
return 1;
}
// Validate peer ID
if (peer_id == 0) {
fprintf(stderr, "Error: Peer ID must be a positive number\n");
return 1;
}
// Connect to registry
int sockfd = connect_to_registry(registry_host, registry_port);
if (sockfd < 0) {
return 1;
}
printf("Connected to registry at %s:%d\n", registry_host, registry_port);
printf("Peer ID: %u\n", peer_id);
// Main command loop
char command[32];
while (1) {
printf("Enter a command: ");
if (fgets(command, sizeof(command), stdin) == NULL) {
break;
}
// Remove newline character
command[strcspn(command, "\n")] = 0;
if (strcmp(command, "JOIN") == 0) {
if (send_join_request(sockfd, peer_id) == 0) {
printf("JOIN request sent successfully\n");
} else {
fprintf(stderr, "Failed to send JOIN request\n");
}
}
else if (strcmp(command, "PUBLISH") == 0) {
if (send_publish_request(sockfd) == 0) {
printf("PUBLISH request sent successfully\n");
} else {
fprintf(stderr, "Failed to send PUBLISH request\n");
}
}
else if (strcmp(command, "SEARCH") == 0) {
char filename[MAX_FILENAME_LEN];
printf("Enter a file name: ");
if (fgets(filename, sizeof(filename), stdin) == NULL) {
fprintf(stderr, "Error reading filename\n");
continue;
}
filename[strcspn(filename, "\n")] = 0;
if (filename[0] == '\0') {
printf("Error: No filename provided\n");
continue;
}
if (send_search_request(sockfd, filename) == 0) {
handle_search_response(sockfd);
} else {
fprintf(stderr, "Failed to send SEARCH request\n");
}
}
else if (strcmp(command, "EXIT") == 0) {
printf("Exiting...\n");
break;
}
else {
printf("Unknown command: %s\n", command);
printf("Available commands: JOIN, PUBLISH, SEARCH, EXIT\n");
}
}
close(sockfd);
return 0;
}
void print_usage(const char *program_name) {
fprintf(stderr, "Usage: %s <registry_host> <registry_port> <peer_id>\n", program_name);
fprintf(stderr, " registry_host: IP address or hostname of registry\n");
fprintf(stderr, " registry_port: Port number (2001-65535)\n");
fprintf(stderr, " peer_id: Positive number less than 2^32-1\n");
fprintf(stderr, "Example: %s localhost 5000 16\n", program_name);
}
int connect_to_registry(const char *hostname, int port) {
int sockfd;
struct sockaddr_in server_addr;
struct hostent *he;
// Create TCP socket
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("socket creation failed");
return -1;
}
// Resolve hostname to IP address
if ((he = gethostbyname(hostname)) == NULL) {
fprintf(stderr, "Error: Cannot resolve hostname '%s'\n", hostname);
close(sockfd);
return -1;
}
// Configure server address structure
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
memcpy(&server_addr.sin_addr, he->h_addr_list[0], he->h_length);
// Establish connection to registry
if (connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
perror("connection failed");
close(sockfd);
return -1;
}
return sockfd;
}
int send_join_request(int sockfd, uint32_t peer_id) {
uint8_t request[5]; // 1 byte action + 4 bytes peer ID
// Build JOIN request
request[0] = ACTION_JOIN;
uint32_t net_peer_id = htonl(peer_id);
memcpy(&request[1], &net_peer_id, sizeof(net_peer_id));
// Send complete request in one packet
ssize_t bytes_sent = send(sockfd, request, sizeof(request), 0);
if (bytes_sent != sizeof(request)) {
perror("send JOIN failed");
return -1;
}
return 0;
}
int send_publish_request(int sockfd) {
DIR *dir;
struct dirent *entry;
uint8_t request[MAX_REQUEST_SIZE];
int offset = 0;
int file_count = 0;
//int DT_REG;
// Open SharedFiles directory
if ((dir = opendir(SHARED_FILES_DIR)) == NULL) {
perror("Cannot open SharedFiles directory");
return -1;
}
// Temporary buffer for file names
char file_list[MAX_REQUEST_SIZE - 5]; // Reserve space for header
int file_list_offset = 0;
// Read directory entries
while ((entry = readdir(dir)) != NULL) {
// Only process regular files (not directories or special files)
if (entry->d_type == DT_REG) {
// Check filename length
if (strlen(entry->d_name) < MAX_FILENAME_LEN - 1) {
int name_len = strlen(entry->d_name);
// Check if we have space in buffer
if (file_list_offset + name_len + 1 < sizeof(file_list)) {
// Copy filename and add null terminator
memcpy(file_list + file_list_offset, entry->d_name, name_len);
file_list_offset += name_len;
file_list[file_list_offset++] = '\0';
file_count++;
} else {
fprintf(stderr, "Warning: Too many files, some will be skipped\n");
break;
}
} else {
fprintf(stderr, "Warning: Filename too long: %s\n", entry->d_name);
}
}
}
closedir(dir);
// Build PUBLISH request header
request[offset++] = ACTION_PUBLISH;
uint32_t net_file_count = htonl(file_count);
memcpy(request + offset, &net_file_count, sizeof(net_file_count));
offset += sizeof(net_file_count);
// Copy file list
memcpy(request + offset, file_list, file_list_offset);
offset += file_list_offset;
// Send complete PUBLISH request
ssize_t bytes_sent = send(sockfd, request, offset, 0);
if (bytes_sent != offset) {
perror("send PUBLISH failed");
return -1;
}
printf("Published %d files\n", file_count);
return 0;
}
int send_search_request(int sockfd, const char *filename) {
int filename_len = strlen(filename);
uint8_t request[1 + MAX_FILENAME_LEN];
int request_len = 1 + filename_len + 1; // Action + filename + NULL
// Validate filename length
if (filename_len >= MAX_FILENAME_LEN) {
fprintf(stderr, "Error: Filename too long (max %d characters)\n", MAX_FILENAME_LEN - 1);
return -1;
}
// Build SEARCH request
request[0] = ACTION_SEARCH;
memcpy(request + 1, filename, filename_len);
request[1 + filename_len] = '\0';
// Send complete SEARCH request
ssize_t bytes_sent = send(sockfd, request, request_len, 0);
if (bytes_sent != request_len) {
perror("send SEARCH failed");
return -1;
}
return 0;
}
void handle_search_response(int sockfd) {
uint8_t response[10]; // 4B ID + 4B IP + 2B port
ssize_t bytes_received;
// Receive SEARCH response from registry
bytes_received = recv(sockfd, response, sizeof(response), 0);
if (bytes_received < 0) {
perror("recv SEARCH response failed");
return;
}
if (bytes_received != sizeof(response)) {
fprintf(stderr, "Error: Incomplete SEARCH response (%zd bytes)\n", bytes_received);
return;
}
// Parse response fields (all in network byte order)
uint32_t peer_id, ip_addr;
uint16_t port;
memcpy(&peer_id, response, sizeof(peer_id));
memcpy(&ip_addr, response + 4, sizeof(ip_addr));
memcpy(&port, response + 8, sizeof(port));
// Convert to host byte order
peer_id = ntohl(peer_id);
ip_addr = ntohl(ip_addr);
port = ntohs(port);
// Check if file was found (all zeros means not found)
if (peer_id == 0 && ip_addr == 0 && port == 0) {
printf("File not indexed by registry\n");
} else {
// Convert IP address to human-readable format using inet_ntop
char ip_str[INET_ADDRSTRLEN];
struct in_addr addr;
addr.s_addr = htonl(ip_addr);
if (inet_ntop(AF_INET, &addr, ip_str, sizeof(ip_str)) == NULL) {
perror("inet_ntop failed");
return;
}
printf("File found at\n");
printf("Peer %u\n", peer_id);
printf("%s:%u\n", ip_str, port);
}
}