root / trunk / code / projects / colonet / ColonetServer / ConnectionPool.cpp @ 75
History | View | Annotate | Download (16.5 KB)
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) {
|
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 |
/* we removed the request from robot constant
|
422 |
if (command_id == REQUEST_FROM_ROBOT) {
|
423 |
if (i < MAX_TOKENS) {
|
424 |
for (;i >= 4; i--) {
|
425 |
int_tokens[i] = int_tokens[i-1];
|
426 |
}
|
427 |
int_tokens[3] = pool_index;
|
428 |
number_int_tokens++;
|
429 |
} else {
|
430 |
//TODO: send an error back to client here also
|
431 |
fprintf(stderr, "Client attempted to request data from the robot but there was not enough room to put in the client's id.\n");
|
432 |
return -1;
|
433 |
}
|
434 |
}
|
435 |
*/
|
436 |
|
437 |
// Fill arguments buffer with arguments
|
438 |
for (i = ROBOT_COMMAND_LEN; i < number_int_tokens-ROBOT_COMMAND_OFFSET; i++) {
|
439 |
arguments[i-ROBOT_COMMAND_LEN] = int_tokens[i]; |
440 |
} |
441 |
|
442 |
// Check the tokens
|
443 |
if (check_tokens(int_tokens, number_int_tokens) < 0) { |
444 |
fprintf(stderr, "%s: Error - Invalid command/request.\n", __FUNCTION__);
|
445 |
return 0; |
446 |
} |
447 |
|
448 |
// Send packet to robot
|
449 |
fprintf(stderr, "Calling wireless->send(%d, %d, %d, arguments)\n",
|
450 |
int_tokens[0], int_tokens[1], int_tokens[2]); |
451 |
wireless->send(int_tokens[0], int_tokens[1], int_tokens[2], arguments); |
452 |
} else if (command_id == REQUEST_FROM_SERVER) { |
453 |
if (number_tokens < 2) |
454 |
return -1; |
455 |
|
456 |
end_pointer=NULL;
|
457 |
int second_token = strtol(tokens[1], &end_pointer, 10); |
458 |
|
459 |
if (!end_pointer || *end_pointer != '\0') { |
460 |
printf("There was an error converting second token into a number.\n");
|
461 |
return -1; |
462 |
} |
463 |
|
464 |
if (second_token == REQUEST_BOM_MATRIX) {
|
465 |
//TODO: rename to indicate its actually the response message
|
466 |
char bom_matrix_buffer[MAX_RESPONSE_LEN];
|
467 |
char temp_bom_matrix_buffer[MAX_RESPONSE_LEN];
|
468 |
|
469 |
//TODO: change after we start keeping track of bom matrix
|
470 |
int number_robots = rand()%10; |
471 |
int bom_matrix[number_robots][number_robots];
|
472 |
for (int ii = 0; ii < number_robots; ii++) { |
473 |
for (int j = 0; j < number_robots; j++) { |
474 |
//do this to generate some -1 values which mean they can't see each other
|
475 |
int matrix_value = rand()%(number_robots+1)-1; |
476 |
bom_matrix[ii][j] = matrix_value; |
477 |
} |
478 |
} |
479 |
|
480 |
printf("number of robots is %d\n", number_robots);
|
481 |
|
482 |
//TODO: separate parameters with spaces
|
483 |
//TODO: make this better
|
484 |
//TODO: make sure I don't need to do MAX_RESPONSE_LENGTH-1
|
485 |
snprintf(bom_matrix_buffer,MAX_RESPONSE_LEN, "%d %d %d", RESPONSE_TO_CLIENT_REQUEST, REQUEST_BOM_MATRIX, number_robots);
|
486 |
for (int ii = 0; ii < number_robots; ii++) { |
487 |
for (int j = 0; j < number_robots; j++) { |
488 |
//TODO: don't use strcpy
|
489 |
strcpy(temp_bom_matrix_buffer, bom_matrix_buffer); |
490 |
//TODO: put length checking in here so array doesn't go out of bounds
|
491 |
//TODO: maybe use strncat?
|
492 |
printf("Buffer is %s\n", bom_matrix_buffer);
|
493 |
strcat(temp_bom_matrix_buffer," %d");
|
494 |
snprintf(bom_matrix_buffer, MAX_RESPONSE_LEN, temp_bom_matrix_buffer, bom_matrix[ii][j]); |
495 |
} |
496 |
} |
497 |
strcat(bom_matrix_buffer,"\n");
|
498 |
write_to_client(pool_index, bom_matrix_buffer, strlen(bom_matrix_buffer)); |
499 |
printf("Sending %s", bom_matrix_buffer);
|
500 |
} else {
|
501 |
char * my_current_message = "Hi, how are you?\n"; |
502 |
printf("Sending %s\n", my_current_message);
|
503 |
write_to_client(pool_index, my_current_message, strlen(my_current_message)); |
504 |
} |
505 |
} |
506 |
|
507 |
return 0; |
508 |
} |
509 |
|
510 |
/**
|
511 |
* @brief Breaks a command up into tokens
|
512 |
*
|
513 |
* @param command The command to tokenize
|
514 |
* @param tokens A two dimensional character array to store the tokens in
|
515 |
*
|
516 |
* @return 0 on success, negative error code on failure
|
517 |
*/
|
518 |
int ConnectionPool::tokenize_command(char* command, char tokens[MAX_TOKENS][MAX_TOKEN_SIZE]) { |
519 |
char* next_token = command;
|
520 |
char* end_token = NULL; |
521 |
int number_tokens = 0; |
522 |
|
523 |
if (!command) {
|
524 |
return -1; |
525 |
} |
526 |
|
527 |
while ((end_token = strstr(next_token, " "))) { |
528 |
*end_token = '\0';
|
529 |
|
530 |
if (strlen(next_token) > MAX_TOKEN_SIZE-1) { |
531 |
return -1; |
532 |
} |
533 |
|
534 |
strcpy(tokens[number_tokens], next_token); |
535 |
|
536 |
number_tokens++; |
537 |
next_token = end_token + 1;
|
538 |
|
539 |
while (isspace(*next_token) && *next_token != '\0') { |
540 |
next_token++; |
541 |
} |
542 |
} |
543 |
|
544 |
if (end_token == NULL && *next_token != '\0') { |
545 |
if (strlen(next_token) > MAX_TOKEN_SIZE-1) { |
546 |
return -1; |
547 |
} |
548 |
|
549 |
strcpy(tokens[number_tokens], next_token); |
550 |
|
551 |
number_tokens++; |
552 |
} |
553 |
|
554 |
return number_tokens;
|
555 |
} |
556 |
|
557 |
/**
|
558 |
* @brief checks a list of tokens to see if it's valid
|
559 |
*
|
560 |
* @param tokens The tokens to check
|
561 |
* @param number_tokens The number of tokens contained in the tokens parameter
|
562 |
*
|
563 |
* @return 0 if tokens is valid
|
564 |
*/
|
565 |
int ConnectionPool::check_tokens(unsigned char* tokens, int number_tokens) { |
566 |
if (number_tokens > 3 + PACKET_DATA_LEN) { |
567 |
/* Too many tokens */
|
568 |
return -1; |
569 |
} |
570 |
|
571 |
if (number_tokens < 3) { |
572 |
/* Not enough tokens */
|
573 |
return -1; |
574 |
} |
575 |
|
576 |
if (tokens[1] != COLONET_REQUEST && tokens[1] != COLONET_COMMAND) { |
577 |
/* Invalid message type */
|
578 |
return -1; |
579 |
} |
580 |
|
581 |
return 0; |
582 |
} |