Beispiel #1
0
int main(int argc, char *argv[])
{
    int c = 0;
    int maxcore = 0;
    bool do_daemonize = false;

    char *pid_file = "/tmp/memlockd.pid";
    char *username = NULL;

    struct passwd *pw = NULL;
    struct rlimit rlim;

    /* register signal callback */
    signals_init();

    /* init settings */
    settings_init();

    /* set stderr non-buffering (for running under, say, daemontools) */
    setbuf(stderr, NULL);

    /* process arguments */
    while ((c = getopt(argc, argv, "a:U:p:s:c:hivl:dru:P:t")) != -1) {
        switch (c) {
            case 'a':
                /* access for unix domain socket, as octal mask (like chmod)*/
                settings.access = strtol(optarg, NULL, 8);
                break;
            case 'p':
                settings.port = atoi(optarg);
                break;
            case 's':
                settings.socketpath = optarg;
                break;
            case 'c':
                settings.maxconns = atoi(optarg);
                break;
            case 'h':
                usage();
                exit(EXIT_SUCCESS);
            case 'i':
                usage_license();
                exit(EXIT_SUCCESS);
            case 'v':
                settings.verbose++;
                break;
            case 'l':
                settings.inter = strdup(optarg);
                break;
            case 'd':
                do_daemonize = true;
                break;
            case 'r':
                maxcore = 1;
                break;
            case 'u':
                username = optarg;
                break;
            case 'P':
                pid_file = optarg;
                break;
#ifdef USE_THREADS
            case 't':
                settings.num_threads = atoi(optarg);
                if (0 == settings.num_threads) {
                    fprintf(stderr, "Number of threads must be greater than 0\n");
                    exit(EXIT_FAILURE);
                }
                break;
#endif
            default:
                fprintf(stderr, "Illegal argument \"%c\"\n", c);
                exit(EXIT_FAILURE);
        }
    }

    /*
     * If needed, increase rlimits to allow as many connections
     * as needed.
     */
    if (getrlimit(RLIMIT_NOFILE, &rlim) != 0) {
        fprintf(stderr, "failed to getrlimit number of files\n");
        exit(EXIT_FAILURE);
    }
    else {
        int maxfiles = settings.maxconns;
        if (rlim.rlim_cur < maxfiles) {
            rlim.rlim_cur = maxfiles + 3;
        }
        if (rlim.rlim_max < rlim.rlim_cur) {
            rlim.rlim_max = rlim.rlim_cur;
        }
        if (setrlimit(RLIMIT_NOFILE, &rlim) != 0) {
            fprintf(stderr, "failed to set rlimit for open files. Try "
                    "running as root or requesting smaller maxconns value.\n");
            exit(EXIT_FAILURE);
        }
    }

    /* do_daemonize if requested */
    /* if we want to ensure our ability to dump core, don't chdir to / */
    if (do_daemonize) {
        int res = 0;
        res = daemon_init();
        if (res != 0) {
            fprintf(stderr, "failed to daemon() in order to do_daemonize\n");
            return -1;
        }
    }

    /* lose root privileges if we have them */
    if (0 == getuid() || 0 == geteuid()) {
        if (NULL == username || '\0' == *username) {
            fprintf(stderr, "can't run as root without the -u switch\n");
            return -1;
        }

        if ((pw = getpwnam(username)) == NULL) {
            fprintf(stderr, "can't find the user %s to switch to\n", username);
            return 1;
        }

        if (setgid(pw->pw_gid) < 0 || setuid(pw->pw_uid) < 0) {
            fprintf(stderr, "failed to assume identity of user %s\n", username);
            return 1;
        }
    }

    /* initialize main thread libevent instance */
    main_base = event_init();

    /* initialize other stuff */
    hashlist_init();
    conn_init();

    stats.started = time(NULL);

    /* start up worker threads if MT mode */
    //thread_init(settings.num_threads, main_base);

    if (do_daemonize) {
        if (daemon_already_running(pid_file) < 0) {
            fprintf(stderr, "server is already running.\n");
            exit(EXIT_FAILURE);
        }
    }

    INIT_LIST_HEAD(&listen_conn);

    /* create unix mode sockets after dropping privileges */
    if (settings.socketpath != NULL) {
        if (socket_unix_init(settings.socketpath, settings.access)) {
            fprintf(stderr, "failed to listen\n");
            exit(EXIT_FAILURE);
        }
    }

    /* create the listening socket, bind it, and init */
    if (settings.socketpath == NULL) {
        if (socket_init(settings.port) < 0) {
            fprintf(stderr, "failed to listen\n");
            exit(EXIT_FAILURE);
        }
    }

    /* start checkpoint and deadlock detect thread */

    /* enter the event loop */
    event_base_loop(main_base, 0);
    
    hashlist_close();

    if (do_daemonize) {
        unlink(pid_file);
    }

    return 0;
}
Beispiel #2
0
int main(int argc, char *argv[])
{
	int c;
	int do_daemonize= 0;
	int maxcore	= 0;
	struct rlimit rlim;
	char unit	= '\0';
	int size_max	= 0;

	int protocol_specified	= 0;
	int tcp_specified	= 0;
	int udp_specified	= 0;

	char *subopts;
	char *subopts_value;

	enum {
		MAXCONNS_FAST = 0,
		HASHPOWER_INIT,
		SLAB_REASSIGN,
		SLAB_AUTOMOVE
	};
	char *const subopts_tokens[] = {
		[MAXCONNS_FAST]	= "maxconns_fast",
		[HASHPOWER_INIT]= "hashpower",
		[SLAB_REASSIGN] = "slab_reassign",
		[SLAB_AUTOMOVE] = "slab_automove",
		NULL
	};

	/* init settings */
	settings_init();
	
	/* set stderr non-buffering (for running under, say, daemontools) */
	setbuf(stderr, NULL);

	/* process arguments */
	while (-1 != (c = getopt(argc, argv,
		"a:"	/* access mask for unix socket */
		"A"	/* enable admin shutdown commannd */
		"p:"	/* TCP port number to listen on */
		"s:"	/* unix socket path to listen on */
		"U:"	/* UDP port number to listen on */
		"m:"	/* max memory to use for items in megabytes */
		"M"	/* return error on memory exhausted */
		"c:"	/* max simultaneous connections */
		"hi"	/* help, licence info */
		"r"	/* maximize core file limit */
		"v"	/* verbose */
		"d"	/* daemon mode */
		"l:"	/* interface to listen on */
		"f:"	/* factor? */
		"n:"	/* minimum space allocated for key+value+flags */
		"D:"	/* prefix delimiter? */
		"L"	/* Large memory pages */
		"R:"	/* max requests per event */
		"C"	/* Disable use of CAS */
		"b:"	/* backlog queue limit */
		"B:"	/* Binding protocol */
		"I:"	/* Max item size */
		"S"	/* Sasl ON */
		"o:"	/* Extended generic options */
	))) {
		switch (c) {
		case 'A':
			/* enables "shutdown" command */
			settings.shutdown_command = 1;
			break;

		case 'a':
			/* access for unix domain socket, as octal mask (like chmod)*/
			settings.access= strtol(optarg,NULL,8);
			break;

		case 'U':
			settings.udpport = atoi(optarg);
			udp_specified = 1;
			break;
		case 'p':
			settings.port = atoi(optarg);
			tcp_specified = 1;
			break;
		case 's':
			settings.socketpath = optarg;
			break;
		case 'm':
			settings.maxbytes = ((size_t)atoi(optarg)) * 1024 * 1024;
			break;
		case 'M':
			settings.evict_to_free = 0;
			break;
		case 'c':
			settings.maxconns = atoi(optarg);
			break;
		case 'h':
			usage();
			exit(EXIT_SUCCESS);
		case 'i':
			usage_license();
			exit(EXIT_SUCCESS);
		case 'v':
			settings.verbose++;
			break;
		case 'l':
			if (settings.inter != NULL) {
				size_t len = strlen(settings.inter) + strlen(optarg) + 2;
				char *p = malloc(len);
				if (p == NULL) {
				fprintf(stderr, "Failed to allocate memory\n");
				return 1;
				}
				snprintf(p, len, "%s,%s", settings.inter, optarg);
				free(settings.inter);
				settings.inter = p;
			} else {
				settings.inter= strdup(optarg);
			}
			break;
		case 'd':
			do_daemonize = 1;
			break;
		case 'r':
			maxcore = 1;
			break;
		case 'R':
			settings.reqs_per_event = atoi(optarg);
			if (settings.reqs_per_event == 0) {
				fprintf(stderr, "Number of requests per event must be greater than 0\n");
				return 1;
			}
			break;
		case 'f':
			if (atof(optarg) <= 1.0) {
				fprintf(stderr, "Factor must be greater than 1\n");
				return 1;
			}
			double_int(optarg, &settings.factor_numerator, &settings.factor_denominator);
			break;
		case 'n':
			settings.chunk_size = atoi(optarg);
			if (settings.chunk_size == 0) {
				fprintf(stderr, "Chunk size must be greater than 0\n");
				return 1;
			}
			break;
		case 'D':
			if (! optarg || ! optarg[0]) {
				fprintf(stderr, "No delimiter specified\n");
				return 1;
			}
			settings.prefix_delimiter = optarg[0];
			settings.detail_enabled = 1;
			break;
		case 'L' :
			if (enable_large_pages() == 0) {
				settings.preallocate = 1;
			} else {
				fprintf(stderr, "Cannot enable large pages on this system\n"
				"(There is no Linux support as of this version)\n");
				return 1;
			}
			break;
		case 'C' :
			settings.use_cas = 0;
			break;
		case 'b' :
			settings.backlog = atoi(optarg);
			break;
		case 'B':
			protocol_specified = 1;
			if (strcmp(optarg, "auto") == 0) {
				settings.binding_protocol = negotiating_prot;
			} else if (strcmp(optarg, "binary") == 0) {
				settings.binding_protocol = binary_prot;
			} else if (strcmp(optarg, "ascii") == 0) {
				settings.binding_protocol = ascii_prot;
			} else {
				fprintf(stderr, "Invalid value for binding protocol: %s\n"
					" -- should be one of auto, binary, or ascii\n", optarg);
				exit(EX_USAGE);
			}
			break;
		case 'I':
			unit = optarg[strlen(optarg)-1];
			if (unit == 'k' || unit == 'm' ||
				unit == 'K' || unit == 'M') {
				optarg[strlen(optarg)-1] = '\0';
				size_max = atoi(optarg);
				if (unit == 'k' || unit == 'K')
				size_max *= 1024;
				if (unit == 'm' || unit == 'M')
				size_max *= 1024 * 1024;
				settings.item_size_max = size_max;
			} else {
				settings.item_size_max = atoi(optarg);
			}
			if (settings.item_size_max < 1024) {
				fprintf(stderr, "Item max size cannot be less than 1024 bytes.\n");
				return 1;
			}
			if (settings.item_size_max > 1024 * 1024 * 128) {
				fprintf(stderr, "Cannot set item size limit higher than 128 mb.\n");
				return 1;
			}
			if (settings.item_size_max > 1024 * 1024) {
				fprintf(stderr, "WARNING: Setting item max size above 1MB is not"
				" recommended!\n"
				" Raising this limit increases the minimum memory requirements\n"
				" and will decrease your memory efficiency.\n"
				);
			}
			break;
		case 'S': /* set Sasl authentication to 1. Default is 0 */
#ifndef ENABLE_SASL
			fprintf(stderr, "This server is not built with SASL support.\n");
			exit(EX_USAGE);
#endif
			settings.sasl = 1;
			break;
		case 'o': /* It's sub-opts time! */
			subopts = optarg;

			while (*subopts != '\0') {

				switch (getsubopt(&subopts, subopts_tokens, &subopts_value)) {
				case MAXCONNS_FAST:
					settings.maxconns_fast = 1;
					break;
				case HASHPOWER_INIT:
					if (subopts_value == NULL) {
						fprintf(stderr, "Missing numeric argument for hashpower\n");
						return 1;
					}
					settings.hashpower_init = atoi(subopts_value);
					if (settings.hashpower_init < 12) {
						fprintf(stderr, "Initial hashtable multiplier of %d is too low\n",
							settings.hashpower_init);
						return 1;
					} else if (settings.hashpower_init > 64) {
						fprintf(stderr, "Initial hashtable multiplier of %d is too high\n"
							"Choose a value based on \"STAT hash_power_level\" from a running instance\n",
							settings.hashpower_init);
						return 1;
					}
					break;
				case SLAB_REASSIGN:
					settings.slab_reassign = 1;
					break;
				case SLAB_AUTOMOVE:
					if (subopts_value == NULL) {
						settings.slab_automove = 1;
						break;
					}
					settings.slab_automove = atoi(subopts_value);
					if (settings.slab_automove < 0 || settings.slab_automove > 2) {
						fprintf(stderr, "slab_automove must be between 0 and 2\n");
						return 1;
					}
					break;
				default:
					printf("Illegal suboption \"%s\"\n", subopts_value);
					return 1;
				}

			}
			break;
		default:
			fprintf(stderr, "Illegal argument \"%c\"\n", c);
			return 1;
		}
	}

	/*
	 * Use one workerthread to serve each UDP port if the user specified
	 * multiple ports
	 */
	if (settings.inter != NULL && strchr(settings.inter, ',')) {
		settings.num_threads_per_udp = 1;
	} else {
		settings.num_threads_per_udp = 0x7fffffff;
	}

	if (settings.sasl) {
		if (!protocol_specified) {
			settings.binding_protocol = binary_prot;
		} else {
			if (settings.binding_protocol != binary_prot) {
				fprintf(stderr, "ERROR: You cannot allow the ASCII protocol while using SASL.\n");
				exit(EX_USAGE);
			}
		}
	}

	if (tcp_specified && !udp_specified) {
		settings.udpport = settings.port;
	} else if (udp_specified && !tcp_specified) {
		settings.port = settings.udpport;
	}

	if (maxcore != 0) {
		struct rlimit rlim_new;

		/*
		* First try raising to infinity; if that fails, try bringing
		* the soft limit to the hard.
		*/
		if (getrlimit(RLIMIT_CORE, &rlim) == 0) {
			rlim_new.rlim_cur = rlim_new.rlim_max = RLIM_INFINITY;
			if (setrlimit(RLIMIT_CORE, &rlim_new)!= 0) {
				/* failed. try raising just to the old max */
				rlim_new.rlim_cur = rlim_new.rlim_max = rlim.rlim_max;
				(void)setrlimit(RLIMIT_CORE, &rlim_new);
			}
		}

		/*
		* getrlimit again to see what we ended up with. Only fail if
		* the soft limit ends up 0, because then no core files will be
		* created at all.
		*/
		if ((getrlimit(RLIMIT_CORE, &rlim) != 0) || rlim.rlim_cur == 0) {
			fprintf(stderr, "failed to ensure corefile creation\n");
			exit(EX_OSERR);
		}
	}

	/*
	* If needed, increase rlimits to allow as many connections
	* as needed.
	*/
	if (getrlimit(RLIMIT_NOFILE, &rlim) != 0) {
		fprintf(stderr, "failed to getrlimit number of files\n");
		exit(EX_OSERR);
	} else {
		rlim.rlim_cur = settings.maxconns;
		rlim.rlim_max = settings.maxconns;
		if (setrlimit(RLIMIT_NOFILE, &rlim) != 0) {
			fprintf(stderr, "failed to set rlimit for open files. Try starting as root or requesting smaller maxconns value.\n");
			exit(EX_OSERR);
		}
	}

	/* lose root privileges if we have them */
	if (getuid() != 0 || geteuid() != 0) {
		fprintf(stderr, "run as root\n");
		exit(EX_USAGE);
	}

	/* Initialize Sasl if -S was specified */
	if (settings.sasl) {
	//	init_sasl();
	}

	/* daemonize if requested */
	/* if we want to ensure our ability to dump core, don't chdir to / */
	if (do_daemonize) {
		if (sigignore(SIGHUP) == -1) {
			perror("Failed to ignore SIGHUP");
		}
		if (daemonize(maxcore, settings.verbose) == -1) {
			fprintf(stderr, "failed to daemon() in order to daemonize\n");
			exit(EXIT_FAILURE);
		}
	}

	main_loop();

	return 0;
}
Beispiel #3
0
int main (int argc, char **argv) {
    int c;
    conn *l_conn;
    struct in_addr addr;
    int lock_memory = 0;
    int daemonize = 0;
    int maxcore = 0;
    char *username = 0;
    struct passwd *pw;
    struct sigaction sa;
    struct rlimit rlim;
    char *pid_file = NULL;

    /* init settings */
    settings_init();

    /* process arguments */
    while ((c = getopt(argc, argv, "p:m:Mc:khirvdl:u:P:")) != -1) {
        switch (c) {
        case 'p':
            settings.port = atoi(optarg);
            break;
        case 'm':
            settings.maxbytes = atoi(optarg)*1024*1024;
            break;
        case 'M':
            settings.evict_to_free = 0;
            break;
        case 'c':
            settings.maxconns = atoi(optarg);
            break;
        case 'h':
            usage();
            exit(0);
        case 'i':
            usage_license();
            exit(0);
        case 'k':
            lock_memory = 1;
            break;
        case 'v':
            settings.verbose++;
            break;
        case 'l':
            if (!inet_aton(optarg, &addr)) {
                fprintf(stderr, "Illegal address: %s\n", optarg);
                return 1;
            } else {
                settings.interface = addr;
            }
            break;
        case 'd':
            daemonize = 1;
            break;
        case 'r':
            maxcore = 1;
            break;
        case 'u':
            username = optarg;
            break;
        case 'P':
            pid_file = optarg;
            break;
        default:
            fprintf(stderr, "Illegal argument \"%c\"\n", c);
            return 1;
        }
    }

    if (maxcore) {
        struct rlimit rlim_new;
        /*
         * First try raising to infinity; if that fails, try bringing
         * the soft limit to the hard.
         */
        if (getrlimit(RLIMIT_CORE, &rlim)==0) {
            rlim_new.rlim_cur = rlim_new.rlim_max = RLIM_INFINITY;
            if (setrlimit(RLIMIT_CORE, &rlim_new)!=0) {
                /* failed. try raising just to the old max */
                rlim_new.rlim_cur = rlim_new.rlim_max =
                                        rlim.rlim_max;
                (void) setrlimit(RLIMIT_CORE, &rlim_new);
            }
        }
        /*
         * getrlimit again to see what we ended up with. Only fail if
         * the soft limit ends up 0, because then no core files will be
         * created at all.
         */

        if ((getrlimit(RLIMIT_CORE, &rlim)!=0) || rlim.rlim_cur==0) {
            fprintf(stderr, "failed to ensure corefile creation\n");
            exit(1);
        }
    }

    /*
     * If needed, increase rlimits to allow as many connections
     * as needed.
     */

    if (getrlimit(RLIMIT_NOFILE, &rlim) != 0) {
        fprintf(stderr, "failed to getrlimit number of files\n");
        exit(1);
    } else {
        int maxfiles = settings.maxconns;
        if (rlim.rlim_cur < maxfiles)
            rlim.rlim_cur = maxfiles + 3;
        if (rlim.rlim_max < rlim.rlim_cur)
            rlim.rlim_max = rlim.rlim_cur;
        if (setrlimit(RLIMIT_NOFILE, &rlim) != 0) {
            fprintf(stderr, "failed to set rlimit for open files. Try running as root or requesting smaller maxconns value.\n");
            exit(1);
        }
    }

    /*
     * initialization order: first create the listening socket
     * (may need root on low ports), then drop root if needed,
     * then daemonise if needed, then init libevent (in some cases
     * descriptors created by libevent wouldn't survive forking).
     */

    /* create the listening socket and bind it */
    l_socket = server_socket(settings.port);
    if (l_socket == -1) {
        fprintf(stderr, "failed to listen\n");
        exit(1);
    }

    /* lose root privileges if we have them */
    if (getuid()== 0 || geteuid()==0) {
        if (username==0 || *username=='\0') {
            fprintf(stderr, "can't run as root without the -u switch\n");
            return 1;
        }
        if ((pw = getpwnam(username)) == 0) {
            fprintf(stderr, "can't find the user %s to switch to\n", username);
            return 1;
        }
        if (setgid(pw->pw_gid)<0 || setuid(pw->pw_uid)<0) {
            fprintf(stderr, "failed to assume identity of user %s\n", username);
            return 1;
        }
    }

    /* daemonize if requested */
    /* if we want to ensure our ability to dump core, don't chdir to / */
    if (daemonize) {
        int res;
        res = daemon(maxcore, settings.verbose);
        if (res == -1) {
            fprintf(stderr, "failed to daemon() in order to daemonize\n");
            return 1;
        }
    }


    /* initialize other stuff */
    item_init();
    event_init();
    stats_init();
    assoc_init();
    conn_init();
    slabs_init(settings.maxbytes);

    /* lock paged memory if needed */
    if (lock_memory) {
#ifdef HAVE_MLOCKALL
        mlockall(MCL_CURRENT | MCL_FUTURE);
#else
        fprintf(stderr, "warning: mlockall() not supported on this platform.  proceeding without.\n");
#endif
    }

    /*
     * ignore SIGPIPE signals; we can use errno==EPIPE if we
     * need that information
     */
    sa.sa_handler = SIG_IGN;
    sa.sa_flags = 0;
    if (sigemptyset(&sa.sa_mask) == -1 ||
            sigaction(SIGPIPE, &sa, 0) == -1) {
        perror("failed to ignore SIGPIPE; sigaction");
        exit(1);
    }

    /* create the initial listening connection */
    if (!(l_conn = conn_new(l_socket, conn_listening, EV_READ | EV_PERSIST))) {
        fprintf(stderr, "failed to create listening connection");
        exit(1);
    }

    /* initialise deletion array and timer event */
    deltotal = 200;
    delcurr = 0;
    todelete = malloc(sizeof(item *)*deltotal);
    delete_handler(0,0,0); /* sets up the event */

    /* save the PID in if we're a daemon */
    if (daemonize)
        save_pid(getpid(),pid_file);

    /* enter the loop */
    event_loop(0);

    /* remove the PID file if we're a daemon */
    if (daemonize)
        remove_pidfile(pid_file);

    return 0;
}