* 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.
*
*
* the library)
*/
-#include "config.h"
+#include <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>
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)
{
}
};
}
}
-/**
- * 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;
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};
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;
}
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;
}
{
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;
}
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;
freeaddrinfo(ai);
- return (num_server_sockets > 0) ? 0 : 1;
+ return (num_server_sockets > 0) ? true : false;
}
/**
{
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)
{
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:
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:
{
}
}
- 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;
}
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]];
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;