Project

General

Profile

Revision 62

Added by Brad Neuman over 16 years ago

Ported (AKA moved) tiny861 code from the old repository
Ceated new folder in the auto recharge project

View differences:

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>
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff