int main(int argc, char **argv)
{
char *p = NULL, *bindhost = NULL, temp[65];
int uid, gid, todaemon = 1, flags = 1, c, i;
struct sockaddr_in server;
struct linger ling = {0, 0};
struct matrix *m;
//使用getopt()函数匹配magent选项。getopt()函数参考:
while(-1 != (c = getopt(argc, argv, "p:u:g:s:Dhvn:l:kb:f:i:"))) {
switch (c) {
case 'u'://设置用户
uid = atoi(optarg);//atoi()函数参考:
if (uid > 0) {
setuid(uid);
seteuid(uid);
}
break;
case 'g':
gid = atoi(optarg);
if (gid > 0) {
setgid(gid);
setegid(gid);
}
break;
case 'v':
verbose_mode = 1;
todaemon = 0;
break;
case 'k':
use_ketama = 1;
break;
case 'D':
todaemon = 0;
break;
case 'p':
port = atoi(optarg);
break;
case 'i':
maxidle = atoi(optarg);
if (maxidle <= 0) maxidle = 20;
break;
case 'n':
maxconns = atoi(optarg);
if (maxconns <= 0) maxconns = 4096;
break;
case 'f':
socketpath = optarg;
break;
case 'l':
bindhost = optarg;
break;
case 'b':
if (backupcnt == 0) {
backups = (struct matrix *) calloc(sizeof(struct matrix), 1);
if (backups == NULL) {
fprintf(stderr, "out of memory for %s\n", optarg);
exit(1);
}
m = backups;
backupcnt = 1;
} else {
backups = (struct matrix *)realloc(backups, sizeof(struct matrix)*(backupcnt+1));
if (backups == NULL) {
fprintf(stderr, "out of memory for %s\n", optarg);
exit(1);
}
m = backups + backupcnt;
backupcnt ++;
}
p = strchr(optarg, ':');
if (p == NULL) {
m->ip = strdup(optarg);
m->port = 11211;
} else {
*p = '\0';
m->ip = strdup(optarg);
*p = ':';
p ++;
m->port = atoi(p);
if (m->port <= 0) m->port = 11211;
}
m->dstaddr.sin_family = AF_INET;
m->dstaddr.sin_addr.s_addr = inet_addr(m->ip);
m->dstaddr.sin_port = htons(m->port);
break;
case 's': /* server string */
if (matrixcnt == 0) {
matrixs = (struct matrix *) calloc(sizeof(struct matrix), 1);
if (matrixs == NULL) {
fprintf(stderr, "out of memory for %s\n", optarg);
exit(1);
}
m = matrixs;
matrixcnt = 1;
} else {
matrixs = (struct matrix *)realloc(matrixs, sizeof(struct matrix)*(matrixcnt+1));
if (matrixs == NULL) {
fprintf(stderr, "out of memory for %s\n", optarg);
exit(1);
}
m = matrixs + matrixcnt;
matrixcnt ++;
}
p = strchr(optarg, ':');
if (p == NULL) {
m->ip = strdup(optarg);
m->port = 11211;
} else {
*p = '\0';
m->ip = strdup(optarg);
*p = ':';
p ++;
m->port = atoi(p);
if (m->port <= 0) m->port = 11211;
}
m->dstaddr.sin_family = AF_INET;
m->dstaddr.sin_addr.s_addr = inet_addr(m->ip);
m->dstaddr.sin_port = htons(m->port);
break;
case 'h':
default:
show_help();
return 1;
}
}
if (matrixcnt == 0) {
fprintf(stderr, "please provide -s \"ip:port\" argument\n\n");
show_help();
exit(1);
}
if (port == 0 && socketpath == NULL) {
fprintf(stderr, "magent must listen on tcp or unix domain socket\n");
exit(1);
}
if (todaemon && daemon(0, 0) == -1) {
fprintf(stderr, "failed to be a daemon\n");
exit(1);
}
if (use_ketama) {
ketama = (struct ketama *)calloc(sizeof(struct ketama), 1);
if (ketama == NULL) {
fprintf(stderr, "not enough memory to create ketama\n");
exit(1);
} else {
ketama->count = matrixcnt;
ketama->weight = (int *)calloc(sizeof(int), ketama->count);
ketama->name = (char **)calloc(sizeof(char *), ketama->count);
if (ketama->weight == NULL || ketama->name == NULL) {
fprintf(stderr, "not enough memory to create ketama\n");
exit(1);
}
for (i = 0; i < ketama->count; i ++) {
ketama->weight[i] = 100;
ketama->totalweight += ketama->weight[i];
snprintf(temp, 64, "%s-%d", matrixs[i].ip, matrixs[i].port);
ketama->name[i] = strdup(temp);
if (ketama->name[i] == NULL) {
fprintf(stderr, "not enough memory to create ketama\n");
exit(1);
}
}
}
if (create_ketama(ketama, 500)) {
fprintf(stderr, "can't create ketama\n");
exit(1);
}
/* update backup server ketama */
if (backupcnt > 0) {
backupkt = (struct ketama *)calloc(sizeof(struct ketama), 1);
if (backupkt == NULL) {
fprintf(stderr, "not enough memory to create ketama\n");
exit(1);
} else {
backupkt->count = backupcnt;
backupkt->weight = (int *)calloc(sizeof(int), backupkt->count);
backupkt->name = (char **)calloc(sizeof(char *), backupkt->count);
if (backupkt->weight == NULL || backupkt->name == NULL) {
fprintf(stderr, "not enough memory to create ketama\n");
exit(1);
}
for (i = 0; i < backupkt->count; i ++) {
backupkt->weight[i] = 100;
backupkt->totalweight += backupkt->weight[i];
snprintf(temp, 64, "%s-%d", backups[i].ip, backups[i].port);
backupkt->name[i] = strdup(temp);
if (backupkt->name[i] == NULL) {
fprintf(stderr, "not enough memory to create ketama\n");
exit(1);
}
}
}
if (create_ketama(backupkt, 500)) {
fprintf(stderr, "can't create backup ketama\n");
exit(1);
}
}
fprintf(stderr, "using ketama algorithm\n");
}
if (port > 0) {
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
fprintf(stderr, "CAN'T CREATE NETWORK SOCKET\n");
return 1;
}
fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFL)|O_NONBLOCK);
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (void *)&flags, sizeof(flags));
setsockopt(sockfd, SOL_SOCKET, SO_LINGER, (void *)&ling, sizeof(ling));
setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, (void *)&flags, sizeof(flags));
memset((char *) &server, 0, sizeof(server));
server.sin_family = AF_INET;
if (bindhost == NULL)
server.sin_addr.s_addr = htonl(INADDR_ANY);
else
server.sin_addr.s_addr = inet_addr(bindhost);
server.sin_port = htons(port);
if (bind(sockfd, (struct sockaddr *) &server, sizeof(server))) {
if (errno != EINTR)
fprintf(stderr, "bind errno = %d: %s\n", errno, strerror(errno));
close(sockfd);
exit(1);
}
if (listen(sockfd, 512)) {
fprintf(stderr, "listen errno = %d: %s\n", errno, strerror(errno));
close(sockfd);
exit(1);
}
}
if (socketpath)
server_socket_unix();
signal(SIGTERM, server_exit);
signal(SIGINT, server_exit);
event_init();
if (sockfd > 0) {
if (verbose_mode)
fprintf(stderr, "memcached agent listen at port %d\n", port);
event_set(&ev_master, sockfd, EV_READ|EV_PERSIST, server_accept, NULL);
event_add(&ev_master, 0);
}
if (unixfd > 0) {
if (verbose_mode)
fprintf(stderr, "memcached agent listen at unix domain socket \"%s\"\n", socketpath);
event_set(&ev_unix, unixfd, EV_READ|EV_PERSIST, server_accept, NULL);
event_add(&ev_unix, 0);
}
event_loop(0);
server_exit(0);
return 0;
}
|