C++: double underscores are reserved
[m6w6/libmemcached] / example / memcached_light.cc
index 791d259be24379ecda39bb81916197198c7bc3b7..714bb16f3dedafb216c753a81cb870f9b074df6e 100644 (file)
@@ -9,11 +9,11 @@
  * With that in mind, let me give you some pointers into the source:
  *   storage.c/h       - Implements the item store for this server and not really
  *                       interesting for this example.
- *   interface_v0.c    - Shows an implementation of the memcached server by using
+ *   interface_v0.cc   - Shows an implementation of the memcached server by using
  *                       the "raw" access to the packets as they arrive
- *   interface_v1.c    - Shows an implementation of the memcached server by using
+ *   interface_v1.cc   - Shows an implementation of the memcached server by using
  *                       the more "logical" interface.
- *   memcached_light.c - This file sets up all of the sockets and run the main
+ *   memcached_light.cc- This file sets up all of the sockets and run the main
  *                       message loop.
  *
  *
@@ -23,7 +23,7 @@
  * the library)
  */
 
-#include "config.h"
+#include <mem_config.h>
 
 #include <libmemcachedprotocol-0.0/handler.h>
 #include <libmemcached/socket.hpp>
 #include "example/storage.h"
 #include "example/memcached_light.h"
 
+#include "util/daemon.hpp"
+#include "util/log.hpp"
+#include "util/pidfile.hpp"
+
+using namespace datadifferential;
+
 #include <event.h>
 
 #include <cassert>
@@ -42,8 +48,9 @@
 #include <getopt.h>
 #include <iostream>
 #include <sys/types.h>
-#include <unistd.h>
-
+#if HAVE_UNISTD_H
+#  include <unistd.h>
+#endif
 extern memcached_binary_protocol_callback_st interface_v0_impl;
 extern memcached_binary_protocol_callback_st interface_v1_impl;
 
@@ -60,15 +67,19 @@ struct connection
 static int maxconns= 1024;
 
 static struct connection *socket_userdata_map;
-static struct event_base *event_base;
+static struct event_base *event_base= NULL;
 
 struct options_st {
-  char *pid_file;
+  std::string pid_file;
+  std::string service;
+  std::string log_file;
   bool is_verbose;
+  bool opt_daemon;
 
   options_st() :
-    pid_file(NULL),
-    is_verbose(false)
+    service("9999"),
+    is_verbose(false),
+    opt_daemon(false)
   {
   }
 };
@@ -125,7 +136,7 @@ static void drive_client(memcached_socket_t fd, short, void *arg)
       flags|= EV_READ;
     }
 
-    event_set(&client->event, (intptr_t)fd, flags, drive_client, client);
+    event_set(&client->event, int(fd), flags, drive_client, client);
     event_base_set(event_base, &client->event);
 
     if (event_add(&client->event, 0) == -1)
@@ -174,7 +185,7 @@ static void accept_handler(memcached_socket_t fd, short, void *arg)
     struct connection *client = &socket_userdata_map[sock];
     client->userdata= c;
 
-    event_set(&client->event, (intptr_t)sock, EV_READ, drive_client, client);
+    event_set(&client->event, int(sock), EV_READ, drive_client, client);
     event_base_set(event_base, &client->event);
     if (event_add(&client->event, 0) == -1)
     {
@@ -185,11 +196,7 @@ static void accept_handler(memcached_socket_t fd, short, void *arg)
   }
 }
 
-/**
- * Create a socket and bind it to a specific port number
- * @param port the port number to bind to
- */
-static int server_socket(const char *port)
+static bool server_socket(util::log_info_st& log_file, const std::string& service)
 {
   struct addrinfo *ai;
   struct addrinfo hints;
@@ -199,19 +206,23 @@ static int server_socket(const char *port)
   hints.ai_family= AF_UNSPEC;
   hints.ai_socktype= SOCK_STREAM;
 
-  int error= getaddrinfo("127.0.0.1", port, &hints, &ai);
+  int error= getaddrinfo("127.0.0.1", service.c_str(), &hints, &ai);
   if (error != 0)
   {
     if (error != EAI_SYSTEM)
     {
-      std::cerr << "getaddrinfo(): " << gai_strerror(error) << std::endl;
+      std::string buffer("getaddrinfo: ");
+      buffer+= gai_strerror(error);
+      log_file.write(util::VERBOSE_ERROR, buffer.c_str());
     }
     else
     {
-      std::cerr << "getaddrinfo(): " << strerror(errno) << std::endl;
+      std::string buffer("getaddrinfo: ");
+      buffer+= strerror(errno);
+      log_file.write(util::VERBOSE_ERROR, buffer.c_str());
     }
 
-    return 0;
+    return false;
   }
 
   struct linger ling= {0, 0};
@@ -221,7 +232,9 @@ static int server_socket(const char *port)
     memcached_socket_t sock= socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
     if (sock == INVALID_SOCKET)
     {
-      std::cerr << "Failed to create socket: " << strerror(errno) << std::endl;
+      std::string buffer("Failed to create socket: ");
+      buffer+= strerror(errno);
+      log_file.write(util::VERBOSE_ERROR, buffer.c_str());
       continue;
     }
 
@@ -238,7 +251,9 @@ static int server_socket(const char *port)
     flags= fcntl(sock, F_GETFL, 0);
     if (flags == -1)
     {
-      std::cerr << "Failed to get socket flags: " << strerror(errno) << std::endl;
+      std::string buffer("Failed to get socket flags: ");
+      buffer+= strerror(errno);
+      log_file.write(util::VERBOSE_ERROR, buffer.c_str());
       closesocket(sock);
       continue;
     }
@@ -247,7 +262,9 @@ static int server_socket(const char *port)
     {
       if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1)
       {
-        std::cerr << "Failed to set socket to nonblocking mode: " << strerror(errno) << std::endl;
+        std::string buffer("Failed to set socket to nonblocking mode: ");
+        buffer+= strerror(errno);
+        log_file.write(util::VERBOSE_ERROR, buffer.c_str());
         closesocket(sock);
         continue;
       }
@@ -288,14 +305,18 @@ static int server_socket(const char *port)
 
     if (listen(sock, 1024) == SOCKET_ERROR)
     {
-      std::cerr << "listen(): " << strerror(errno) << std::endl;
+      std::string buffer("listen(): ");
+      buffer+= strerror(errno);
+      log_file.write(util::VERBOSE_ERROR, buffer.c_str());
       closesocket(sock);
       continue;
     }
 
     if (global_options.is_verbose)
     {
-      std::cout << "Listening to " << port << std::endl;
+      std::string buffer("Listening to: ");
+      buffer+= global_options.service;
+      log_file.write(util::VERBOSE_NOTICE, buffer.c_str());
     }
 
     server_sockets[num_server_sockets++]= sock;
@@ -303,7 +324,7 @@ static int server_socket(const char *port)
 
   freeaddrinfo(ai);
 
-  return (num_server_sockets > 0) ? 0 : 1;
+  return (num_server_sockets > 0) ? true : false;
 }
 
 /**
@@ -414,45 +435,35 @@ int main(int argc, char **argv)
 {
   memcached_binary_protocol_callback_st *interface= &interface_v0_impl;
 
-  event_base= event_init();
-  if (event_base == NULL)
-  {
-    std::cerr << "Failed to create an instance of libevent" << std::endl;
-    return EXIT_FAILURE;
-  }
-
-  /*
-   * We need to initialize the handlers manually due to a bug in the
-   * warnings generated by struct initialization in gcc (all the way up to 4.4)
-   */
-  initialize_interface_v0_handler();
-  initialize_interface_v1_handler();
-
   {
     enum long_option_t {
       OPT_HELP,
       OPT_VERBOSE,
+      OPT_DAEMON,
       OPT_PROTOCOL_VERSION,
       OPT_VERSION,
       OPT_PORT,
       OPT_MAX_CONNECTIONS,
+      OPT_LOGFILE,
       OPT_PIDFILE
     };
 
     static struct option long_options[]=
     {
-      {"help", no_argument, NULL, OPT_HELP},
-      {"port", required_argument, NULL, OPT_PORT},
-      {"verbose", no_argument, NULL, OPT_VERBOSE},
-      {"protocol", required_argument, NULL, OPT_PROTOCOL_VERSION},
-      {"version", no_argument, NULL, OPT_VERSION},
-      {"max-connections", required_argument, NULL, OPT_MAX_CONNECTIONS},
-      {"pid-file", required_argument, NULL, OPT_PIDFILE},
+      { "help", no_argument, NULL, OPT_HELP },
+      { "port", required_argument, NULL, OPT_PORT },
+      { "verbose", no_argument, NULL, OPT_VERBOSE },
+      { "daemon", no_argument, NULL, OPT_DAEMON },
+      { "protocol", no_argument, NULL, OPT_PROTOCOL_VERSION },
+      { "version", no_argument, NULL, OPT_VERSION },
+      { "max-connections", required_argument, NULL, OPT_MAX_CONNECTIONS },
+      { "pid-file", required_argument, NULL, OPT_PIDFILE },
+      { "log-file", required_argument, NULL, OPT_LOGFILE },
       {0, 0, 0, 0}
     };
 
+    bool opt_help= false;
     int option_index;
-    bool has_port= false;
     bool done= false;
     while (done == false)
     {
@@ -467,16 +478,26 @@ int main(int argc, char **argv)
         break;
 
       case OPT_PIDFILE:
-        global_options.pid_file= strdup(optarg);
+        global_options.pid_file= optarg;
+        break;
+
+      case OPT_LOGFILE:
+        global_options.log_file= optarg;
         break;
 
       case OPT_VERBOSE:
         global_options.is_verbose= true;
         break;
 
+      case OPT_VERSION:
+        break;
+
+      case OPT_DAEMON:
+        global_options.opt_daemon= true;
+        break;
+
       case OPT_PORT:
-        has_port= true;
-        (void)server_socket(optarg);
+        global_options.service= optarg;
         break;
 
       case OPT_MAX_CONNECTIONS:
@@ -484,12 +505,8 @@ int main(int argc, char **argv)
         break;
 
       case OPT_HELP:  /* FALLTHROUGH */
-        std::cout << "Usage: " << argv[0] << std::endl;
-        for (struct option *ptr_option= long_options; ptr_option->name; ptr_option++)
-        {
-          std::cout << "\t" << ptr_option->name << std::endl;
-        }
-        return EXIT_SUCCESS;
+        opt_help= true;
+        break;
 
       default:
         {
@@ -499,42 +516,55 @@ int main(int argc, char **argv)
       }
     }
 
-    if (has_port == false)
+    if (opt_help)
     {
-      (void)server_socket("9999");
+      std::cout << "Usage: " << argv[0] << std::endl;
+      for (struct option *ptr_option= long_options; ptr_option->name; ptr_option++)
+      {
+        std::cout << "\t" << ptr_option->name << std::endl;
+      }
+      return EXIT_SUCCESS;
     }
   }
 
-  if (! initialize_storage())
+  if (global_options.opt_daemon)
+  {
+    util::daemonize(false, true);
+  }
+
+  if (initialize_storage() == false)
   {
     /* Error message already printed */
     return EXIT_FAILURE;
   }
 
-  if (global_options.pid_file)
+  util::Pidfile _pid_file(global_options.pid_file);
+
+  if (_pid_file.create() == false)
   {
-    FILE *pid_file;
-    uint32_t pid;
+    std::cerr << "Failed to create pid-file" <<  _pid_file.error_message() << std::endl;
+    return EXIT_FAILURE;
+  }
 
-    pid_file= fopen(global_options.pid_file, "w+");
+  util::log_info_st log_file(argv[0], global_options.log_file, false);
+  log_file.write(util::VERBOSE_NOTICE, "starting log");
 
-    if (pid_file == NULL)
-    {
-      perror(strerror(get_socket_errno()));
-      abort();
-    }
+  /*
+   * We need to initialize the handlers manually due to a bug in the
+   * warnings generated by struct initialization in gcc (all the way up to 4.4)
+   */
+  initialize_interface_v0_handler(log_file);
+  initialize_interface_v1_handler(log_file);
 
-    pid= (uint32_t)getpid();
-    if (global_options.is_verbose)
-    {
-      std::cout << "pid:" << pid << std::endl;
-    }
-    fclose(pid_file);
+
+  if (server_socket(log_file, global_options.service) == false)
+  {
+    return EXIT_FAILURE;
   }
 
   if (num_server_sockets == 0)
   {
-    std::cerr << "No server sockets are available" << std::endl;
+    log_file.write(util::VERBOSE_ERROR, "No server sockets are available.");
     return EXIT_FAILURE;
   }
 
@@ -550,37 +580,67 @@ int main(int argc, char **argv)
   struct memcached_protocol_st *protocol_handle;
   if ((protocol_handle= memcached_protocol_create_instance()) == NULL)
   {
-    std::cerr << "Failed to allocate protocol handle" << std::endl;
+    log_file.write(util::VERBOSE_ERROR, "No server sockets are available.");
     return EXIT_FAILURE;
   }
 
   socket_userdata_map= (struct connection*)calloc((size_t)(maxconns), sizeof(struct connection));
   if (socket_userdata_map == NULL)
   {
-    std::cerr << "Failed to allocate room for connections" << std::endl;
+    log_file.write(util::VERBOSE_ERROR, "Failed to allocate room for connections");
     return EXIT_FAILURE;
   }
 
   memcached_binary_protocol_set_callbacks(protocol_handle, interface);
   memcached_binary_protocol_set_pedantic(protocol_handle, true);
 
+  event_base= event_init();
+  if (event_base == NULL)
+  {
+    std::cerr << "Failed to create an instance of libevent" << std::endl;
+    return EXIT_FAILURE;
+  }
+
   for (int xx= 0; xx < num_server_sockets; ++xx)
   {
     struct connection *conn= &socket_userdata_map[server_sockets[xx]];
     conn->userdata= protocol_handle;
 
-    event_set(&conn->event, (intptr_t)server_sockets[xx], EV_READ | EV_PERSIST, accept_handler, conn);
+    event_set(&conn->event, int(server_sockets[xx]), EV_READ | EV_PERSIST, accept_handler, conn);
 
     event_base_set(event_base, &conn->event);
     if (event_add(&conn->event, 0) == -1)
     {
-      std::cerr << "Failed to add event for " << server_sockets[xx] << std::endl;
+      log_file.write(util::VERBOSE_ERROR, "Failed to add event");
       closesocket(server_sockets[xx]);
     }
   }
 
+  if (global_options.opt_daemon)
+  {
+    if (util::daemon_is_ready(true) == false)
+    {
+      log_file.write(util::VERBOSE_ERROR, "Failed for util::daemon_is_ready()");
+      return EXIT_FAILURE;
+    }
+  }
+
+
   /* Serve all of the clients */
-  event_base_loop(event_base, 0);
+  switch (event_base_loop(event_base, 0))
+  {
+  case -1:
+    log_file.write(util::VERBOSE_ERROR, "event_base_loop() failed");
+    break;
+
+  case 1:
+    log_file.write(util::VERBOSE_ERROR, "event_base_loop(), no events were registered");
+    break;
+
+  default:
+    break;
+  }
+  log_file.write(util::VERBOSE_NOTICE, "exiting");
 
   /* NOTREACHED */
   return EXIT_SUCCESS;