-
Notifications
You must be signed in to change notification settings - Fork 0
/
server.c
234 lines (188 loc) · 7.42 KB
/
server.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
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netdb.h>
#include "chess.c"
#define PORT "21202" // for my birthday 02/12/2002
#define IP NULL
#define BACKLOG 2
#define NUM_CLIENTS 2
#define MESSAGE_SIZE 1000
char board[8][8];
int get_and_bind_to_socket(char *ip, char *port) {
// get socket file descriptor
// set configuration for getaddrinfo():
struct addrinfo server_information;
server_information.ai_family = AF_UNSPEC; // IPv4 or IPv6
server_information.ai_socktype = SOCK_STREAM; // TCP Stream Socket
server_information.ai_flags = AI_PASSIVE; // automatically fill in host IP if address NULL
struct addrinfo *server_adress_info;
printf("Getting host address information... ");
int result = getaddrinfo(
ip, // host ip
port, // use constant port number defined at top of file "21202"
&server_information, // points to struct with server information
&server_adress_info // points to result struct to hold address information
);
// success and error messages
if (result == 0) {
printf("Success\n");
}
else {
printf("%s\n", gai_strerror(result));
exit(EXIT_FAILURE);
}
printf("Getting socket file descriptor... ");
// get server socket descriptor
int server_socket = socket(server_adress_info -> ai_family, server_adress_info -> ai_socktype, server_adress_info -> ai_protocol);
// success and error messages
if (server_socket == -1) {
printf("Failed\n");
printf("Error Number: %i\n", errno);
exit(EXIT_FAILURE);
}
else {
printf("Success\n");
}
// Bind socket to port
printf("Binding socket to port %s... ", PORT);
int bind_server_socket = bind(server_socket, server_adress_info -> ai_addr, server_adress_info -> ai_addrlen); // bind socket file descriptior to port on the machine
// success and error messages
if (bind_server_socket == 0) {
printf("Success\n");
}
else {
printf("Failed to bind socket to port %s\n", PORT);
printf("Error Number: %i\n", errno);
exit(EXIT_FAILURE);
}
return server_socket;
}
void listen_on_socket(int server_socket) {
printf("Preparing to listen for connections on port %s...", PORT);
// listen on port binded to socked file descriptor with a single queued connection allowed
int listening = listen(server_socket, BACKLOG);
// success and error messages
if (listening == 0) {
printf("Success\n");
}
else {
printf("Failed to listen for connections on port %s\n", PORT);
printf("Error Number: %i\n", errno);
exit(EXIT_FAILURE);
}
}
void accept_client(int server_socket, int* client_socket, int* max_socket_fd) {
// define parameters for accept function
struct sockaddr_storage client_address;
socklen_t address_size = sizeof(client_address);
// accept client connection and update client address and address size information
*client_socket = accept(server_socket, (struct sockaddr *)&client_address, &address_size);
// success and error messages
if (*client_socket == -1) {
printf("Failed to accept connection on port %s\n", PORT);
printf("Error Number: %i\n", errno);
exit(EXIT_FAILURE);
}
else {
printf("Client succesfully connected (fd: %d)\n", *client_socket);
}
// update max socket fd for later select function if new client socket fd is greater than running max
if (*client_socket + 1 > *max_socket_fd) *max_socket_fd = *client_socket + 1;
}
void receive_message(int client_socket, char *message) {
printf("Waiting for message from client\n");
int receiving = recv(client_socket, message, MESSAGE_SIZE, 0); // wait and receive message from client socket and save to message string
printf("Received message: %s", message);
}
const char* process_message(char* message, int player_num) {
printf("Processing message\n");
// invalid case
if (make_move(board, message, player_num) == -1) {
return "invalid\n";
}
return get_board_text(board);
}
void send_message(int client_socket, const char *message) {
send(client_socket, message, MESSAGE_SIZE, 0); // send message to client socket
}
int communicate(int active_client_socket, int passive_client_socket, int active_player_num) {
char message[MESSAGE_SIZE]; // initialize message string
memset(message, 0, MESSAGE_SIZE); // empty out message string
receive_message(active_client_socket, message); // receive string from active_client and store in message
// exit condition
if (strcmp("exit\n", message) == 0) {
send_message(passive_client_socket, "exit\n"); // notify passive client to disconnect
return 0; // client disconnect return value
}
const char* return_message = process_message(message, active_player_num); // process message from client
printf("Message to send:\n%s", return_message);
// invalid message condition
if (strcmp("invalid\n", return_message) == 0) {
send_message(active_client_socket, return_message); // notify active client that message was invalid
return -1; // client invalid message return value
}
// send both clients return message after active_client's message has been processed
send_message(active_client_socket, return_message);
send_message(passive_client_socket, return_message);
return 1;
}
void close_connection(int server_socket) {
printf("Closing server socket... ");
int closing = close(server_socket); // close server socket to no longer send or recieve on connection with client socket
// success and error messages
if (closing == 0) {
printf("Success\n");
}
else {
printf("Failed to close server socket on port %s\n", PORT);
printf("Error Number: %i", errno);
}
}
int main(void) {
int server_socket;
int client_one_socket;
int client_two_socket;
int max_socket_fd = 0;
// Get and bind to host socket
server_socket = get_and_bind_to_socket(IP, PORT);
// Listen on server socket
listen_on_socket(server_socket);
// Accept client sockets
printf("Waiting for clients...\n");
accept_client(server_socket, &client_one_socket, &max_socket_fd); // accept client one and save fd in client_one_socket
send_message(client_one_socket, "player_one\n");
accept_client(server_socket, &client_two_socket, &max_socket_fd); // accept client two and save fd in client_two_socket
send_message(client_two_socket, "player_two\n");
printf("(max socket fd: %d)\n", max_socket_fd); // print running maxfd (mostly for bugging)
set_board_start(board);
int status; // keeps track of communicate status for program logic
while (1) {
communicate1: // label to repeat communicate with client_one_socket in case of invalid message
status = communicate(client_one_socket, client_two_socket, 1);
// invalid message condition
if (status == -1) {
goto communicate1; // repeat communicate process
}
// exit condition
else if (status == 0) {
break;
}
communicate2: // label to repeat communicate with client_one_socket in case of invalid message
status = communicate(client_two_socket, client_one_socket, 2);
// invalid message condition
if (status == -1) {
goto communicate2;
}
// exit condition
else if (status == 0) {
break;
}
}
// close connection and finish
close_connection(server_socket);
}