-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathclient.c
304 lines (270 loc) · 8.88 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
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
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#include <string.h> /* memset() */
#include <time.h>
#include <sys/time.h> /* select() */
/* Definations */
#define EXIT_SUCCESS 0
#define EXIT_FAILURE 1
#define MAX_MSG 100
#define SOCKET_ERROR -1
//void Broadcast();
int isReadable(int sd, int * error, int timeOut);
void getInput(char* inp, int size_inp);
void errorExit(char *errorMessage);
void clearScreen();
void AppHeadLine();
void iSleep(float milis);
int main(int argc, char *argv[]) {
int sockfd;
struct sockaddr_in their_addr; // connector's address information
struct hostent *he;
int numbytes;
char okMsg[] = "OK";
char initMsg[] = "init"; // Broadcast message in this protocol
char readyMsg[] = "ready"; // Server reply ready to serve
char reqMsg[] = "req"; // Client request
char charPort[50]; //store user input for port
char charBroadCastMask[30]; //store user input for port
char serverAddr[30];
// if (argc != 3) {
// errorExit("usage: client subnet_mask port\n");
// }
//Ask port number for server
clearScreen();
AppHeadLine();
printf("Please enter server port to connect\nPort[9999]:");
getInput(charPort, sizeof charPort);
if (strlen(charPort) == 0) {
printf("Client need port.\n- Client will use 9999 as default.\n");
strcpy(charPort, "9999"); // use 9999 as default port. Assign it to port since user have no input
//TODO: We will need to check more. E.g: check integer.
}
//
//Add server addr
// printf("Please enter Server Addr\nAddr[127.0.0.1]:");
// getInput(serverAddr, sizeof serverAddr);
// if (strlen(serverAddr) == 0) {
// printf(
// "Client need server addr.\n- Client will use 127.0.0.1 as default.\n");
// strcpy(serverAddr, "127.0.0.1"); // use 127.0.0.1 as default Addr. Assign it to Addr since user have no input
// //TODO: We will need to check more. E.g: Check IP format.
// }
//Ask broadcast Address
printf("Please enter Broadcast Addr\nAddr[255.255.255.255]:");
//http://en.wikipedia.org/wiki/Broadcast_address
getInput(charBroadCastMask, sizeof charBroadCastMask);
if (strlen(charBroadCastMask) == 0) {
printf(
"Client need Broadcast Addr.\n- Client will use 255.255.255.255 as default.\n");
strcpy(charBroadCastMask, "255.255.255.255"); // use 255.255.255.255 as default mask.
//TODO: We will need to check more. E.g: Check IP format.
}
//
if ((he = gethostbyname(charBroadCastMask)) == NULL) { // get the host info
errorExit("Error: gethostbyname");
}
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
errorExit("Error: socket");
}
// allows broadcastPermission
int broadcastPermission = 1;
if (setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &broadcastPermission,
sizeof broadcastPermission) == -1) {
errorExit("Error: setsockopt");
}
their_addr.sin_family = AF_INET; // host byte order
their_addr.sin_port = htons(atoi(charPort)); // short, network byte order
their_addr.sin_addr = *((struct in_addr *) he->h_addr);
memset(their_addr.sin_zero, '\0', sizeof their_addr.sin_zero);
if ((numbytes = sendto(sockfd, initMsg, sizeof initMsg, 0,
(struct sockaddr *) &their_addr, sizeof their_addr)) == -1) {
errorExit("Error: sendto");
}
printf("sent message \"%s\", %d bytes to %s\n", initMsg, numbytes,
inet_ntoa(their_addr.sin_addr));
int error, timeOut, n;
timeOut = 300; // ms <-------------------------------------------------------inportant if you want to change timeout waiting reply
char msg[MAX_MSG];
/* init buffer */
memset(msg, 0x0, MAX_MSG);
int addrLen = sizeof(their_addr);
//Just try to get server reply
while (1) {
if (isReadable(sockfd, &error, timeOut)) {
memset(&msg, 0, sizeof msg);
n = recvfrom(sockfd, msg, MAX_MSG, 0,
(struct sockaddr *) &their_addr, &addrLen);
strcpy(serverAddr, inet_ntoa(their_addr.sin_addr));
printf("Server address is %s\n", serverAddr);
printf("Server reply: packet contains \"%s\"\n", msg);
printf("Server reply: \"%s\", %d bytes to %s\n", msg, n,
inet_ntoa(their_addr.sin_addr));
break;
} else {
printf("No Reply: I try again.");
if ((numbytes = sendto(sockfd, initMsg, sizeof initMsg, 0,
(struct sockaddr *) &their_addr, sizeof their_addr))
== -1) {
errorExit("Error: sendto");
}
printf("sent message %s, %d bytes to %s\n", initMsg, numbytes,
inet_ntoa(their_addr.sin_addr));
}
}
//TODO: I need to change Broadcast Socket to normal
//UPDATE: to change broadcast to server ip
//This is not to broadcast to all pc after init message from server
//Can remove if it is not require
if ((he = gethostbyname(serverAddr)) == NULL) { // get the host info
errorExit("Error: gethostbyname");
}
their_addr.sin_family = AF_INET; // host byte order
their_addr.sin_port = htons(atoi(charPort)); // short, network byte order
their_addr.sin_addr = *((struct in_addr *) he->h_addr);
memset(their_addr.sin_zero, '\0', sizeof their_addr.sin_zero);
///UPDATE END
//Try to get message length
int intNumChar; //Number of chare need to request to server
msg[0] = '\0';
while (1) {
if (isReadable(sockfd, &error, timeOut)) {
memset(&msg, 0, sizeof msg);
n = recvfrom(sockfd, msg, MAX_MSG, 0,
(struct sockaddr *) &their_addr, &addrLen);
printf("Server reply: Number of Char to request \"%s\"\n", msg);
intNumChar = atoi(msg);
break;
} else {
printf("No Reply: Exit.");
if ((numbytes = sendto(sockfd, initMsg, sizeof initMsg, 0,
(struct sockaddr *) &their_addr, sizeof their_addr))
== -1) {
errorExit("Error: sendto");
}
break;
}
}
//Now start sending request and get chars
char charSvrMsg[intNumChar]; //Store Server Message
int j;
int intFaultNumber = 0;
TRY: printf("Server give me:");
for (j = intFaultNumber; j < intNumChar; j++) {
usleep(100);
if ((numbytes = sendto(sockfd, reqMsg, MAX_MSG, 0,
(struct sockaddr *) &their_addr, sizeof their_addr)) == -1) {
errorExit("Error: sendto");
}
char charTemp[1];
if (isReadable(sockfd, &error, timeOut)) {
memset(&charTemp, 0, sizeof charTemp);
n = recvfrom(sockfd, charTemp, sizeof charTemp, 0,
(struct sockaddr *) &their_addr, &addrLen);
//printf("byte :%d\n",n); //DEBUG: See number of bytes
printf("%c", charTemp[0]);
//Keep it
charSvrMsg[j] = charTemp[0];
} else {
charSvrMsg[j] = 0;
printf("\nNo Reply: I skip to next.\n");
}
}
printf("\n");
//Say ready to server
printf("\nFull Sting: %s\n", charSvrMsg);
if ((numbytes = sendto(sockfd, readyMsg, sizeof readyMsg, 0,
(struct sockaddr *) &their_addr, sizeof their_addr)) == -1) {
errorExit("Error: sendto");
}
//Now I reply server with full string
if ((numbytes = sendto(sockfd, charSvrMsg, sizeof charSvrMsg, 0,
(struct sockaddr *) &their_addr, sizeof their_addr)) == -1) {
errorExit("Error: sendto");
}
while (1) {
if (isReadable(sockfd, &error, timeOut)) {
memset(&msg, 0, sizeof msg);
n = recvfrom(sockfd, msg, MAX_MSG, 0,
(struct sockaddr *) &their_addr, &addrLen);
//printf("Server reply the result: \"%s\"\n", msg);
if (strcmp(msg, okMsg) != 0) {
//Can not get OK
//Need to try again
intFaultNumber = atoi(msg);
printf("Server reply fault at %d. Need to retry\n",
intFaultNumber + 1);
goto TRY;
break;
} else {
printf("Server reply: Ok\n");
printf("Now, Client will exit.\n\n");
break;
}
break;
} else {
printf("No Server approve client request\n\n");
close(sockfd);
return 0;
}
}
close(sockfd);
return 0;
}
/* Network Functions */
int isReadable(int sd, int * error, int timeOut) { // milliseconds
fd_set socketReadSet;
FD_ZERO(&socketReadSet);
FD_SET(sd, &socketReadSet);
struct timeval tv;
if (timeOut) {
tv.tv_sec = timeOut / 1000;
tv.tv_usec = (timeOut % 1000) * 1000;
} else {
tv.tv_sec = 0;
tv.tv_usec = 0;
} // if
if (select(sd + 1, &socketReadSet, 0, 0, &tv) == SOCKET_ERROR) {
*error = 1;
return 0;
} // if
*error = 0;
return FD_ISSET(sd, &socketReadSet) != 0;
} /* isReadable */
/* Helper functions */
void iSleep(float milis) {
usleep(milis * 1000);
}
void getInput(char* inp, int size_inp) {
fflush (stdout);
fgets(inp, size_inp, stdin);
char *enterchar = strchr(inp, '\n'); /* search for newline character */
if (enterchar != NULL) {
*enterchar = '\0'; /* overwrite trailing newline */
}
}
void errorExit(char *errorMessage) {
printf("%s\n", errorMessage);
perror(errorMessage);
exit(EXIT_FAILURE); /* Exit App with error. If another app is calling this App, they know this status*/
}
void clearScreen() {
const char* CLEAR_SCREE_ANSI = "\e[1;1H\e[2J";
write(STDOUT_FILENO, CLEAR_SCREE_ANSI, 12);
}
void AppHeadLine() {
printf(
"__________________________________________________________________________\n\n");
printf("Game Client Application \n");
printf(
"__________________________________________________________________________\n\n");
}