~yolanda.robla/ubuntu/trusty/memcached/add_distribution

« back to all changes in this revision

Viewing changes to memcached.c

  • Committer: Bazaar Package Importer
  • Author(s): Jay Bonci
  • Date: 2004-05-05 17:25:25 UTC
  • Revision ID: james.westby@ubuntu.com-20040505172525-ullh634q1xce88jl
Tags: upstream-1.1.11
ImportĀ upstreamĀ versionĀ 1.1.11

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
 
2
/*
 
3
 *  memcached - memory caching daemon
 
4
 *
 
5
 *       http://www.danga.com/memcached/
 
6
 *
 
7
 *  Copyright 2003 Danga Interactive, Inc.  All rights reserved.
 
8
 *
 
9
 *  Use and distribution licensed under the BSD license.  See
 
10
 *  the LICENSE file for full text.
 
11
 *
 
12
 *  Authors:
 
13
 *      Anatoly Vorobey <mellon@pobox.com>
 
14
 *      Brad Fitzpatrick <brad@danga.com>
 
15
 *
 
16
 *  $Id: memcached.c,v 1.47 2004/04/24 20:00:59 avva Exp $
 
17
 */
 
18
 
 
19
#include "config.h"
 
20
#include <sys/types.h>
 
21
#include <sys/stat.h>
 
22
#include <sys/time.h>
 
23
#include <sys/socket.h>
 
24
#include <sys/signal.h>
 
25
#include <sys/resource.h>
 
26
/* some POSIX systems need the following definition
 
27
 * to get mlockall flags out of sys/mman.h.  */
 
28
#ifndef _P1003_1B_VISIBLE
 
29
#define _P1003_1B_VISIBLE
 
30
#endif
 
31
#include <pwd.h>
 
32
#include <sys/mman.h>
 
33
#include <fcntl.h>
 
34
#include <stdlib.h>
 
35
#include <stdio.h>
 
36
#include <string.h>
 
37
#include <unistd.h>
 
38
#include <netinet/in.h>
 
39
#include <netinet/tcp.h>
 
40
#include <arpa/inet.h>
 
41
#include <errno.h>
 
42
#include <time.h>
 
43
#include <event.h>
 
44
#include <assert.h>
 
45
 
 
46
#ifdef HAVE_MALLOC_H
 
47
#include <malloc.h>
 
48
#endif
 
49
 
 
50
#include "memcached.h"
 
51
 
 
52
struct stats stats;
 
53
struct settings settings;
 
54
 
 
55
static item **todelete = 0;
 
56
static int delcurr;
 
57
static int deltotal;
 
58
 
 
59
time_t realtime(time_t exptime) {
 
60
    time_t now;
 
61
 
 
62
    /* no. of seconds in 30 days - largest possible delta exptime */
 
63
    #define REALTIME_MAXDELTA 60*60*24*30
 
64
 
 
65
    if (exptime == 0) return 0; /* 0 means never expire */
 
66
 
 
67
    if (exptime > REALTIME_MAXDELTA)
 
68
        return exptime;
 
69
    else {
 
70
        now = time(0);
 
71
        return exptime + now;
 
72
    }
 
73
}
 
74
 
 
75
void stats_init(void) {
 
76
    stats.curr_items = stats.total_items = stats.curr_conns = stats.total_conns = stats.conn_structs = 0;
 
77
    stats.get_cmds = stats.set_cmds = stats.get_hits = stats.get_misses = 0;
 
78
    stats.curr_bytes = stats.bytes_read = stats.bytes_written = 0;
 
79
    stats.started = time(0);
 
80
}
 
81
 
 
82
void stats_reset(void) {
 
83
    stats.total_items = stats.total_conns = 0;
 
84
    stats.get_cmds = stats.set_cmds = stats.get_hits = stats.get_misses = 0;
 
85
    stats.bytes_read = stats.bytes_written = 0;
 
86
}
 
87
 
 
88
void settings_init(void) {
 
89
    settings.port = 11211;
 
90
    settings.interface.s_addr = htonl(INADDR_ANY);
 
91
    settings.maxbytes = 64*1024*1024; /* default is 64MB */
 
92
    settings.maxconns = 1024;         /* to limit connections-related memory to about 5MB */
 
93
    settings.verbose = 0;
 
94
    settings.oldest_live = 0;
 
95
    settings.evict_to_free = 1;       /* push old items out of cache when memory runs out */
 
96
}
 
97
 
 
98
conn **freeconns;
 
99
int freetotal;
 
100
int freecurr;
 
101
 
 
102
void set_cork (conn *c, int val) {
 
103
    if (c->is_corked == val) return;
 
104
    c->is_corked = val;
 
105
#ifdef TCP_NOPUSH
 
106
    setsockopt(c->sfd, IPPROTO_TCP, TCP_NOPUSH, &val, sizeof(val));
 
107
#endif
 
108
}
 
109
 
 
110
void conn_init(void) {
 
111
    freetotal = 200;
 
112
    freecurr = 0;
 
113
    freeconns = (conn **)malloc(sizeof (conn *)*freetotal);
 
114
    return;
 
115
}
 
116
 
 
117
conn *conn_new(int sfd, int init_state, int event_flags) {
 
118
    conn *c;
 
119
 
 
120
    /* do we have a free conn structure from a previous close? */
 
121
    if (freecurr > 0) {
 
122
        c = freeconns[--freecurr];
 
123
    } else { /* allocate a new one */
 
124
        if (!(c = (conn *)malloc(sizeof(conn)))) {
 
125
            perror("malloc()");
 
126
            return 0;
 
127
        }
 
128
        c->rbuf = c->wbuf = 0;
 
129
        c->ilist = 0;
 
130
 
 
131
        c->rbuf = (char *) malloc(DATA_BUFFER_SIZE);
 
132
        c->wbuf = (char *) malloc(DATA_BUFFER_SIZE);
 
133
        c->ilist = (item **) malloc(sizeof(item *)*200);
 
134
 
 
135
        if (c->rbuf == 0 || c->wbuf == 0 || c->ilist == 0) {
 
136
            if (c->rbuf != 0) free(c->rbuf);
 
137
            if (c->wbuf != 0) free(c->wbuf);
 
138
            if (c->ilist !=0) free(c->ilist);
 
139
            free(c);
 
140
            perror("malloc()");
 
141
            return 0;
 
142
        }
 
143
        c->rsize = c->wsize = DATA_BUFFER_SIZE;
 
144
        c->isize = 200;
 
145
        stats.conn_structs++;
 
146
    }
 
147
 
 
148
    if (settings.verbose > 1) {
 
149
        if (init_state == conn_listening)
 
150
            fprintf(stderr, "<%d server listening\n", sfd);
 
151
        else
 
152
            fprintf(stderr, "<%d new client connection\n", sfd);
 
153
    }
 
154
 
 
155
    c->sfd = sfd;
 
156
    c->state = init_state;
 
157
    c->rlbytes = 0;
 
158
    c->rbytes = c->wbytes = 0;
 
159
    c->wcurr = c->wbuf;
 
160
    c->rcurr = c->rbuf;
 
161
    c->icurr = c->ilist; 
 
162
    c->ileft = 0;
 
163
    c->iptr = c->ibuf;
 
164
    c->ibytes = 0;
 
165
 
 
166
    c->write_and_go = conn_read;
 
167
    c->write_and_free = 0;
 
168
    c->item = 0;
 
169
 
 
170
    c->is_corked = 0;
 
171
 
 
172
    event_set(&c->event, sfd, event_flags, event_handler, (void *)c);
 
173
    c->ev_flags = event_flags;
 
174
 
 
175
    if (event_add(&c->event, 0) == -1) {
 
176
        free(c);
 
177
        return 0;
 
178
    }
 
179
 
 
180
    stats.curr_conns++;
 
181
    stats.total_conns++;
 
182
 
 
183
    return c;
 
184
}
 
185
 
 
186
void conn_close(conn *c) {
 
187
    /* delete the event, the socket and the conn */
 
188
    event_del(&c->event);
 
189
 
 
190
    if (settings.verbose > 1)
 
191
        fprintf(stderr, "<%d connection closed.\n", c->sfd);
 
192
 
 
193
    close(c->sfd);
 
194
 
 
195
    if (c->item) {
 
196
        item_free(c->item);
 
197
    }
 
198
 
 
199
    if (c->ileft) {
 
200
        for (; c->ileft > 0; c->ileft--,c->icurr++) {
 
201
            item_remove(*(c->icurr));
 
202
        }
 
203
    }
 
204
 
 
205
    if (c->write_and_free) {
 
206
        free(c->write_and_free);
 
207
    }
 
208
 
 
209
    /* if we have enough space in the free connections array, put the structure there */
 
210
    if (freecurr < freetotal) {
 
211
        freeconns[freecurr++] = c;
 
212
    } else {
 
213
        /* try to enlarge free connections array */
 
214
        conn **new_freeconns = realloc(freeconns, sizeof(conn *)*freetotal*2);
 
215
        if (new_freeconns) {
 
216
            freetotal *= 2;
 
217
            freeconns = new_freeconns;
 
218
            freeconns[freecurr++] = c;
 
219
        } else {
 
220
            free(c->rbuf);
 
221
            free(c->wbuf);
 
222
            free(c->ilist);
 
223
            free(c);
 
224
        }
 
225
    }
 
226
 
 
227
    stats.curr_conns--;
 
228
 
 
229
    return;
 
230
}
 
231
 
 
232
void out_string(conn *c, char *str) {
 
233
    int len;
 
234
 
 
235
    if (settings.verbose > 1)
 
236
        fprintf(stderr, ">%d %s\n", c->sfd, str);
 
237
 
 
238
    len = strlen(str);
 
239
    if (len + 2 > c->wsize) {
 
240
        /* ought to be always enough. just fail for simplicity */
 
241
        str = "SERVER_ERROR output line too long";
 
242
        len = strlen(str);
 
243
    }
 
244
 
 
245
    strcpy(c->wbuf, str);
 
246
    strcat(c->wbuf, "\r\n");
 
247
    c->wbytes = len + 2;
 
248
    c->wcurr = c->wbuf;
 
249
 
 
250
    c->state = conn_write;
 
251
    c->write_and_go = conn_read;
 
252
    return;
 
253
}
 
254
 
 
255
/* 
 
256
 * we get here after reading the value in set/add/replace commands. The command
 
257
 * has been stored in c->item_comm, and the item is ready in c->item.
 
258
 */
 
259
 
 
260
void complete_nread(conn *c) {
 
261
    item *it = c->item;
 
262
    int comm = c->item_comm;
 
263
    item *old_it;
 
264
    time_t now = time(0);
 
265
 
 
266
    stats.set_cmds++;
 
267
 
 
268
    while(1) {
 
269
        if (strncmp(ITEM_data(it) + it->nbytes - 2, "\r\n", 2) != 0) {
 
270
            out_string(c, "CLIENT_ERROR bad data chunk");
 
271
            break;
 
272
        }
 
273
 
 
274
        old_it = assoc_find(ITEM_key(it));
 
275
 
 
276
        if (old_it && old_it->exptime && old_it->exptime < now) {
 
277
            item_unlink(old_it);
 
278
            old_it = 0;
 
279
        }
 
280
 
 
281
        if (old_it && comm==NREAD_ADD) {
 
282
            item_update(old_it);
 
283
            out_string(c, "NOT_STORED");
 
284
            break;
 
285
        }
 
286
        
 
287
        if (!old_it && comm == NREAD_REPLACE) {
 
288
            out_string(c, "NOT_STORED");
 
289
            break;
 
290
        }
 
291
 
 
292
        if (old_it && (old_it->it_flags & ITEM_DELETED) && (comm == NREAD_REPLACE || comm == NREAD_ADD)) {
 
293
            out_string(c, "NOT_STORED");
 
294
            break;
 
295
        }
 
296
        
 
297
        if (old_it) {
 
298
            item_replace(old_it, it);
 
299
        } else item_link(it);
 
300
        
 
301
        c->item = 0;
 
302
        out_string(c, "STORED");
 
303
        return;
 
304
    }
 
305
            
 
306
    item_free(it); 
 
307
    c->item = 0; 
 
308
    return;
 
309
}
 
310
 
 
311
void process_stat(conn *c, char *command) {
 
312
    time_t now = time(0);
 
313
 
 
314
    if (strcmp(command, "stats") == 0) {
 
315
        char temp[1024];
 
316
        pid_t pid = getpid();
 
317
        char *pos = temp;
 
318
        struct rusage usage;
 
319
        
 
320
        getrusage(RUSAGE_SELF, &usage);
 
321
 
 
322
        pos += sprintf(pos, "STAT pid %u\r\n", pid);
 
323
        pos += sprintf(pos, "STAT uptime %lu\r\n", now - stats.started);
 
324
        pos += sprintf(pos, "STAT time %u\r\n", now);
 
325
        pos += sprintf(pos, "STAT version " VERSION "\r\n");
 
326
        pos += sprintf(pos, "STAT rusage_user %u:%u\r\n", usage.ru_utime.tv_sec, usage.ru_utime.tv_usec);
 
327
        pos += sprintf(pos, "STAT rusage_system %u:%u\r\n", usage.ru_stime.tv_sec, usage.ru_stime.tv_usec);
 
328
        pos += sprintf(pos, "STAT curr_items %u\r\n", stats.curr_items);
 
329
        pos += sprintf(pos, "STAT total_items %u\r\n", stats.total_items);
 
330
        pos += sprintf(pos, "STAT bytes %llu\r\n", stats.curr_bytes);
 
331
        pos += sprintf(pos, "STAT curr_connections %u\r\n", stats.curr_conns - 1); /* ignore listening conn */
 
332
        pos += sprintf(pos, "STAT total_connections %u\r\n", stats.total_conns);
 
333
        pos += sprintf(pos, "STAT connection_structures %u\r\n", stats.conn_structs);
 
334
        pos += sprintf(pos, "STAT cmd_get %u\r\n", stats.get_cmds);
 
335
        pos += sprintf(pos, "STAT cmd_set %u\r\n", stats.set_cmds);
 
336
        pos += sprintf(pos, "STAT get_hits %u\r\n", stats.get_hits);
 
337
        pos += sprintf(pos, "STAT get_misses %u\r\n", stats.get_misses);
 
338
        pos += sprintf(pos, "STAT bytes_read %llu\r\n", stats.bytes_read);
 
339
        pos += sprintf(pos, "STAT bytes_written %llu\r\n", stats.bytes_written);
 
340
        pos += sprintf(pos, "STAT limit_maxbytes %u\r\n", settings.maxbytes);
 
341
        pos += sprintf(pos, "END");
 
342
        out_string(c, temp);
 
343
        return;
 
344
    }
 
345
 
 
346
    if (strcmp(command, "stats reset") == 0) {
 
347
        stats_reset();
 
348
        out_string(c, "RESET");
 
349
        return;
 
350
    }
 
351
 
 
352
#ifdef HAVE_MALLOC_H
 
353
#ifdef HAVE_STRUCT_MALLINFO
 
354
    if (strcmp(command, "stats malloc") == 0) {
 
355
        char temp[512];
 
356
        struct mallinfo info;
 
357
        char *pos = temp;
 
358
 
 
359
        info = mallinfo();
 
360
        pos += sprintf(pos, "STAT arena_size %d\r\n", info.arena);
 
361
        pos += sprintf(pos, "STAT free_chunks %d\r\n", info.ordblks);
 
362
        pos += sprintf(pos, "STAT fastbin_blocks %d\r\n", info.smblks);
 
363
        pos += sprintf(pos, "STAT mmapped_regions %d\r\n", info.hblks);
 
364
        pos += sprintf(pos, "STAT mmapped_space %d\r\n", info.hblkhd);
 
365
        pos += sprintf(pos, "STAT max_total_alloc %d\r\n", info.usmblks);
 
366
        pos += sprintf(pos, "STAT fastbin_space %d\r\n", info.fsmblks);
 
367
        pos += sprintf(pos, "STAT total_alloc %d\r\n", info.uordblks);
 
368
        pos += sprintf(pos, "STAT total_free %d\r\n", info.fordblks);
 
369
        pos += sprintf(pos, "STAT releasable_space %d\r\nEND", info.keepcost);
 
370
        out_string(c, temp);
 
371
        return;
 
372
    }
 
373
#endif /* HAVE_STRUCT_MALLINFO */
 
374
#endif /* HAVE_MALLOC_H */
 
375
 
 
376
    if (strcmp(command, "stats maps") == 0) {
 
377
        char *wbuf;
 
378
        int wsize = 8192; /* should be enough */
 
379
        int fd;
 
380
        int res;
 
381
 
 
382
        wbuf = (char *)malloc(wsize);
 
383
        if (wbuf == 0) {
 
384
            out_string(c, "SERVER_ERROR out of memory");
 
385
            return;
 
386
        }
 
387
            
 
388
        fd = open("/proc/self/maps", O_RDONLY);
 
389
        if (fd == -1) {
 
390
            out_string(c, "SERVER_ERROR cannot open the maps file");
 
391
            free(wbuf);
 
392
            return;
 
393
        }
 
394
 
 
395
        res = read(fd, wbuf, wsize - 6);  /* 6 = END\r\n\0 */
 
396
        if (res == wsize - 6) {
 
397
            out_string(c, "SERVER_ERROR buffer overflow");
 
398
            free(wbuf); close(fd);
 
399
            return;
 
400
        }
 
401
        if (res == 0 || res == -1) {
 
402
            out_string(c, "SERVER_ERROR can't read the maps file");
 
403
            free(wbuf); close(fd);
 
404
            return;
 
405
        }
 
406
        strcpy(wbuf + res, "END\r\n");
 
407
        c->write_and_free=wbuf;
 
408
        c->wcurr=wbuf;
 
409
        c->wbytes = res + 6;
 
410
        c->state = conn_write;
 
411
        c->write_and_go = conn_read;
 
412
        close(fd);
 
413
        return;
 
414
    }
 
415
 
 
416
    if (strncmp(command, "stats cachedump", 15) == 0) {
 
417
        char *buf;
 
418
        unsigned int bytes, id, limit = 0;
 
419
        char *start = command + 15;
 
420
        if (sscanf(start, "%u %u\r\n", &id, &limit) < 1) {
 
421
            out_string(c, "CLIENT_ERROR bad command line");
 
422
            return;
 
423
        }
 
424
 
 
425
        buf = item_cachedump(id, limit, &bytes);
 
426
        if (buf == 0) {
 
427
            out_string(c, "SERVER_ERROR out of memory");
 
428
            return;
 
429
        }
 
430
 
 
431
        c->write_and_free = buf;
 
432
        c->wcurr = buf;
 
433
        c->wbytes = bytes;
 
434
        c->state = conn_write;
 
435
        c->write_and_go = conn_read;
 
436
        return;
 
437
    }
 
438
 
 
439
    if (strcmp(command, "stats slabs")==0) {
 
440
        int bytes = 0;
 
441
        char *buf = slabs_stats(&bytes);
 
442
        if (!buf) {
 
443
            out_string(c, "SERVER_ERROR out of memory");
 
444
            return;
 
445
        }
 
446
        c->write_and_free = buf;
 
447
        c->wcurr = buf;
 
448
        c->wbytes = bytes;
 
449
        c->state = conn_write;
 
450
        c->write_and_go = conn_read;
 
451
        return;
 
452
    }
 
453
 
 
454
    if (strcmp(command, "stats items")==0) {
 
455
        char buffer[4096];
 
456
        item_stats(buffer, 4096);
 
457
        out_string(c, buffer);
 
458
        return;
 
459
    }
 
460
 
 
461
    if (strcmp(command, "stats sizes")==0) {
 
462
        int bytes = 0;
 
463
        char *buf = item_stats_sizes(&bytes);
 
464
        if (! buf) {
 
465
            out_string(c, "SERVER_ERROR out of memory");
 
466
            return;
 
467
        }
 
468
 
 
469
        c->write_and_free = buf;
 
470
        c->wcurr = buf;
 
471
        c->wbytes = bytes;
 
472
        c->state = conn_write;
 
473
        c->write_and_go = conn_read;
 
474
        return;
 
475
    }
 
476
 
 
477
    out_string(c, "ERROR");
 
478
}
 
479
 
 
480
void process_command(conn *c, char *command) {
 
481
    
 
482
    int comm = 0;
 
483
    int incr = 0;
 
484
 
 
485
    /* 
 
486
     * for commands set/add/replace, we build an item and read the data
 
487
     * directly into it, then continue in nread_complete().
 
488
     */ 
 
489
 
 
490
    if (settings.verbose > 1)
 
491
        fprintf(stderr, "<%d %s\n", c->sfd, command);
 
492
 
 
493
    /* All incoming commands will require a response, so we cork at the beginning,
 
494
       and uncork at the very end (usually by means of out_string)  */
 
495
    set_cork(c, 1);
 
496
 
 
497
    if ((strncmp(command, "add ", 4) == 0 && (comm = NREAD_ADD)) || 
 
498
        (strncmp(command, "set ", 4) == 0 && (comm = NREAD_SET)) ||
 
499
        (strncmp(command, "replace ", 8) == 0 && (comm = NREAD_REPLACE))) {
 
500
 
 
501
        char key[251];
 
502
        int flags;
 
503
        time_t expire;
 
504
        int len, res;
 
505
        item *it;
 
506
 
 
507
        res = sscanf(command, "%*s %250s %u %lu %d\n", key, &flags, &expire, &len);
 
508
        if (res!=4 || strlen(key)==0 ) {
 
509
            out_string(c, "CLIENT_ERROR bad command line format");
 
510
            return;
 
511
        }
 
512
        expire = realtime(expire);
 
513
        it = item_alloc(key, flags, expire, len+2);
 
514
        if (it == 0) {
 
515
            out_string(c, "SERVER_ERROR out of memory");
 
516
            /* swallow the data line */
 
517
            c->write_and_go = conn_swallow;
 
518
            c->sbytes = len+2;
 
519
            return;
 
520
        }
 
521
 
 
522
        c->item_comm = comm;
 
523
        c->item = it;
 
524
        c->rcurr = ITEM_data(it);
 
525
        c->rlbytes = it->nbytes;
 
526
        c->state = conn_nread;
 
527
        return;
 
528
    }
 
529
 
 
530
    if ((strncmp(command, "incr ", 5) == 0 && (incr = 1)) ||
 
531
        (strncmp(command, "decr ", 5) == 0)) {
 
532
        char temp[32];
 
533
        unsigned int value;
 
534
        item *it;
 
535
        unsigned int delta;
 
536
        char key[251];
 
537
        int res;
 
538
        char *ptr;
 
539
        time_t now = time(0);
 
540
 
 
541
        res = sscanf(command, "%*s %250s %u\n", key, &delta);
 
542
        if (res!=2 || strlen(key)==0 ) {
 
543
            out_string(c, "CLIENT_ERROR bad command line format");
 
544
            return;
 
545
        }
 
546
        
 
547
        it = assoc_find(key);
 
548
        if (it && (it->it_flags & ITEM_DELETED)) {
 
549
            it = 0;
 
550
        }
 
551
        if (it && it->exptime && it->exptime < now) {
 
552
            item_unlink(it);
 
553
            it = 0;
 
554
        }
 
555
 
 
556
        if (!it) {
 
557
            out_string(c, "NOT_FOUND");
 
558
            return;
 
559
        }
 
560
 
 
561
        ptr = ITEM_data(it);
 
562
        while (*ptr && (*ptr<'0' && *ptr>'9')) ptr++;
 
563
        
 
564
        value = atoi(ptr);
 
565
 
 
566
        if (incr)
 
567
            value+=delta;
 
568
        else {
 
569
            if (delta >= value) value = 0;
 
570
            else value-=delta;
 
571
        }
 
572
 
 
573
        sprintf(temp, "%u", value);
 
574
        res = strlen(temp);
 
575
        if (res + 2 > it->nbytes) { /* need to realloc */
 
576
            item *new_it;
 
577
            new_it = item_alloc(ITEM_key(it), it->flags, it->exptime, res + 2 );
 
578
            if (new_it == 0) {
 
579
                out_string(c, "SERVER_ERROR out of memory");
 
580
                return;
 
581
            }
 
582
            memcpy(ITEM_data(new_it), temp, res);
 
583
            memcpy(ITEM_data(new_it) + res, "\r\n", 2);
 
584
            item_replace(it, new_it);
 
585
        } else { /* replace in-place */
 
586
            memcpy(ITEM_data(it), temp, res);
 
587
            memset(ITEM_data(it) + res, ' ', it->nbytes-res-2);
 
588
        }
 
589
        out_string(c, temp);
 
590
        return;
 
591
    }
 
592
        
 
593
    if (strncmp(command, "get ", 4) == 0) {
 
594
 
 
595
        char *start = command + 4;
 
596
        char key[251];
 
597
        int next;
 
598
        int i = 0;
 
599
        item *it;
 
600
        time_t now = time(0);
 
601
 
 
602
        while(sscanf(start, " %250s%n", key, &next) >= 1) {
 
603
            start+=next;
 
604
            stats.get_cmds++;
 
605
            it = assoc_find(key);
 
606
            if (it && (it->it_flags & ITEM_DELETED)) {
 
607
                it = 0;
 
608
            }
 
609
            if (settings.oldest_live && it && 
 
610
                it->time <= settings.oldest_live) {
 
611
                it = 0;
 
612
            }
 
613
            if (it && it->exptime && it->exptime < now) {
 
614
                item_unlink(it);
 
615
                it = 0;
 
616
            }
 
617
 
 
618
            if (it) {
 
619
                stats.get_hits++;
 
620
                it->refcount++;
 
621
                item_update(it);
 
622
                *(c->ilist + i) = it;
 
623
                i++;
 
624
                if (i > c->isize) {
 
625
                    c->isize *= 2;
 
626
                    c->ilist = realloc(c->ilist, sizeof(item *)*c->isize);
 
627
                }
 
628
            } else stats.get_misses++;
 
629
        }
 
630
        c->icurr = c->ilist;
 
631
        c->ileft = i;
 
632
        if (c->ileft) {
 
633
            c->ipart = 0;
 
634
            c->state = conn_mwrite;
 
635
            c->ibytes = 0;
 
636
            return;
 
637
        } else {
 
638
            out_string(c, "END");
 
639
            return;
 
640
        }
 
641
    }
 
642
 
 
643
    if (strncmp(command, "delete ", 7) == 0) {
 
644
        char key[251];
 
645
        item *it;
 
646
        int res;
 
647
        time_t exptime = 0;
 
648
 
 
649
        res = sscanf(command, "%*s %250s %d", key, &exptime);
 
650
        it = assoc_find(key);
 
651
        if (!it) {
 
652
            out_string(c, "NOT_FOUND");
 
653
            return;
 
654
        }
 
655
 
 
656
        exptime = realtime(exptime);
 
657
 
 
658
        it->refcount++;
 
659
        /* use its expiration time as its deletion time now */
 
660
        it->exptime = exptime;
 
661
        it->it_flags |= ITEM_DELETED;
 
662
        todelete[delcurr++] = it;
 
663
        if (delcurr >= deltotal) {
 
664
            deltotal *= 2;
 
665
            todelete = realloc(todelete, sizeof(item *)*deltotal);
 
666
        }
 
667
        out_string(c, "DELETED");
 
668
        return;
 
669
    }
 
670
        
 
671
    if (strncmp(command, "stats", 5) == 0) {
 
672
        process_stat(c, command);
 
673
        return;
 
674
    }
 
675
 
 
676
    if (strcmp(command, "flush_all") == 0) {
 
677
        settings.oldest_live = time(0);
 
678
        out_string(c, "OK");
 
679
        return;
 
680
    }
 
681
 
 
682
    if (strcmp(command, "version") == 0) {
 
683
        out_string(c, "VERSION " VERSION);
 
684
        return;
 
685
    }
 
686
 
 
687
    if (strcmp(command, "quit") == 0) {
 
688
        c->state = conn_closing;
 
689
        return;
 
690
    }
 
691
 
 
692
    if (strncmp(command, "slabs reassign ", 15) == 0) {
 
693
        int src, dst;
 
694
        char *start = command+15;
 
695
        if (sscanf(start, "%u %u\r\n", &src, &dst) == 2) {
 
696
            int rv = slabs_reassign(src, dst);
 
697
            if (rv == 1) {
 
698
                out_string(c, "DONE");
 
699
                return;
 
700
            }
 
701
            if (rv == 0) {
 
702
                out_string(c, "CANT");
 
703
                return;
 
704
            }
 
705
            if (rv == -1) {
 
706
                out_string(c, "BUSY");
 
707
                return;
 
708
            }
 
709
        }
 
710
        out_string(c, "CLIENT_ERROR bogus command");
 
711
        return;
 
712
    }
 
713
    
 
714
    out_string(c, "ERROR");
 
715
    return;
 
716
}
 
717
 
 
718
/* 
 
719
 * if we have a complete line in the buffer, process it and move whatever
 
720
 * remains in the buffer to its beginning.
 
721
 */
 
722
int try_read_command(conn *c) {
 
723
    char *el, *cont;
 
724
 
 
725
    if (!c->rbytes)
 
726
        return 0;
 
727
    el = memchr(c->rbuf, '\n', c->rbytes);
 
728
    if (!el)
 
729
        return 0;
 
730
    cont = el + 1;
 
731
    if (el - c->rbuf > 1 && *(el - 1) == '\r') {
 
732
        el--;
 
733
    }
 
734
    *el = '\0';
 
735
 
 
736
    process_command(c, c->rbuf);
 
737
 
 
738
    if (cont - c->rbuf < c->rbytes) { /* more stuff in the buffer */
 
739
        memmove(c->rbuf, cont, c->rbytes - (cont - c->rbuf));
 
740
    }
 
741
    c->rbytes -= (cont - c->rbuf);
 
742
    return 1;
 
743
}
 
744
 
 
745
/*
 
746
 * read from network as much as we can, handle buffer overflow and connection
 
747
 * close. 
 
748
 * return 0 if there's nothing to read on the first read.
 
749
 */
 
750
int try_read_network(conn *c) {
 
751
    int gotdata = 0;
 
752
    int res;
 
753
    while (1) {
 
754
        if (c->rbytes >= c->rsize) {
 
755
            char *new_rbuf = realloc(c->rbuf, c->rsize*2);
 
756
            if (!new_rbuf) {
 
757
                if (settings.verbose > 0)
 
758
                    fprintf(stderr, "Couldn't realloc input buffer\n");
 
759
                c->rbytes = 0; /* ignore what we read */
 
760
                out_string(c, "SERVER_ERROR out of memory");
 
761
                c->write_and_go = conn_closing;
 
762
                return 1;
 
763
            }
 
764
            c->rbuf = new_rbuf; c->rsize *= 2;
 
765
        }
 
766
        res = read(c->sfd, c->rbuf + c->rbytes, c->rsize - c->rbytes);
 
767
        if (res > 0) {
 
768
            stats.bytes_read += res;
 
769
            gotdata = 1;
 
770
            c->rbytes += res;
 
771
            continue;
 
772
        }
 
773
        if (res == 0) {
 
774
            /* connection closed */
 
775
            c->state = conn_closing;
 
776
            return 1;
 
777
        }
 
778
        if (res == -1) {
 
779
            if (errno == EAGAIN || errno == EWOULDBLOCK) break;
 
780
            else return 0;
 
781
        }
 
782
    }
 
783
    return gotdata;
 
784
}
 
785
 
 
786
int update_event(conn *c, int new_flags) {
 
787
    if (c->ev_flags == new_flags)
 
788
        return 1;
 
789
    if (event_del(&c->event) == -1) return 0;
 
790
    event_set(&c->event, c->sfd, new_flags, event_handler, (void *)c);
 
791
    c->ev_flags = new_flags;
 
792
    if (event_add(&c->event, 0) == -1) return 0;
 
793
    return 1;
 
794
}
 
795
    
 
796
void drive_machine(conn *c) {
 
797
 
 
798
    int exit = 0;
 
799
    int sfd, flags = 1;
 
800
    socklen_t addrlen;
 
801
    struct sockaddr addr;
 
802
    conn *newc;
 
803
    int res;
 
804
 
 
805
    while (!exit) {
 
806
        /* printf("state %d\n", c->state);*/
 
807
        switch(c->state) {
 
808
        case conn_listening:
 
809
            addrlen = sizeof(addr);
 
810
            if ((sfd = accept(c->sfd, &addr, &addrlen)) == -1) {
 
811
                if (errno == EAGAIN || errno == EWOULDBLOCK) {
 
812
                    exit = 1;
 
813
                    break;
 
814
                } else {
 
815
                    perror("accept()");
 
816
                }
 
817
                break;
 
818
            }
 
819
            if ((flags = fcntl(sfd, F_GETFL, 0)) < 0 ||
 
820
                fcntl(sfd, F_SETFL, flags | O_NONBLOCK) < 0) {
 
821
                perror("setting O_NONBLOCK");
 
822
                close(sfd);
 
823
                break;
 
824
            }            
 
825
            newc = conn_new(sfd, conn_read, EV_READ | EV_PERSIST);
 
826
            if (!newc) {
 
827
                if (settings.verbose > 0)
 
828
                    fprintf(stderr, "couldn't create new connection\n");
 
829
                close(sfd);
 
830
                break;
 
831
            }
 
832
 
 
833
            break;
 
834
 
 
835
        case conn_read:
 
836
            if (try_read_command(c)) {
 
837
                continue;
 
838
            }
 
839
            if (try_read_network(c)) {
 
840
                continue;
 
841
            }
 
842
            /* we have no command line and no data to read from network */
 
843
            if (!update_event(c, EV_READ | EV_PERSIST)) {
 
844
                if (settings.verbose > 0)
 
845
                    fprintf(stderr, "Couldn't update event\n");
 
846
                c->state = conn_closing;
 
847
                break;
 
848
            }
 
849
            exit = 1;
 
850
            break;
 
851
 
 
852
        case conn_nread:
 
853
            /* we are reading rlbytes into rcurr; */
 
854
            if (c->rlbytes == 0) {
 
855
                complete_nread(c);
 
856
                break;
 
857
            }
 
858
            /* first check if we have leftovers in the conn_read buffer */
 
859
            if (c->rbytes > 0) {
 
860
                int tocopy = c->rbytes > c->rlbytes ? c->rlbytes : c->rbytes;
 
861
                memcpy(c->rcurr, c->rbuf, tocopy);
 
862
                c->rcurr += tocopy;
 
863
                c->rlbytes -= tocopy;
 
864
                if (c->rbytes > tocopy) {
 
865
                    memmove(c->rbuf, c->rbuf+tocopy, c->rbytes - tocopy);
 
866
                }
 
867
                c->rbytes -= tocopy;
 
868
                break;
 
869
            }
 
870
 
 
871
            /*  now try reading from the socket */
 
872
            res = read(c->sfd, c->rcurr, c->rlbytes);
 
873
            if (res > 0) {
 
874
                stats.bytes_read += res;
 
875
                c->rcurr += res;
 
876
                c->rlbytes -= res;
 
877
                break;
 
878
            }
 
879
            if (res == 0) { /* end of stream */
 
880
                c->state = conn_closing;
 
881
                break;
 
882
            }
 
883
            if (res == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
 
884
                if (!update_event(c, EV_READ | EV_PERSIST)) {
 
885
                    if (settings.verbose > 0) 
 
886
                        fprintf(stderr, "Couldn't update event\n");
 
887
                    c->state = conn_closing;
 
888
                    break;
 
889
                }
 
890
                exit = 1;
 
891
                break;
 
892
            }
 
893
            /* otherwise we have a real error, on which we close the connection */
 
894
            if (settings.verbose > 0)
 
895
                fprintf(stderr, "Failed to read, and not due to blocking\n");
 
896
            c->state = conn_closing;
 
897
            break;
 
898
 
 
899
        case conn_swallow:
 
900
            /* we are reading sbytes and throwing them away */
 
901
            if (c->sbytes == 0) {
 
902
                c->state = conn_read;
 
903
                break;
 
904
            }
 
905
 
 
906
            /* first check if we have leftovers in the conn_read buffer */
 
907
            if (c->rbytes > 0) {
 
908
                int tocopy = c->rbytes > c->sbytes ? c->sbytes : c->rbytes;
 
909
                c->sbytes -= tocopy;
 
910
                if (c->rbytes > tocopy) {
 
911
                    memmove(c->rbuf, c->rbuf+tocopy, c->rbytes - tocopy);
 
912
                }
 
913
                c->rbytes -= tocopy;
 
914
                break;
 
915
            }
 
916
 
 
917
            /*  now try reading from the socket */
 
918
            res = read(c->sfd, c->rbuf, c->rsize > c->sbytes ? c->sbytes : c->rsize);
 
919
            if (res > 0) {
 
920
                stats.bytes_read += res;
 
921
                c->sbytes -= res;
 
922
                break;
 
923
            }
 
924
            if (res == 0) { /* end of stream */
 
925
                c->state = conn_closing;
 
926
                break;
 
927
            }
 
928
            if (res == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
 
929
                if (!update_event(c, EV_READ | EV_PERSIST)) {
 
930
                    if (settings.verbose > 0)
 
931
                        fprintf(stderr, "Couldn't update event\n");
 
932
                    c->state = conn_closing;
 
933
                    break;
 
934
                }
 
935
                exit = 1;
 
936
                break;
 
937
            }
 
938
            /* otherwise we have a real error, on which we close the connection */
 
939
            if (settings.verbose > 0)
 
940
                fprintf(stderr, "Failed to read, and not due to blocking\n");
 
941
            c->state = conn_closing;
 
942
            break;
 
943
 
 
944
        case conn_write:
 
945
            /* we are writing wbytes bytes starting from wcurr */
 
946
            if (c->wbytes == 0) {
 
947
                if (c->write_and_free) {
 
948
                    free(c->write_and_free);
 
949
                    c->write_and_free = 0;
 
950
                }
 
951
                c->state = c->write_and_go;
 
952
                if (c->state == conn_read)
 
953
                    set_cork(c, 0);
 
954
                break;
 
955
            }
 
956
            res = write(c->sfd, c->wcurr, c->wbytes);
 
957
            if (res > 0) {
 
958
                stats.bytes_written += res;
 
959
                c->wcurr  += res;
 
960
                c->wbytes -= res;
 
961
                break;
 
962
            }
 
963
            if (res == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
 
964
                if (!update_event(c, EV_WRITE | EV_PERSIST)) {
 
965
                    if (settings.verbose > 0)
 
966
                        fprintf(stderr, "Couldn't update event\n");
 
967
                    c->state = conn_closing;
 
968
                    break;
 
969
                }                
 
970
                exit = 1;
 
971
                break;
 
972
            }
 
973
            /* if res==0 or res==-1 and error is not EAGAIN or EWOULDBLOCK,
 
974
               we have a real error, on which we close the connection */
 
975
            if (settings.verbose > 0)
 
976
                fprintf(stderr, "Failed to write, and not due to blocking\n");
 
977
            c->state = conn_closing;
 
978
            break;
 
979
        case conn_mwrite:
 
980
            /* 
 
981
             * we're writing ibytes bytes from iptr. iptr alternates between
 
982
             * ibuf, where we build a string "VALUE...", and ITEM_data(it) for the 
 
983
             * current item. When we finish a chunk, we choose the next one using 
 
984
             * ipart, which has the following semantics: 0 - start the loop, 1 - 
 
985
             * we finished ibuf, go to current ITEM_data(it); 2 - we finished ITEM_data(it),
 
986
             * move to the next item and build its ibuf; 3 - we finished all items, 
 
987
             * write "END".
 
988
             */
 
989
            if (c->ibytes > 0) {
 
990
                res = write(c->sfd, c->iptr, c->ibytes);
 
991
                if (res > 0) {
 
992
                    stats.bytes_written += res;
 
993
                    c->iptr += res;
 
994
                    c->ibytes -= res;
 
995
                    break;
 
996
                }
 
997
                if (res == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
 
998
                    if (!update_event(c, EV_WRITE | EV_PERSIST)) {
 
999
                        if (settings.verbose > 0)
 
1000
                            fprintf(stderr, "Couldn't update event\n");
 
1001
                        c->state = conn_closing;
 
1002
                        break;
 
1003
                    }
 
1004
                    exit = 1;
 
1005
                    break;
 
1006
                }
 
1007
                /* if res==0 or res==-1 and error is not EAGAIN or EWOULDBLOCK,
 
1008
                   we have a real error, on which we close the connection */
 
1009
                if (settings.verbose > 0)
 
1010
                    fprintf(stderr, "Failed to write, and not due to blocking\n");
 
1011
                c->state = conn_closing;
 
1012
                break;
 
1013
            } else {
 
1014
                item *it;
 
1015
                /* we finished a chunk, decide what to do next */
 
1016
                switch (c->ipart) {
 
1017
                case 1:
 
1018
                    it = *(c->icurr);
 
1019
                    assert((it->it_flags & ITEM_SLABBED) == 0);
 
1020
                    c->iptr = ITEM_data(it);
 
1021
                    c->ibytes = it->nbytes;
 
1022
                    c->ipart = 2;
 
1023
                    break;
 
1024
                case 2:
 
1025
                    it = *(c->icurr);
 
1026
                    item_remove(it);
 
1027
                    c->ileft--;
 
1028
                    if (c->ileft <= 0) {
 
1029
                        c->ipart = 3;
 
1030
                        break;
 
1031
                    } else {
 
1032
                        c->icurr++;
 
1033
                    }
 
1034
                    /* FALL THROUGH */
 
1035
                case 0:
 
1036
                    it = *(c->icurr);
 
1037
                    assert((it->it_flags & ITEM_SLABBED) == 0);
 
1038
                    sprintf(c->ibuf, "VALUE %s %u %u\r\n", ITEM_key(it), it->flags, it->nbytes - 2);
 
1039
                    if (settings.verbose > 1)
 
1040
                        fprintf(stderr, ">%d sending key %s\n", c->sfd, ITEM_key(it));
 
1041
                    c->iptr = c->ibuf;
 
1042
                    c->ibytes = strlen(c->iptr);
 
1043
                    c->ipart = 1;
 
1044
                    break;
 
1045
                case 3:
 
1046
                    out_string(c, "END");
 
1047
                    break;
 
1048
                }
 
1049
            }
 
1050
            break;
 
1051
 
 
1052
        case conn_closing:
 
1053
            conn_close(c);
 
1054
            exit = 1;
 
1055
            break;
 
1056
        }
 
1057
 
 
1058
    }
 
1059
 
 
1060
    return;
 
1061
}
 
1062
 
 
1063
 
 
1064
void event_handler(int fd, short which, void *arg) {
 
1065
    conn *c;
 
1066
    
 
1067
    c = (conn *)arg;
 
1068
    c->which = which;
 
1069
 
 
1070
    /* sanity */
 
1071
    if (fd != c->sfd) {
 
1072
        if (settings.verbose > 0)
 
1073
            fprintf(stderr, "Catastrophic: event fd doesn't match conn fd!\n");
 
1074
        conn_close(c);
 
1075
        return;
 
1076
    }
 
1077
 
 
1078
    /* do as much I/O as possible until we block */
 
1079
    drive_machine(c);
 
1080
 
 
1081
    /* wait for next event */
 
1082
    return;
 
1083
}
 
1084
 
 
1085
int new_socket(void) {
 
1086
    int sfd;
 
1087
    int flags;
 
1088
 
 
1089
    if ((sfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
 
1090
        perror("socket()");
 
1091
        return -1;
 
1092
    }
 
1093
 
 
1094
    if ((flags = fcntl(sfd, F_GETFL, 0)) < 0 ||
 
1095
        fcntl(sfd, F_SETFL, flags | O_NONBLOCK) < 0) {
 
1096
        perror("setting O_NONBLOCK");
 
1097
        close(sfd);
 
1098
        return -1;
 
1099
    }
 
1100
    return sfd;
 
1101
}
 
1102
 
 
1103
int server_socket(int port) {
 
1104
    int sfd;
 
1105
    struct linger ling = {0, 0};
 
1106
    struct sockaddr_in addr;
 
1107
    int flags =1;
 
1108
 
 
1109
    if ((sfd = new_socket()) == -1) {
 
1110
        return -1;
 
1111
    }
 
1112
 
 
1113
    setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &flags, sizeof(flags));
 
1114
    setsockopt(sfd, SOL_SOCKET, SO_KEEPALIVE, &flags, sizeof(flags));
 
1115
    setsockopt(sfd, SOL_SOCKET, SO_LINGER, &ling, sizeof(ling));
 
1116
#if !defined(TCP_NOPUSH)
 
1117
    setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, &flags, sizeof(flags));
 
1118
#endif
 
1119
 
 
1120
    addr.sin_family = AF_INET;
 
1121
    addr.sin_port = htons(port);
 
1122
    addr.sin_addr = settings.interface;
 
1123
    if (bind(sfd, (struct sockaddr *) &addr, sizeof(addr)) == -1) {
 
1124
        perror("bind()");
 
1125
        close(sfd);
 
1126
        return -1;
 
1127
    }
 
1128
    if (listen(sfd, 1024) == -1) {
 
1129
        perror("listen()");
 
1130
        close(sfd);
 
1131
        return -1;
 
1132
    }
 
1133
    return sfd;
 
1134
}
 
1135
 
 
1136
/* invoke right before gdb is called, on assert */
 
1137
void pre_gdb () {
 
1138
    int i = 0;
 
1139
    if(l_socket) close(l_socket);
 
1140
    for (i=3; i<=500; i++) close(i); /* so lame */
 
1141
    kill(getpid(), SIGABRT);
 
1142
}
 
1143
 
 
1144
struct event deleteevent;
 
1145
 
 
1146
void delete_handler(int fd, short which, void *arg) {
 
1147
    struct timeval t;
 
1148
 
 
1149
    evtimer_del(&deleteevent);
 
1150
    evtimer_set(&deleteevent, delete_handler, 0);
 
1151
    t.tv_sec = 5; t.tv_usec=0;
 
1152
    evtimer_add(&deleteevent, &t);
 
1153
 
 
1154
    {
 
1155
        int i, j=0;
 
1156
        time_t now = time(0);
 
1157
        for (i=0; i<delcurr; i++) {
 
1158
            item *it = todelete[i];
 
1159
            if (it->exptime < now) {
 
1160
                assert(it->refcount > 0);
 
1161
                it->it_flags &= ~ITEM_DELETED;
 
1162
                item_unlink(it);
 
1163
                item_remove(it);
 
1164
            } else {
 
1165
                todelete[j++] = it;
 
1166
            }
 
1167
        }
 
1168
        delcurr = j;
 
1169
    }
 
1170
                
 
1171
    return;
 
1172
}
 
1173
        
 
1174
void usage(void) {
 
1175
    printf(PACKAGE " " VERSION "\n");
 
1176
    printf("-p <num>      port number to listen on\n");
 
1177
    printf("-l <ip_addr>  interface to listen on, default is INDRR_ANY\n");
 
1178
    printf("-d            run as a daemon\n");
 
1179
    printf("-r            maximize core file limit\n");
 
1180
    printf("-u <username> assume identity of <username> (only when run as root)\n");
 
1181
    printf("-m <num>      max memory to use for items in megabytes, default is 64 MB\n");
 
1182
    printf("-M            return error on memory exhausted (rather than removing items)\n");
 
1183
    printf("-c <num>      max simultaneous connections, default is 1024\n");
 
1184
    printf("-k            lock down all paged memory\n");
 
1185
    printf("-v            verbose (print errors/warnings while in event loop)\n");
 
1186
    printf("-vv           very verbose (also print client commands/reponses)\n");
 
1187
    printf("-h            print this help and exit\n");
 
1188
    printf("-i            print memcached and libevent license\n");
 
1189
    return;
 
1190
}
 
1191
 
 
1192
void usage_license(void) {
 
1193
    printf(PACKAGE " " VERSION "\n\n");
 
1194
    printf(
 
1195
        "Copyright (c) 2003, Danga Interactive, Inc. <http://www.danga.com/>\n"
 
1196
        "All rights reserved.\n"
 
1197
        "\n"
 
1198
        "Redistribution and use in source and binary forms, with or without\n"
 
1199
        "modification, are permitted provided that the following conditions are\n"
 
1200
        "met:\n"
 
1201
        "\n"
 
1202
        "    * Redistributions of source code must retain the above copyright\n"
 
1203
        "notice, this list of conditions and the following disclaimer.\n"
 
1204
        "\n"
 
1205
        "    * Redistributions in binary form must reproduce the above\n"
 
1206
        "copyright notice, this list of conditions and the following disclaimer\n"
 
1207
        "in the documentation and/or other materials provided with the\n"
 
1208
        "distribution.\n"
 
1209
        "\n"
 
1210
        "    * Neither the name of the Danga Interactive nor the names of its\n"
 
1211
        "contributors may be used to endorse or promote products derived from\n"
 
1212
        "this software without specific prior written permission.\n"
 
1213
        "\n"
 
1214
        "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
 
1215
        "\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
 
1216
        "LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
 
1217
        "A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
 
1218
        "OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
 
1219
        "SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
 
1220
        "LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
 
1221
        "DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
 
1222
        "THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
 
1223
        "(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
 
1224
        "OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
 
1225
        "\n"
 
1226
        "\n"
 
1227
        "This product includes software developed by Niels Provos.\n"
 
1228
        "\n"
 
1229
        "[ libevent ]\n"
 
1230
        "\n"
 
1231
        "Copyright 2000-2003 Niels Provos <provos@citi.umich.edu>\n"
 
1232
        "All rights reserved.\n"
 
1233
        "\n"
 
1234
        "Redistribution and use in source and binary forms, with or without\n"
 
1235
        "modification, are permitted provided that the following conditions\n"
 
1236
        "are met:\n"
 
1237
        "1. Redistributions of source code must retain the above copyright\n"
 
1238
        "   notice, this list of conditions and the following disclaimer.\n"
 
1239
        "2. Redistributions in binary form must reproduce the above copyright\n"
 
1240
        "   notice, this list of conditions and the following disclaimer in the\n"
 
1241
        "   documentation and/or other materials provided with the distribution.\n"
 
1242
        "3. All advertising materials mentioning features or use of this software\n"
 
1243
        "   must display the following acknowledgement:\n"
 
1244
        "      This product includes software developed by Niels Provos.\n"
 
1245
        "4. The name of the author may not be used to endorse or promote products\n"
 
1246
        "   derived from this software without specific prior written permission.\n"
 
1247
        "\n"
 
1248
        "THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n"
 
1249
        "IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n"
 
1250
        "OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n"
 
1251
        "IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\n"
 
1252
        "INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n"
 
1253
        "NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
 
1254
        "DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
 
1255
        "THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
 
1256
        "(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\n"
 
1257
        "THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
 
1258
    );
 
1259
 
 
1260
    return;
 
1261
}
 
1262
 
 
1263
int l_socket=0;
 
1264
 
 
1265
int main (int argc, char **argv) {
 
1266
    int c;
 
1267
    conn *l_conn;
 
1268
    struct in_addr addr;
 
1269
    int lock_memory = 0;
 
1270
    int daemonize = 0;
 
1271
    int maxcore = 0;
 
1272
    char *username = 0;
 
1273
    struct passwd *pw;
 
1274
    struct sigaction sa;
 
1275
    struct rlimit rlim;
 
1276
 
 
1277
    /* init settings */
 
1278
    settings_init();
 
1279
 
 
1280
    /* process arguments */
 
1281
    while ((c = getopt(argc, argv, "p:m:Mc:khirvdl:u:")) != -1) {
 
1282
        switch (c) {
 
1283
        case 'p':
 
1284
            settings.port = atoi(optarg);
 
1285
            break;
 
1286
        case 'm':
 
1287
            settings.maxbytes = atoi(optarg)*1024*1024;
 
1288
            break;
 
1289
        case 'M':
 
1290
            settings.evict_to_free = 0;
 
1291
            break;
 
1292
        case 'c':
 
1293
            settings.maxconns = atoi(optarg);
 
1294
            break;
 
1295
        case 'h':
 
1296
            usage();
 
1297
            exit(0);
 
1298
        case 'i':
 
1299
            usage_license();
 
1300
            exit(0);
 
1301
        case 'k':
 
1302
            lock_memory = 1;
 
1303
            break;
 
1304
        case 'v':
 
1305
            settings.verbose++;
 
1306
            break;
 
1307
        case 'l':
 
1308
            if (!inet_aton(optarg, &addr)) {
 
1309
                fprintf(stderr, "Illegal address: %s\n", optarg);
 
1310
                return 1;
 
1311
            } else {
 
1312
                settings.interface = addr;
 
1313
            }
 
1314
            break;
 
1315
        case 'd':
 
1316
            daemonize = 1;
 
1317
            break;
 
1318
        case 'r':
 
1319
            maxcore = 1;
 
1320
            break;
 
1321
        case 'u':
 
1322
            username = optarg;
 
1323
            break;
 
1324
        default:
 
1325
            fprintf(stderr, "Illegal argument \"%c\"\n", c);
 
1326
            return 1;
 
1327
        }
 
1328
    }
 
1329
 
 
1330
    if (maxcore) {
 
1331
        struct rlimit rlim_new;
 
1332
        /* 
 
1333
         * First try raising to infinity; if that fails, try bringing
 
1334
         * the soft limit to the hard. 
 
1335
         */
 
1336
        if (getrlimit(RLIMIT_CORE, &rlim)==0) {
 
1337
            rlim_new.rlim_cur = rlim_new.rlim_max = RLIM_INFINITY;
 
1338
            if (setrlimit(RLIMIT_CORE, &rlim_new)!=0) {
 
1339
                /* failed. try raising just to the old max */
 
1340
                rlim_new.rlim_cur = rlim_new.rlim_max = 
 
1341
                    rlim.rlim_max;
 
1342
                (void) setrlimit(RLIMIT_CORE, &rlim_new);
 
1343
            }
 
1344
        }
 
1345
        /* 
 
1346
         * getrlimit again to see what we ended up with. Only fail if 
 
1347
         * the soft limit ends up 0, because then no core files will be 
 
1348
         * created at all.
 
1349
         */
 
1350
           
 
1351
        if ((getrlimit(RLIMIT_CORE, &rlim)!=0) || rlim.rlim_cur==0) {
 
1352
            fprintf(stderr, "failed to ensure corefile creation\n");
 
1353
            exit(1);
 
1354
        }
 
1355
    }
 
1356
                        
 
1357
    /* 
 
1358
     * If needed, increase rlimits to allow as many connections
 
1359
     * as needed.
 
1360
     */
 
1361
    
 
1362
    if (getrlimit(RLIMIT_NOFILE, &rlim) != 0) {
 
1363
        fprintf(stderr, "failed to getrlimit number of files\n");
 
1364
        exit(1);
 
1365
    } else {
 
1366
        int maxfiles = settings.maxconns;
 
1367
        if (rlim.rlim_cur < maxfiles) 
 
1368
            rlim.rlim_cur = maxfiles + 3;
 
1369
        if (rlim.rlim_max < rlim.rlim_cur)
 
1370
            rlim.rlim_max = rlim.rlim_cur;
 
1371
        if (setrlimit(RLIMIT_NOFILE, &rlim) != 0) {
 
1372
            fprintf(stderr, "failed to set rlimit for open files. Try running as root or requesting smaller maxconns value.\n");
 
1373
            exit(1);
 
1374
        }
 
1375
    }
 
1376
 
 
1377
    /* 
 
1378
     * initialization order: first create the listening socket
 
1379
     * (may need root on low ports), then drop root if needed,
 
1380
     * then daemonise if needed, then init libevent (in some cases
 
1381
     * descriptors created by libevent wouldn't survive forking).
 
1382
     */
 
1383
 
 
1384
    /* create the listening socket and bind it */
 
1385
    l_socket = server_socket(settings.port);
 
1386
    if (l_socket == -1) {
 
1387
        fprintf(stderr, "failed to listen\n");
 
1388
        exit(1);
 
1389
    }
 
1390
 
 
1391
    /* lose root privileges if we have them */
 
1392
    if (getuid()== 0 || geteuid()==0) {
 
1393
        if (username==0 || *username=='\0') {
 
1394
            fprintf(stderr, "can't run as root without the -u switch\n");
 
1395
            return 1;
 
1396
        }
 
1397
        if ((pw = getpwnam(username)) == 0) {
 
1398
            fprintf(stderr, "can't find the user %s to switch to\n", username);
 
1399
            return 1;
 
1400
        }
 
1401
        if (setgid(pw->pw_gid)<0 || setuid(pw->pw_uid)<0) {
 
1402
            fprintf(stderr, "failed to assume identity of user %s\n", username);
 
1403
            return 1;
 
1404
        }
 
1405
    }
 
1406
 
 
1407
    /* daemonize if requested */
 
1408
    /* if we want to ensure our ability to dump core, don't chdir to / */
 
1409
    if (daemonize) {
 
1410
        int res;
 
1411
        res = daemon(maxcore, settings.verbose);
 
1412
        if (res == -1) {
 
1413
            fprintf(stderr, "failed to daemon() in order to daemonize\n");
 
1414
            return 1;
 
1415
        }
 
1416
    }
 
1417
 
 
1418
 
 
1419
    /* initialize other stuff */
 
1420
    item_init();
 
1421
    event_init();
 
1422
    stats_init();
 
1423
    assoc_init();
 
1424
    conn_init();
 
1425
    slabs_init(settings.maxbytes);
 
1426
 
 
1427
    /* lock paged memory if needed */
 
1428
    if (lock_memory) {
 
1429
#ifdef HAVE_MLOCKALL
 
1430
        mlockall(MCL_CURRENT | MCL_FUTURE);
 
1431
#else
 
1432
        fprintf(stderr, "warning: mlockall() not supported on this platform.  proceeding without.\n");
 
1433
#endif
 
1434
    }
 
1435
 
 
1436
    /*
 
1437
     * ignore SIGPIPE signals; we can use errno==EPIPE if we
 
1438
     * need that information
 
1439
     */
 
1440
    sa.sa_handler = SIG_IGN;
 
1441
    sa.sa_flags = 0;
 
1442
    if (sigemptyset(&sa.sa_mask) == -1 ||
 
1443
        sigaction(SIGPIPE, &sa, 0) == -1) {
 
1444
        perror("failed to ignore SIGPIPE; sigaction");
 
1445
        exit(1); 
 
1446
    }
 
1447
 
 
1448
    /* create the initial listening connection */
 
1449
    if (!(l_conn = conn_new(l_socket, conn_listening, EV_READ | EV_PERSIST))) {
 
1450
        fprintf(stderr, "failed to create listening connection");
 
1451
        exit(1);
 
1452
    }
 
1453
 
 
1454
    /* initialise deletion array and timer event */
 
1455
    deltotal = 200; delcurr = 0;
 
1456
    todelete = malloc(sizeof(item *)*deltotal);
 
1457
    delete_handler(0,0,0); /* sets up the event */
 
1458
 
 
1459
    /* enter the loop */
 
1460
    event_loop(0);
 
1461
 
 
1462
    return 0;
 
1463
}
 
1464