-
Notifications
You must be signed in to change notification settings - Fork 6
/
main.c
275 lines (214 loc) · 9.93 KB
/
main.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
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
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <time.h>
#include <math.h>
#define MAX_MSG_SIZE 1024
char sendBuffer[MAX_MSG_SIZE];
char recvBuffer[MAX_MSG_SIZE];
#define TRUE 1
#define SLEEP_DELAY 2
void error(const char* msg) {
perror(msg);
exit(1);
}
/*
* Set the server's parameters such as host address and port number.
*/
struct sockaddr_in setup_server_params(const char *hostname, uint16_t port) {
struct sockaddr_in serverParams;
memset(&serverParams, '\0', sizeof(struct sockaddr_in));
serverParams.sin_family = AF_INET;
serverParams.sin_addr.s_addr = htonl(INADDR_ANY);
serverParams.sin_port = htons(port);
return serverParams;
}
int socket_setup() {
int sockfd = -1; int opt = TRUE;
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
error("\n Error : Could not create socket \n");
}
//set master socket to allow multiple connections , this is just a good habit, it will work without this
if( setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt)) < 0 ) {
error("setsockopt");
}
return sockfd;
}
int socket_bind(int sockfd, struct sockaddr_in serv_addr) {
int recvValue = bind(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
if (recvValue < 0) {
error("Error in binding");
}
return recvValue; // a value < 0 is a failure
}
int server_connect(int sockfd, struct sockaddr_in serv_addr, int port) {
memset(&serv_addr, '\0', sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(port);
if(inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr)<=0)
{
error("\n inet_pton error occured\n");
}
if( connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
{
error("\n Error : Connect Failed \n");
}
return sockfd;
}
/*
* This is a request listening service, it services all types of requests from the client;
* it needs to parse the type of request to determine the appropriate action.
* The clock value is passed by value to make some (integer) manipulations and easily print to stdout (for debugging purposes).
* The clock value is also passed by reference so as to update the actual process's internal clock when it is receives the new offset from the client.
* */
void socket_server_start(int sockfd, int clock, int* clockref) {
/* The accept call blocks until a connection is found */
int connfd = accept(sockfd, (struct sockaddr*) NULL, NULL);
//close(sockfd);
//printf("\nRequest Accepted:\n");
printf("\t::Waiting for New Request data\n");
int numBytes = read(connfd,recvBuffer,sizeof(recvBuffer)-1); // This is where server gets input from client
if (numBytes < 0) error("ERROR reading from socket");
//printf("Data Received from client: %s \n",recvBuffer); // This is displayed on the server end.
char* token = strtok(recvBuffer, " "); // extract request data, get the first token, i.e. the <key> in [key: value]
/* Determine the type of request: is it a request for my current clock OR to set my clock? */
if (strstr(token, "your_clock_value:")) { // This is the first request asking for my current clock
//printf("Label for clock_value_request\n");
token = strtok(NULL, " "); // fetch the next token in recvBuffer, i.e. the <value> in [key: value]
/* Data for client... */
printf("Preparing Response...\n");
memset(sendBuffer, '\0', sizeof(sendBuffer)); // clear send buffer before sending response data
sprintf(sendBuffer, "%d", clock); // strcpy(sendBuffer, sprintf(clock));
numBytes = write(connfd, sendBuffer, strlen(sendBuffer));
if (numBytes < 0) {
error("Error sending response.");
}
printf("My Clock Value: %d\n", clock);
printf("Response: My current clock value sent!\n");
}
if (strstr(token, "set_clock:")) { // This is the second request to update my clock.
//printf("Label for set_clock\n");
token = strtok(NULL, " "); // fetch the next token in recvBuffer, i.e. the <value> in [key: value]
int offset = atoi(token); // convert new clock value to int
clock = clock + offset; // set new value for clock.
*clockref = clock;
/* Data for client... */
printf("Preparing Response...\n");
memset(sendBuffer, '\0', sizeof(sendBuffer)); // clear send buffer before sending response data
sprintf(sendBuffer, "%d", clock);
numBytes = write(connfd, sendBuffer, strlen(sendBuffer));
if (numBytes < 0) {
error("Error sending response.");
}
printf("My Clock Value: %d\n", clock);
printf("Response: Clock Updated! New Clock value sent!\n _______________________ \n\n");
}
//printf("My Clock Value: %d\n", clock);
memset(recvBuffer, '\0', sizeof(recvBuffer)); // after retrieving value, reset recvBuffer for next request.
}
void set_clock(int sockfd, int value) {
printf("Sending new clock offset Request...\n");
memset(recvBuffer, '\0',sizeof(recvBuffer));
printf("new clock offset: %d\n", value);
sprintf(sendBuffer, "set_clock: %d", value); // new value to be sent...
int numBytes = write(sockfd, sendBuffer, strlen(sendBuffer)); // sending operation
if (numBytes < 0) {
error("Error sending request.");
}
printf("Clock Offset Request: sent!\n");
// Get response...
memset(recvBuffer, '\0', sizeof(recvBuffer));
numBytes = read(sockfd, recvBuffer, sizeof(recvBuffer)-1); // reading response
if (numBytes < 0) {
error("ERROR reading from socket");
}
printf("Server Response for clock offset: %s\t",recvBuffer);
printf("sleeping...\n\n");
sleep(SLEEP_DELAY);
//close(sockfd);
}
char* get_clock(int sockfd, char* value) {
printf("Sending Request...\n");
memset(recvBuffer, '\0',sizeof(recvBuffer));
strcpy(sendBuffer, "your_clock_value: 1001"); // value to be sent
int numBytes = write(sockfd, sendBuffer, strlen(sendBuffer)); // sending operation
if (numBytes < 0) {
error("Error sending request.");
}
printf("Request: sent!\n");
// Get response...
memset(recvBuffer, '\0', sizeof(recvBuffer));
numBytes = read(sockfd, recvBuffer, sizeof(recvBuffer)-1); // reading response
if (numBytes < 0) {
error("ERROR reading from socket");
}
printf("Server Response for clock value: %s\t",recvBuffer);
printf("sleeping...\n\n");
sleep(SLEEP_DELAY);
//close(sockfd);
return recvBuffer;
}
int main(int argc, char* argv[]) {
uint32_t portList[3] = {7002, 7003, 7004};
uint8_t clocks[3] = {0,0,0};
int total = 0;
size_t numberOfPorts = sizeof(portList)/sizeof(portList[0]);
//printf("Number of Processes to send to: %zu\n", numberOfPorts);
if (argc != 3) {
error("\n Usage: program port processID\n");
}
uint16_t port = atoi(argv[1]);
time_t timer;
srand((unsigned) time(&timer));
//int clock = atoi(argv[2]); // must be a signed integer because clock offset may be negative.
/* clock must be a signed integer because the after update by clock offset from client, it might be negative */
int clock = rand() % 20; // generates a random number between 1 and 20
/* Check the User Provided Process ID, if it is number 1, then it is the requesting process */
if (atoi(argv[2]) == 1) {
printf("I am the sending process\n\n");
for (int processIndex = 0; processIndex < numberOfPorts; ++processIndex) {
/* Initiate Server Features. */
struct sockaddr_in serverAddress = setup_server_params("127.0.0.1", portList[processIndex]);
int sockfd = socket_setup();
printf("Requesting clock value from Process %d with sockfd %d on port %d\n", processIndex+1, sockfd, portList[processIndex]);
sockfd = server_connect(sockfd, serverAddress, portList[processIndex]);
clocks[processIndex] = atoi(get_clock(sockfd, "your_clock_value"));
total = total + clocks[processIndex];
}
// All clock values have been received at this point, so calculate synchronizing average...
int average = (total / numberOfPorts);
printf("________________________\n\n");
// new request to send updated clock offset values
for (int processIndex = 0; processIndex < numberOfPorts; ++processIndex) {
/* Initiate Server Features. */
struct sockaddr_in serverAddress = setup_server_params("127.0.0.1", portList[processIndex]);
int sockfd = socket_setup();
sockfd = server_connect(sockfd, serverAddress, portList[processIndex]);
clock = average - clocks[processIndex]; // calculate clock offset
printf("Sending new clock value offset to Process %d with sockfd %d on port %d\n", processIndex+1, sockfd, portList[processIndex]);
set_clock(sockfd, clock); //send updated clock offset value
}
}
else {
printf("I am the receiver process: \t Waiting for requests...\n\n");
const int CONN_BACKLOG_NUM = 1; // Max length of queue of pending connections for var sockfd.
/* Initiate Server Parameters */
struct sockaddr_in myAddr = setup_server_params("127.0.0.1", port);
while (1) {
int sockfd = socket_setup();
//inform user of socket number - used in send and receive commands
printf("\nNew connection, socket fd is %d , ip is : %s , port : %d \n" , sockfd , inet_ntoa(myAddr.sin_addr) , ntohs(myAddr.sin_port));
socket_bind(sockfd, myAddr);
listen(sockfd, CONN_BACKLOG_NUM);
printf("listening on sockfd: %d on port: %d \n", sockfd, port);
socket_server_start(sockfd, clock, &clock); // pass a ref to the processes clock to update later.
close(sockfd);
}
}
return 0;
}