Revision 62
Ported (AKA moved) tiny861 code from the old repository
Ceated new folder in the auto recharge project
branches/charge_board/code/projects/colonet/ColonetServer/Makefile | ||
---|---|---|
1 |
# ColonetServer makefile |
|
2 |
|
|
3 |
CC = g++ |
|
4 |
CFLAGS = -Wall -Wshadow -Wextra -g |
|
5 |
|
|
6 |
COLONETCPPFILES = ColonetServer.cpp client.cpp ConnectionPool.cpp |
|
7 |
COLONETCPPOBJECTS = $(COLONETCPPFILES:.cpp=.o) |
|
8 |
COLONETFILES = options.c |
|
9 |
COLONETOBJECTS = $(COLONETFILES:.c=.o) |
|
10 |
LOGGINGFILES = Log.cpp |
|
11 |
LOGGINGOBJECTS = $(LOGGINGFILES:.cpp=.o) |
|
12 |
|
|
13 |
VPATH = ../lib:../lib/colonet_wireless |
|
14 |
INCLUDE_DIRS = ../lib/colonet_wireless ../lib |
|
15 |
LIBRARY_DIRS = ../lib |
|
16 |
|
|
17 |
|
|
18 |
#this takes the include directory and puts a -I in front of each directory name before being used in a gcc statement |
|
19 |
INCLUDE_DIRS_FOR_GCC = $(patsubst %, -I %, $(INCLUDE_DIRS)) |
|
20 |
#this takes the library directory and puts a -L in front of each directory name so it can be used in a gcc statement |
|
21 |
LIBRARY_DIRS_FOR_GCC = $(patsubst %,-L%, $(LIBRARY_DIRS)) |
|
22 |
|
|
23 |
.PHONY : all clean |
|
24 |
|
|
25 |
all: ColonetServer |
|
26 |
|
|
27 |
#TODO: make a variable that handles the multiple -I blah stuff so it doesn't have to be written on every line |
|
28 |
#TODO: make use of VPATH or vpath directive to point at lib directory and then use -lcolonet_wireless |
|
29 |
ColonetServer: $(COLONETCPPFILES) $(COLONETFILES) $(LOGGINGFILES) -lcolonet_wireless |
|
30 |
$(CC) $(CFLAGS) -c $(COLONETFILES) $(INCLUDE_DIRS_FOR_GCC) |
|
31 |
$(CC) $(CFLAGS) -c $(COLONETCPPFILES) $(INCLUDE_DIRS_FOR_GCC) |
|
32 |
$(CC) $(CFLAGS) -c $(LOGGINGFILES) $(INCLUDE_DIRS_FOR_GCC) |
|
33 |
$(CC) $(CFLAGS) $(COLONETOBJECTS) $(COLONETCPPOBJECTS) $(LOGGINGOBJECTS) $(LIBRARY_DIRS_FOR_GCC) -lpthread -lcolonet_wireless $(INCLUDE_DIRS_FOR_GCC) -o $@ |
|
34 |
|
|
35 |
clean: |
|
36 |
rm -rf *.o ColonetServer |
branches/charge_board/code/projects/colonet/ColonetServer/ConnectionPool.cpp | ||
---|---|---|
1 |
/** |
|
2 |
* @file ConnectionPool.cpp |
|
3 |
* |
|
4 |
* @author Jason Knichel |
|
5 |
* @date 7/22/07 |
|
6 |
*/ |
|
7 |
|
|
8 |
#include <sys/select.h> |
|
9 |
#include <ctype.h> |
|
10 |
#include <errno.h> |
|
11 |
#include <unistd.h> |
|
12 |
#include <string.h> |
|
13 |
#include <stdlib.h> |
|
14 |
#include <stdio.h> |
|
15 |
|
|
16 |
#include "includes/ConnectionPool.h" |
|
17 |
#include "includes/client.h" |
|
18 |
#include "../lib/colonet_defs.h" |
|
19 |
|
|
20 |
/** |
|
21 |
* @brief The default constructor for ConnectionPool |
|
22 |
*/ |
|
23 |
ConnectionPool::ConnectionPool() { |
|
24 |
max_file_descriptor = 0; |
|
25 |
next_available_slot = 0; |
|
26 |
number_clients_ready = 0; |
|
27 |
|
|
28 |
FD_ZERO(&ready_set); |
|
29 |
FD_ZERO(&read_set); |
|
30 |
FD_ZERO(&write_set); |
|
31 |
|
|
32 |
memset(&client_file_descriptor_array, 0, sizeof(int)*MAX_CONNECTIONS); |
|
33 |
memset(&read_buffer, 0, sizeof(char *)*MAX_CONNECTIONS); |
|
34 |
memset(&read_buffer_size, 0, sizeof(int)*MAX_CONNECTIONS); |
|
35 |
memset(&write_buffer, 0, sizeof(char *)*MAX_CONNECTIONS); |
|
36 |
memset(&write_buffer_size, 0, sizeof(int)*MAX_CONNECTIONS); |
|
37 |
} |
|
38 |
|
|
39 |
/** |
|
40 |
* @brief The destructor for ConnectionPool |
|
41 |
*/ |
|
42 |
ConnectionPool::~ConnectionPool() { |
|
43 |
} |
|
44 |
|
|
45 |
/** |
|
46 |
* @brief Adds a client to the connection pool |
|
47 |
* |
|
48 |
* @param client_file_descriptor The file descriptor to add to the connection pool |
|
49 |
* |
|
50 |
* @return 0 on success, negative error code on failure |
|
51 |
*/ |
|
52 |
int ConnectionPool::add_client(int client_file_descriptor) { |
|
53 |
if (client_file_descriptor < 0) { |
|
54 |
return ERROR_INVALID_CLIENT_DESCRIPTOR; |
|
55 |
} |
|
56 |
|
|
57 |
if (next_available_slot == MAX_CONNECTIONS) { |
|
58 |
return ERROR_TOO_MANY_CLIENTS; |
|
59 |
} |
|
60 |
|
|
61 |
if (client_file_descriptor > max_file_descriptor) { |
|
62 |
max_file_descriptor = client_file_descriptor; |
|
63 |
} |
|
64 |
|
|
65 |
FD_SET(client_file_descriptor, &ready_set); |
|
66 |
|
|
67 |
int next_slot = next_available_slot; |
|
68 |
|
|
69 |
client_file_descriptor_array[next_slot] = client_file_descriptor; |
|
70 |
read_buffer[next_slot] = (char*) malloc(sizeof(char) * READ_BUFFER_SIZE); |
|
71 |
if (!(read_buffer[next_slot])) { |
|
72 |
return ERROR_ALLOCATING_MEMORY; |
|
73 |
} |
|
74 |
read_buffer_size[next_slot] = 0; |
|
75 |
write_buffer[next_slot] = (char *)malloc(sizeof(char) * WRITE_BUFFER_SIZE); |
|
76 |
|
|
77 |
if (!(write_buffer[next_slot])) { |
|
78 |
free(read_buffer[next_slot]); |
|
79 |
return ERROR_ALLOCATING_MEMORY; |
|
80 |
} |
|
81 |
|
|
82 |
write_buffer_size[next_slot] = 0; |
|
83 |
|
|
84 |
next_available_slot++; |
|
85 |
|
|
86 |
return 0; |
|
87 |
} |
|
88 |
|
|
89 |
/** |
|
90 |
* @brief Removes a client from the connection pool |
|
91 |
* |
|
92 |
* @param The index in the pool of the client to remove |
|
93 |
* |
|
94 |
* @return 0 on success, negative error code on failure |
|
95 |
*/ |
|
96 |
int ConnectionPool::remove_client(int pool_index) { |
|
97 |
if (pool_index < 0 || pool_index >= next_available_slot) { |
|
98 |
return ERROR_INVALID_CLIENT_DESCRIPTOR; |
|
99 |
} |
|
100 |
|
|
101 |
int client_file_descriptor = client_file_descriptor_array[pool_index]; |
|
102 |
|
|
103 |
if (FD_ISSET(client_file_descriptor, &ready_set)) { |
|
104 |
FD_CLR(client_file_descriptor, &ready_set); |
|
105 |
} |
|
106 |
if (FD_ISSET(client_file_descriptor, &read_set)) { |
|
107 |
FD_CLR(client_file_descriptor, &read_set); |
|
108 |
} |
|
109 |
if (FD_ISSET(client_file_descriptor, &write_set)) { |
|
110 |
FD_CLR(client_file_descriptor, &write_set); |
|
111 |
} |
|
112 |
|
|
113 |
free(read_buffer[pool_index]); |
|
114 |
free(write_buffer[pool_index]); |
|
115 |
for (int j = pool_index; j < next_available_slot - 1; j++) { |
|
116 |
client_file_descriptor_array[pool_index] = client_file_descriptor_array[pool_index+1]; |
|
117 |
read_buffer[pool_index] = read_buffer[pool_index+1]; |
|
118 |
read_buffer_size[pool_index] = read_buffer_size[pool_index+1]; |
|
119 |
write_buffer[pool_index] = write_buffer[pool_index+1]; |
|
120 |
write_buffer_size[pool_index] = write_buffer_size[pool_index+1]; |
|
121 |
} |
|
122 |
next_available_slot--; |
|
123 |
int temp_max_file_descriptor = 0; |
|
124 |
|
|
125 |
for (int j = 0; j < next_available_slot; j++) { |
|
126 |
if (client_file_descriptor_array[j] > temp_max_file_descriptor) |
|
127 |
temp_max_file_descriptor = client_file_descriptor_array[j]; |
|
128 |
} |
|
129 |
max_file_descriptor = temp_max_file_descriptor; |
|
130 |
|
|
131 |
printf("Removing client.\n"); |
|
132 |
|
|
133 |
return 0; |
|
134 |
} |
|
135 |
|
|
136 |
/** |
|
137 |
* @brief Checks the status of the clients |
|
138 |
* |
|
139 |
* Sees is any clients are ready to read from their file descriptor or are |
|
140 |
* ready to write to their file descriptor. |
|
141 |
* |
|
142 |
* @param wireless A pointer to the wireless object |
|
143 |
* |
|
144 |
* @return 0 on success, negative error code on error |
|
145 |
*/ |
|
146 |
//TODO: test that it drops commands properly if it gets sent too much data |
|
147 |
// do we want it to drop the data or drop the connection? |
|
148 |
int ConnectionPool::check_clients(ColonetWireless * wireless) { |
|
149 |
char temporary_buffer[READ_BUFFER_SIZE]; |
|
150 |
char temporary_command_buffer[READ_BUFFER_SIZE+1]; |
|
151 |
int i; |
|
152 |
int client_file_descriptor; |
|
153 |
int num_bytes_read; |
|
154 |
int length; |
|
155 |
int sent; |
|
156 |
int command_length; |
|
157 |
|
|
158 |
for (i = 0; i < next_available_slot; i++) { |
|
159 |
client_file_descriptor = client_file_descriptor_array[i]; |
|
160 |
|
|
161 |
if (FD_ISSET(client_file_descriptor, &read_set)) { |
|
162 |
num_bytes_read = read(client_file_descriptor, temporary_buffer, READ_BUFFER_SIZE); |
|
163 |
|
|
164 |
if (num_bytes_read == 0 || (num_bytes_read == -1 && errno == ECONNRESET)) { |
|
165 |
remove_client(i); |
|
166 |
i--; |
|
167 |
continue; |
|
168 |
} |
|
169 |
|
|
170 |
while (num_bytes_read > 0) { |
|
171 |
length = num_bytes_read; |
|
172 |
|
|
173 |
if (length + read_buffer_size[i] > READ_BUFFER_SIZE) { |
|
174 |
length = READ_BUFFER_SIZE - read_buffer_size[i]; |
|
175 |
} |
|
176 |
|
|
177 |
memcpy(read_buffer[i]+read_buffer_size[i], temporary_buffer, length); |
|
178 |
read_buffer_size[i] += length; |
|
179 |
num_bytes_read -= length; |
|
180 |
|
|
181 |
if (num_bytes_read > 0) { |
|
182 |
memmove(temporary_buffer, temporary_buffer+length, READ_BUFFER_SIZE - length); |
|
183 |
} |
|
184 |
|
|
185 |
printf("Read buffer is %s\n", read_buffer[i]); |
|
186 |
|
|
187 |
char* newline_position; |
|
188 |
|
|
189 |
while ((newline_position = strstr(read_buffer[i], "\n"))) { |
|
190 |
|
|
191 |
//if no newline if found in the entire readbuffer (when its full), |
|
192 |
//toss out the command |
|
193 |
// because either the command being given is too long or someone is trying |
|
194 |
// to do something bad to the server |
|
195 |
//TODO: this is from before all this code was put in the loop. reconsider |
|
196 |
// how to check this error condition and do it elsewhere |
|
197 |
if (!newline_position && (read_buffer_size[i] == READ_BUFFER_SIZE)) { |
|
198 |
read_buffer_size[i] = 0; |
|
199 |
break; |
|
200 |
} |
|
201 |
|
|
202 |
//if no newline is found then there is not a command in the buffer |
|
203 |
if (!newline_position) { |
|
204 |
break; |
|
205 |
} |
|
206 |
|
|
207 |
command_length = (newline_position - read_buffer[i])+1; |
|
208 |
|
|
209 |
//the newline was found in garbage in the currently not used portion |
|
210 |
// of the read buffer |
|
211 |
if (command_length > read_buffer_size[i]) { |
|
212 |
break; |
|
213 |
} |
|
214 |
|
|
215 |
memcpy(temporary_command_buffer, read_buffer[i], command_length); |
|
216 |
//do command_length-1 to get rid of the newline terminating the command |
|
217 |
temporary_command_buffer[command_length-1] = '\0'; |
|
218 |
//did this because telnet was putting a \r\n on the end instead of just \n |
|
219 |
if (isspace(temporary_command_buffer[command_length-2])) { |
|
220 |
temporary_command_buffer[command_length-2] = '\0'; |
|
221 |
} |
|
222 |
|
|
223 |
memmove(read_buffer[i], read_buffer[i]+command_length, read_buffer_size[i] - command_length); |
|
224 |
read_buffer_size[i] -= command_length; |
|
225 |
|
|
226 |
if (command_length > MAX_COMMAND_LEN) { |
|
227 |
printf("The command was too long. Tossing command out.\n"); |
|
228 |
break; |
|
229 |
} |
|
230 |
|
|
231 |
if (parse_command(temporary_command_buffer, i, wireless) < 0) { |
|
232 |
printf("There was an error parsing command\n"); |
|
233 |
break; |
|
234 |
} |
|
235 |
} |
|
236 |
} |
|
237 |
} |
|
238 |
|
|
239 |
if (FD_ISSET(client_file_descriptor, &write_set)) { |
|
240 |
if (write_buffer_size[i] == 0) { |
|
241 |
continue; |
|
242 |
} |
|
243 |
|
|
244 |
sent = write(client_file_descriptor, write_buffer[i], write_buffer_size[i]); |
|
245 |
memmove(write_buffer[i], write_buffer[i]+sent, WRITE_BUFFER_SIZE - sent); |
|
246 |
write_buffer_size[i] -= sent; |
|
247 |
} |
|
248 |
} |
|
249 |
|
|
250 |
return 0; |
|
251 |
} |
|
252 |
|
|
253 |
/** |
|
254 |
* @brief Puts text into a write buffer that will be written to a client's file |
|
255 |
* descriptor sometime when the client is ready to write. |
|
256 |
* |
|
257 |
* @param pool_index Index in the pool of the client to write to |
|
258 |
* @param message The message to be written |
|
259 |
* @param length The length of the message |
|
260 |
* |
|
261 |
* @return 0 on success, negative error code on failure |
|
262 |
*/ |
|
263 |
int ConnectionPool::write_to_client(int pool_index, char * message, int length) { |
|
264 |
if (pool_index < 0 || pool_index >= next_available_slot) { |
|
265 |
return ERROR_INVALID_CLIENT_ID; |
|
266 |
} |
|
267 |
|
|
268 |
if (!message) { |
|
269 |
return ERROR_INVALID_MESSAGE; |
|
270 |
} |
|
271 |
|
|
272 |
if (length < 0) { |
|
273 |
return ERROR_INVALID_MESSAGE_LENGTH; |
|
274 |
} |
|
275 |
|
|
276 |
if (length > (WRITE_BUFFER_SIZE-write_buffer_size[pool_index])) { |
|
277 |
//TODO: make this a logging statement instead of a print statement |
|
278 |
printf("There is not enough room in the write buffer to send the data to the client.\n"); |
|
279 |
return ERROR_NOT_ENOUGH_ROOM; |
|
280 |
} |
|
281 |
|
|
282 |
memcpy(write_buffer[pool_index], message, length); |
|
283 |
write_buffer_size[pool_index] += length; |
|
284 |
|
|
285 |
return 0; |
|
286 |
} |
|
287 |
|
|
288 |
/** |
|
289 |
* @brief Sets the socket to listen on |
|
290 |
* |
|
291 |
* @param listen_socket The socket to listen on |
|
292 |
* |
|
293 |
* @return void |
|
294 |
*/ |
|
295 |
void ConnectionPool::set_listen_socket_in_ready_set(int listen_socket) { |
|
296 |
if (listen_socket < 0) |
|
297 |
return; |
|
298 |
|
|
299 |
FD_SET(listen_socket, &ready_set); |
|
300 |
} |
|
301 |
|
|
302 |
/** |
|
303 |
* @brief Find out what file descriptors are ready to write to and read from |
|
304 |
* |
|
305 |
* @param listen_socket The socket to listen on |
|
306 |
* @param select_timeout The timeout for the select statement |
|
307 |
* |
|
308 |
* @return 0 |
|
309 |
*/ |
|
310 |
int ConnectionPool::perform_select(int listen_socket) { |
|
311 |
read_set = ready_set; |
|
312 |
write_set = ready_set; |
|
313 |
|
|
314 |
struct timeval select_timeout; |
|
315 |
memset(&select_timeout, 0, sizeof(select_timeout)); |
|
316 |
|
|
317 |
//TODO(Jason): think about why I put this there |
|
318 |
if (max_file_descriptor < listen_socket) |
|
319 |
max_file_descriptor = listen_socket; |
|
320 |
|
|
321 |
number_clients_ready = select(max_file_descriptor+1, &(read_set), &(write_set), NULL, &select_timeout); |
|
322 |
|
|
323 |
if (number_clients_ready < 0) { |
|
324 |
perror(__FUNCTION__); |
|
325 |
} |
|
326 |
|
|
327 |
return 0; |
|
328 |
} |
|
329 |
|
|
330 |
int ConnectionPool::is_socket_ready_to_read(int socket) { |
|
331 |
return FD_ISSET(socket, &read_set); |
|
332 |
} |
|
333 |
|
|
334 |
int ConnectionPool::is_socket_ready_to_write(int socket) { |
|
335 |
return FD_ISSET(socket, &write_set); |
|
336 |
} |
|
337 |
|
|
338 |
int ConnectionPool::get_max_file_descriptor() { |
|
339 |
return max_file_descriptor; |
|
340 |
} |
|
341 |
|
|
342 |
void ConnectionPool::set_max_file_descriptor(int new_max_file_descriptor) { |
|
343 |
max_file_descriptor = new_max_file_descriptor; |
|
344 |
} |
|
345 |
|
|
346 |
int ConnectionPool::get_next_available_slot() { |
|
347 |
return next_available_slot; |
|
348 |
} |
|
349 |
|
|
350 |
int ConnectionPool::get_number_clients_ready() { |
|
351 |
return number_clients_ready; |
|
352 |
} |
|
353 |
|
|
354 |
void ConnectionPool::set_number_clients_ready(int new_number_clients_ready) { |
|
355 |
number_clients_ready = new_number_clients_ready; |
|
356 |
} |
|
357 |
|
|
358 |
fd_set ConnectionPool::get_ready_set() { |
|
359 |
return ready_set; |
|
360 |
} |
|
361 |
|
|
362 |
fd_set ConnectionPool::get_read_set() { |
|
363 |
return read_set; |
|
364 |
} |
|
365 |
|
|
366 |
void ConnectionPool::set_read_set(fd_set new_set) { |
|
367 |
read_set = new_set; |
|
368 |
} |
|
369 |
|
|
370 |
fd_set ConnectionPool::get_write_set() { |
|
371 |
return write_set; |
|
372 |
} |
|
373 |
|
|
374 |
void ConnectionPool::set_write_set(fd_set new_set) { |
|
375 |
write_set = new_set; |
|
376 |
} |
|
377 |
|
|
378 |
//TODO: write a function to write data into the write buffers (jason: what was this referring to?) |
|
379 |
int ConnectionPool::parse_command(char* command, int pool_index, ColonetWireless * wireless) { |
|
380 |
char tokens[MAX_TOKENS][MAX_TOKEN_SIZE]; |
|
381 |
unsigned char int_tokens[MAX_TOKENS]; |
|
382 |
int number_tokens = 0; |
|
383 |
char* end_pointer = NULL; |
|
384 |
int command_id; |
|
385 |
int i; |
|
386 |
unsigned char arguments[PACKET_DATA_LEN]; |
|
387 |
|
|
388 |
memset(arguments, 1, PACKET_DATA_LEN); |
|
389 |
|
|
390 |
if (!command) { |
|
391 |
return -1; |
|
392 |
} |
|
393 |
|
|
394 |
if (pool_index < 0) { |
|
395 |
return -1; |
|
396 |
} |
|
397 |
|
|
398 |
if (pool_index >= next_available_slot) { |
|
399 |
return -1; |
|
400 |
} |
|
401 |
|
|
402 |
if ((number_tokens = tokenize_command(command, tokens)) < 0) { |
|
403 |
return -1; |
|
404 |
} |
|
405 |
|
|
406 |
//the 10 in the function call indicates number is base 10 |
|
407 |
command_id = strtol(tokens[0], &end_pointer, 10); |
|
408 |
|
|
409 |
if (!end_pointer || *end_pointer != '\0') { |
|
410 |
printf("There was an error converting first token into a number.\n"); |
|
411 |
return -1; |
|
412 |
} |
|
413 |
|
|
414 |
if (command_id == SEND_TO_ROBOT || REQUEST_FROM_ROBOT) { |
|
415 |
int number_int_tokens = number_tokens; |
|
416 |
|
|
417 |
/* Convert tokens to ints */ |
|
418 |
for (i = ROBOT_COMMAND_OFFSET; i < number_int_tokens; i++) { |
|
419 |
int_tokens[i-ROBOT_COMMAND_OFFSET] = atoi(tokens[i]); |
|
420 |
} |
|
421 |
if (command_id == REQUEST_FROM_ROBOT) { |
|
422 |
if (i < MAX_TOKENS) { |
|
423 |
for (;i >= 4; i--) { |
|
424 |
int_tokens[i] = int_tokens[i-1]; |
|
425 |
} |
|
426 |
int_tokens[3] = pool_index; |
|
427 |
number_int_tokens++; |
|
428 |
} else { |
|
429 |
//TODO: send an error back to client here also |
|
430 |
fprintf(stderr, "Client attempted to request data from the robot but there was not enough room to put in the client's id.\n"); |
|
431 |
return -1; |
|
432 |
} |
|
433 |
} |
|
434 |
|
|
435 |
/* Fill arguments buffer with arguments */ |
|
436 |
for (i = ROBOT_COMMAND_LEN; i < number_int_tokens-ROBOT_COMMAND_OFFSET; i++) { |
|
437 |
arguments[i-ROBOT_COMMAND_LEN] = int_tokens[i]; |
|
438 |
} |
|
439 |
|
|
440 |
/* Check the tokens */ |
|
441 |
if (check_tokens(int_tokens, number_int_tokens) < 0) { |
|
442 |
fprintf(stderr, "%s: Error - Invalid command/request.\n", __FUNCTION__); |
|
443 |
return 0; |
|
444 |
} |
|
445 |
|
|
446 |
/* Send packet to robot */ |
|
447 |
fprintf(stderr, "Calling wireless->send(%d, %d, %d, arguments)\n", |
|
448 |
int_tokens[0], int_tokens[1], int_tokens[2]); |
|
449 |
wireless->send(int_tokens[0], int_tokens[1], int_tokens[2], arguments); |
|
450 |
} |
|
451 |
|
|
452 |
return 0; |
|
453 |
} |
|
454 |
|
|
455 |
/** |
|
456 |
* @brief Breaks a command up into tokens |
|
457 |
* |
|
458 |
* @param command The command to tokenize |
|
459 |
* @param tokens A two dimensional character array to store the tokens in |
|
460 |
* |
|
461 |
* @return 0 on success, negative error code on failure |
|
462 |
*/ |
|
463 |
int ConnectionPool::tokenize_command(char* command, char tokens[MAX_TOKENS][MAX_TOKEN_SIZE]) { |
|
464 |
char* next_token = command; |
|
465 |
char* end_token = NULL; |
|
466 |
int number_tokens = 0; |
|
467 |
|
|
468 |
if (!command) { |
|
469 |
return -1; |
|
470 |
} |
|
471 |
|
|
472 |
while ((end_token = strstr(next_token, " "))) { |
|
473 |
*end_token = '\0'; |
|
474 |
|
|
475 |
if (strlen(next_token) > MAX_TOKEN_SIZE-1) { |
|
476 |
return -1; |
|
477 |
} |
|
478 |
|
|
479 |
strcpy(tokens[number_tokens], next_token); |
|
480 |
|
|
481 |
number_tokens++; |
|
482 |
next_token = end_token + 1; |
|
483 |
|
|
484 |
while (isspace(*next_token) && *next_token != '\0') { |
|
485 |
next_token++; |
|
486 |
} |
|
487 |
} |
|
488 |
|
|
489 |
if (end_token == NULL && *next_token != '\0') { |
|
490 |
if (strlen(next_token) > MAX_TOKEN_SIZE-1) { |
|
491 |
return -1; |
|
492 |
} |
|
493 |
|
|
494 |
strcpy(tokens[number_tokens], next_token); |
|
495 |
|
|
496 |
number_tokens++; |
|
497 |
} |
|
498 |
|
|
499 |
return number_tokens; |
|
500 |
} |
|
501 |
|
|
502 |
/** |
|
503 |
* @brief checks a list of tokens to see if it's valid |
|
504 |
* |
|
505 |
* @param tokens The tokens to check |
|
506 |
* @param number_tokens The number of tokens contained in the tokens parameter |
|
507 |
* |
|
508 |
* @return 0 if tokens is valid |
|
509 |
*/ |
|
510 |
int ConnectionPool::check_tokens(unsigned char* tokens, int number_tokens) { |
|
511 |
if (number_tokens > 3 + PACKET_DATA_LEN) { |
|
512 |
/* Too many tokens */ |
|
513 |
return -1; |
|
514 |
} |
|
515 |
|
|
516 |
if (number_tokens < 3) { |
|
517 |
/* Not enough tokens */ |
|
518 |
return -1; |
|
519 |
} |
|
520 |
|
|
521 |
if (tokens[1] != COLONET_REQUEST && tokens[1] != COLONET_COMMAND) { |
|
522 |
/* Invalid message type */ |
|
523 |
return -1; |
|
524 |
} |
|
525 |
|
|
526 |
return 0; |
|
527 |
} |
branches/charge_board/code/projects/colonet/ColonetServer/ColonetServer.cpp | ||
---|---|---|
1 |
/** |
|
2 |
* @file ColonetServer.cpp |
|
3 |
* |
|
4 |
* @brief colonet_server - primary server application for Colonet |
|
5 |
* |
|
6 |
* @author Jason Knichel |
|
7 |
* @author Eugene Marinelli |
|
8 |
* @date 10/31/06 |
|
9 |
*/ |
|
10 |
|
|
11 |
#include <colonet_wireless.h> |
|
12 |
#include <sys/select.h> |
|
13 |
#include <sys/socket.h> |
|
14 |
#include <netinet/in.h> |
|
15 |
#include <errno.h> |
|
16 |
#include <arpa/inet.h> |
|
17 |
|
|
18 |
#include <fcntl.h> |
|
19 |
|
|
20 |
#include <colonet_wireless.h> |
|
21 |
|
|
22 |
#include "includes/ColonetServer.h" |
|
23 |
#include "includes/ConnectionPool.h" |
|
24 |
#include "includes/client.h" |
|
25 |
#include "includes/options.h" |
|
26 |
#include "includes/Log.h" |
|
27 |
|
|
28 |
#define LISTEN_BACKLOG 5 |
|
29 |
#define LOG_BUFFER_LENGTH 128 |
|
30 |
|
|
31 |
ConnectionPool * connection_pool; |
|
32 |
|
|
33 |
/** |
|
34 |
* @brief Default constructor for ColonetServer |
|
35 |
*/ |
|
36 |
ColonetServer::ColonetServer(): logger("logFile.txt") { |
|
37 |
listen_socket = 0; |
|
38 |
} |
|
39 |
|
|
40 |
/** |
|
41 |
* @brief Destructor for ColonetServer |
|
42 |
*/ |
|
43 |
ColonetServer::~ColonetServer() { |
|
44 |
} |
|
45 |
|
|
46 |
/** |
|
47 |
* @brief Initializes the various elements needed for the server to run |
|
48 |
* |
|
49 |
* @param argc The number of command line arguments passed to the program |
|
50 |
* @param argv The command line arguments passed to the program |
|
51 |
* |
|
52 |
* @return 0 on success, negative error code on failure |
|
53 |
*/ |
|
54 |
int ColonetServer::initialize_server(int argc, char * argv[]) { |
|
55 |
printf("Initializing Server...\n"); |
|
56 |
|
|
57 |
parseCmdLine(argc, argv); |
|
58 |
|
|
59 |
if (initialize_connection(optionsG.listen_port) < 0) { |
|
60 |
return -1; |
|
61 |
} |
|
62 |
|
|
63 |
if (initialize_wireless() < 0) { |
|
64 |
fprintf(stderr, "%s: initWireless failed\n", __FUNCTION__); |
|
65 |
return -1; |
|
66 |
} |
|
67 |
|
|
68 |
return 0; |
|
69 |
} |
|
70 |
|
|
71 |
/** |
|
72 |
* @brief Starts the server listening on the socket that was opened for listening |
|
73 |
* |
|
74 |
* @return 0 on success, negative error code on failure |
|
75 |
*/ |
|
76 |
int ColonetServer::start_listening() { |
|
77 |
if (listen(listen_socket, LISTEN_BACKLOG) < 0) { |
|
78 |
log_error("\t\nThere was an error telling the socket to " |
|
79 |
"listen for connections from clients. Terminating Server...\n"); |
|
80 |
return -1; |
|
81 |
} |
|
82 |
return 0; |
|
83 |
} |
|
84 |
|
|
85 |
/** |
|
86 |
* @brief Logs an error message to the log file |
|
87 |
*/ |
|
88 |
int ColonetServer::log_error(char * error_message) { |
|
89 |
return logger.logMessage(LOG_TYPE_ERROR, error_message); |
|
90 |
} |
|
91 |
|
|
92 |
/** |
|
93 |
* @brief Logs a message to the log file |
|
94 |
*/ |
|
95 |
int ColonetServer::log_message(char * message) { |
|
96 |
return logger.logMessage(LOG_TYPE_MESSAGE, message); |
|
97 |
} |
|
98 |
|
|
99 |
/** |
|
100 |
* @brief Starts the server running (starts an infinite loop) |
|
101 |
*/ |
|
102 |
int ColonetServer::run_server() { |
|
103 |
connection_pool.set_listen_socket_in_ready_set(listen_socket); |
|
104 |
|
|
105 |
//TODO: why is all of this in that if statement and not just conn_pool.maxfd = listen_socket ? |
|
106 |
if (listen_socket > connection_pool.get_max_file_descriptor()) { |
|
107 |
connection_pool.set_max_file_descriptor(listen_socket); |
|
108 |
|
|
109 |
int accept_socket = 0; |
|
110 |
struct sockaddr_in client_addr; |
|
111 |
socklen_t client_addr_size = sizeof(client_addr); |
|
112 |
|
|
113 |
log_message("Server initialized. About to start listening for connections"); |
|
114 |
|
|
115 |
while(1) { |
|
116 |
connection_pool.perform_select(listen_socket); |
|
117 |
|
|
118 |
//either no descriptors are ready or there was an error |
|
119 |
if (connection_pool.get_number_clients_ready() <= 0) { |
|
120 |
continue; |
|
121 |
} |
|
122 |
|
|
123 |
if (connection_pool.is_socket_ready_to_read(listen_socket)) { |
|
124 |
printf("Something is trying to connect...\n"); |
|
125 |
if ((accept_socket = accept(listen_socket, (struct sockaddr*) &client_addr, &client_addr_size)) < 0) { |
|
126 |
if (errno == EMFILE) { |
|
127 |
printf("\tWhen attempting to accept a connection, " |
|
128 |
"reached the per process limit of file descriptors." |
|
129 |
" Dropping the new connection.\n"); |
|
130 |
continue; |
|
131 |
} else { |
|
132 |
printf("\tThere was an error when attempting to accept a connection"); |
|
133 |
} |
|
134 |
continue; |
|
135 |
} |
|
136 |
|
|
137 |
char log_buffer[LOG_BUFFER_LENGTH]; |
|
138 |
snprintf(log_buffer, LOG_BUFFER_LENGTH, "Client at address %s attempting to connect.", |
|
139 |
inet_ntoa(client_addr.sin_addr)); |
|
140 |
logger.logMessage(LOG_TYPE_CONNECT, log_buffer); |
|
141 |
|
|
142 |
if (connection_pool.add_client(accept_socket) < 0) { |
|
143 |
printf("\tThere was an error when trying to add a client to the connection pool."); |
|
144 |
continue; |
|
145 |
} |
|
146 |
|
|
147 |
snprintf(log_buffer, LOG_BUFFER_LENGTH, "Client at address %s successfully added to connection pool.", |
|
148 |
inet_ntoa(client_addr.sin_addr)); |
|
149 |
logger.logMessage(LOG_TYPE_CONNECT, log_buffer); |
|
150 |
} |
|
151 |
|
|
152 |
if (connection_pool.check_clients(wireless) < 0) { |
|
153 |
printf("\tThere was an error trying to update the clients."); |
|
154 |
continue; |
|
155 |
} |
|
156 |
} |
|
157 |
} |
|
158 |
|
|
159 |
return 0; |
|
160 |
} |
|
161 |
|
|
162 |
/** |
|
163 |
* @todo This method is here because the wireless message handler has a dependency on the connection_pool |
|
164 |
* This should be removed when that dependency is broken |
|
165 |
* |
|
166 |
* @return A pointer to the connection pool |
|
167 |
*/ |
|
168 |
ConnectionPool * ColonetServer::get_connection_pool_pointer() { |
|
169 |
return &connection_pool; |
|
170 |
} |
|
171 |
|
|
172 |
/** |
|
173 |
* @brief Initializes the wireless |
|
174 |
* |
|
175 |
* @return 0 on success, negative error code on error |
|
176 |
*/ |
|
177 |
int ColonetServer::initialize_wireless() { |
|
178 |
char* log_filename = NULL; |
|
179 |
|
|
180 |
if (optionsG.logging_enabled) { |
|
181 |
log_filename = optionsG.log_filename; |
|
182 |
} |
|
183 |
|
|
184 |
wireless = new ColonetWireless(optionsG.wireless_port, |
|
185 |
wirelessMessageHandler, log_filename, |
|
186 |
/*!optionsG.listener_mode*/false, true); |
|
187 |
//Note: last arg set to true ignores token ring; in general, this should |
|
188 |
//probably be false (changed for demo purposes) |
|
189 |
|
|
190 |
if (!wireless->run_listener_thread()) { |
|
191 |
return -1; |
|
192 |
} |
|
193 |
|
|
194 |
return 0; |
|
195 |
} |
|
196 |
|
|
197 |
/** |
|
198 |
* @brief Initialize a connection to listen on |
|
199 |
* |
|
200 |
* @port The port to try to open to listen on |
|
201 |
* |
|
202 |
* @return 0 on success, negative error code on error |
|
203 |
*/ |
|
204 |
int ColonetServer::initialize_connection(int port) { |
|
205 |
printf("Initializing connection that will be used to listen for " |
|
206 |
"clients...\n"); |
|
207 |
int options = 1; |
|
208 |
struct sockaddr_in my_address; |
|
209 |
|
|
210 |
//get a socket fd |
|
211 |
if ((listen_socket = socket(AF_INET, SOCK_STREAM, 0)) < 0) { |
|
212 |
printf("\tThere was an error creating a socket\n"); |
|
213 |
return -1; |
|
214 |
} |
|
215 |
|
|
216 |
//set up the address struct |
|
217 |
memset(&my_address,'\0',sizeof(my_address)); |
|
218 |
my_address.sin_family = AF_INET; |
|
219 |
my_address.sin_addr.s_addr = htonl(INADDR_ANY); |
|
220 |
my_address.sin_port = htons(port); |
|
221 |
|
|
222 |
setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR, &options, sizeof(options)); |
|
223 |
|
|
224 |
//get the current socket options |
|
225 |
if ((options = fcntl(listen_socket, F_GETFL)) < 0) { |
|
226 |
printf("\tThere was an error getting the socket options.\n"); |
|
227 |
return -1; |
|
228 |
} |
|
229 |
|
|
230 |
//set the socket to non blocking |
|
231 |
options = (options | O_NONBLOCK); |
|
232 |
if (fcntl(listen_socket, F_SETFL, options) < 0) { |
|
233 |
printf("\tThere was an error setting the socket to be non blocking.\n"); |
|
234 |
return -1; |
|
235 |
} |
|
236 |
|
|
237 |
//bind the socket to listen on the specified port |
|
238 |
if (bind(listen_socket, (struct sockaddr *) &my_address, sizeof(my_address)) < 0) { |
|
239 |
printf("\tThere was an error binding the socket\n"); |
|
240 |
return -1; |
|
241 |
} |
|
242 |
|
|
243 |
return 0; |
|
244 |
} |
|
245 |
|
|
246 |
/** |
|
247 |
* @brief The main function of the server |
|
248 |
* |
|
249 |
* @param argc The number of command line arguments passed to the program |
|
250 |
* @param argv The command line arguments passed to the program |
|
251 |
* |
|
252 |
* @return 0 on success, negative error code on error |
|
253 |
*/ |
|
254 |
int main(int argc, char** argv) { |
|
255 |
ColonetServer colonet_server; |
|
256 |
|
|
257 |
connection_pool = colonet_server.get_connection_pool_pointer(); |
|
258 |
|
|
259 |
if (colonet_server.initialize_server(argc, argv) < 0) { |
|
260 |
colonet_server.log_error("\t\nThere was an error initializing the server. " |
|
261 |
"Terminating server...\n"); |
|
262 |
return -1; |
|
263 |
} |
|
264 |
|
|
265 |
if (colonet_server.start_listening() < 0) { |
|
266 |
return -1; |
|
267 |
} |
|
268 |
|
|
269 |
colonet_server.run_server(); |
|
270 |
|
|
271 |
return 0; |
|
272 |
} |
|
273 |
|
|
274 |
//this is old code that was commented out that I didn't want to delete yet |
|
275 |
/* |
|
276 |
int parseCommandLine(int argc, char * argv[], commandParams_t * params) |
|
277 |
{ |
|
278 |
printf("Parsing Command Line...\n"); |
|
279 |
if (!params) |
|
280 |
return -1; |
|
281 |
|
|
282 |
//if no command line parameters were specified, set to defaults |
|
283 |
if (argc == 1) { |
|
284 |
printf("No port was specified for listening for client connections." |
|
285 |
" Defaulting to %d\n", DEFAULTPORT); |
|
286 |
params->listenPort = DEFAULTPORT; |
|
287 |
} |
|
288 |
|
|
289 |
if (!argv) |
|
290 |
return -1; |
|
291 |
|
|
292 |
int i; |
|
293 |
for (i = 1; i < argc; i++) { |
|
294 |
char * temp = argv[i]; |
|
295 |
if (temp[0] != '-') |
|
296 |
{ |
|
297 |
printUsage(argv[0]); |
|
298 |
return -1; |
|
299 |
} |
|
300 |
|
|
301 |
switch(temp[1]) |
|
302 |
{ |
|
303 |
case 'h': printUsage(argv[0]); |
|
304 |
break; |
|
305 |
case 'p': |
|
306 |
{ |
|
307 |
if (i >= argc-1) |
|
308 |
{ |
|
309 |
printUsage(argv[0]); |
|
310 |
return -1; |
|
311 |
} |
|
312 |
i++; |
|
313 |
char * portString = argv[i]; |
|
314 |
char * endptr = NULL; |
|
315 |
int port = strtol(portString, &endptr, 10); |
|
316 |
if (*endptr != '\0') |
|
317 |
{ |
|
318 |
printf("Invalid port specified...%s, %d\n", endptr, port); |
|
319 |
return -1; |
|
320 |
} |
|
321 |
if (port < SMALLEST_POSS_LISTEN_PORT) |
|
322 |
{ |
|
323 |
printf("You cannot listen on a port less than %d.\n", |
|
324 |
SMALLEST_POSS_LISTEN_PORT); |
|
325 |
return -1; |
|
326 |
} |
|
327 |
params->listenPort = port; |
|
328 |
printf("Setting port to listen on to %d.\n", params->listenPort); |
|
329 |
} |
|
330 |
break; |
|
331 |
default: printUsage(argv[0]); |
|
332 |
return -1; |
|
333 |
break; |
|
334 |
} |
|
335 |
} |
|
336 |
|
|
337 |
return 0; |
|
338 |
} |
|
339 |
*/ |
|
340 |
|
branches/charge_board/code/projects/colonet/ColonetServer/includes/ConnectionPool.h | ||
---|---|---|
1 |
/** |
|
2 |
* @author Jason Knichel |
|
3 |
* @date 7/22/07 |
|
4 |
*/ |
|
5 |
|
|
6 |
#ifndef CONNECTION_POOL_H |
|
7 |
#define CONNECTION_POOL_H |
|
8 |
|
|
9 |
#include <sys/select.h> |
|
10 |
|
|
11 |
#include <colonet_wireless.h> |
|
12 |
|
|
13 |
#define MAX_TOKENS 15 |
|
14 |
#define MAX_TOKEN_SIZE 30 |
|
15 |
|
|
16 |
#define ROBOT_COMMAND_OFFSET 1 |
|
17 |
#define ROBOT_COMMAND_LEN 3 |
|
18 |
|
|
19 |
#define ERROR_INVALID_CLIENT_DESCRIPTOR -1 |
|
20 |
#define ERROR_TOO_MANY_CLIENTS -2 |
|
21 |
#define ERROR_ALLOCATING_MEMORY -3 |
|
22 |
#define ERROR_NOT_ENOUGH_ROOM -4 |
|
23 |
#define ERROR_INVALID_COMMAND -5 |
|
24 |
#define ERROR_INVALID_CLIENT_ID -6 |
|
25 |
#define ERROR_INVALID_MESSAGE -7 |
|
26 |
#define ERROR_INVALID_MESSAGE_LENGTH -8 |
|
27 |
|
|
28 |
#define MAX_CONNECTIONS 250 |
|
29 |
#define READ_BUFFER_SIZE 1024 |
|
30 |
#define WRITE_BUFFER_SIZE 1024 |
|
31 |
|
|
32 |
class ConnectionPool { |
|
33 |
|
|
34 |
public: |
|
35 |
ConnectionPool(); |
|
36 |
~ConnectionPool(); |
|
37 |
|
|
38 |
int add_client(int client_file_descriptor); |
|
39 |
int remove_client(int pool_index); |
|
40 |
int check_clients(ColonetWireless * wireless); |
|
41 |
int write_to_client(int pool_index, char * message, int length); |
|
42 |
void set_listen_socket_in_ready_set(int listen_socket); |
|
43 |
int perform_select(int listen_socket); |
|
44 |
int is_socket_ready_to_read(int socket); |
|
45 |
int is_socket_ready_to_write(int socket); |
|
46 |
|
|
47 |
|
|
48 |
int get_max_file_descriptor(); |
|
49 |
void set_max_file_descriptor(int new_max_file_descriptor); |
|
50 |
|
|
51 |
int get_next_available_slot(); |
|
52 |
|
|
53 |
int get_number_clients_ready(); |
|
54 |
void set_number_clients_ready(int new_number_clients_ready); |
|
55 |
|
|
56 |
fd_set get_ready_set(); |
|
57 |
|
|
58 |
fd_set get_read_set(); |
|
59 |
void set_read_set(fd_set new_set); |
|
60 |
|
|
61 |
fd_set get_write_set(); |
|
62 |
void set_write_set(fd_set new_set); |
|
63 |
|
|
64 |
private: |
|
65 |
int max_file_descriptor; |
|
66 |
int next_available_slot; |
|
67 |
int number_clients_ready; |
|
68 |
fd_set ready_set; |
|
69 |
fd_set read_set; |
|
70 |
fd_set write_set; |
|
71 |
int client_file_descriptor_array[MAX_CONNECTIONS]; |
|
72 |
char * read_buffer[MAX_CONNECTIONS]; |
|
73 |
int read_buffer_size[MAX_CONNECTIONS]; |
|
74 |
char * write_buffer[MAX_CONNECTIONS]; |
|
75 |
int write_buffer_size[MAX_CONNECTIONS]; |
|
76 |
|
|
77 |
int parse_command(char* command, int pool_index, ColonetWireless * wireless); |
|
78 |
int tokenize_command(char* command, char tokens[MAX_TOKENS][MAX_TOKEN_SIZE]); |
|
79 |
int check_tokens(unsigned char* tokens, int number_tokens); |
|
80 |
}; |
|
81 |
|
|
82 |
#endif |
branches/charge_board/code/projects/colonet/ColonetServer/includes/Log.h | ||
---|---|---|
1 |
/** |
|
2 |
* |
|
3 |
* @author Jason Knichel |
|
4 |
* |
|
5 |
*/ |
|
6 |
|
|
7 |
#ifndef LOGGING_H |
|
8 |
#define LOGGING_H |
|
9 |
|
|
10 |
#include <time.h> |
|
11 |
#include <stdio.h> |
|
12 |
|
|
13 |
#define LOG_TYPE_START_LOG 0 |
|
14 |
#define LOG_TYPE_CONNECT 1 |
|
15 |
#define LOG_TYPE_DISCONNECT 2 |
|
16 |
#define LOG_TYPE_ERROR 3 |
|
17 |
#define LOG_TYPE_MESSAGE 4 |
|
18 |
|
|
19 |
#define LOG_MAX_TYPE_LENGTH 25 |
|
20 |
#define LOG_MAX_TIME_LENGTH 64 |
|
21 |
|
|
22 |
class Log { |
|
23 |
public: |
|
24 |
Log(char * fileName); |
|
25 |
~Log(); |
|
26 |
|
|
27 |
int logMessage(int type, char * message); |
|
28 |
|
|
29 |
private: |
|
30 |
struct tm getCurrentTime(); |
|
31 |
|
|
32 |
FILE * logFile; |
|
33 |
}; |
|
34 |
|
|
35 |
#endif |
branches/charge_board/code/projects/colonet/ColonetServer/includes/ColonetServer.h | ||
---|---|---|
1 |
/** |
|
2 |
* @author Jason Knichel |
|
3 |
* @date 9/10/07 |
|
4 |
*/ |
|
5 |
|
|
6 |
#ifndef COLONETSERVER_H |
|
7 |
#define COLONETSERVER_H |
|
8 |
|
|
9 |
#include <colonet_wireless.h> |
|
10 |
#include "ConnectionPool.h" |
|
11 |
#include "Log.h" |
|
12 |
|
|
13 |
class ColonetServer { |
|
14 |
public: |
|
15 |
ColonetServer(); |
|
16 |
~ColonetServer(); |
|
17 |
int initialize_server(int argc, char * argv[]); |
|
18 |
|
|
19 |
int start_listening(); |
|
20 |
|
|
21 |
int log_error(char * error_message); |
|
22 |
int log_message(char * message); |
|
23 |
|
|
24 |
int run_server(); |
|
25 |
|
|
26 |
ConnectionPool * get_connection_pool_pointer(); |
|
27 |
|
|
28 |
private: |
|
29 |
ConnectionPool connection_pool; |
|
30 |
Log logger; |
|
31 |
ColonetWireless* wireless; |
|
32 |
int listen_socket; |
|
33 |
|
|
34 |
int initialize_wireless(); |
|
35 |
int initialize_connection(int port); |
|
36 |
}; |
|
37 |
|
|
38 |
#endif |
branches/charge_board/code/projects/colonet/ColonetServer/includes/options.h | ||
---|---|---|
1 |
/** |
|
2 |
* @file options.h |
|
3 |
* @brief Options for ColonetServer |
|
4 |
* @author Eugene Marinelli |
|
5 |
* @date 2/13/07 |
|
6 |
*/ |
|
7 |
|
|
8 |
#ifndef OPTIONS_H |
|
9 |
#define OPTIONS_H |
|
10 |
|
|
11 |
#define DEFAULTPORT 10123 |
|
12 |
#define SMALLEST_POSS_LISTEN_PORT 2000 |
|
13 |
|
|
14 |
typedef struct { |
|
15 |
int listen_port; |
|
16 |
char wireless_port[80]; |
|
17 |
char log_filename[80]; |
|
18 |
bool logging_enabled; |
|
19 |
bool listener_mode; |
|
20 |
} ColonetServerOptionsT; |
|
21 |
|
|
22 |
extern ColonetServerOptionsT optionsG; |
|
23 |
|
|
24 |
void parseCmdLine(int argc, char** argv); |
|
25 |
|
|
26 |
#endif |
branches/charge_board/code/projects/colonet/ColonetServer/includes/client.h | ||
---|---|---|
1 |
/** |
|
2 |
* |
|
3 |
* @author Jason Knichel |
|
4 |
* |
|
5 |
*/ |
|
6 |
|
|
7 |
#ifndef CLIENT_H |
|
8 |
#define CLIENT_H |
|
9 |
|
|
10 |
#include <colonet_wireless.h> |
|
11 |
|
|
12 |
int wirelessMessageHandler(ColonetPacket* pkt); |
|
13 |
int initWireless(void); |
|
14 |
void send_wireless_message(unsigned char msg_dest, unsigned char msg_type, |
|
15 |
unsigned char msg_code, unsigned char* data); |
|
16 |
|
|
17 |
#endif |
branches/charge_board/code/projects/colonet/ColonetServer/Log.cpp | ||
---|---|---|
1 |
/** |
|
2 |
* @file Logging.cpp |
|
3 |
* |
|
4 |
* @brief This file contains the code to do logging for Colonet |
|
5 |
* |
|
6 |
* @author Jason Knichel |
|
7 |
* |
|
8 |
*/ |
|
9 |
|
|
10 |
#include <time.h> |
|
11 |
#include <string.h> |
|
12 |
#include <stdio.h> |
|
13 |
|
|
14 |
#include "includes/Log.h" |
|
15 |
|
|
16 |
/** |
|
17 |
* @brief Constructor for the Log class |
|
18 |
* |
|
19 |
* @param filename The name of the file to output log statements to |
|
20 |
*/ |
|
21 |
Log::Log(char * filename) { |
|
22 |
printf("Creating log object\n"); |
|
23 |
|
|
24 |
if (!filename) { |
|
25 |
fprintf(stderr, "Provided a null filename when trying to create a log.\n"); |
|
26 |
return; |
|
27 |
} |
|
28 |
|
|
29 |
logFile = fopen(filename, "a"); //open file for appending |
|
30 |
if (!logFile) { |
|
31 |
fprintf(stderr, "Error opening %s as log file.\n", filename); |
|
32 |
return; |
|
33 |
} |
|
34 |
|
|
35 |
printf("About to log start message.\n"); |
|
36 |
logMessage(LOG_TYPE_START_LOG, "Starting server"); |
|
37 |
} |
|
38 |
|
|
39 |
/** |
|
40 |
* @brief Destructor for the Log class |
|
41 |
*/ |
|
42 |
Log::~Log() { |
|
43 |
if (!logFile) |
|
44 |
fclose(logFile); |
|
45 |
} |
|
46 |
|
|
47 |
/** |
|
48 |
* @brief A function to get the current time |
|
49 |
* |
|
50 |
* @return A struct tm that represents the current time |
|
51 |
*/ |
|
52 |
struct tm Log::getCurrentTime() { |
|
53 |
struct tm currTime; |
|
54 |
memset(&currTime, 0, sizeof(struct tm)); |
|
55 |
|
|
56 |
time_t t = time(NULL); |
|
57 |
localtime_r(&t, &currTime); |
|
58 |
|
|
59 |
return currTime; |
|
60 |
} |
|
61 |
|
|
62 |
/** |
|
63 |
* @brief This method logs a message with the specified type |
|
64 |
* |
|
65 |
* @param type The type of the message to log |
|
66 |
* @param message The message to log |
|
67 |
* |
|
68 |
* @return 0 on success, negative error code on error |
|
69 |
*/ |
|
70 |
int Log::logMessage(int type, char * message) { |
|
71 |
if (!logFile) { |
|
72 |
fprintf(stderr, "Tried to log a message but the file pointer was null.\n"); |
|
73 |
return -1; |
|
74 |
} |
|
75 |
|
|
76 |
if (!message) { |
|
77 |
fprintf(stderr, "Tried to log a null message.\n"); |
|
78 |
return -1; |
|
79 |
} |
|
80 |
|
|
81 |
static char * start_log = "Starting Log"; |
|
82 |
static char * connect = "Client Connecting"; |
|
83 |
static char * disconnect = "Client Disconnecting"; |
|
84 |
static char * error = "Error"; |
|
85 |
static char * logGenMessage = "Generic Message"; |
|
86 |
|
|
87 |
char * messageType; |
|
88 |
|
|
89 |
switch(type) { |
|
90 |
case LOG_TYPE_START_LOG: |
|
91 |
messageType = start_log; |
|
92 |
break; |
|
93 |
case LOG_TYPE_CONNECT: |
|
94 |
messageType = connect; |
|
95 |
break; |
|
96 |
case LOG_TYPE_DISCONNECT: |
|
97 |
messageType = disconnect; |
|
98 |
break; |
|
99 |
case LOG_TYPE_ERROR: |
|
100 |
messageType = error; |
|
101 |
break; |
|
102 |
case LOG_TYPE_MESSAGE: |
|
103 |
messageType = logGenMessage; |
|
104 |
break; |
|
105 |
default: |
|
106 |
fprintf(stderr, "Tried to log a message with an invalid type.\n"); |
|
107 |
return -1; |
|
108 |
} |
|
109 |
|
|
110 |
struct tm currTime = getCurrentTime(); |
|
111 |
|
|
112 |
char buffer[LOG_MAX_TIME_LENGTH]; |
|
113 |
asctime_r(&currTime, buffer); |
|
114 |
int len = strlen(buffer); |
|
115 |
buffer[len-1] = '\0'; //remove the newline that is put at the end by asctime_r |
|
116 |
fprintf(logFile, "%s %*s %s\n", buffer, LOG_MAX_TYPE_LENGTH, messageType, message); |
|
117 |
fflush(logFile); |
|
118 |
|
|
119 |
return 0; |
|
120 |
} |
branches/charge_board/code/projects/colonet/ColonetServer/client.cpp | ||
---|---|---|
1 |
/** @file client.c |
|
2 |
* |
|
3 |
* @author Jason Knichel |
|
4 |
* @author Eugene Marinelli |
|
5 |
* |
|
6 |
* @TODO remove dependency on connection_pool |
|
7 |
* @bug Weird segfault when processing tokens |
|
8 |
*/ |
|
9 |
|
|
10 |
#include <string.h> |
|
11 |
#include <stdio.h> |
|
12 |
#include <unistd.h> |
|
13 |
#include <ctype.h> |
|
14 |
#include <errno.h> |
|
15 |
|
|
16 |
#include <colonet_wireless.h> |
|
17 |
|
|
18 |
#include "includes/client.h" |
|
19 |
#include "includes/options.h" |
|
20 |
#include "includes/ConnectionPool.h" |
|
21 |
|
|
22 |
/* Globals */ |
|
23 |
extern ConnectionPool * connection_pool; |
|
24 |
|
|
25 |
|
|
26 |
/* Public functions */ |
|
27 |
int wirelessMessageHandler(ColonetPacket* pkt) |
|
28 |
{ |
|
29 |
printf("Received wireless message!!!\n"); |
|
30 |
if (!pkt) { |
|
31 |
printf("The packet pointer was null.\n"); |
|
32 |
return -1; |
|
33 |
} |
|
34 |
|
|
35 |
if ((int)pkt->msg_type == COLONET_RESPONSE) { |
|
36 |
printf("response\n"); |
|
37 |
|
|
38 |
int dest = (int)(pkt->msg_dest); |
|
39 |
char buffer[WRITE_BUFFER_SIZE]; |
|
40 |
|
|
41 |
int value = (int)(pkt->data[0]); |
|
42 |
snprintf(buffer, WRITE_BUFFER_SIZE, "%d\n", value); |
|
43 |
|
|
44 |
int len = strlen(buffer); |
|
45 |
if (connection_pool->write_to_client(dest, buffer, len) == ERROR_INVALID_CLIENT_ID) { |
|
46 |
printf("The robot wanted to pass the data to a client not in the pool.\n"); |
|
47 |
return -1; |
|
48 |
} |
|
49 |
|
|
50 |
printf("Put data in write buffer for client.\n"); |
|
51 |
} else { |
|
52 |
printf("not a response\n"); |
|
53 |
} |
|
54 |
|
|
55 |
pkt = 0; |
|
56 |
return 0; |
|
57 |
} |
branches/charge_board/code/projects/colonet/ColonetServer/options.c | ||
---|---|---|
1 |
/** |
|
2 |
* @file options.c |
|
3 |
* |
|
4 |
* @brief Options for ColonetServer |
|
5 |
* |
|
6 |
* @author Eugene Marinelli |
|
7 |
* |
|
8 |
* @date 2/13/07 |
|
9 |
* |
|
10 |
* @bug Usage not written |
|
11 |
*/ |
|
12 |
|
|
13 |
#include <stdio.h> |
|
14 |
#include <getopt.h> |
|
15 |
#include <string.h> |
|
16 |
#include <stdlib.h> |
|
17 |
|
|
18 |
#include <colonet_defs.h> |
|
19 |
|
|
20 |
#include "includes/options.h" |
|
21 |
|
|
22 |
ColonetServerOptionsT optionsG; |
|
23 |
|
|
24 |
/** |
|
25 |
* @brief Prints the usage of the program |
|
26 |
*/ |
|
27 |
static void printUsage() { |
|
28 |
printf("USAGE:\n"); |
|
29 |
} |
|
30 |
|
|
31 |
/** |
|
32 |
* @brief Parses the command line arguments |
|
33 |
* |
|
34 |
* @param argc The number of arguments passed to the program |
|
35 |
* @param argv The arguments passed to the program |
|
36 |
* |
|
37 |
* @return Void |
|
38 |
*/ |
|
39 |
void parseCmdLine(int argc, char** argv) { |
|
40 |
int c; |
|
41 |
|
|
42 |
memset(&optionsG, 0, sizeof(ColonetServerOptionsT)); |
|
43 |
|
|
44 |
if (argc < 2) { |
|
45 |
printf("No port was specified for listening for client connections." |
|
46 |
" Defaulting to %d\n", DEFAULTPORT); |
|
47 |
} |
|
48 |
|
|
49 |
/* Defaults */ |
|
50 |
optionsG.listen_port = DEFAULTPORT; |
|
51 |
strcpy(optionsG.wireless_port, USB_PORT); |
|
52 |
optionsG.logging_enabled = false; |
|
53 |
optionsG.listener_mode = false; |
|
54 |
|
|
55 |
/* Parse args */ |
|
56 |
while (1) { |
|
57 |
c = getopt(argc, argv, "p:l:w:su"); |
|
58 |
|
|
59 |
if (c == -1) { |
|
60 |
break; |
|
61 |
} |
|
62 |
|
|
63 |
switch (c) { |
|
64 |
case 'p': |
|
65 |
/* Listen port */ |
|
66 |
optionsG.listen_port = atoi(optarg); |
|
67 |
|
|
68 |
if (optionsG.listen_port < SMALLEST_POSS_LISTEN_PORT) { |
|
69 |
printf("You cannot listen on a port less than %d.\n", |
|
70 |
SMALLEST_POSS_LISTEN_PORT); |
|
71 |
printf("Setting listener port to %d\n", DEFAULTPORT); |
|
72 |
optionsG.listen_port = DEFAULTPORT; |
|
73 |
} |
|
74 |
break; |
|
75 |
case 'w': |
|
76 |
/* Set wireless port */ |
|
77 |
strcpy(optionsG.wireless_port, optarg); |
|
78 |
break; |
|
79 |
case 'l': |
|
80 |
/* Set log filename (and enable logging) */ |
|
81 |
strcpy(optionsG.log_filename, optarg); |
|
82 |
optionsG.logging_enabled = true; |
|
83 |
break; |
|
84 |
case 's': |
|
85 |
/* Enable listener mode */ |
|
86 |
optionsG.listener_mode = true; |
|
87 |
break; |
|
88 |
case 'u': |
|
89 |
printUsage(); |
|
90 |
} |
|
91 |
} |
|
92 |
} |
branches/charge_board/code/projects/colonet/ColonetGUI/Colonet.xcodeproj/gmtress.mode1 | ||
---|---|---|
1 |
<?xml version="1.0" encoding="UTF-8"?> |
|
2 |
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> |
|
3 |
<plist version="1.0"> |
|
4 |
<dict> |
|
5 |
<key>ActivePerspectiveName</key> |
|
6 |
<string>Project</string> |
|
7 |
<key>AllowedModules</key> |
|
8 |
<array> |
|
9 |
<dict> |
|
10 |
<key>BundleLoadPath</key> |
|
11 |
<string></string> |
|
12 |
<key>MaxInstances</key> |
|
13 |
<string>n</string> |
|
14 |
<key>Module</key> |
|
15 |
<string>PBXSmartGroupTreeModule</string> |
|
16 |
<key>Name</key> |
|
17 |
<string>Groups and Files Outline View</string> |
|
18 |
</dict> |
|
19 |
<dict> |
|
20 |
<key>BundleLoadPath</key> |
|
21 |
<string></string> |
|
22 |
<key>MaxInstances</key> |
|
23 |
<string>n</string> |
|
24 |
<key>Module</key> |
|
25 |
<string>PBXNavigatorGroup</string> |
|
26 |
<key>Name</key> |
|
27 |
<string>Editor</string> |
|
28 |
</dict> |
|
29 |
<dict> |
|
30 |
<key>BundleLoadPath</key> |
|
31 |
<string></string> |
|
32 |
<key>MaxInstances</key> |
|
33 |
<string>n</string> |
|
34 |
<key>Module</key> |
|
35 |
<string>XCTaskListModule</string> |
|
36 |
<key>Name</key> |
|
37 |
<string>Task List</string> |
|
38 |
</dict> |
|
39 |
<dict> |
|
40 |
<key>BundleLoadPath</key> |
|
41 |
<string></string> |
|
42 |
<key>MaxInstances</key> |
|
43 |
<string>n</string> |
|
44 |
<key>Module</key> |
|
45 |
<string>XCDetailModule</string> |
|
46 |
<key>Name</key> |
|
47 |
<string>File and Smart Group Detail Viewer</string> |
|
48 |
</dict> |
|
49 |
<dict> |
|
50 |
<key>BundleLoadPath</key> |
|
51 |
<string></string> |
|
52 |
<key>MaxInstances</key> |
|
53 |
<string>1</string> |
|
54 |
<key>Module</key> |
|
55 |
<string>PBXBuildResultsModule</string> |
|
56 |
<key>Name</key> |
|
57 |
<string>Detailed Build Results Viewer</string> |
|
58 |
</dict> |
|
59 |
<dict> |
|
60 |
<key>BundleLoadPath</key> |
|
61 |
<string></string> |
|
62 |
<key>MaxInstances</key> |
|
63 |
<string>1</string> |
|
64 |
<key>Module</key> |
|
65 |
<string>PBXProjectFindModule</string> |
|
66 |
<key>Name</key> |
|
67 |
<string>Project Batch Find Tool</string> |
|
68 |
</dict> |
|
69 |
<dict> |
|
70 |
<key>BundleLoadPath</key> |
|
71 |
<string></string> |
Also available in: Unified diff