--- /dev/null
+/* LibMemcached
+ * Copyright (C) 2006-2009 Brian Aker
+ * All rights reserved.
+ *
+ * Use and distribution licensed under the BSD license. See
+ * the COPYING file in the parent directory for full text.
+ *
+ * Summary:
+ *
+ */
+
+/*
+ Startup, and shutdown the memcached servers.
+*/
+
+#define TEST_PORT_BASE MEMCACHED_DEFAULT_PORT+10
+
+#define PID_FILE_BASE "/tmp/%ulibmemcached_memc.pid"
+
+#include "config.h"
+
+#include <assert.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <libmemcached/memcached.h>
+#include <libmemcached/util.h>
+
+#include <libtest/server.h>
+
+static struct timespec global_sleep_value= { .tv_sec= 0, .tv_nsec= 50000 };
+
+static void global_sleep(void)
+{
+#ifdef WIN32
+ sleep(1);
+#else
+ nanosleep(&global_sleep_value, NULL);
+#endif
+}
+
+static void kill_file(const char *file_buffer)
+{
+ FILE *fp= fopen(file_buffer, "r");
+
+ while ((fp= fopen(file_buffer, "r")))
+ {
+ char pid_buffer[1024];
+
+ if (fgets(pid_buffer, sizeof(pid_buffer), fp) != NULL)
+ {
+ pid_t pid= (pid_t)atoi(pid_buffer);
+ if (pid != 0)
+ {
+ if (kill(pid, SIGTERM) == -1)
+ {
+ remove(file_buffer); // If this happens we may be dealing with a dead server that left its pid file.
+ }
+ else
+ {
+ uint32_t counter= 3;
+ while ((kill(pid, 0) == 0) && --counter)
+ {
+ global_sleep();
+ }
+ }
+ }
+ }
+
+ global_sleep();
+
+ fclose(fp);
+ }
+}
+
+void server_startup(server_startup_st *construct)
+{
+ if ((construct->server_list= getenv("MEMCACHED_SERVERS")))
+ {
+ printf("servers %s\n", construct->server_list);
+ construct->servers= memcached_servers_parse(construct->server_list);
+ construct->server_list= NULL;
+ construct->count= 0;
+ }
+ else
+ {
+ {
+ char server_string_buffer[8096];
+ char *end_ptr;
+ end_ptr= server_string_buffer;
+
+ for (uint32_t x= 0; x < construct->count; x++)
+ {
+ int status;
+ in_port_t port;
+
+ {
+ char *var;
+ char variable_buffer[1024];
+
+ snprintf(variable_buffer, sizeof(variable_buffer), "LIBMEMCACHED_PORT_%u", x);
+
+ if ((var= getenv(variable_buffer)))
+ {
+ port= (in_port_t)atoi(var);
+ }
+ else
+ {
+ port= (in_port_t)(x + TEST_PORT_BASE);
+ }
+ }
+
+ char buffer[PATH_MAX];
+ snprintf(buffer, sizeof(buffer), PID_FILE_BASE, x);
+ kill_file(buffer);
+
+ if (x == 0)
+ {
+ snprintf(buffer, sizeof(buffer), "%s -d -u root -P "PID_FILE_BASE" -t 1 -p %u -U %u -m 128",
+ MEMCACHED_BINARY, x, port, port);
+ }
+ else
+ {
+ snprintf(buffer, sizeof(buffer), "%s -d -u root -P "PID_FILE_BASE" -t 1 -p %u -U %u",
+ MEMCACHED_BINARY, x, port, port);
+ }
+ if (libmemcached_util_ping("localhost", port, NULL))
+ {
+ fprintf(stderr, "Server on port %u already exists\n", port);
+ }
+ else
+ {
+ status= system(buffer);
+ fprintf(stderr, "STARTING SERVER: %s status:%d\n", buffer, status);
+ }
+ int count;
+ size_t remaining_length= sizeof(server_string_buffer) - (size_t)(end_ptr -server_string_buffer);
+ count= snprintf(end_ptr, remaining_length, "localhost:%u,", port);
+
+ if ((size_t)count >= remaining_length || count < 0)
+ {
+ fprintf(stderr, "server names grew to be larger then buffer allowed\n");
+ abort();
+ }
+ end_ptr+= count;
+ }
+ *end_ptr= 0;
+
+
+ int *pids= calloc(construct->count, sizeof(int));
+ for (uint32_t x= 0; x < construct->count; x++)
+ {
+ char buffer[PATH_MAX]; /* Nothing special for number */
+
+ snprintf(buffer, sizeof(buffer), PID_FILE_BASE, x);
+
+ uint32_t counter= 3000; // Absurd, just to catch run away process
+ while (pids[x] <= 0 && --counter)
+ {
+ FILE *file= fopen(buffer, "r");
+ if (file)
+ {
+ char pid_buffer[1024];
+ char *found= fgets(pid_buffer, sizeof(pid_buffer), file);
+
+ if (found)
+ {
+ pids[x]= atoi(pid_buffer);
+ fclose(file);
+
+ if (pids[x] > 0)
+ break;
+ }
+ fclose(file);
+ }
+ global_sleep();
+ }
+
+ bool was_started= false;
+ if (pids[x] > 0)
+ {
+ counter= 30;
+ while (--counter)
+ {
+ if (kill(pids[x], 0) == 0)
+ {
+ was_started= true;
+ break;
+ }
+ global_sleep();
+ }
+ }
+
+ if (was_started == false)
+ {
+ fprintf(stderr, "Failed to open buffer %s(%d)\n", buffer, pids[x]);
+ for (uint32_t y= 0; y < construct->count; y++)
+ {
+ if (pids[y] > 0)
+ kill(pids[y], SIGTERM);
+ }
+ abort();
+ }
+ }
+ free(pids);
+
+ construct->server_list= strdup(server_string_buffer);
+ }
+ printf("servers %s\n", construct->server_list);
+ construct->servers= memcached_servers_parse(construct->server_list);
+ }
+
+ assert(construct->servers);
+
+ srandom((unsigned int)time(NULL));
+
+ for (uint32_t x= 0; x < memcached_server_list_count(construct->servers); x++)
+ {
+ printf("\t%s : %d\n", memcached_server_name(&construct->servers[x]), memcached_server_port(&construct->servers[x]));
+ assert(construct->servers[x].fd == -1);
+ assert(construct->servers[x].cursor_active == 0);
+ }
+
+ printf("\n");
+}
+
+void server_shutdown(server_startup_st *construct)
+{
+ if (construct->server_list)
+ {
+ for (uint32_t x= 0; x < construct->count; x++)
+ {
+ char file_buffer[PATH_MAX]; /* Nothing special for number */
+ snprintf(file_buffer, sizeof(file_buffer), PID_FILE_BASE, x);
+ kill_file(file_buffer);
+ }
+
+ free(construct->server_list);
+ }
+}