Project

General

Profile

Revision 62

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