root / trunk / code / projects / colonet / ColonetServer / ConnectionPool.cpp @ 118
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 |
#include <colonet_wireless.h> |
20 |
|
21 |
/**
|
22 |
* @brief The default constructor for ConnectionPool
|
23 |
*/
|
24 |
ConnectionPool::ConnectionPool() { |
25 |
max_file_descriptor = 0;
|
26 |
next_available_slot = 0;
|
27 |
number_clients_ready = 0;
|
28 |
|
29 |
FD_ZERO(&ready_set); |
30 |
FD_ZERO(&read_set); |
31 |
FD_ZERO(&write_set); |
32 |
|
33 |
memset(&client_file_descriptor_array, 0, sizeof(int)*MAX_CONNECTIONS); |
34 |
memset(&read_buffer, 0, sizeof(char *)*MAX_CONNECTIONS); |
35 |
memset(&read_buffer_size, 0, sizeof(int)*MAX_CONNECTIONS); |
36 |
memset(&write_buffer, 0, sizeof(char *)*MAX_CONNECTIONS); |
37 |
memset(&write_buffer_size, 0, sizeof(int)*MAX_CONNECTIONS); |
38 |
} |
39 |
|
40 |
/**
|
41 |
* @brief The destructor for ConnectionPool
|
42 |
*/
|
43 |
ConnectionPool::~ConnectionPool() { |
44 |
} |
45 |
|
46 |
/**
|
47 |
* @brief Adds a client to the connection pool
|
48 |
*
|
49 |
* @param client_file_descriptor The file descriptor to add to the connection pool
|
50 |
*
|
51 |
* @return 0 on success, negative error code on failure
|
52 |
*/
|
53 |
int ConnectionPool::add_client(int client_file_descriptor) { |
54 |
if (client_file_descriptor < 0) { |
55 |
return ERROR_INVALID_CLIENT_DESCRIPTOR;
|
56 |
} |
57 |
|
58 |
if (next_available_slot == MAX_CONNECTIONS) {
|
59 |
return ERROR_TOO_MANY_CLIENTS;
|
60 |
} |
61 |
|
62 |
if (client_file_descriptor > max_file_descriptor) {
|
63 |
max_file_descriptor = client_file_descriptor; |
64 |
} |
65 |
|
66 |
FD_SET(client_file_descriptor, &ready_set); |
67 |
|
68 |
int next_slot = next_available_slot;
|
69 |
|
70 |
client_file_descriptor_array[next_slot] = client_file_descriptor; |
71 |
read_buffer[next_slot] = (char*) malloc(sizeof(char) * READ_BUFFER_SIZE); |
72 |
if (!(read_buffer[next_slot])) {
|
73 |
return ERROR_ALLOCATING_MEMORY;
|
74 |
} |
75 |
read_buffer_size[next_slot] = 0;
|
76 |
write_buffer[next_slot] = (char *)malloc(sizeof(char) * WRITE_BUFFER_SIZE); |
77 |
|
78 |
if (!(write_buffer[next_slot])) {
|
79 |
free(read_buffer[next_slot]); |
80 |
return ERROR_ALLOCATING_MEMORY;
|
81 |
} |
82 |
|
83 |
write_buffer_size[next_slot] = 0;
|
84 |
|
85 |
next_available_slot++; |
86 |
|
87 |
return 0; |
88 |
} |
89 |
|
90 |
/**
|
91 |
* @brief Removes a client from the connection pool
|
92 |
*
|
93 |
* @param The index in the pool of the client to remove
|
94 |
*
|
95 |
* @return 0 on success, negative error code on failure
|
96 |
*/
|
97 |
int ConnectionPool::remove_client(int pool_index) { |
98 |
if (pool_index < 0 || pool_index >= next_available_slot) { |
99 |
return ERROR_INVALID_CLIENT_DESCRIPTOR;
|
100 |
} |
101 |
|
102 |
int client_file_descriptor = client_file_descriptor_array[pool_index];
|
103 |
|
104 |
if (FD_ISSET(client_file_descriptor, &ready_set)) {
|
105 |
FD_CLR(client_file_descriptor, &ready_set); |
106 |
} |
107 |
if (FD_ISSET(client_file_descriptor, &read_set)) {
|
108 |
FD_CLR(client_file_descriptor, &read_set); |
109 |
} |
110 |
if (FD_ISSET(client_file_descriptor, &write_set)) {
|
111 |
FD_CLR(client_file_descriptor, &write_set); |
112 |
} |
113 |
|
114 |
free(read_buffer[pool_index]); |
115 |
free(write_buffer[pool_index]); |
116 |
for (int j = pool_index; j < next_available_slot - 1; j++) { |
117 |
client_file_descriptor_array[pool_index] = client_file_descriptor_array[pool_index+1];
|
118 |
read_buffer[pool_index] = read_buffer[pool_index+1];
|
119 |
read_buffer_size[pool_index] = read_buffer_size[pool_index+1];
|
120 |
write_buffer[pool_index] = write_buffer[pool_index+1];
|
121 |
write_buffer_size[pool_index] = write_buffer_size[pool_index+1];
|
122 |
} |
123 |
next_available_slot--; |
124 |
int temp_max_file_descriptor = 0; |
125 |
|
126 |
for (int j = 0; j < next_available_slot; j++) { |
127 |
if (client_file_descriptor_array[j] > temp_max_file_descriptor)
|
128 |
temp_max_file_descriptor = client_file_descriptor_array[j]; |
129 |
} |
130 |
max_file_descriptor = temp_max_file_descriptor; |
131 |
|
132 |
printf("Removing client.\n");
|
133 |
|
134 |
return 0; |
135 |
} |
136 |
|
137 |
/**
|
138 |
* @brief Checks the status of the clients
|
139 |
*
|
140 |
* Sees is any clients are ready to read from their file descriptor or are
|
141 |
* ready to write to their file descriptor.
|
142 |
*
|
143 |
* @return 0 on success, negative error code on error
|
144 |
*/
|
145 |
//TODO: test that it drops commands properly if it gets sent too much data
|
146 |
// do we want it to drop the data or drop the connection?
|
147 |
int ConnectionPool::check_clients() {
|
148 |
char temporary_buffer[READ_BUFFER_SIZE];
|
149 |
char temporary_command_buffer[READ_BUFFER_SIZE+1]; |
150 |
int i;
|
151 |
int client_file_descriptor;
|
152 |
int num_bytes_read;
|
153 |
int length;
|
154 |
int sent;
|
155 |
int command_length;
|
156 |
|
157 |
for (i = 0; i < next_available_slot; i++) { |
158 |
client_file_descriptor = client_file_descriptor_array[i]; |
159 |
|
160 |
if (FD_ISSET(client_file_descriptor, &read_set)) {
|
161 |
num_bytes_read = read(client_file_descriptor, temporary_buffer, READ_BUFFER_SIZE); |
162 |
|
163 |
if (num_bytes_read == 0 || (num_bytes_read == -1 && errno == ECONNRESET)) { |
164 |
remove_client(i); |
165 |
i--; |
166 |
continue;
|
167 |
} |
168 |
|
169 |
while (num_bytes_read > 0) { |
170 |
length = num_bytes_read; |
171 |
|
172 |
if (length + read_buffer_size[i] > READ_BUFFER_SIZE) {
|
173 |
length = READ_BUFFER_SIZE - read_buffer_size[i]; |
174 |
} |
175 |
|
176 |
memcpy(read_buffer[i]+read_buffer_size[i], temporary_buffer, length); |
177 |
read_buffer_size[i] += length; |
178 |
num_bytes_read -= length; |
179 |
|
180 |
if (num_bytes_read > 0) { |
181 |
memmove(temporary_buffer, temporary_buffer+length, READ_BUFFER_SIZE - length); |
182 |
} |
183 |
|
184 |
printf("Read buffer is %s\n", read_buffer[i]);
|
185 |
|
186 |
char* newline_position;
|
187 |
|
188 |
while ((newline_position = strstr(read_buffer[i], "\n"))) { |
189 |
|
190 |
//if no newline if found in the entire readbuffer (when its full),
|
191 |
//toss out the command
|
192 |
// because either the command being given is too long or someone is trying
|
193 |
// to do something bad to the server
|
194 |
//TODO: this is from before all this code was put in the loop. reconsider
|
195 |
// how to check this error condition and do it elsewhere
|
196 |
if (!newline_position && (read_buffer_size[i] == READ_BUFFER_SIZE)) {
|
197 |
read_buffer_size[i] = 0;
|
198 |
break;
|
199 |
} |
200 |
|
201 |
//if no newline is found then there is not a command in the buffer
|
202 |
if (!newline_position) {
|
203 |
break;
|
204 |
} |
205 |
|
206 |
command_length = (newline_position - read_buffer[i])+1;
|
207 |
|
208 |
//the newline was found in garbage in the currently not used portion
|
209 |
// of the read buffer
|
210 |
if (command_length > read_buffer_size[i]) {
|
211 |
break;
|
212 |
} |
213 |
|
214 |
memcpy(temporary_command_buffer, read_buffer[i], command_length); |
215 |
//do command_length-1 to get rid of the newline terminating the command
|
216 |
temporary_command_buffer[command_length-1] = '\0'; |
217 |
//did this because telnet was putting a \r\n on the end instead of just \n
|
218 |
if (isspace(temporary_command_buffer[command_length-2])) { |
219 |
temporary_command_buffer[command_length-2] = '\0'; |
220 |
} |
221 |
|
222 |
memmove(read_buffer[i], read_buffer[i]+command_length, read_buffer_size[i] - command_length); |
223 |
read_buffer_size[i] -= command_length; |
224 |
|
225 |
if (command_length > MAX_COMMAND_LEN) {
|
226 |
printf("The command was too long. Tossing command out.\n");
|
227 |
break;
|
228 |
} |
229 |
|
230 |
if (parse_command(temporary_command_buffer, i) < 0) { |
231 |
printf("There was an error parsing command\n");
|
232 |
break;
|
233 |
} |
234 |
} |
235 |
} |
236 |
} |
237 |
|
238 |
if (FD_ISSET(client_file_descriptor, &write_set)) {
|
239 |
if (write_buffer_size[i] == 0) { |
240 |
continue;
|
241 |
} |
242 |
|
243 |
sent = write(client_file_descriptor, write_buffer[i], write_buffer_size[i]); |
244 |
memmove(write_buffer[i], write_buffer[i]+sent, WRITE_BUFFER_SIZE - sent); |
245 |
write_buffer_size[i] -= sent; |
246 |
} |
247 |
} |
248 |
|
249 |
return 0; |
250 |
} |
251 |
|
252 |
/**
|
253 |
* @brief Puts text into a write buffer that will be written to a client's file
|
254 |
* descriptor sometime when the client is ready to write.
|
255 |
*
|
256 |
* @param pool_index Index in the pool of the client to write to
|
257 |
* @param message The message to be written
|
258 |
* @param length The length of the message
|
259 |
*
|
260 |
* @return 0 on success, negative error code on failure
|
261 |
*/
|
262 |
int ConnectionPool::write_to_client(int pool_index, char * message, int length) { |
263 |
if (pool_index < 0 || pool_index >= next_available_slot) { |
264 |
return ERROR_INVALID_CLIENT_ID;
|
265 |
} |
266 |
|
267 |
if (!message) {
|
268 |
return ERROR_INVALID_MESSAGE;
|
269 |
} |
270 |
|
271 |
if (length < 0) { |
272 |
return ERROR_INVALID_MESSAGE_LENGTH;
|
273 |
} |
274 |
|
275 |
if (length > (WRITE_BUFFER_SIZE-write_buffer_size[pool_index])) {
|
276 |
//TODO: make this a logging statement instead of a print statement
|
277 |
printf("There is not enough room in the write buffer to send the data to the client.\n");
|
278 |
return ERROR_NOT_ENOUGH_ROOM;
|
279 |
} |
280 |
|
281 |
memcpy(write_buffer[pool_index], message, length); |
282 |
write_buffer_size[pool_index] += length; |
283 |
|
284 |
return 0; |
285 |
} |
286 |
|
287 |
/**
|
288 |
* @brief Sets the socket to listen on
|
289 |
*
|
290 |
* @param listen_socket The socket to listen on
|
291 |
*
|
292 |
* @return void
|
293 |
*/
|
294 |
void ConnectionPool::set_listen_socket_in_ready_set(int listen_socket) { |
295 |
if (listen_socket < 0) |
296 |
return;
|
297 |
|
298 |
FD_SET(listen_socket, &ready_set); |
299 |
} |
300 |
|
301 |
/**
|
302 |
* @brief Find out what file descriptors are ready to write to and read from
|
303 |
*
|
304 |
* @param listen_socket The socket to listen on
|
305 |
* @param select_timeout The timeout for the select statement
|
306 |
*
|
307 |
* @return 0
|
308 |
*/
|
309 |
int ConnectionPool::perform_select(int listen_socket) { |
310 |
read_set = ready_set; |
311 |
write_set = ready_set; |
312 |
|
313 |
struct timeval select_timeout;
|
314 |
memset(&select_timeout, 0, sizeof(select_timeout)); |
315 |
|
316 |
//TODO(Jason): think about why I put this there
|
317 |
if (max_file_descriptor < listen_socket)
|
318 |
max_file_descriptor = listen_socket; |
319 |
|
320 |
number_clients_ready = select(max_file_descriptor+1, &(read_set), &(write_set), NULL, &select_timeout); |
321 |
|
322 |
if (number_clients_ready < 0) { |
323 |
perror(__FUNCTION__); |
324 |
} |
325 |
|
326 |
return 0; |
327 |
} |
328 |
|
329 |
int ConnectionPool::is_socket_ready_to_read(int socket) { |
330 |
return FD_ISSET(socket, &read_set);
|
331 |
} |
332 |
|
333 |
int ConnectionPool::is_socket_ready_to_write(int socket) { |
334 |
return FD_ISSET(socket, &write_set);
|
335 |
} |
336 |
|
337 |
int ConnectionPool::get_max_file_descriptor() {
|
338 |
return max_file_descriptor;
|
339 |
} |
340 |
|
341 |
void ConnectionPool::set_max_file_descriptor(int new_max_file_descriptor) { |
342 |
max_file_descriptor = new_max_file_descriptor; |
343 |
} |
344 |
|
345 |
int ConnectionPool::get_next_available_slot() {
|
346 |
return next_available_slot;
|
347 |
} |
348 |
|
349 |
int ConnectionPool::get_number_clients_ready() {
|
350 |
return number_clients_ready;
|
351 |
} |
352 |
|
353 |
void ConnectionPool::set_number_clients_ready(int new_number_clients_ready) { |
354 |
number_clients_ready = new_number_clients_ready; |
355 |
} |
356 |
|
357 |
fd_set ConnectionPool::get_ready_set() { |
358 |
return ready_set;
|
359 |
} |
360 |
|
361 |
fd_set ConnectionPool::get_read_set() { |
362 |
return read_set;
|
363 |
} |
364 |
|
365 |
void ConnectionPool::set_read_set(fd_set new_set) {
|
366 |
read_set = new_set; |
367 |
} |
368 |
|
369 |
fd_set ConnectionPool::get_write_set() { |
370 |
return write_set;
|
371 |
} |
372 |
|
373 |
void ConnectionPool::set_write_set(fd_set new_set) {
|
374 |
write_set = new_set; |
375 |
} |
376 |
|
377 |
//TODO: write a function to write data into the write buffers (jason: what was this referring to?)
|
378 |
int ConnectionPool::parse_command(char* command, int pool_index) { |
379 |
char tokens[MAX_TOKENS][MAX_TOKEN_SIZE];
|
380 |
unsigned char int_tokens[MAX_TOKENS]; |
381 |
int number_tokens = 0; |
382 |
char* end_pointer = NULL; |
383 |
int command_id;
|
384 |
int i;
|
385 |
unsigned char arguments[PACKET_DATA_LEN]; |
386 |
|
387 |
memset(arguments, 1, PACKET_DATA_LEN);
|
388 |
|
389 |
if (!command) {
|
390 |
return -1; |
391 |
} |
392 |
|
393 |
if (pool_index < 0) { |
394 |
return -1; |
395 |
} |
396 |
|
397 |
if (pool_index >= next_available_slot) {
|
398 |
return -1; |
399 |
} |
400 |
|
401 |
if ((number_tokens = tokenize_command(command, tokens)) < 0) { |
402 |
return -1; |
403 |
} |
404 |
|
405 |
//the 10 in the function call indicates number is base 10
|
406 |
command_id = strtol(tokens[0], &end_pointer, 10); |
407 |
|
408 |
if (!end_pointer || *end_pointer != '\0') { |
409 |
printf("There was an error converting first token into a number.\n");
|
410 |
return -1; |
411 |
} |
412 |
|
413 |
if (command_id == SEND_TO_ROBOT) {
|
414 |
int number_int_tokens = number_tokens;
|
415 |
|
416 |
// Convert tokens to ints
|
417 |
for (i = ROBOT_COMMAND_OFFSET; i < number_int_tokens; i++) {
|
418 |
int_tokens[i-ROBOT_COMMAND_OFFSET] = atoi(tokens[i]); |
419 |
} |
420 |
/* we removed the request from robot constant
|
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 |
|
436 |
// Fill arguments buffer with arguments
|
437 |
for (i = ROBOT_COMMAND_LEN; i < number_int_tokens-ROBOT_COMMAND_OFFSET;
|
438 |
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 colonet_wl_send(%d, %d, %d, arguments)\n",
|
450 |
int_tokens[0], int_tokens[1], int_tokens[2]); |
451 |
colonet_wl_send(pool_index, int_tokens[0],
|
452 |
(ColonetMessageType)int_tokens[1], int_tokens[2], |
453 |
arguments); |
454 |
} else if (command_id == REQUEST_FROM_SERVER) { |
455 |
if (number_tokens < 2) |
456 |
return -1; |
457 |
|
458 |
end_pointer=NULL;
|
459 |
int second_token = strtol(tokens[1], &end_pointer, 10); |
460 |
|
461 |
if (!end_pointer || *end_pointer != '\0') { |
462 |
printf("There was an error converting second token into a number.\n");
|
463 |
return -1; |
464 |
} |
465 |
|
466 |
if (second_token == REQUEST_BOM_MATRIX) {
|
467 |
//TODO: rename to indicate its actually the response message
|
468 |
char bom_matrix_buffer[MAX_RESPONSE_LEN];
|
469 |
char temp_bom_matrix_buffer[MAX_RESPONSE_LEN];
|
470 |
|
471 |
//TODO: change after we start keeping track of bom matrix
|
472 |
int number_robots = rand()%10; |
473 |
int bom_matrix[number_robots][number_robots];
|
474 |
for (int ii = 0; ii < number_robots; ii++) { |
475 |
for (int j = 0; j < number_robots; j++) { |
476 |
//do this to generate some -1 values which mean they can't see each other
|
477 |
int matrix_value = rand()%(number_robots+1)-1; |
478 |
bom_matrix[ii][j] = matrix_value; |
479 |
} |
480 |
} |
481 |
|
482 |
printf("number of robots is %d\n", number_robots);
|
483 |
|
484 |
//TODO: separate parameters with spaces
|
485 |
//TODO: make this better
|
486 |
//TODO: make sure I don't need to do MAX_RESPONSE_LENGTH-1
|
487 |
snprintf(bom_matrix_buffer,MAX_RESPONSE_LEN, "%d %d %d", RESPONSE_TO_CLIENT_REQUEST, REQUEST_BOM_MATRIX, number_robots);
|
488 |
for (int ii = 0; ii < number_robots; ii++) { |
489 |
for (int j = 0; j < number_robots; j++) { |
490 |
//TODO: don't use strcpy
|
491 |
strcpy(temp_bom_matrix_buffer, bom_matrix_buffer); |
492 |
//TODO: put length checking in here so array doesn't go out of bounds
|
493 |
//TODO: maybe use strncat?
|
494 |
printf("Buffer is %s\n", bom_matrix_buffer);
|
495 |
strcat(temp_bom_matrix_buffer," %d");
|
496 |
snprintf(bom_matrix_buffer, MAX_RESPONSE_LEN, temp_bom_matrix_buffer, bom_matrix[ii][j]); |
497 |
} |
498 |
} |
499 |
strcat(bom_matrix_buffer,"\n");
|
500 |
write_to_client(pool_index, bom_matrix_buffer, strlen(bom_matrix_buffer)); |
501 |
printf("Sending %s", bom_matrix_buffer);
|
502 |
} else {
|
503 |
char * my_current_message = "Hi, how are you?\n"; |
504 |
printf("Sending %s\n", my_current_message);
|
505 |
write_to_client(pool_index, my_current_message, strlen(my_current_message)); |
506 |
} |
507 |
} |
508 |
|
509 |
return 0; |
510 |
} |
511 |
|
512 |
/**
|
513 |
* @brief Breaks a command up into tokens
|
514 |
*
|
515 |
* @param command The command to tokenize
|
516 |
* @param tokens A two dimensional character array to store the tokens in
|
517 |
*
|
518 |
* @return 0 on success, negative error code on failure
|
519 |
*/
|
520 |
int ConnectionPool::tokenize_command(char* command, char tokens[MAX_TOKENS][MAX_TOKEN_SIZE]) { |
521 |
char* next_token = command;
|
522 |
char* end_token = NULL; |
523 |
int number_tokens = 0; |
524 |
|
525 |
if (!command) {
|
526 |
return -1; |
527 |
} |
528 |
|
529 |
while ((end_token = strstr(next_token, " "))) { |
530 |
*end_token = '\0';
|
531 |
|
532 |
if (strlen(next_token) > MAX_TOKEN_SIZE-1) { |
533 |
return -1; |
534 |
} |
535 |
|
536 |
strcpy(tokens[number_tokens], next_token); |
537 |
|
538 |
number_tokens++; |
539 |
next_token = end_token + 1;
|
540 |
|
541 |
while (isspace(*next_token) && *next_token != '\0') { |
542 |
next_token++; |
543 |
} |
544 |
} |
545 |
|
546 |
if (end_token == NULL && *next_token != '\0') { |
547 |
if (strlen(next_token) > MAX_TOKEN_SIZE-1) { |
548 |
return -1; |
549 |
} |
550 |
|
551 |
strcpy(tokens[number_tokens], next_token); |
552 |
|
553 |
number_tokens++; |
554 |
} |
555 |
|
556 |
return number_tokens;
|
557 |
} |
558 |
|
559 |
/**
|
560 |
* @brief checks a list of tokens to see if it's valid
|
561 |
*
|
562 |
* @param tokens The tokens to check
|
563 |
* @param number_tokens The number of tokens contained in the tokens parameter
|
564 |
*
|
565 |
* @return 0 if tokens is valid
|
566 |
*/
|
567 |
int ConnectionPool::check_tokens(unsigned char* tokens, int number_tokens) { |
568 |
if (number_tokens > 3 + PACKET_DATA_LEN) { |
569 |
/* Too many tokens */
|
570 |
return -1; |
571 |
} |
572 |
|
573 |
if (number_tokens < 3) { |
574 |
/* Not enough tokens */
|
575 |
return -1; |
576 |
} |
577 |
|
578 |
if (tokens[1] != COLONET_REQUEST && tokens[1] != COLONET_COMMAND) { |
579 |
/* Invalid message type */
|
580 |
return -1; |
581 |
} |
582 |
|
583 |
return 0; |
584 |
} |