Project

General

Profile

Statistics
| Revision:

root / trunk / code / projects / colonet / ColonetServer / ColonetServer.cpp @ 24

History | View | Annotate | Download (7.82 KB)

1 11 emarinel
/** @file ColonetServer.cpp
2
 *
3
 * @brief colonet_server - primary server application for Colonet
4
 *
5
 * @author Jason Knichel
6
 * @author Eugene Marinelli
7
 * @date 10/31/06
8
 */
9
10
#include <colonet_wireless.h>
11
#include <sys/select.h>
12
#include <sys/socket.h>
13
#include <netinet/in.h>
14
#include <errno.h>
15
#include <arpa/inet.h>
16
17 23 jknichel
#include <fcntl.h>
18
19 20 jknichel
#include <colonet_wireless.h>
20
21
#include "includes/ColonetServer.h"
22 11 emarinel
#include "includes/ConnectionPool.h"
23
#include "includes/client.h"
24
#include "includes/options.h"
25
#include "includes/Logging.h"
26
27
#define LISTEN_BACKLOG 5
28
#define LOG_BUFFER_LENGTH 128
29
30 20 jknichel
ConnectionPool * connection_pool;
31 22 jknichel
ColonetWireless* wireless;
32 20 jknichel
33
ColonetServer::ColonetServer(): logger("logFile.txt") {
34 24 jknichel
  listen_socket = 0;
35 20 jknichel
}
36
37
ColonetServer::~ColonetServer() {
38
}
39
40
int ColonetServer::initialize_server(int argc, char * argv[]) {
41
  printf("Initializing Server...\n");
42
43
  parseCmdLine(argc, argv);
44
45
  if (initConnection(optionsG.listen_port) < 0)
46
    return -1;
47
48 22 jknichel
  if (initialize_wireless() < 0) {
49 20 jknichel
    fprintf(stderr, "%s: initWireless failed\n", __FUNCTION__);
50
    return -1;
51
  }
52
53
  return 0;
54
}
55
56 22 jknichel
57 20 jknichel
int ColonetServer::log_error(char * error_message) {
58
  return logger.logMessage(LOG_TYPE_ERROR, error_message);
59
}
60
61
int ColonetServer::log_message(char * message) {
62
  return logger.logMessage(LOG_TYPE_MESSAGE, message);
63
}
64
65 24 jknichel
int ColonetServer::run_server() {
66 20 jknichel
  connection_pool.set_listen_socket_in_ready_set(listen_socket);
67
68
  //TODO: why is all of this in that if statement and not just conn_pool.maxfd = listen_socket ?
69
  if (listen_socket > connection_pool.get_max_file_descriptor()) {
70
    connection_pool.set_max_file_descriptor(listen_socket);
71
72 11 emarinel
    int acceptSocket = 0;
73
    struct sockaddr_in clientAddr;
74
    socklen_t clen = sizeof(clientAddr);
75
    struct timeval selectTimeout;
76
77
    memset(&selectTimeout,0,sizeof(selectTimeout));
78
79 20 jknichel
    logger.logMessage(LOG_TYPE_MESSAGE, "Server initialized.  About to start listening for connections");
80 11 emarinel
81
    while(1) {
82 20 jknichel
      connection_pool.perform_select(listen_socket, &selectTimeout);
83 11 emarinel
84
      //either no descriptors are ready or there was an error
85
      //TODO: check for specific errors
86
      if (connection_pool.get_number_clients_ready() <= 0) {
87
        continue;
88
      }
89
90 20 jknichel
      if (connection_pool.is_socket_ready_to_read(listen_socket)) {
91 11 emarinel
        printf("Something is trying to connect...\n");
92 20 jknichel
        if ((acceptSocket = accept(listen_socket, (struct sockaddr*) &clientAddr, &clen)) < 0) {
93 11 emarinel
          if (errno == EMFILE) {
94
            printf("\tWhen attempting to accept a connection, "
95
                   "reached the per process limit of file descriptors."
96
                   "  Dropping the new connection.\n");
97
            continue;
98
          } else {
99
            printf("\tThere was an error when attempting to accept a "
100
                   "connection");
101
          }
102
          continue;
103
        }
104
105
        char logBuffer[LOG_BUFFER_LENGTH];
106
        snprintf(logBuffer, LOG_BUFFER_LENGTH, "Client at address %s attempting to connect.", inet_ntoa(clientAddr.sin_addr));
107 20 jknichel
        logger.logMessage(LOG_TYPE_CONNECT, logBuffer);
108 11 emarinel
109
        //TODO: remove this
110
        //printf("Attempting to add a client.\n");
111
112
113
        if (connection_pool.add_client(acceptSocket) < 0) {
114
          printf("\tThere was an error when trying to add a client to the "
115
                 "connection pool.");
116
          continue;
117
        }
118
119
        snprintf(logBuffer, LOG_BUFFER_LENGTH, "Client at address %s successfully added to connection pool.", inet_ntoa(clientAddr.sin_addr));
120 20 jknichel
        logger.logMessage(LOG_TYPE_CONNECT, logBuffer);
121 11 emarinel
122
      }
123
124 22 jknichel
      if (connection_pool.check_clients(wireless) < 0) {
125 11 emarinel
        printf("\tThere was an error trying to update the clients.");
126
        continue;
127
      }
128
    }
129
  }
130
131 20 jknichel
  return 0;
132 11 emarinel
}
133 20 jknichel
134
ConnectionPool * ColonetServer::get_connection_pool_pointer() {
135
  return &connection_pool;
136
}
137 22 jknichel
138 24 jknichel
int ColonetServer::get_listen_socket() {
139
  return listen_socket;
140
}
141
142 23 jknichel
int ColonetServer::initialize_wireless()
143
{
144
  char* log_filename = NULL;
145 22 jknichel
146 23 jknichel
  if (optionsG.logging_enabled) {
147
    log_filename = optionsG.log_filename;
148
  }
149
150
  wireless = new ColonetWireless(optionsG.wireless_port,
151
                                 wirelessMessageHandler, log_filename,
152
                                 /*!optionsG.listener_mode*/false, true);
153
  //Note: last arg set to true ignores token ring;  in general, this should
154
  //probably be false (changed for demo purposes)
155
156
  if (!wireless->run_listener_thread()) {
157
                return -1;
158
        }
159
160
        return 0;
161
}
162
163
int ColonetServer::initConnection(int port)
164
{
165
  printf("Initializing connection that will be used to listen for "
166
         "clients...\n");
167
  int opts = 1;
168
  struct sockaddr_in my_addr;
169
170
  //get a socket fd
171 24 jknichel
  if ((listen_socket = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
172 23 jknichel
    printf("\tThere was an error creating a socket\n");
173
    return -1;
174
  }
175
176
  //set up the address struct
177
  memset(&my_addr,'\0',sizeof(my_addr));
178
  my_addr.sin_family = AF_INET;
179
  my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
180
  my_addr.sin_port = htons(port);
181
182 24 jknichel
  setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR, &opts, sizeof(opts));
183 23 jknichel
184
  //get the current socket options
185 24 jknichel
  if ((opts = fcntl(listen_socket, F_GETFL)) < 0) {
186 23 jknichel
    printf("\tThere was an error getting the socket options.\n");
187
    return -1;
188
  }
189
190
  //set the socket to non blocking
191
  opts = (opts | O_NONBLOCK);
192 24 jknichel
  if (fcntl(listen_socket, F_SETFL, opts) < 0) {
193 23 jknichel
    printf("\tThere was an error setting the socket to be non blocking.\n");
194
    return -1;
195
  }
196
197
  //bind the socket to listen on the specified port
198 24 jknichel
  if (bind(listen_socket, (struct sockaddr *) &my_addr, sizeof(my_addr)) < 0) {
199 23 jknichel
    printf("\tThere was an error binding the socket\n");
200
    return -1;
201
  }
202
203
  return 0;
204
}
205
206 24 jknichel
int main(int argc, char** argv) {
207
  ColonetServer colonet_server;
208
209
  connection_pool = colonet_server.get_connection_pool_pointer();
210
211
  if (colonet_server.initialize_server(argc, argv) < 0) {
212
    colonet_server.log_error("\t\nThere was an error initializing the server. "
213
                             "Terminating server...\n");
214
    return -1;
215
  }
216
217
  if (listen(colonet_server.get_listen_socket(), LISTEN_BACKLOG) < 0) {
218
    colonet_server.log_error("\t\nThere was an error telling the socket to "
219
                             "listen for connections from clients.  Terminating Server...\n");
220
    return -1;
221
  }
222
223
  colonet_server.run_server();
224
225
  return 0;
226
}
227
228 23 jknichel
//this is old code that was commented out that I didn't want to delete yet
229
/*
230
int parseCommandLine(int argc, char * argv[], commandParams_t * params)
231
{
232
  printf("Parsing Command Line...\n");
233
  if (!params)
234
    return -1;
235

236
  //if no command line parameters were specified, set to defaults
237
  if (argc == 1) {
238
    printf("No port was specified for listening for client connections."
239
           "  Defaulting to %d\n", DEFAULTPORT);
240
    params->listenPort = DEFAULTPORT;
241
  }
242

243
  if (!argv)
244
    return -1;
245

246
  int i;
247
  for (i = 1; i < argc; i++) {
248
    char * temp = argv[i];
249
    if (temp[0] != '-')
250
      {
251
        printUsage(argv[0]);
252
        return -1;
253
      }
254

255
    switch(temp[1])
256
      {
257
      case 'h': printUsage(argv[0]);
258
        break;
259
      case 'p':
260
        {
261
          if (i >= argc-1)
262
            {
263
              printUsage(argv[0]);
264
              return -1;
265
            }
266
          i++;
267
          char * portString = argv[i];
268
          char * endptr = NULL;
269
          int port = strtol(portString, &endptr, 10);
270
          if (*endptr != '\0')
271
            {
272
              printf("Invalid port specified...%s, %d\n", endptr, port);
273
              return -1;
274
            }
275
          if (port < SMALLEST_POSS_LISTEN_PORT)
276
            {
277
              printf("You cannot listen on a port less than %d.\n",
278
                     SMALLEST_POSS_LISTEN_PORT);
279
              return -1;
280
            }
281
          params->listenPort = port;
282
          printf("Setting port to listen on to %d.\n", params->listenPort);
283
        }
284
        break;
285
      default: printUsage(argv[0]);
286
        return -1;
287
        break;
288
      }
289
  }
290

291
  return 0;
292
}
293
*/