libutil++  1.9.3
 All Classes Functions Variables
server.cpp
1 /*
2 ** libutil++
3 ** $Id: server.cpp 1653 2016-02-28 19:54:59Z sella $
4 ** Copyright (c) 2011-2016 Digital Genesis, LLC. All Rights Reserved.
5 ** Released under the LGPL Version 2.1 License.
6 ** http://www.digitalgenesis.com
7 */
8 
9 static const char rcsid[] __attribute__((used)) = "$Id: server.cpp 1653 2016-02-28 19:54:59Z sella $";
10 
11 #include "test.h"
12 
13 #include <stdio.h>
14 #include <signal.h>
15 #include <stdlib.h>
16 #include <unistd.h>
17 #include <pthread.h>
18 
19 #include <mutex>
20 #include <condition_variable>
21 
22 #include "alias.h"
23 #include "version.h"
24 #include "sella/util/Log.h"
25 #include "sella/util/String.h"
26 #include "sella/util/CommandLine.h"
27 #include "sella/net/IPAddressPort.h"
28 #include "sella/net/SocketMux.h"
29 #include "sella/net/SecureTCPSocket.h"
30 
31 namespace sella {
32  namespace server {
33  bool running = true;
34  int debug = 0;
35  }
36 }
37 
38 using namespace sella::server;
39 using namespace sella::util;
40 using namespace sella::net;
41 
42 bool init_config(int argc, char **argv);
43 bool init_signals(void);
44 void sighandler(int sig);
45 
46 int main(int argc, char **argv) {
47  SET_FORMAT(SimpleLogFormat());
48  SET_IDENTIFIER("server");
49  SET_OPTION(Log::WithStderrOption);
50 
51  init_config(argc, argv);
52  init_signals();
53 
54  INFO("Using %s v%s", libutilxx__package(), libutilxx__version());
55 
56  try {
57  INFO("Setting up server...");
58 
59  SecureTCPSocket::shared server = SecureTCPSocket::shared_ptr(AF_INET);
60 
61  server->setCertificateFile("../contrib/cert.pem");
62  server->setPrivateKeyFile("../contrib/key.pem");
63  //server->setPasswordFile("../contrib/key.secret");
64  server->setProtocol(SecureTCPSocket::SSLv3, false);
65  server->setCiphers(SecureTCPSocket::PerformanceCiphers); /* Higher performance, but less secure. */
66  server->setPreferServerCiphers(); /* Will prefer client ciphers and ordering without this. */
67 
68  server->setSoReuseAddr();
69  server->setBlock(false);
70  server->bind("127.0.0.1", 9876);
71  server->setSoReuseAddr();
72  server->listen();
73 
74  SocketMux mux;
75 
76  mux.insertRead(server);
77 
78  INFO("Using %s", server->getSSLLibraryVersion());
79  INFO("Waiting for a connection on %s", server->getLocalIPAddressPort().c_str());
80 
81  int c, n;
82  while (running) {
83  if ((c = mux.rselect()) > 0) {
84  auto &pending = mux.getReadList();
85 
86  for (auto p = pending.begin(); p != pending.end(); ++p) {
87  if (*p == server) {
88  SecureTCPSocket::shared client = std::static_pointer_cast<SecureTCPSocket>(server->accept());
89 
90  INFO("Established connection %s using protocol %s with cipher %s", client->getRemoteIPAddressPort().c_str(), client->getActiveProtocol(), client->getActiveCipher());
91 
92  mux.insertRead(client);
93  } else { /* Handle client */
94  if ((*p)->isUsable()) {
95  std::string buf;
96  if ((n = (*p)->recv(buf)) > 0) { /* May trigger disconnect */
97  INFO("Recv: %s", buf.c_str());
98 
99  if (rand() % 5 == 0) {
100  int r = rand() % 5;
101 
102  if (r == 0) {
103  (*p)->send("Hail to the king, baby.");
104  } else if (r == 1) {
105  (*p)->send("I got it, I got it! I know your damn words, alright?.");
106  } else if (r == 2) {
107  (*p)->send("Good. Bad. I'm the guy with the gun.");
108  } else if (r == 3) {
109  (*p)->send("Alright you primitive screwheads, listen up!");
110  } else {
111  (*p)->send("It's a trick, get an axe.");
112  }
113  }
114  }
115  }
116 
117  if (!(*p)->isUsable()) {
118  INFO("Client disconnected");
119 
120  mux.removeRead(*p);
121  }
122  }
123  }
124  }
125  }
126  } catch (SocketException &e) {
127  INFO("Exception: %s", e.what());
128 
129  return EXIT_FAILURE;
130  }
131 
132  INFO("Clean shutdwn");
133 
134  return EXIT_SUCCESS;
135 }
136 
137 bool init_config(int argc, char **argv) {
138  std::string m;
139  sella::util::CommandLine cmdln(argc, argv);
140 
141  cmdln.add('d', "debug", "set debug level to INT", "INT", debug, 0, 9);
142  cmdln.add();
143  cmdln.add('h', "help", "display this help screen");
144  cmdln.add('v', "version", "display version information");
145 
146  std::map<std::string, std::string> conf = cmdln.parse(stdin);
147 
148  if (conf.find("help") != conf.end()) {
149  printf("%s v%s\n", libutilxx__package(), libutilxx__version());
150  cmdln.usage(stdout, EXIT_SUCCESS);
151  } else if (conf.find("version") != conf.end()) {
152  printf("%s v%s\n", libutilxx__package(), libutilxx__version());
153 
154  exit(EXIT_SUCCESS);
155  }
156 
157  if (conf.find("debug") != conf.end()) {
158  debug = atoi(conf["debug"].c_str());
159 
160  switch (debug) {
161  case 9:
162  SET_TRACE("all");
163  SET_LOGMASK(LOG_UPTO(LOG_DEBUG));
164 
165  case 3:
166  SET_TRACE(PACKAGE "-detail");
167 
168  case 2:
169  SET_TRACE(PACKAGE);
170 
171  case 1:
172  SET_TRACE("print");
173  }
174  }
175 
176  return true;
177 }
178 
179 bool init_signals(void) {
180  struct sigaction act, old;
181 
182  act.sa_handler = sighandler;
183  sigemptyset(&act.sa_mask);
184  act.sa_flags = SA_RESTART;
185 
186  if (sigaction(SIGINT, NULL, &old) < 0) {
187  fprintf(stderr, "Failed to retrieve signal handler for SIGINT.\n");
188  } else if (old.sa_handler == SIG_DFL) {
189  if (sigaction(SIGINT, &act, NULL) < 0) {
190  fprintf(stderr, "Failed to install signal handler for SIGINT.\n");
191  }
192  }
193 
194  if (sigaction(SIGTERM, NULL, &old) < 0) {
195  fprintf(stderr, "Failed to retrieve signal handler for SIGTERM.\n");
196  } else if (old.sa_handler == SIG_DFL) {
197  if (sigaction(SIGTERM, &act, NULL) < 0) {
198  fprintf(stderr, "Failed to install signal handler for SIGTERM.\n");
199  }
200  }
201 
202  if (sigaction(SIGHUP, NULL, &old) < 0) {
203  fprintf(stderr, "Failed to retrieve signal handler for SIGHUP.\n");
204  } else if (old.sa_handler == SIG_DFL) {
205  if (sigaction(SIGHUP, &act, NULL) < 0) {
206  fprintf(stderr, "Failed to install signal handler for SIGHUP.\n");
207  }
208  }
209 
210  if (sigaction(SIGUSR1, NULL, &old) < 0) {
211  fprintf(stderr, "Failed to retrieve signal handler for SIGUSR1.\n");
212  } else if (old.sa_handler == SIG_DFL) {
213  if (sigaction(SIGUSR1, &act, NULL) < 0) {
214  fprintf(stderr, "Failed to install signal handler for SIGUSR1.\n");
215  }
216  }
217 
218  if (sigaction(SIGUSR2, NULL, &old) < 0) {
219  fprintf(stderr, "Failed to retrieve signal handler for SIGUSR2.\n");
220  } else if (old.sa_handler == SIG_DFL) {
221  if (sigaction(SIGUSR2, &act, NULL) < 0) {
222  fprintf(stderr, "Failed to install signal handler for SIGUSR2.\n");
223  }
224  }
225 
226  if (sigaction(SIGPIPE, NULL, &old) < 0) { /* Prevents send() and write() on broken socket from terminating. */
227  fprintf(stderr, "Failed to retrieve signal handler for SIGPIPE.\n");
228  } else if (old.sa_handler == SIG_DFL) {
229  if (sigaction(SIGPIPE, &act, NULL) < 0) {
230  fprintf(stderr, "Failed to install signal handler for SIGPIPE.\n");
231  }
232  }
233 
234  return true;
235 }
236 
237 void sighandler(int sig) { /* Do not call syslog within handler. Will cause hangs/crash. */
238  switch (sig) {
239  case SIGINT:
240  case SIGTERM:
241  running = false;
242 
243  break;
244 
245  case SIGHUP:
246  running = false;
247 
248  break;
249 
250  case SIGUSR1:
251  break;
252 
253  case SIGUSR2:
254  break;
255 
256  case SIGPIPE:
257  break;
258 
259  default:
260  break;
261  }
262 }
263 
264 /*
265 ** vim: noet ts=3 sw=3
266 */