~john-koepi/ubuntu/trusty/memcached/default

1 by Jay Bonci
Import upstream version 1.1.11
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
 */
1.2.1 by Jay Bonci
Import upstream version 1.2.2
16
#include "memcached.h"
1 by Jay Bonci
Import upstream version 1.1.11
17
#include <sys/stat.h>
18
#include <sys/socket.h>
1.1.2 by Jay Bonci
Import upstream version 1.2.1
19
#include <sys/un.h>
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
20
#include <signal.h>
1 by Jay Bonci
Import upstream version 1.1.11
21
#include <sys/resource.h>
1.1.2 by Jay Bonci
Import upstream version 1.2.1
22
#include <sys/uio.h>
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
23
#include <ctype.h>
24
#include <stdarg.h>
1.1.2 by Jay Bonci
Import upstream version 1.2.1
25
1 by Jay Bonci
Import upstream version 1.1.11
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
1.1.2 by Jay Bonci
Import upstream version 1.2.1
31
/* need this to get IOV_MAX on some platforms. */
32
#ifndef __need_IOV_MAX
33
#define __need_IOV_MAX
34
#endif
1 by Jay Bonci
Import upstream version 1.1.11
35
#include <pwd.h>
36
#include <sys/mman.h>
37
#include <fcntl.h>
38
#include <netinet/tcp.h>
39
#include <arpa/inet.h>
40
#include <errno.h>
1.2.1 by Jay Bonci
Import upstream version 1.2.2
41
#include <stdlib.h>
42
#include <stdio.h>
43
#include <string.h>
1 by Jay Bonci
Import upstream version 1.1.11
44
#include <time.h>
45
#include <assert.h>
1.1.2 by Jay Bonci
Import upstream version 1.2.1
46
#include <limits.h>
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
47
#include <sysexits.h>
1.3.4 by David Martínez Moreno
Import upstream version 1.4.1
48
#include <stddef.h>
1.1.2 by Jay Bonci
Import upstream version 1.2.1
49
50
/* FreeBSD 4.x doesn't have IOV_MAX exposed. */
51
#ifndef IOV_MAX
1.2.3 by David Martínez Moreno
Import upstream version 1.2.4
52
#if defined(__FreeBSD__) || defined(__APPLE__)
1.1.2 by Jay Bonci
Import upstream version 1.2.1
53
# define IOV_MAX 1024
54
#endif
55
#endif
1.2.1 by Jay Bonci
Import upstream version 1.2.2
56
57
/*
58
 * forward declarations
59
 */
60
static void drive_machine(conn *c);
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
61
static int new_socket(struct addrinfo *ai);
1.2.1 by Jay Bonci
Import upstream version 1.2.2
62
static int try_read_command(conn *c);
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
63
64
enum try_read_result {
65
    READ_DATA_RECEIVED,
66
    READ_NO_DATA_RECEIVED,
67
    READ_ERROR,            /** an error occured (on the socket) (or client closed connection) */
68
    READ_MEMORY_ERROR      /** failed to allocate more memory */
69
};
70
71
static enum try_read_result try_read_network(conn *c);
72
static enum try_read_result try_read_udp(conn *c);
73
74
static void conn_set_state(conn *c, enum conn_states state);
1.2.1 by Jay Bonci
Import upstream version 1.2.2
75
76
/* stats */
77
static void stats_init(void);
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
78
static void server_stats(ADD_STAT add_stats, conn *c);
79
static void process_stat_settings(ADD_STAT add_stats, void *c);
80
1.2.1 by Jay Bonci
Import upstream version 1.2.2
81
82
/* defaults */
83
static void settings_init(void);
84
85
/* event handling, network IO */
86
static void event_handler(const int fd, const short which, void *arg);
87
static void conn_close(conn *c);
88
static void conn_init(void);
89
static bool update_event(conn *c, const int new_flags);
90
static void complete_nread(conn *c);
91
static void process_command(conn *c, char *command);
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
92
static void write_and_free(conn *c, char *buf, int bytes);
1.2.1 by Jay Bonci
Import upstream version 1.2.2
93
static int ensure_iov_space(conn *c);
94
static int add_iov(conn *c, const void *buf, int len);
95
static int add_msghdr(conn *c);
96
1.4.3 by David Martínez Moreno
Import upstream version 1.4.5
97
1.2.1 by Jay Bonci
Import upstream version 1.2.2
98
static void conn_free(conn *c);
99
100
/** exported globals **/
1 by Jay Bonci
Import upstream version 1.1.11
101
struct stats stats;
102
struct settings settings;
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
103
time_t process_started;     /* when the process was started */
1 by Jay Bonci
Import upstream version 1.1.11
104
1.1.11 by Scott Kitterman
Import upstream version 1.4.11
105
struct slab_rebalance slab_rebal;
106
volatile int slab_rebalance_signal;
107
1.2.1 by Jay Bonci
Import upstream version 1.2.2
108
/** file scope variables **/
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
109
static conn *listen_conn = NULL;
1.2.1 by Jay Bonci
Import upstream version 1.2.2
110
static struct event_base *main_base;
1.1.2 by Jay Bonci
Import upstream version 1.2.1
111
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
112
enum transmit_result {
113
    TRANSMIT_COMPLETE,   /** All done writing. */
114
    TRANSMIT_INCOMPLETE, /** More data remaining to write. */
115
    TRANSMIT_SOFT_ERROR, /** Can't write any more right now. */
116
    TRANSMIT_HARD_ERROR  /** Can't write (c->state is set to conn_closing) */
117
};
118
119
static enum transmit_result transmit(conn *c);
1.1.2 by Jay Bonci
Import upstream version 1.2.1
120
1.4.4 by Arno Töll
Import upstream version 1.4.7
121
/* This reduces the latency without adding lots of extra wiring to be able to
122
 * notify the listener thread of when to listen again.
123
 * Also, the clock timer could be broken out into its own thread and we
124
 * can block the listener via a condition.
125
 */
126
static volatile bool allow_new_conns = true;
127
static struct event maxconnsevent;
128
static void maxconns_handler(const int fd, const short which, void *arg) {
129
    struct timeval t = {.tv_sec = 0, .tv_usec = 10000};
130
131
    if (fd == -42 || allow_new_conns == false) {
132
        /* reschedule in 10ms if we need to keep polling */
133
        evtimer_set(&maxconnsevent, maxconns_handler, 0);
134
        event_base_set(main_base, &maxconnsevent);
135
        evtimer_add(&maxconnsevent, &t);
136
    } else {
137
        evtimer_del(&maxconnsevent);
138
        accept_new_conns(true);
139
    }
140
}
141
1.1.2 by Jay Bonci
Import upstream version 1.2.1
142
#define REALTIME_MAXDELTA 60*60*24*30
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
143
1.2.1 by Jay Bonci
Import upstream version 1.2.2
144
/*
145
 * given time value that's either unix time or delta from current unix time, return
146
 * unix time. Use the fact that delta can't exceed one month (and real time value can't
147
 * be that low).
148
 */
149
static rel_time_t realtime(const time_t exptime) {
1 by Jay Bonci
Import upstream version 1.1.11
150
    /* no. of seconds in 30 days - largest possible delta exptime */
151
152
    if (exptime == 0) return 0; /* 0 means never expire */
153
1.2.1 by Jay Bonci
Import upstream version 1.2.2
154
    if (exptime > REALTIME_MAXDELTA) {
155
        /* if item expiration is at/before the server started, give it an
156
           expiration time of 1 second after the server started.
157
           (because 0 means don't expire).  without this, we'd
158
           underflow and wrap around to some large value way in the
159
           future, effectively making items expiring in the past
160
           really expiring never */
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
161
        if (exptime <= process_started)
1.2.1 by Jay Bonci
Import upstream version 1.2.2
162
            return (rel_time_t)1;
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
163
        return (rel_time_t)(exptime - process_started);
1.2.1 by Jay Bonci
Import upstream version 1.2.2
164
    } else {
165
        return (rel_time_t)(exptime + current_time);
1 by Jay Bonci
Import upstream version 1.1.11
166
    }
167
}
168
1.2.1 by Jay Bonci
Import upstream version 1.2.2
169
static void stats_init(void) {
1 by Jay Bonci
Import upstream version 1.1.11
170
    stats.curr_items = stats.total_items = stats.curr_conns = stats.total_conns = stats.conn_structs = 0;
1.4.3 by David Martínez Moreno
Import upstream version 1.4.5
171
    stats.get_cmds = stats.set_cmds = stats.get_hits = stats.get_misses = stats.evictions = stats.reclaimed = 0;
1.1.9 by Scott Kitterman
Import upstream version 1.4.9
172
    stats.touch_cmds = stats.touch_misses = stats.touch_hits = stats.rejected_conns = 0;
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
173
    stats.curr_bytes = stats.listen_disabled_num = 0;
1.1.9 by Scott Kitterman
Import upstream version 1.4.9
174
    stats.hash_power_level = stats.hash_bytes = stats.hash_is_expanding = 0;
175
    stats.expired_unfetched = stats.evicted_unfetched = 0;
1.1.11 by Scott Kitterman
Import upstream version 1.4.11
176
    stats.slabs_moved = 0;
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
177
    stats.accepting_conns = true; /* assuming we start in this state. */
1.1.11 by Scott Kitterman
Import upstream version 1.4.11
178
    stats.slab_reassign_running = false;
1.1.2 by Jay Bonci
Import upstream version 1.2.1
179
180
    /* make the time we started always be 2 seconds before we really
181
       did, so time(0) - time.started is never zero.  if so, things
182
       like 'settings.oldest_live' which act as booleans as well as
183
       values are now false in boolean context... */
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
184
    process_started = time(0) - 2;
1.2.1 by Jay Bonci
Import upstream version 1.2.2
185
    stats_prefix_init();
1 by Jay Bonci
Import upstream version 1.1.11
186
}
187
1.2.1 by Jay Bonci
Import upstream version 1.2.2
188
static void stats_reset(void) {
189
    STATS_LOCK();
1 by Jay Bonci
Import upstream version 1.1.11
190
    stats.total_items = stats.total_conns = 0;
1.1.9 by Scott Kitterman
Import upstream version 1.4.9
191
    stats.rejected_conns = 0;
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
192
    stats.evictions = 0;
1.4.3 by David Martínez Moreno
Import upstream version 1.4.5
193
    stats.reclaimed = 0;
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
194
    stats.listen_disabled_num = 0;
1.2.1 by Jay Bonci
Import upstream version 1.2.2
195
    stats_prefix_clear();
196
    STATS_UNLOCK();
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
197
    threadlocal_stats_reset();
198
    item_stats_reset();
1 by Jay Bonci
Import upstream version 1.1.11
199
}
200
1.2.1 by Jay Bonci
Import upstream version 1.2.2
201
static void settings_init(void) {
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
202
    settings.use_cas = true;
203
    settings.access = 0700;
1 by Jay Bonci
Import upstream version 1.1.11
204
    settings.port = 11211;
1.3.2 by David Martínez Moreno
Import upstream version 1.2.8
205
    settings.udpport = 11211;
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
206
    /* By default this string should be NULL for getaddrinfo() */
207
    settings.inter = NULL;
1.2.3 by David Martínez Moreno
Import upstream version 1.2.4
208
    settings.maxbytes = 64 * 1024 * 1024; /* default is 64MB */
1 by Jay Bonci
Import upstream version 1.1.11
209
    settings.maxconns = 1024;         /* to limit connections-related memory to about 5MB */
210
    settings.verbose = 0;
211
    settings.oldest_live = 0;
212
    settings.evict_to_free = 1;       /* push old items out of cache when memory runs out */
1.1.2 by Jay Bonci
Import upstream version 1.2.1
213
    settings.socketpath = NULL;       /* by default, not using a unix socket */
214
    settings.factor = 1.25;
215
    settings.chunk_size = 48;         /* space for a modest key and value */
1.3.5 by David Martínez Moreno
Import upstream version 1.4.2
216
    settings.num_threads = 4;         /* N workers */
1.4.4 by Arno Töll
Import upstream version 1.4.7
217
    settings.num_threads_per_udp = 0;
1.2.1 by Jay Bonci
Import upstream version 1.2.2
218
    settings.prefix_delimiter = ':';
219
    settings.detail_enabled = 0;
1.3.2 by David Martínez Moreno
Import upstream version 1.2.8
220
    settings.reqs_per_event = 20;
221
    settings.backlog = 1024;
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
222
    settings.binding_protocol = negotiating_prot;
1.3.5 by David Martínez Moreno
Import upstream version 1.4.2
223
    settings.item_size_max = 1024 * 1024; /* The famous 1MB upper limit. */
1.1.9 by Scott Kitterman
Import upstream version 1.4.9
224
    settings.maxconns_fast = false;
225
    settings.hashpower_init = 0;
1.1.11 by Scott Kitterman
Import upstream version 1.4.11
226
    settings.slab_reassign = false;
227
    settings.slab_automove = false;
1.1.2 by Jay Bonci
Import upstream version 1.2.1
228
}
229
230
/*
231
 * Adds a message header to a connection.
232
 *
233
 * Returns 0 on success, -1 on out-of-memory.
234
 */
1.2.1 by Jay Bonci
Import upstream version 1.2.2
235
static int add_msghdr(conn *c)
1.1.2 by Jay Bonci
Import upstream version 1.2.1
236
{
237
    struct msghdr *msg;
238
1.2.1 by Jay Bonci
Import upstream version 1.2.2
239
    assert(c != NULL);
240
1.1.2 by Jay Bonci
Import upstream version 1.2.1
241
    if (c->msgsize == c->msgused) {
242
        msg = realloc(c->msglist, c->msgsize * 2 * sizeof(struct msghdr));
243
        if (! msg)
244
            return -1;
245
        c->msglist = msg;
246
        c->msgsize *= 2;
247
    }
248
249
    msg = c->msglist + c->msgused;
250
251
    /* this wipes msg_iovlen, msg_control, msg_controllen, and
252
       msg_flags, the last 3 of which aren't defined on solaris: */
253
    memset(msg, 0, sizeof(struct msghdr));
254
255
    msg->msg_iov = &c->iov[c->iovused];
1.2.3 by David Martínez Moreno
Import upstream version 1.2.4
256
257
    if (c->request_addr_size > 0) {
258
        msg->msg_name = &c->request_addr;
259
        msg->msg_namelen = c->request_addr_size;
260
    }
1.1.2 by Jay Bonci
Import upstream version 1.2.1
261
262
    c->msgbytes = 0;
263
    c->msgused++;
264
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
265
    if (IS_UDP(c->transport)) {
1.1.2 by Jay Bonci
Import upstream version 1.2.1
266
        /* Leave room for the UDP header, which we'll fill in later. */
267
        return add_iov(c, NULL, UDP_HEADER_SIZE);
268
    }
269
270
    return 0;
1.2.1 by Jay Bonci
Import upstream version 1.2.2
271
}
272
273
274
/*
275
 * Free list management for connections.
276
 */
277
278
static conn **freeconns;
279
static int freetotal;
280
static int freecurr;
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
281
/* Lock for connection freelist */
282
static pthread_mutex_t conn_lock = PTHREAD_MUTEX_INITIALIZER;
1.2.1 by Jay Bonci
Import upstream version 1.2.2
283
284
285
static void conn_init(void) {
1 by Jay Bonci
Import upstream version 1.1.11
286
    freetotal = 200;
287
    freecurr = 0;
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
288
    if ((freeconns = calloc(freetotal, sizeof(conn *))) == NULL) {
289
        fprintf(stderr, "Failed to allocate connection structures\n");
1.2.1 by Jay Bonci
Import upstream version 1.2.2
290
    }
1 by Jay Bonci
Import upstream version 1.1.11
291
    return;
292
}
293
1.2.1 by Jay Bonci
Import upstream version 1.2.2
294
/*
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
295
 * Returns a connection from the freelist, if any.
1.2.1 by Jay Bonci
Import upstream version 1.2.2
296
 */
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
297
conn *conn_from_freelist() {
1 by Jay Bonci
Import upstream version 1.1.11
298
    conn *c;
299
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
300
    pthread_mutex_lock(&conn_lock);
1 by Jay Bonci
Import upstream version 1.1.11
301
    if (freecurr > 0) {
302
        c = freeconns[--freecurr];
1.2.1 by Jay Bonci
Import upstream version 1.2.2
303
    } else {
304
        c = NULL;
305
    }
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
306
    pthread_mutex_unlock(&conn_lock);
1.2.1 by Jay Bonci
Import upstream version 1.2.2
307
308
    return c;
309
}
310
311
/*
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
312
 * Adds a connection to the freelist. 0 = success.
1.2.1 by Jay Bonci
Import upstream version 1.2.2
313
 */
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
314
bool conn_add_to_freelist(conn *c) {
315
    bool ret = true;
316
    pthread_mutex_lock(&conn_lock);
1.2.1 by Jay Bonci
Import upstream version 1.2.2
317
    if (freecurr < freetotal) {
318
        freeconns[freecurr++] = c;
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
319
        ret = false;
1.2.1 by Jay Bonci
Import upstream version 1.2.2
320
    } else {
321
        /* try to enlarge free connections array */
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
322
        size_t newsize = freetotal * 2;
323
        conn **new_freeconns = realloc(freeconns, sizeof(conn *) * newsize);
1.2.1 by Jay Bonci
Import upstream version 1.2.2
324
        if (new_freeconns) {
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
325
            freetotal = newsize;
1.2.1 by Jay Bonci
Import upstream version 1.2.2
326
            freeconns = new_freeconns;
327
            freeconns[freecurr++] = c;
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
328
            ret = false;
1.2.1 by Jay Bonci
Import upstream version 1.2.2
329
        }
330
    }
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
331
    pthread_mutex_unlock(&conn_lock);
332
    return ret;
333
}
334
335
static const char *prot_text(enum protocol prot) {
336
    char *rv = "unknown";
337
    switch(prot) {
338
        case ascii_prot:
339
            rv = "ascii";
340
            break;
341
        case binary_prot:
342
            rv = "binary";
343
            break;
344
        case negotiating_prot:
345
            rv = "auto-negotiate";
346
            break;
347
    }
348
    return rv;
349
}
350
351
conn *conn_new(const int sfd, enum conn_states init_state,
352
                const int event_flags,
353
                const int read_buffer_size, enum network_transport transport,
354
                struct event_base *base) {
1.2.1 by Jay Bonci
Import upstream version 1.2.2
355
    conn *c = conn_from_freelist();
356
357
    if (NULL == c) {
1.3.2 by David Martínez Moreno
Import upstream version 1.2.8
358
        if (!(c = (conn *)calloc(1, sizeof(conn)))) {
359
            fprintf(stderr, "calloc()\n");
1.2.1 by Jay Bonci
Import upstream version 1.2.2
360
            return NULL;
1 by Jay Bonci
Import upstream version 1.1.11
361
        }
1.3.2 by David Martínez Moreno
Import upstream version 1.2.8
362
        MEMCACHED_CONN_CREATE(c);
363
1 by Jay Bonci
Import upstream version 1.1.11
364
        c->rbuf = c->wbuf = 0;
365
        c->ilist = 0;
1.2.3 by David Martínez Moreno
Import upstream version 1.2.4
366
        c->suffixlist = 0;
1.1.2 by Jay Bonci
Import upstream version 1.2.1
367
        c->iov = 0;
368
        c->msglist = 0;
369
        c->hdrbuf = 0;
370
371
        c->rsize = read_buffer_size;
372
        c->wsize = DATA_BUFFER_SIZE;
373
        c->isize = ITEM_LIST_INITIAL;
1.2.3 by David Martínez Moreno
Import upstream version 1.2.4
374
        c->suffixsize = SUFFIX_LIST_INITIAL;
1.1.2 by Jay Bonci
Import upstream version 1.2.1
375
        c->iovsize = IOV_LIST_INITIAL;
376
        c->msgsize = MSG_LIST_INITIAL;
377
        c->hdrsize = 0;
378
1.2.1 by Jay Bonci
Import upstream version 1.2.2
379
        c->rbuf = (char *)malloc((size_t)c->rsize);
380
        c->wbuf = (char *)malloc((size_t)c->wsize);
381
        c->ilist = (item **)malloc(sizeof(item *) * c->isize);
1.2.3 by David Martínez Moreno
Import upstream version 1.2.4
382
        c->suffixlist = (char **)malloc(sizeof(char *) * c->suffixsize);
1.2.1 by Jay Bonci
Import upstream version 1.2.2
383
        c->iov = (struct iovec *)malloc(sizeof(struct iovec) * c->iovsize);
384
        c->msglist = (struct msghdr *)malloc(sizeof(struct msghdr) * c->msgsize);
1.1.2 by Jay Bonci
Import upstream version 1.2.1
385
386
        if (c->rbuf == 0 || c->wbuf == 0 || c->ilist == 0 || c->iov == 0 ||
1.2.3 by David Martínez Moreno
Import upstream version 1.2.4
387
                c->msglist == 0 || c->suffixlist == 0) {
1.3.2 by David Martínez Moreno
Import upstream version 1.2.8
388
            conn_free(c);
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
389
            fprintf(stderr, "malloc()\n");
1.2.1 by Jay Bonci
Import upstream version 1.2.2
390
            return NULL;
1 by Jay Bonci
Import upstream version 1.1.11
391
        }
1.1.2 by Jay Bonci
Import upstream version 1.2.1
392
1.2.1 by Jay Bonci
Import upstream version 1.2.2
393
        STATS_LOCK();
1 by Jay Bonci
Import upstream version 1.1.11
394
        stats.conn_structs++;
1.2.1 by Jay Bonci
Import upstream version 1.2.2
395
        STATS_UNLOCK();
1 by Jay Bonci
Import upstream version 1.1.11
396
    }
397
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
398
    c->transport = transport;
399
    c->protocol = settings.binding_protocol;
400
401
    /* unix socket mode doesn't need this, so zeroed out.  but why
402
     * is this done for every command?  presumably for UDP
403
     * mode.  */
404
    if (!settings.socketpath) {
405
        c->request_addr_size = sizeof(c->request_addr);
406
    } else {
407
        c->request_addr_size = 0;
408
    }
409
1 by Jay Bonci
Import upstream version 1.1.11
410
    if (settings.verbose > 1) {
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
411
        if (init_state == conn_listening) {
412
            fprintf(stderr, "<%d server listening (%s)\n", sfd,
413
                prot_text(c->protocol));
414
        } else if (IS_UDP(transport)) {
1.1.2 by Jay Bonci
Import upstream version 1.2.1
415
            fprintf(stderr, "<%d server listening (udp)\n", sfd);
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
416
        } else if (c->protocol == negotiating_prot) {
417
            fprintf(stderr, "<%d new auto-negotiating client connection\n",
418
                    sfd);
419
        } else if (c->protocol == ascii_prot) {
420
            fprintf(stderr, "<%d new ascii client connection.\n", sfd);
421
        } else if (c->protocol == binary_prot) {
422
            fprintf(stderr, "<%d new binary client connection.\n", sfd);
423
        } else {
424
            fprintf(stderr, "<%d new unknown (%d) client connection\n",
425
                sfd, c->protocol);
426
            assert(false);
427
        }
1 by Jay Bonci
Import upstream version 1.1.11
428
    }
429
430
    c->sfd = sfd;
431
    c->state = init_state;
432
    c->rlbytes = 0;
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
433
    c->cmd = -1;
1 by Jay Bonci
Import upstream version 1.1.11
434
    c->rbytes = c->wbytes = 0;
435
    c->wcurr = c->wbuf;
436
    c->rcurr = c->rbuf;
1.1.2 by Jay Bonci
Import upstream version 1.2.1
437
    c->ritem = 0;
438
    c->icurr = c->ilist;
1.2.3 by David Martínez Moreno
Import upstream version 1.2.4
439
    c->suffixcurr = c->suffixlist;
1 by Jay Bonci
Import upstream version 1.1.11
440
    c->ileft = 0;
1.2.3 by David Martínez Moreno
Import upstream version 1.2.4
441
    c->suffixleft = 0;
1.1.2 by Jay Bonci
Import upstream version 1.2.1
442
    c->iovused = 0;
443
    c->msgcurr = 0;
444
    c->msgused = 0;
1 by Jay Bonci
Import upstream version 1.1.11
445
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
446
    c->write_and_go = init_state;
1 by Jay Bonci
Import upstream version 1.1.11
447
    c->write_and_free = 0;
448
    c->item = 0;
449
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
450
    c->noreply = false;
451
1 by Jay Bonci
Import upstream version 1.1.11
452
    event_set(&c->event, sfd, event_flags, event_handler, (void *)c);
1.2.1 by Jay Bonci
Import upstream version 1.2.2
453
    event_base_set(base, &c->event);
1 by Jay Bonci
Import upstream version 1.1.11
454
    c->ev_flags = event_flags;
455
456
    if (event_add(&c->event, 0) == -1) {
1.2.1 by Jay Bonci
Import upstream version 1.2.2
457
        if (conn_add_to_freelist(c)) {
458
            conn_free(c);
1.1.1 by Jay Bonci
Import upstream version 1.1.12
459
        }
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
460
        perror("event_add");
1.2.1 by Jay Bonci
Import upstream version 1.2.2
461
        return NULL;
1 by Jay Bonci
Import upstream version 1.1.11
462
    }
463
1.2.1 by Jay Bonci
Import upstream version 1.2.2
464
    STATS_LOCK();
1 by Jay Bonci
Import upstream version 1.1.11
465
    stats.curr_conns++;
466
    stats.total_conns++;
1.2.1 by Jay Bonci
Import upstream version 1.2.2
467
    STATS_UNLOCK();
1 by Jay Bonci
Import upstream version 1.1.11
468
1.3.2 by David Martínez Moreno
Import upstream version 1.2.8
469
    MEMCACHED_CONN_ALLOCATE(c->sfd);
470
1 by Jay Bonci
Import upstream version 1.1.11
471
    return c;
472
}
473
1.2.1 by Jay Bonci
Import upstream version 1.2.2
474
static void conn_cleanup(conn *c) {
475
    assert(c != NULL);
1 by Jay Bonci
Import upstream version 1.1.11
476
477
    if (c->item) {
1.2.1 by Jay Bonci
Import upstream version 1.2.2
478
        item_remove(c->item);
1.1.2 by Jay Bonci
Import upstream version 1.2.1
479
        c->item = 0;
1 by Jay Bonci
Import upstream version 1.1.11
480
    }
481
1.2.1 by Jay Bonci
Import upstream version 1.2.2
482
    if (c->ileft != 0) {
1 by Jay Bonci
Import upstream version 1.1.11
483
        for (; c->ileft > 0; c->ileft--,c->icurr++) {
484
            item_remove(*(c->icurr));
485
        }
486
    }
487
1.2.3 by David Martínez Moreno
Import upstream version 1.2.4
488
    if (c->suffixleft != 0) {
489
        for (; c->suffixleft > 0; c->suffixleft--, c->suffixcurr++) {
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
490
            cache_free(c->thread->suffix_cache, *(c->suffixcurr));
1.2.3 by David Martínez Moreno
Import upstream version 1.2.4
491
        }
492
    }
493
1 by Jay Bonci
Import upstream version 1.1.11
494
    if (c->write_and_free) {
495
        free(c->write_and_free);
1.1.2 by Jay Bonci
Import upstream version 1.2.1
496
        c->write_and_free = 0;
497
    }
1.4.3 by David Martínez Moreno
Import upstream version 1.4.5
498
499
    if (c->sasl_conn) {
500
        assert(settings.sasl);
501
        sasl_dispose(&c->sasl_conn);
502
        c->sasl_conn = NULL;
503
    }
1.4.4 by Arno Töll
Import upstream version 1.4.7
504
505
    if (IS_UDP(c->transport)) {
506
        conn_set_state(c, conn_read);
507
    }
1.1.2 by Jay Bonci
Import upstream version 1.2.1
508
}
509
510
/*
511
 * Frees a connection.
512
 */
1.2.1 by Jay Bonci
Import upstream version 1.2.2
513
void conn_free(conn *c) {
1.1.2 by Jay Bonci
Import upstream version 1.2.1
514
    if (c) {
1.3.2 by David Martínez Moreno
Import upstream version 1.2.8
515
        MEMCACHED_CONN_DESTROY(c);
1.1.2 by Jay Bonci
Import upstream version 1.2.1
516
        if (c->hdrbuf)
517
            free(c->hdrbuf);
518
        if (c->msglist)
519
            free(c->msglist);
520
        if (c->rbuf)
521
            free(c->rbuf);
522
        if (c->wbuf)
523
            free(c->wbuf);
524
        if (c->ilist)
525
            free(c->ilist);
1.2.3 by David Martínez Moreno
Import upstream version 1.2.4
526
        if (c->suffixlist)
527
            free(c->suffixlist);
1.1.2 by Jay Bonci
Import upstream version 1.2.1
528
        if (c->iov)
529
            free(c->iov);
530
        free(c);
531
    }
532
}
533
1.2.1 by Jay Bonci
Import upstream version 1.2.2
534
static void conn_close(conn *c) {
535
    assert(c != NULL);
536
1.1.2 by Jay Bonci
Import upstream version 1.2.1
537
    /* delete the event, the socket and the conn */
538
    event_del(&c->event);
539
540
    if (settings.verbose > 1)
541
        fprintf(stderr, "<%d connection closed.\n", c->sfd);
542
1.3.2 by David Martínez Moreno
Import upstream version 1.2.8
543
    MEMCACHED_CONN_RELEASE(c->sfd);
1.1.2 by Jay Bonci
Import upstream version 1.2.1
544
    close(c->sfd);
1.4.4 by Arno Töll
Import upstream version 1.4.7
545
    pthread_mutex_lock(&conn_lock);
546
    allow_new_conns = true;
547
    pthread_mutex_unlock(&conn_lock);
1.1.2 by Jay Bonci
Import upstream version 1.2.1
548
    conn_cleanup(c);
549
550
    /* if the connection has big buffers, just free it */
1.2.1 by Jay Bonci
Import upstream version 1.2.2
551
    if (c->rsize > READ_BUFFER_HIGHWAT || conn_add_to_freelist(c)) {
1.1.2 by Jay Bonci
Import upstream version 1.2.1
552
        conn_free(c);
1.2.1 by Jay Bonci
Import upstream version 1.2.2
553
    }
554
555
    STATS_LOCK();
1 by Jay Bonci
Import upstream version 1.1.11
556
    stats.curr_conns--;
1.2.1 by Jay Bonci
Import upstream version 1.2.2
557
    STATS_UNLOCK();
1 by Jay Bonci
Import upstream version 1.1.11
558
559
    return;
560
}
561
1.1.2 by Jay Bonci
Import upstream version 1.2.1
562
/*
563
 * Shrinks a connection's buffers if they're too big.  This prevents
564
 * periodic large "get" requests from permanently chewing lots of server
565
 * memory.
566
 *
567
 * This should only be called in between requests since it can wipe output
568
 * buffers!
569
 */
1.2.1 by Jay Bonci
Import upstream version 1.2.2
570
static void conn_shrink(conn *c) {
571
    assert(c != NULL);
572
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
573
    if (IS_UDP(c->transport))
1.1.2 by Jay Bonci
Import upstream version 1.2.1
574
        return;
575
576
    if (c->rsize > READ_BUFFER_HIGHWAT && c->rbytes < DATA_BUFFER_SIZE) {
1.2.1 by Jay Bonci
Import upstream version 1.2.2
577
        char *newbuf;
578
1.1.2 by Jay Bonci
Import upstream version 1.2.1
579
        if (c->rcurr != c->rbuf)
1.2.1 by Jay Bonci
Import upstream version 1.2.2
580
            memmove(c->rbuf, c->rcurr, (size_t)c->rbytes);
581
582
        newbuf = (char *)realloc((void *)c->rbuf, DATA_BUFFER_SIZE);
583
584
        if (newbuf) {
585
            c->rbuf = newbuf;
586
            c->rsize = DATA_BUFFER_SIZE;
587
        }
588
        /* TODO check other branch... */
1.1.2 by Jay Bonci
Import upstream version 1.2.1
589
        c->rcurr = c->rbuf;
590
    }
591
592
    if (c->isize > ITEM_LIST_HIGHWAT) {
1.2.1 by Jay Bonci
Import upstream version 1.2.2
593
        item **newbuf = (item**) realloc((void *)c->ilist, ITEM_LIST_INITIAL * sizeof(c->ilist[0]));
594
        if (newbuf) {
595
            c->ilist = newbuf;
596
            c->isize = ITEM_LIST_INITIAL;
597
        }
598
    /* TODO check error condition? */
1.1.2 by Jay Bonci
Import upstream version 1.2.1
599
    }
600
601
    if (c->msgsize > MSG_LIST_HIGHWAT) {
1.2.1 by Jay Bonci
Import upstream version 1.2.2
602
        struct msghdr *newbuf = (struct msghdr *) realloc((void *)c->msglist, MSG_LIST_INITIAL * sizeof(c->msglist[0]));
603
        if (newbuf) {
604
            c->msglist = newbuf;
605
            c->msgsize = MSG_LIST_INITIAL;
606
        }
607
    /* TODO check error condition? */
1.1.2 by Jay Bonci
Import upstream version 1.2.1
608
    }
609
610
    if (c->iovsize > IOV_LIST_HIGHWAT) {
1.2.1 by Jay Bonci
Import upstream version 1.2.2
611
        struct iovec *newbuf = (struct iovec *) realloc((void *)c->iov, IOV_LIST_INITIAL * sizeof(c->iov[0]));
612
        if (newbuf) {
613
            c->iov = newbuf;
614
            c->iovsize = IOV_LIST_INITIAL;
615
        }
616
    /* TODO check return value */
1.1.2 by Jay Bonci
Import upstream version 1.2.1
617
    }
618
}
619
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
620
/**
621
 * Convert a state name to a human readable form.
622
 */
623
static const char *state_text(enum conn_states state) {
624
    const char* const statenames[] = { "conn_listening",
625
                                       "conn_new_cmd",
626
                                       "conn_waiting",
627
                                       "conn_read",
628
                                       "conn_parse_cmd",
629
                                       "conn_write",
630
                                       "conn_nread",
631
                                       "conn_swallow",
632
                                       "conn_closing",
633
                                       "conn_mwrite" };
634
    return statenames[state];
635
}
636
1.1.2 by Jay Bonci
Import upstream version 1.2.1
637
/*
638
 * Sets a connection's current state in the state machine. Any special
639
 * processing that needs to happen on certain state transitions can
640
 * happen here.
641
 */
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
642
static void conn_set_state(conn *c, enum conn_states state) {
1.2.1 by Jay Bonci
Import upstream version 1.2.2
643
    assert(c != NULL);
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
644
    assert(state >= conn_listening && state < conn_max_state);
1.2.1 by Jay Bonci
Import upstream version 1.2.2
645
1.1.2 by Jay Bonci
Import upstream version 1.2.1
646
    if (state != c->state) {
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
647
        if (settings.verbose > 2) {
648
            fprintf(stderr, "%d: going from %s to %s\n",
649
                    c->sfd, state_text(c->state),
650
                    state_text(state));
1.1.2 by Jay Bonci
Import upstream version 1.2.1
651
        }
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
652
653
        if (state == conn_write || state == conn_mwrite) {
1.3.2 by David Martínez Moreno
Import upstream version 1.2.8
654
            MEMCACHED_PROCESS_COMMAND_END(c->sfd, c->wbuf, c->wbytes);
655
        }
1.4.4 by Arno Töll
Import upstream version 1.4.7
656
        c->state = state;
1.1.2 by Jay Bonci
Import upstream version 1.2.1
657
    }
658
}
659
1.2.3 by David Martínez Moreno
Import upstream version 1.2.4
660
/*
1.1.2 by Jay Bonci
Import upstream version 1.2.1
661
 * Ensures that there is room for another struct iovec in a connection's
662
 * iov list.
663
 *
664
 * Returns 0 on success, -1 on out-of-memory.
665
 */
1.2.1 by Jay Bonci
Import upstream version 1.2.2
666
static int ensure_iov_space(conn *c) {
667
    assert(c != NULL);
668
1.1.2 by Jay Bonci
Import upstream version 1.2.1
669
    if (c->iovused >= c->iovsize) {
670
        int i, iovnum;
1.2.1 by Jay Bonci
Import upstream version 1.2.2
671
        struct iovec *new_iov = (struct iovec *)realloc(c->iov,
1.1.2 by Jay Bonci
Import upstream version 1.2.1
672
                                (c->iovsize * 2) * sizeof(struct iovec));
673
        if (! new_iov)
674
            return -1;
675
        c->iov = new_iov;
676
        c->iovsize *= 2;
677
678
        /* Point all the msghdr structures at the new list. */
679
        for (i = 0, iovnum = 0; i < c->msgused; i++) {
680
            c->msglist[i].msg_iov = &c->iov[iovnum];
681
            iovnum += c->msglist[i].msg_iovlen;
682
        }
683
    }
684
685
    return 0;
686
}
687
688
689
/*
690
 * Adds data to the list of pending data that will be written out to a
691
 * connection.
692
 *
693
 * Returns 0 on success, -1 on out-of-memory.
694
 */
695
1.2.1 by Jay Bonci
Import upstream version 1.2.2
696
static int add_iov(conn *c, const void *buf, int len) {
1.1.2 by Jay Bonci
Import upstream version 1.2.1
697
    struct msghdr *m;
698
    int leftover;
1.2.1 by Jay Bonci
Import upstream version 1.2.2
699
    bool limit_to_mtu;
700
701
    assert(c != NULL);
1.1.2 by Jay Bonci
Import upstream version 1.2.1
702
703
    do {
704
        m = &c->msglist[c->msgused - 1];
705
706
        /*
707
         * Limit UDP packets, and the first payloads of TCP replies, to
708
         * UDP_MAX_PAYLOAD_SIZE bytes.
709
         */
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
710
        limit_to_mtu = IS_UDP(c->transport) || (1 == c->msgused);
1.1.2 by Jay Bonci
Import upstream version 1.2.1
711
712
        /* We may need to start a new msghdr if this one is full. */
713
        if (m->msg_iovlen == IOV_MAX ||
714
            (limit_to_mtu && c->msgbytes >= UDP_MAX_PAYLOAD_SIZE)) {
715
            add_msghdr(c);
716
            m = &c->msglist[c->msgused - 1];
717
        }
718
1.2.1 by Jay Bonci
Import upstream version 1.2.2
719
        if (ensure_iov_space(c) != 0)
1.1.2 by Jay Bonci
Import upstream version 1.2.1
720
            return -1;
721
722
        /* If the fragment is too big to fit in the datagram, split it up */
723
        if (limit_to_mtu && len + c->msgbytes > UDP_MAX_PAYLOAD_SIZE) {
724
            leftover = len + c->msgbytes - UDP_MAX_PAYLOAD_SIZE;
725
            len -= leftover;
726
        } else {
727
            leftover = 0;
728
        }
729
730
        m = &c->msglist[c->msgused - 1];
1.2.1 by Jay Bonci
Import upstream version 1.2.2
731
        m->msg_iov[m->msg_iovlen].iov_base = (void *)buf;
1.1.2 by Jay Bonci
Import upstream version 1.2.1
732
        m->msg_iov[m->msg_iovlen].iov_len = len;
733
734
        c->msgbytes += len;
735
        c->iovused++;
736
        m->msg_iovlen++;
737
738
        buf = ((char *)buf) + len;
739
        len = leftover;
740
    } while (leftover > 0);
741
742
    return 0;
743
}
744
745
746
/*
747
 * Constructs a set of UDP headers and attaches them to the outgoing messages.
748
 */
1.2.1 by Jay Bonci
Import upstream version 1.2.2
749
static int build_udp_headers(conn *c) {
1.1.2 by Jay Bonci
Import upstream version 1.2.1
750
    int i;
751
    unsigned char *hdr;
752
1.2.1 by Jay Bonci
Import upstream version 1.2.2
753
    assert(c != NULL);
754
1.1.2 by Jay Bonci
Import upstream version 1.2.1
755
    if (c->msgused > c->hdrsize) {
756
        void *new_hdrbuf;
757
        if (c->hdrbuf)
758
            new_hdrbuf = realloc(c->hdrbuf, c->msgused * 2 * UDP_HEADER_SIZE);
759
        else
760
            new_hdrbuf = malloc(c->msgused * 2 * UDP_HEADER_SIZE);
761
        if (! new_hdrbuf)
762
            return -1;
1.2.1 by Jay Bonci
Import upstream version 1.2.2
763
        c->hdrbuf = (unsigned char *)new_hdrbuf;
1.1.2 by Jay Bonci
Import upstream version 1.2.1
764
        c->hdrsize = c->msgused * 2;
765
    }
766
767
    hdr = c->hdrbuf;
768
    for (i = 0; i < c->msgused; i++) {
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
769
        c->msglist[i].msg_iov[0].iov_base = (void*)hdr;
1.1.2 by Jay Bonci
Import upstream version 1.2.1
770
        c->msglist[i].msg_iov[0].iov_len = UDP_HEADER_SIZE;
771
        *hdr++ = c->request_id / 256;
772
        *hdr++ = c->request_id % 256;
773
        *hdr++ = i / 256;
774
        *hdr++ = i % 256;
775
        *hdr++ = c->msgused / 256;
776
        *hdr++ = c->msgused % 256;
777
        *hdr++ = 0;
778
        *hdr++ = 0;
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
779
        assert((void *) hdr == (caddr_t)c->msglist[i].msg_iov[0].iov_base + UDP_HEADER_SIZE);
1.1.2 by Jay Bonci
Import upstream version 1.2.1
780
    }
781
782
    return 0;
783
}
784
785
1.2.1 by Jay Bonci
Import upstream version 1.2.2
786
static void out_string(conn *c, const char *str) {
787
    size_t len;
788
789
    assert(c != NULL);
1 by Jay Bonci
Import upstream version 1.1.11
790
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
791
    if (c->noreply) {
792
        if (settings.verbose > 1)
793
            fprintf(stderr, ">%d NOREPLY %s\n", c->sfd, str);
794
        c->noreply = false;
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
795
        conn_set_state(c, conn_new_cmd);
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
796
        return;
797
    }
798
1 by Jay Bonci
Import upstream version 1.1.11
799
    if (settings.verbose > 1)
800
        fprintf(stderr, ">%d %s\n", c->sfd, str);
801
1.4.4 by Arno Töll
Import upstream version 1.4.7
802
    /* Nuke a partial output... */
803
    c->msgcurr = 0;
804
    c->msgused = 0;
805
    c->iovused = 0;
806
    add_msghdr(c);
807
1 by Jay Bonci
Import upstream version 1.1.11
808
    len = strlen(str);
1.2.1 by Jay Bonci
Import upstream version 1.2.2
809
    if ((len + 2) > c->wsize) {
1 by Jay Bonci
Import upstream version 1.1.11
810
        /* ought to be always enough. just fail for simplicity */
811
        str = "SERVER_ERROR output line too long";
812
        len = strlen(str);
813
    }
814
1.2.1 by Jay Bonci
Import upstream version 1.2.2
815
    memcpy(c->wbuf, str, len);
1.3.2 by David Martínez Moreno
Import upstream version 1.2.8
816
    memcpy(c->wbuf + len, "\r\n", 2);
1 by Jay Bonci
Import upstream version 1.1.11
817
    c->wbytes = len + 2;
818
    c->wcurr = c->wbuf;
819
1.1.2 by Jay Bonci
Import upstream version 1.2.1
820
    conn_set_state(c, conn_write);
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
821
    c->write_and_go = conn_new_cmd;
1 by Jay Bonci
Import upstream version 1.1.11
822
    return;
823
}
824
1.1.2 by Jay Bonci
Import upstream version 1.2.1
825
/*
1 by Jay Bonci
Import upstream version 1.1.11
826
 * we get here after reading the value in set/add/replace commands. The command
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
827
 * has been stored in c->cmd, and the item is ready in c->item.
1 by Jay Bonci
Import upstream version 1.1.11
828
 */
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
829
static void complete_nread_ascii(conn *c) {
1.2.1 by Jay Bonci
Import upstream version 1.2.2
830
    assert(c != NULL);
831
1 by Jay Bonci
Import upstream version 1.1.11
832
    item *it = c->item;
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
833
    int comm = c->cmd;
834
    enum store_item_type ret;
1 by Jay Bonci
Import upstream version 1.1.11
835
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
836
    pthread_mutex_lock(&c->thread->stats.mutex);
837
    c->thread->stats.slab_stats[it->slabs_clsid].set_cmds++;
838
    pthread_mutex_unlock(&c->thread->stats.mutex);
1.2.1 by Jay Bonci
Import upstream version 1.2.2
839
1.1.2 by Jay Bonci
Import upstream version 1.2.1
840
    if (strncmp(ITEM_data(it) + it->nbytes - 2, "\r\n", 2) != 0) {
841
        out_string(c, "CLIENT_ERROR bad data chunk");
1.2.1 by Jay Bonci
Import upstream version 1.2.2
842
    } else {
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
843
      ret = store_item(it, comm, c);
844
845
#ifdef ENABLE_DTRACE
846
      uint64_t cas = ITEM_get_cas(it);
847
      switch (c->cmd) {
848
      case NREAD_ADD:
849
          MEMCACHED_COMMAND_ADD(c->sfd, ITEM_key(it), it->nkey,
850
                                (ret == 1) ? it->nbytes : -1, cas);
851
          break;
852
      case NREAD_REPLACE:
853
          MEMCACHED_COMMAND_REPLACE(c->sfd, ITEM_key(it), it->nkey,
854
                                    (ret == 1) ? it->nbytes : -1, cas);
855
          break;
856
      case NREAD_APPEND:
857
          MEMCACHED_COMMAND_APPEND(c->sfd, ITEM_key(it), it->nkey,
858
                                   (ret == 1) ? it->nbytes : -1, cas);
859
          break;
860
      case NREAD_PREPEND:
861
          MEMCACHED_COMMAND_PREPEND(c->sfd, ITEM_key(it), it->nkey,
862
                                    (ret == 1) ? it->nbytes : -1, cas);
863
          break;
864
      case NREAD_SET:
865
          MEMCACHED_COMMAND_SET(c->sfd, ITEM_key(it), it->nkey,
866
                                (ret == 1) ? it->nbytes : -1, cas);
867
          break;
868
      case NREAD_CAS:
869
          MEMCACHED_COMMAND_CAS(c->sfd, ITEM_key(it), it->nkey, it->nbytes,
870
                                cas);
871
          break;
872
      }
873
#endif
874
875
      switch (ret) {
876
      case STORED:
1.2.3 by David Martínez Moreno
Import upstream version 1.2.4
877
          out_string(c, "STORED");
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
878
          break;
879
      case EXISTS:
1.2.3 by David Martínez Moreno
Import upstream version 1.2.4
880
          out_string(c, "EXISTS");
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
881
          break;
882
      case NOT_FOUND:
1.2.3 by David Martínez Moreno
Import upstream version 1.2.4
883
          out_string(c, "NOT_FOUND");
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
884
          break;
885
      case NOT_STORED:
1.2.3 by David Martínez Moreno
Import upstream version 1.2.4
886
          out_string(c, "NOT_STORED");
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
887
          break;
888
      default:
889
          out_string(c, "SERVER_ERROR Unhandled storage type.");
890
      }
891
892
    }
893
894
    item_remove(c->item);       /* release the c->item reference */
895
    c->item = 0;
896
}
897
898
/**
899
 * get a pointer to the start of the request struct for the current command
900
 */
901
static void* binary_get_request(conn *c) {
902
    char *ret = c->rcurr;
903
    ret -= (sizeof(c->binary_header) + c->binary_header.request.keylen +
904
            c->binary_header.request.extlen);
905
906
    assert(ret >= c->rbuf);
907
    return ret;
908
}
909
910
/**
911
 * get a pointer to the key in this request
912
 */
913
static char* binary_get_key(conn *c) {
914
    return c->rcurr - (c->binary_header.request.keylen);
915
}
916
917
static void add_bin_header(conn *c, uint16_t err, uint8_t hdr_len, uint16_t key_len, uint32_t body_len) {
918
    protocol_binary_response_header* header;
919
920
    assert(c);
921
922
    c->msgcurr = 0;
923
    c->msgused = 0;
924
    c->iovused = 0;
925
    if (add_msghdr(c) != 0) {
926
        /* XXX:  out_string is inappropriate here */
927
        out_string(c, "SERVER_ERROR out of memory");
928
        return;
929
    }
930
931
    header = (protocol_binary_response_header *)c->wbuf;
932
933
    header->response.magic = (uint8_t)PROTOCOL_BINARY_RES;
934
    header->response.opcode = c->binary_header.request.opcode;
935
    header->response.keylen = (uint16_t)htons(key_len);
936
937
    header->response.extlen = (uint8_t)hdr_len;
938
    header->response.datatype = (uint8_t)PROTOCOL_BINARY_RAW_BYTES;
939
    header->response.status = (uint16_t)htons(err);
940
941
    header->response.bodylen = htonl(body_len);
942
    header->response.opaque = c->opaque;
1.3.5 by David Martínez Moreno
Import upstream version 1.4.2
943
    header->response.cas = htonll(c->cas);
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
944
945
    if (settings.verbose > 1) {
946
        int ii;
947
        fprintf(stderr, ">%d Writing bin response:", c->sfd);
948
        for (ii = 0; ii < sizeof(header->bytes); ++ii) {
949
            if (ii % 4 == 0) {
950
                fprintf(stderr, "\n>%d  ", c->sfd);
951
            }
952
            fprintf(stderr, " 0x%02x", header->bytes[ii]);
953
        }
954
        fprintf(stderr, "\n");
955
    }
956
957
    add_iov(c, c->wbuf, sizeof(header->response));
958
}
959
960
static void write_bin_error(conn *c, protocol_binary_response_status err, int swallow) {
961
    const char *errstr = "Unknown error";
962
    size_t len;
963
964
    switch (err) {
965
    case PROTOCOL_BINARY_RESPONSE_ENOMEM:
966
        errstr = "Out of memory";
967
        break;
968
    case PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND:
969
        errstr = "Unknown command";
970
        break;
971
    case PROTOCOL_BINARY_RESPONSE_KEY_ENOENT:
972
        errstr = "Not found";
973
        break;
974
    case PROTOCOL_BINARY_RESPONSE_EINVAL:
975
        errstr = "Invalid arguments";
976
        break;
977
    case PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS:
978
        errstr = "Data exists for key.";
979
        break;
980
    case PROTOCOL_BINARY_RESPONSE_E2BIG:
981
        errstr = "Too large.";
982
        break;
983
    case PROTOCOL_BINARY_RESPONSE_DELTA_BADVAL:
984
        errstr = "Non-numeric server-side value for incr or decr";
985
        break;
986
    case PROTOCOL_BINARY_RESPONSE_NOT_STORED:
987
        errstr = "Not stored.";
988
        break;
1.4.3 by David Martínez Moreno
Import upstream version 1.4.5
989
    case PROTOCOL_BINARY_RESPONSE_AUTH_ERROR:
990
        errstr = "Auth failure.";
991
        break;
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
992
    default:
993
        assert(false);
994
        errstr = "UNHANDLED ERROR";
995
        fprintf(stderr, ">%d UNHANDLED ERROR: %d\n", c->sfd, err);
996
    }
997
1.3.5 by David Martínez Moreno
Import upstream version 1.4.2
998
    if (settings.verbose > 1) {
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
999
        fprintf(stderr, ">%d Writing an error: %s\n", c->sfd, errstr);
1000
    }
1001
1002
    len = strlen(errstr);
1003
    add_bin_header(c, err, 0, 0, len);
1004
    if (len > 0) {
1005
        add_iov(c, errstr, len);
1006
    }
1007
    conn_set_state(c, conn_mwrite);
1008
    if(swallow > 0) {
1009
        c->sbytes = swallow;
1010
        c->write_and_go = conn_swallow;
1011
    } else {
1012
        c->write_and_go = conn_new_cmd;
1013
    }
1014
}
1015
1016
/* Form and send a response to a command over the binary protocol */
1017
static void write_bin_response(conn *c, void *d, int hlen, int keylen, int dlen) {
1018
    if (!c->noreply || c->cmd == PROTOCOL_BINARY_CMD_GET ||
1019
        c->cmd == PROTOCOL_BINARY_CMD_GETK) {
1020
        add_bin_header(c, 0, hlen, keylen, dlen);
1021
        if(dlen > 0) {
1022
            add_iov(c, d, dlen);
1023
        }
1024
        conn_set_state(c, conn_mwrite);
1025
        c->write_and_go = conn_new_cmd;
1026
    } else {
1027
        conn_set_state(c, conn_new_cmd);
1028
    }
1029
}
1030
1031
static void complete_incr_bin(conn *c) {
1032
    item *it;
1033
    char *key;
1034
    size_t nkey;
1.4.4 by Arno Töll
Import upstream version 1.4.7
1035
    /* Weird magic in add_delta forces me to pad here */
1036
    char tmpbuf[INCR_MAX_STORAGE_LEN];
1037
    uint64_t cas = 0;
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
1038
1039
    protocol_binary_response_incr* rsp = (protocol_binary_response_incr*)c->wbuf;
1040
    protocol_binary_request_incr* req = binary_get_request(c);
1041
1042
    assert(c != NULL);
1043
    assert(c->wsize >= sizeof(*rsp));
1044
1045
    /* fix byteorder in the request */
1.3.5 by David Martínez Moreno
Import upstream version 1.4.2
1046
    req->message.body.delta = ntohll(req->message.body.delta);
1047
    req->message.body.initial = ntohll(req->message.body.initial);
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
1048
    req->message.body.expiration = ntohl(req->message.body.expiration);
1049
    key = binary_get_key(c);
1050
    nkey = c->binary_header.request.keylen;
1051
1.3.5 by David Martínez Moreno
Import upstream version 1.4.2
1052
    if (settings.verbose > 1) {
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
1053
        int i;
1054
        fprintf(stderr, "incr ");
1055
1056
        for (i = 0; i < nkey; i++) {
1057
            fprintf(stderr, "%c", key[i]);
1058
        }
1059
        fprintf(stderr, " %lld, %llu, %d\n",
1060
                (long long)req->message.body.delta,
1061
                (long long)req->message.body.initial,
1062
                req->message.body.expiration);
1063
    }
1064
1.4.4 by Arno Töll
Import upstream version 1.4.7
1065
    if (c->binary_header.request.cas != 0) {
1066
        cas = c->binary_header.request.cas;
1067
    }
1068
    switch(add_delta(c, key, nkey, c->cmd == PROTOCOL_BINARY_CMD_INCREMENT,
1069
                     req->message.body.delta, tmpbuf,
1070
                     &cas)) {
1071
    case OK:
1072
        rsp->message.body.value = htonll(strtoull(tmpbuf, NULL, 10));
1073
        if (cas) {
1074
            c->cas = cas;
1075
        }
1076
        write_bin_response(c, &rsp->message.body, 0, 0,
1077
                           sizeof(rsp->message.body.value));
1078
        break;
1079
    case NON_NUMERIC:
1080
        write_bin_error(c, PROTOCOL_BINARY_RESPONSE_DELTA_BADVAL, 0);
1081
        break;
1082
    case EOM:
1083
        write_bin_error(c, PROTOCOL_BINARY_RESPONSE_ENOMEM, 0);
1084
        break;
1085
    case DELTA_ITEM_NOT_FOUND:
1086
        if (req->message.body.expiration != 0xffffffff) {
1087
            /* Save some room for the response */
1088
            rsp->message.body.value = htonll(req->message.body.initial);
1089
            it = item_alloc(key, nkey, 0, realtime(req->message.body.expiration),
1090
                            INCR_MAX_STORAGE_LEN);
1091
1092
            if (it != NULL) {
1093
                snprintf(ITEM_data(it), INCR_MAX_STORAGE_LEN, "%llu",
1094
                         (unsigned long long)req->message.body.initial);
1095
1096
                if (store_item(it, NREAD_ADD, c)) {
1097
                    c->cas = ITEM_get_cas(it);
1098
                    write_bin_response(c, &rsp->message.body, 0, 0, sizeof(rsp->message.body.value));
1099
                } else {
1100
                    write_bin_error(c, PROTOCOL_BINARY_RESPONSE_NOT_STORED, 0);
1101
                }
1102
                item_remove(it);         /* release our reference */
1103
            } else {
1104
                write_bin_error(c, PROTOCOL_BINARY_RESPONSE_ENOMEM, 0);
1105
            }
1106
        } else {
1107
            pthread_mutex_lock(&c->thread->stats.mutex);
1108
            if (c->cmd == PROTOCOL_BINARY_CMD_INCREMENT) {
1109
                c->thread->stats.incr_misses++;
1110
            } else {
1111
                c->thread->stats.decr_misses++;
1112
            }
1113
            pthread_mutex_unlock(&c->thread->stats.mutex);
1114
1115
            write_bin_error(c, PROTOCOL_BINARY_RESPONSE_KEY_ENOENT, 0);
1116
        }
1117
        break;
1118
    case DELTA_ITEM_CAS_MISMATCH:
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
1119
        write_bin_error(c, PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS, 0);
1.4.4 by Arno Töll
Import upstream version 1.4.7
1120
        break;
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
1121
    }
1122
}
1123
1124
static void complete_update_bin(conn *c) {
1125
    protocol_binary_response_status eno = PROTOCOL_BINARY_RESPONSE_EINVAL;
1126
    enum store_item_type ret = NOT_STORED;
1127
    assert(c != NULL);
1128
1129
    item *it = c->item;
1130
1131
    pthread_mutex_lock(&c->thread->stats.mutex);
1132
    c->thread->stats.slab_stats[it->slabs_clsid].set_cmds++;
1133
    pthread_mutex_unlock(&c->thread->stats.mutex);
1134
1135
    /* We don't actually receive the trailing two characters in the bin
1136
     * protocol, so we're going to just set them here */
1137
    *(ITEM_data(it) + it->nbytes - 2) = '\r';
1138
    *(ITEM_data(it) + it->nbytes - 1) = '\n';
1139
1140
    ret = store_item(it, c->cmd, c);
1141
1142
#ifdef ENABLE_DTRACE
1143
    uint64_t cas = ITEM_get_cas(it);
1144
    switch (c->cmd) {
1145
    case NREAD_ADD:
1146
        MEMCACHED_COMMAND_ADD(c->sfd, ITEM_key(it), it->nkey,
1147
                              (ret == STORED) ? it->nbytes : -1, cas);
1148
        break;
1149
    case NREAD_REPLACE:
1150
        MEMCACHED_COMMAND_REPLACE(c->sfd, ITEM_key(it), it->nkey,
1151
                                  (ret == STORED) ? it->nbytes : -1, cas);
1152
        break;
1153
    case NREAD_APPEND:
1154
        MEMCACHED_COMMAND_APPEND(c->sfd, ITEM_key(it), it->nkey,
1155
                                 (ret == STORED) ? it->nbytes : -1, cas);
1156
        break;
1157
    case NREAD_PREPEND:
1158
        MEMCACHED_COMMAND_PREPEND(c->sfd, ITEM_key(it), it->nkey,
1159
                                 (ret == STORED) ? it->nbytes : -1, cas);
1160
        break;
1161
    case NREAD_SET:
1162
        MEMCACHED_COMMAND_SET(c->sfd, ITEM_key(it), it->nkey,
1163
                              (ret == STORED) ? it->nbytes : -1, cas);
1164
        break;
1165
    }
1166
#endif
1167
1168
    switch (ret) {
1169
    case STORED:
1170
        /* Stored */
1171
        write_bin_response(c, NULL, 0, 0, 0);
1172
        break;
1173
    case EXISTS:
1174
        write_bin_error(c, PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS, 0);
1175
        break;
1176
    case NOT_FOUND:
1177
        write_bin_error(c, PROTOCOL_BINARY_RESPONSE_KEY_ENOENT, 0);
1178
        break;
1179
    case NOT_STORED:
1180
        if (c->cmd == NREAD_ADD) {
1181
            eno = PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS;
1182
        } else if(c->cmd == NREAD_REPLACE) {
1183
            eno = PROTOCOL_BINARY_RESPONSE_KEY_ENOENT;
1184
        } else {
1185
            eno = PROTOCOL_BINARY_RESPONSE_NOT_STORED;
1186
        }
1187
        write_bin_error(c, eno, 0);
1188
    }
1189
1190
    item_remove(c->item);       /* release the c->item reference */
1191
    c->item = 0;
1192
}
1193
1.1.9 by Scott Kitterman
Import upstream version 1.4.9
1194
static void process_bin_touch(conn *c) {
1195
    item *it;
1196
1197
    protocol_binary_response_get* rsp = (protocol_binary_response_get*)c->wbuf;
1198
    char* key = binary_get_key(c);
1199
    size_t nkey = c->binary_header.request.keylen;
1200
    protocol_binary_request_touch *t = (void *)&c->binary_header;
1201
    uint32_t exptime = ntohl(t->message.body.expiration);
1202
1203
    if (settings.verbose > 1) {
1204
        int ii;
1205
        /* May be GAT/GATQ/etc */
1206
        fprintf(stderr, "<%d TOUCH ", c->sfd);
1207
        for (ii = 0; ii < nkey; ++ii) {
1208
            fprintf(stderr, "%c", key[ii]);
1209
        }
1210
        fprintf(stderr, "\n");
1211
    }
1212
1213
    it = item_touch(key, nkey, realtime(exptime));
1214
1215
    if (it) {
1216
        /* the length has two unnecessary bytes ("\r\n") */
1217
        uint16_t keylen = 0;
1218
        uint32_t bodylen = sizeof(rsp->message.body) + (it->nbytes - 2);
1219
1220
        item_update(it);
1221
        pthread_mutex_lock(&c->thread->stats.mutex);
1222
        c->thread->stats.touch_cmds++;
1223
        c->thread->stats.slab_stats[it->slabs_clsid].touch_hits++;
1224
        pthread_mutex_unlock(&c->thread->stats.mutex);
1225
1226
        MEMCACHED_COMMAND_TOUCH(c->sfd, ITEM_key(it), it->nkey,
1227
                                it->nbytes, ITEM_get_cas(it));
1228
1229
        if (c->cmd == PROTOCOL_BINARY_CMD_TOUCH) {
1230
            bodylen -= it->nbytes - 2;
1231
        } else if (c->cmd == PROTOCOL_BINARY_CMD_GATK) {
1232
            bodylen += nkey;
1233
            keylen = nkey;
1234
        }
1235
1236
        add_bin_header(c, 0, sizeof(rsp->message.body), keylen, bodylen);
1237
        rsp->message.header.response.cas = htonll(ITEM_get_cas(it));
1238
1239
        // add the flags
1240
        rsp->message.body.flags = htonl(strtoul(ITEM_suffix(it), NULL, 10));
1241
        add_iov(c, &rsp->message.body, sizeof(rsp->message.body));
1242
1243
        if (c->cmd == PROTOCOL_BINARY_CMD_GATK) {
1244
            add_iov(c, ITEM_key(it), nkey);
1245
        }
1246
1247
        /* Add the data minus the CRLF */
1248
        if (c->cmd != PROTOCOL_BINARY_CMD_TOUCH) {
1249
            add_iov(c, ITEM_data(it), it->nbytes - 2);
1250
        }
1251
1252
        conn_set_state(c, conn_mwrite);
1253
        c->write_and_go = conn_new_cmd;
1254
        /* Remember this command so we can garbage collect it later */
1255
        c->item = it;
1256
    } else {
1257
        pthread_mutex_lock(&c->thread->stats.mutex);
1258
        c->thread->stats.touch_cmds++;
1259
        c->thread->stats.touch_misses++;
1260
        pthread_mutex_unlock(&c->thread->stats.mutex);
1261
1262
        MEMCACHED_COMMAND_TOUCH(c->sfd, key, nkey, -1, 0);
1263
1264
        if (c->noreply) {
1265
            conn_set_state(c, conn_new_cmd);
1266
        } else {
1267
            if (c->cmd == PROTOCOL_BINARY_CMD_GATK) {
1268
                char *ofs = c->wbuf + sizeof(protocol_binary_response_header);
1269
                add_bin_header(c, PROTOCOL_BINARY_RESPONSE_KEY_ENOENT,
1270
                        0, nkey, nkey);
1271
                memcpy(ofs, key, nkey);
1272
                add_iov(c, ofs, nkey);
1273
                conn_set_state(c, conn_mwrite);
1274
                c->write_and_go = conn_new_cmd;
1275
            } else {
1276
                write_bin_error(c, PROTOCOL_BINARY_RESPONSE_KEY_ENOENT, 0);
1277
            }
1278
        }
1279
    }
1280
1281
    if (settings.detail_enabled) {
1282
        stats_prefix_record_get(key, nkey, NULL != it);
1283
    }
1284
}
1285
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
1286
static void process_bin_get(conn *c) {
1287
    item *it;
1288
1289
    protocol_binary_response_get* rsp = (protocol_binary_response_get*)c->wbuf;
1290
    char* key = binary_get_key(c);
1291
    size_t nkey = c->binary_header.request.keylen;
1292
1.3.5 by David Martínez Moreno
Import upstream version 1.4.2
1293
    if (settings.verbose > 1) {
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
1294
        int ii;
1295
        fprintf(stderr, "<%d GET ", c->sfd);
1296
        for (ii = 0; ii < nkey; ++ii) {
1297
            fprintf(stderr, "%c", key[ii]);
1298
        }
1299
        fprintf(stderr, "\n");
1300
    }
1301
1302
    it = item_get(key, nkey);
1303
    if (it) {
1304
        /* the length has two unnecessary bytes ("\r\n") */
1305
        uint16_t keylen = 0;
1306
        uint32_t bodylen = sizeof(rsp->message.body) + (it->nbytes - 2);
1307
1.1.9 by Scott Kitterman
Import upstream version 1.4.9
1308
        item_update(it);
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
1309
        pthread_mutex_lock(&c->thread->stats.mutex);
1310
        c->thread->stats.get_cmds++;
1311
        c->thread->stats.slab_stats[it->slabs_clsid].get_hits++;
1312
        pthread_mutex_unlock(&c->thread->stats.mutex);
1313
1314
        MEMCACHED_COMMAND_GET(c->sfd, ITEM_key(it), it->nkey,
1315
                              it->nbytes, ITEM_get_cas(it));
1316
1317
        if (c->cmd == PROTOCOL_BINARY_CMD_GETK) {
1318
            bodylen += nkey;
1319
            keylen = nkey;
1320
        }
1321
        add_bin_header(c, 0, sizeof(rsp->message.body), keylen, bodylen);
1.3.5 by David Martínez Moreno
Import upstream version 1.4.2
1322
        rsp->message.header.response.cas = htonll(ITEM_get_cas(it));
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
1323
1324
        // add the flags
1325
        rsp->message.body.flags = htonl(strtoul(ITEM_suffix(it), NULL, 10));
1326
        add_iov(c, &rsp->message.body, sizeof(rsp->message.body));
1327
1328
        if (c->cmd == PROTOCOL_BINARY_CMD_GETK) {
1329
            add_iov(c, ITEM_key(it), nkey);
1330
        }
1331
1332
        /* Add the data minus the CRLF */
1333
        add_iov(c, ITEM_data(it), it->nbytes - 2);
1334
        conn_set_state(c, conn_mwrite);
1.1.9 by Scott Kitterman
Import upstream version 1.4.9
1335
        c->write_and_go = conn_new_cmd;
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
1336
        /* Remember this command so we can garbage collect it later */
1337
        c->item = it;
1338
    } else {
1339
        pthread_mutex_lock(&c->thread->stats.mutex);
1340
        c->thread->stats.get_cmds++;
1341
        c->thread->stats.get_misses++;
1342
        pthread_mutex_unlock(&c->thread->stats.mutex);
1343
1344
        MEMCACHED_COMMAND_GET(c->sfd, key, nkey, -1, 0);
1345
1346
        if (c->noreply) {
1347
            conn_set_state(c, conn_new_cmd);
1348
        } else {
1349
            if (c->cmd == PROTOCOL_BINARY_CMD_GETK) {
1350
                char *ofs = c->wbuf + sizeof(protocol_binary_response_header);
1351
                add_bin_header(c, PROTOCOL_BINARY_RESPONSE_KEY_ENOENT,
1352
                        0, nkey, nkey);
1353
                memcpy(ofs, key, nkey);
1354
                add_iov(c, ofs, nkey);
1355
                conn_set_state(c, conn_mwrite);
1.1.9 by Scott Kitterman
Import upstream version 1.4.9
1356
                c->write_and_go = conn_new_cmd;
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
1357
            } else {
1358
                write_bin_error(c, PROTOCOL_BINARY_RESPONSE_KEY_ENOENT, 0);
1359
            }
1360
        }
1361
    }
1362
1363
    if (settings.detail_enabled) {
1364
        stats_prefix_record_get(key, nkey, NULL != it);
1365
    }
1366
}
1367
1368
static void append_bin_stats(const char *key, const uint16_t klen,
1369
                             const char *val, const uint32_t vlen,
1370
                             conn *c) {
1371
    char *buf = c->stats.buffer + c->stats.offset;
1372
    uint32_t bodylen = klen + vlen;
1373
    protocol_binary_response_header header = {
1374
        .response.magic = (uint8_t)PROTOCOL_BINARY_RES,
1375
        .response.opcode = PROTOCOL_BINARY_CMD_STAT,
1376
        .response.keylen = (uint16_t)htons(klen),
1377
        .response.datatype = (uint8_t)PROTOCOL_BINARY_RAW_BYTES,
1378
        .response.bodylen = htonl(bodylen),
1379
        .response.opaque = c->opaque
1380
    };
1381
1382
    memcpy(buf, header.bytes, sizeof(header.response));
1383
    buf += sizeof(header.response);
1384
1385
    if (klen > 0) {
1386
        memcpy(buf, key, klen);
1387
        buf += klen;
1388
1389
        if (vlen > 0) {
1390
            memcpy(buf, val, vlen);
1391
        }
1392
    }
1393
1394
    c->stats.offset += sizeof(header.response) + bodylen;
1395
}
1396
1397
static void append_ascii_stats(const char *key, const uint16_t klen,
1398
                               const char *val, const uint32_t vlen,
1399
                               conn *c) {
1400
    char *pos = c->stats.buffer + c->stats.offset;
1.3.4 by David Martínez Moreno
Import upstream version 1.4.1
1401
    uint32_t nbytes = 0;
1402
    int remaining = c->stats.size - c->stats.offset;
1403
    int room = remaining - 1;
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
1404
1405
    if (klen == 0 && vlen == 0) {
1.3.4 by David Martínez Moreno
Import upstream version 1.4.1
1406
        nbytes = snprintf(pos, room, "END\r\n");
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
1407
    } else if (vlen == 0) {
1.3.4 by David Martínez Moreno
Import upstream version 1.4.1
1408
        nbytes = snprintf(pos, room, "STAT %s\r\n", key);
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
1409
    } else {
1.3.4 by David Martínez Moreno
Import upstream version 1.4.1
1410
        nbytes = snprintf(pos, room, "STAT %s %s\r\n", key, val);
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
1411
    }
1412
1413
    c->stats.offset += nbytes;
1414
}
1415
1416
static bool grow_stats_buf(conn *c, size_t needed) {
1417
    size_t nsize = c->stats.size;
1418
    size_t available = nsize - c->stats.offset;
1419
    bool rv = true;
1420
1421
    /* Special case: No buffer -- need to allocate fresh */
1422
    if (c->stats.buffer == NULL) {
1423
        nsize = 1024;
1424
        available = c->stats.size = c->stats.offset = 0;
1425
    }
1426
1427
    while (needed > available) {
1428
        assert(nsize > 0);
1429
        nsize = nsize << 1;
1430
        available = nsize - c->stats.offset;
1431
    }
1432
1433
    if (nsize != c->stats.size) {
1434
        char *ptr = realloc(c->stats.buffer, nsize);
1435
        if (ptr) {
1436
            c->stats.buffer = ptr;
1437
            c->stats.size = nsize;
1438
        } else {
1439
            rv = false;
1440
        }
1441
    }
1442
1443
    return rv;
1444
}
1445
1446
static void append_stats(const char *key, const uint16_t klen,
1447
                  const char *val, const uint32_t vlen,
1448
                  const void *cookie)
1449
{
1450
    /* value without a key is invalid */
1451
    if (klen == 0 && vlen > 0) {
1452
        return ;
1453
    }
1454
1455
    conn *c = (conn*)cookie;
1456
1457
    if (c->protocol == binary_prot) {
1458
        size_t needed = vlen + klen + sizeof(protocol_binary_response_header);
1459
        if (!grow_stats_buf(c, needed)) {
1460
            return ;
1461
        }
1462
        append_bin_stats(key, klen, val, vlen, c);
1463
    } else {
1464
        size_t needed = vlen + klen + 10; // 10 == "STAT = \r\n"
1465
        if (!grow_stats_buf(c, needed)) {
1466
            return ;
1467
        }
1468
        append_ascii_stats(key, klen, val, vlen, c);
1469
    }
1470
1471
    assert(c->stats.offset <= c->stats.size);
1472
}
1473
1474
static void process_bin_stat(conn *c) {
1475
    char *subcommand = binary_get_key(c);
1476
    size_t nkey = c->binary_header.request.keylen;
1477
1.3.5 by David Martínez Moreno
Import upstream version 1.4.2
1478
    if (settings.verbose > 1) {
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
1479
        int ii;
1480
        fprintf(stderr, "<%d STATS ", c->sfd);
1481
        for (ii = 0; ii < nkey; ++ii) {
1482
            fprintf(stderr, "%c", subcommand[ii]);
1483
        }
1484
        fprintf(stderr, "\n");
1485
    }
1486
1487
    if (nkey == 0) {
1488
        /* request all statistics */
1489
        server_stats(&append_stats, c);
1490
        (void)get_stats(NULL, 0, &append_stats, c);
1491
    } else if (strncmp(subcommand, "reset", 5) == 0) {
1492
        stats_reset();
1493
    } else if (strncmp(subcommand, "settings", 8) == 0) {
1494
        process_stat_settings(&append_stats, c);
1495
    } else if (strncmp(subcommand, "detail", 6) == 0) {
1496
        char *subcmd_pos = subcommand + 6;
1497
        if (strncmp(subcmd_pos, " dump", 5) == 0) {
1498
            int len;
1499
            char *dump_buf = stats_prefix_dump(&len);
1500
            if (dump_buf == NULL || len <= 0) {
1501
                write_bin_error(c, PROTOCOL_BINARY_RESPONSE_ENOMEM, 0);
1502
                return ;
1503
            } else {
1504
                append_stats("detailed", strlen("detailed"), dump_buf, len, c);
1505
                free(dump_buf);
1506
            }
1507
        } else if (strncmp(subcmd_pos, " on", 3) == 0) {
1508
            settings.detail_enabled = 1;
1509
        } else if (strncmp(subcmd_pos, " off", 4) == 0) {
1510
            settings.detail_enabled = 0;
1511
        } else {
1512
            write_bin_error(c, PROTOCOL_BINARY_RESPONSE_KEY_ENOENT, 0);
1513
            return;
1514
        }
1515
    } else {
1516
        if (get_stats(subcommand, nkey, &append_stats, c)) {
1517
            if (c->stats.buffer == NULL) {
1518
                write_bin_error(c, PROTOCOL_BINARY_RESPONSE_ENOMEM, 0);
1519
            } else {
1520
                write_and_free(c, c->stats.buffer, c->stats.offset);
1521
                c->stats.buffer = NULL;
1522
            }
1523
        } else {
1524
            write_bin_error(c, PROTOCOL_BINARY_RESPONSE_KEY_ENOENT, 0);
1525
        }
1526
1527
        return;
1528
    }
1529
1530
    /* Append termination package and start the transfer */
1531
    append_stats(NULL, 0, NULL, 0, c);
1532
    if (c->stats.buffer == NULL) {
1533
        write_bin_error(c, PROTOCOL_BINARY_RESPONSE_ENOMEM, 0);
1534
    } else {
1535
        write_and_free(c, c->stats.buffer, c->stats.offset);
1536
        c->stats.buffer = NULL;
1537
    }
1538
}
1539
1540
static void bin_read_key(conn *c, enum bin_substates next_substate, int extra) {
1541
    assert(c);
1542
    c->substate = next_substate;
1543
    c->rlbytes = c->keylen + extra;
1.3.4 by David Martínez Moreno
Import upstream version 1.4.1
1544
1545
    /* Ok... do we have room for the extras and the key in the input buffer? */
1546
    ptrdiff_t offset = c->rcurr + sizeof(protocol_binary_request_header) - c->rbuf;
1547
    if (c->rlbytes > c->rsize - offset) {
1548
        size_t nsize = c->rsize;
1549
        size_t size = c->rlbytes + sizeof(protocol_binary_request_header);
1550
1551
        while (size > nsize) {
1552
            nsize *= 2;
1553
        }
1554
1555
        if (nsize != c->rsize) {
1.3.5 by David Martínez Moreno
Import upstream version 1.4.2
1556
            if (settings.verbose > 1) {
1.3.4 by David Martínez Moreno
Import upstream version 1.4.1
1557
                fprintf(stderr, "%d: Need to grow buffer from %lu to %lu\n",
1558
                        c->sfd, (unsigned long)c->rsize, (unsigned long)nsize);
1559
            }
1560
            char *newm = realloc(c->rbuf, nsize);
1561
            if (newm == NULL) {
1562
                if (settings.verbose) {
1563
                    fprintf(stderr, "%d: Failed to grow buffer.. closing connection\n",
1564
                            c->sfd);
1565
                }
1566
                conn_set_state(c, conn_closing);
1567
                return;
1568
            }
1569
1570
            c->rbuf= newm;
1571
            /* rcurr should point to the same offset in the packet */
1572
            c->rcurr = c->rbuf + offset - sizeof(protocol_binary_request_header);
1573
            c->rsize = nsize;
1574
        }
1575
        if (c->rbuf != c->rcurr) {
1576
            memmove(c->rbuf, c->rcurr, c->rbytes);
1577
            c->rcurr = c->rbuf;
1.3.5 by David Martínez Moreno
Import upstream version 1.4.2
1578
            if (settings.verbose > 1) {
1.3.4 by David Martínez Moreno
Import upstream version 1.4.1
1579
                fprintf(stderr, "%d: Repack input buffer\n", c->sfd);
1580
            }
1581
        }
1582
    }
1583
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
1584
    /* preserve the header in the buffer.. */
1585
    c->ritem = c->rcurr + sizeof(protocol_binary_request_header);
1586
    conn_set_state(c, conn_nread);
1587
}
1588
1.3.5 by David Martínez Moreno
Import upstream version 1.4.2
1589
/* Just write an error message and disconnect the client */
1590
static void handle_binary_protocol_error(conn *c) {
1591
    write_bin_error(c, PROTOCOL_BINARY_RESPONSE_EINVAL, 0);
1592
    if (settings.verbose) {
1593
        fprintf(stderr, "Protocol error (opcode %02x), close connection %d\n",
1594
                c->binary_header.request.opcode, c->sfd);
1595
    }
1596
    c->write_and_go = conn_closing;
1597
}
1598
1.4.3 by David Martínez Moreno
Import upstream version 1.4.5
1599
static void init_sasl_conn(conn *c) {
1600
    assert(c);
1601
    /* should something else be returned? */
1602
    if (!settings.sasl)
1603
        return;
1604
1605
    if (!c->sasl_conn) {
1606
        int result=sasl_server_new("memcached",
1.1.12 by Clint Byrum
Import upstream version 1.4.13
1607
                                   NULL,
1608
                                   my_sasl_hostname[0] ? my_sasl_hostname : NULL,
1609
                                   NULL, NULL,
1.4.3 by David Martínez Moreno
Import upstream version 1.4.5
1610
                                   NULL, 0, &c->sasl_conn);
1611
        if (result != SASL_OK) {
1612
            if (settings.verbose) {
1613
                fprintf(stderr, "Failed to initialize SASL conn.\n");
1614
            }
1615
            c->sasl_conn = NULL;
1616
        }
1617
    }
1618
}
1619
1620
static void bin_list_sasl_mechs(conn *c) {
1621
    // Guard against a disabled SASL.
1622
    if (!settings.sasl) {
1623
        write_bin_error(c, PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND,
1624
                        c->binary_header.request.bodylen
1625
                        - c->binary_header.request.keylen);
1626
        return;
1627
    }
1628
1629
    init_sasl_conn(c);
1630
    const char *result_string = NULL;
1631
    unsigned int string_length = 0;
1632
    int result=sasl_listmech(c->sasl_conn, NULL,
1633
                             "",   /* What to prepend the string with */
1634
                             " ",  /* What to separate mechanisms with */
1635
                             "",   /* What to append to the string */
1636
                             &result_string, &string_length,
1637
                             NULL);
1638
    if (result != SASL_OK) {
1639
        /* Perhaps there's a better error for this... */
1640
        if (settings.verbose) {
1641
            fprintf(stderr, "Failed to list SASL mechanisms.\n");
1642
        }
1643
        write_bin_error(c, PROTOCOL_BINARY_RESPONSE_AUTH_ERROR, 0);
1644
        return;
1645
    }
1646
    write_bin_response(c, (char*)result_string, 0, 0, string_length);
1647
}
1648
1649
static void process_bin_sasl_auth(conn *c) {
1650
    // Guard for handling disabled SASL on the server.
1651
    if (!settings.sasl) {
1652
        write_bin_error(c, PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND,
1653
                        c->binary_header.request.bodylen
1654
                        - c->binary_header.request.keylen);
1655
        return;
1656
    }
1657
1658
    assert(c->binary_header.request.extlen == 0);
1659
1660
    int nkey = c->binary_header.request.keylen;
1661
    int vlen = c->binary_header.request.bodylen - nkey;
1662
1663
    if (nkey > MAX_SASL_MECH_LEN) {
1664
        write_bin_error(c, PROTOCOL_BINARY_RESPONSE_EINVAL, vlen);
1665
        c->write_and_go = conn_swallow;
1666
        return;
1667
    }
1668
1669
    char *key = binary_get_key(c);
1670
    assert(key);
1671
1672
    item *it = item_alloc(key, nkey, 0, 0, vlen);
1673
1674
    if (it == 0) {
1675
        write_bin_error(c, PROTOCOL_BINARY_RESPONSE_ENOMEM, vlen);
1676
        c->write_and_go = conn_swallow;
1677
        return;
1678
    }
1679
1680
    c->item = it;
1681
    c->ritem = ITEM_data(it);
1682
    c->rlbytes = vlen;
1683
    conn_set_state(c, conn_nread);
1684
    c->substate = bin_reading_sasl_auth_data;
1685
}
1686
1687
static void process_bin_complete_sasl_auth(conn *c) {
1688
    assert(settings.sasl);
1689
    const char *out = NULL;
1690
    unsigned int outlen = 0;
1691
1692
    assert(c->item);
1693
    init_sasl_conn(c);
1694
1695
    int nkey = c->binary_header.request.keylen;
1696
    int vlen = c->binary_header.request.bodylen - nkey;
1697
1698
    char mech[nkey+1];
1699
    memcpy(mech, ITEM_key((item*)c->item), nkey);
1700
    mech[nkey] = 0x00;
1701
1702
    if (settings.verbose)
1703
        fprintf(stderr, "mech:  ``%s'' with %d bytes of data\n", mech, vlen);
1704
1705
    const char *challenge = vlen == 0 ? NULL : ITEM_data((item*) c->item);
1706
1707
    int result=-1;
1708
1709
    switch (c->cmd) {
1710
    case PROTOCOL_BINARY_CMD_SASL_AUTH:
1711
        result = sasl_server_start(c->sasl_conn, mech,
1712
                                   challenge, vlen,
1713
                                   &out, &outlen);
1714
        break;
1715
    case PROTOCOL_BINARY_CMD_SASL_STEP:
1716
        result = sasl_server_step(c->sasl_conn,
1717
                                  challenge, vlen,
1718
                                  &out, &outlen);
1719
        break;
1720
    default:
1721
        assert(false); /* CMD should be one of the above */
1722
        /* This code is pretty much impossible, but makes the compiler
1723
           happier */
1724
        if (settings.verbose) {
1725
            fprintf(stderr, "Unhandled command %d with challenge %s\n",
1726
                    c->cmd, challenge);
1727
        }
1728
        break;
1729
    }
1730
1731
    item_unlink(c->item);
1732
1733
    if (settings.verbose) {
1734
        fprintf(stderr, "sasl result code:  %d\n", result);
1735
    }
1736
1737
    switch(result) {
1738
    case SASL_OK:
1739
        write_bin_response(c, "Authenticated", 0, 0, strlen("Authenticated"));
1740
        pthread_mutex_lock(&c->thread->stats.mutex);
1741
        c->thread->stats.auth_cmds++;
1742
        pthread_mutex_unlock(&c->thread->stats.mutex);
1743
        break;
1744
    case SASL_CONTINUE:
1745
        add_bin_header(c, PROTOCOL_BINARY_RESPONSE_AUTH_CONTINUE, 0, 0, outlen);
1746
        if(outlen > 0) {
1747
            add_iov(c, out, outlen);
1748
        }
1749
        conn_set_state(c, conn_mwrite);
1750
        c->write_and_go = conn_new_cmd;
1751
        break;
1752
    default:
1753
        if (settings.verbose)
1754
            fprintf(stderr, "Unknown sasl response:  %d\n", result);
1755
        write_bin_error(c, PROTOCOL_BINARY_RESPONSE_AUTH_ERROR, 0);
1756
        pthread_mutex_lock(&c->thread->stats.mutex);
1757
        c->thread->stats.auth_cmds++;
1758
        c->thread->stats.auth_errors++;
1759
        pthread_mutex_unlock(&c->thread->stats.mutex);
1760
    }
1761
}
1762
1763
static bool authenticated(conn *c) {
1764
    assert(settings.sasl);
1765
    bool rv = false;
1766
1767
    switch (c->cmd) {
1768
    case PROTOCOL_BINARY_CMD_SASL_LIST_MECHS: /* FALLTHROUGH */
1769
    case PROTOCOL_BINARY_CMD_SASL_AUTH:       /* FALLTHROUGH */
1770
    case PROTOCOL_BINARY_CMD_SASL_STEP:       /* FALLTHROUGH */
1771
    case PROTOCOL_BINARY_CMD_VERSION:         /* FALLTHROUGH */
1772
        rv = true;
1773
        break;
1774
    default:
1775
        if (c->sasl_conn) {
1776
            const void *uname = NULL;
1777
            sasl_getprop(c->sasl_conn, SASL_USERNAME, &uname);
1778
            rv = uname != NULL;
1779
        }
1780
    }
1781
1782
    if (settings.verbose > 1) {
1783
        fprintf(stderr, "authenticated() in cmd 0x%02x is %s\n",
1784
                c->cmd, rv ? "true" : "false");
1785
    }
1786
1787
    return rv;
1788
}
1789
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
1790
static void dispatch_bin_command(conn *c) {
1791
    int protocol_error = 0;
1792
1793
    int extlen = c->binary_header.request.extlen;
1794
    int keylen = c->binary_header.request.keylen;
1795
    uint32_t bodylen = c->binary_header.request.bodylen;
1796
1.4.3 by David Martínez Moreno
Import upstream version 1.4.5
1797
    if (settings.sasl && !authenticated(c)) {
1798
        write_bin_error(c, PROTOCOL_BINARY_RESPONSE_AUTH_ERROR, 0);
1799
        c->write_and_go = conn_closing;
1800
        return;
1801
    }
1802
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
1803
    MEMCACHED_PROCESS_COMMAND_START(c->sfd, c->rcurr, c->rbytes);
1804
    c->noreply = true;
1.3.5 by David Martínez Moreno
Import upstream version 1.4.2
1805
1806
    /* binprot supports 16bit keys, but internals are still 8bit */
1807
    if (keylen > KEY_MAX_LENGTH) {
1808
        handle_binary_protocol_error(c);
1809
        return;
1810
    }
1811
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
1812
    switch (c->cmd) {
1813
    case PROTOCOL_BINARY_CMD_SETQ:
1814
        c->cmd = PROTOCOL_BINARY_CMD_SET;
1815
        break;
1816
    case PROTOCOL_BINARY_CMD_ADDQ:
1817
        c->cmd = PROTOCOL_BINARY_CMD_ADD;
1818
        break;
1819
    case PROTOCOL_BINARY_CMD_REPLACEQ:
1820
        c->cmd = PROTOCOL_BINARY_CMD_REPLACE;
1821
        break;
1822
    case PROTOCOL_BINARY_CMD_DELETEQ:
1823
        c->cmd = PROTOCOL_BINARY_CMD_DELETE;
1824
        break;
1825
    case PROTOCOL_BINARY_CMD_INCREMENTQ:
1826
        c->cmd = PROTOCOL_BINARY_CMD_INCREMENT;
1827
        break;
1828
    case PROTOCOL_BINARY_CMD_DECREMENTQ:
1829
        c->cmd = PROTOCOL_BINARY_CMD_DECREMENT;
1830
        break;
1831
    case PROTOCOL_BINARY_CMD_QUITQ:
1832
        c->cmd = PROTOCOL_BINARY_CMD_QUIT;
1833
        break;
1834
    case PROTOCOL_BINARY_CMD_FLUSHQ:
1835
        c->cmd = PROTOCOL_BINARY_CMD_FLUSH;
1836
        break;
1837
    case PROTOCOL_BINARY_CMD_APPENDQ:
1838
        c->cmd = PROTOCOL_BINARY_CMD_APPEND;
1839
        break;
1840
    case PROTOCOL_BINARY_CMD_PREPENDQ:
1841
        c->cmd = PROTOCOL_BINARY_CMD_PREPEND;
1842
        break;
1843
    case PROTOCOL_BINARY_CMD_GETQ:
1844
        c->cmd = PROTOCOL_BINARY_CMD_GET;
1845
        break;
1846
    case PROTOCOL_BINARY_CMD_GETKQ:
1847
        c->cmd = PROTOCOL_BINARY_CMD_GETK;
1848
        break;
1.1.9 by Scott Kitterman
Import upstream version 1.4.9
1849
    case PROTOCOL_BINARY_CMD_GATQ:
1850
        c->cmd = PROTOCOL_BINARY_CMD_GAT;
1851
        break;
1852
    case PROTOCOL_BINARY_CMD_GATKQ:
1853
        c->cmd = PROTOCOL_BINARY_CMD_GAT;
1854
        break;
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
1855
    default:
1856
        c->noreply = false;
1857
    }
1858
1859
    switch (c->cmd) {
1860
        case PROTOCOL_BINARY_CMD_VERSION:
1861
            if (extlen == 0 && keylen == 0 && bodylen == 0) {
1862
                write_bin_response(c, VERSION, 0, 0, strlen(VERSION));
1863
            } else {
1864
                protocol_error = 1;
1865
            }
1866
            break;
1867
        case PROTOCOL_BINARY_CMD_FLUSH:
1868
            if (keylen == 0 && bodylen == extlen && (extlen == 0 || extlen == 4)) {
1869
                bin_read_key(c, bin_read_flush_exptime, extlen);
1870
            } else {
1871
                protocol_error = 1;
1872
            }
1873
            break;
1874
        case PROTOCOL_BINARY_CMD_NOOP:
1875
            if (extlen == 0 && keylen == 0 && bodylen == 0) {
1876
                write_bin_response(c, NULL, 0, 0, 0);
1877
            } else {
1878
                protocol_error = 1;
1879
            }
1880
            break;
1881
        case PROTOCOL_BINARY_CMD_SET: /* FALLTHROUGH */
1882
        case PROTOCOL_BINARY_CMD_ADD: /* FALLTHROUGH */
1883
        case PROTOCOL_BINARY_CMD_REPLACE:
1884
            if (extlen == 8 && keylen != 0 && bodylen >= (keylen + 8)) {
1885
                bin_read_key(c, bin_reading_set_header, 8);
1886
            } else {
1887
                protocol_error = 1;
1888
            }
1889
            break;
1890
        case PROTOCOL_BINARY_CMD_GETQ:  /* FALLTHROUGH */
1891
        case PROTOCOL_BINARY_CMD_GET:   /* FALLTHROUGH */
1892
        case PROTOCOL_BINARY_CMD_GETKQ: /* FALLTHROUGH */
1893
        case PROTOCOL_BINARY_CMD_GETK:
1894
            if (extlen == 0 && bodylen == keylen && keylen > 0) {
1895
                bin_read_key(c, bin_reading_get_key, 0);
1896
            } else {
1897
                protocol_error = 1;
1898
            }
1899
            break;
1900
        case PROTOCOL_BINARY_CMD_DELETE:
1901
            if (keylen > 0 && extlen == 0 && bodylen == keylen) {
1902
                bin_read_key(c, bin_reading_del_header, extlen);
1903
            } else {
1904
                protocol_error = 1;
1905
            }
1906
            break;
1907
        case PROTOCOL_BINARY_CMD_INCREMENT:
1908
        case PROTOCOL_BINARY_CMD_DECREMENT:
1909
            if (keylen > 0 && extlen == 20 && bodylen == (keylen + extlen)) {
1910
                bin_read_key(c, bin_reading_incr_header, 20);
1911
            } else {
1912
                protocol_error = 1;
1913
            }
1914
            break;
1915
        case PROTOCOL_BINARY_CMD_APPEND:
1916
        case PROTOCOL_BINARY_CMD_PREPEND:
1917
            if (keylen > 0 && extlen == 0) {
1918
                bin_read_key(c, bin_reading_set_header, 0);
1919
            } else {
1920
                protocol_error = 1;
1921
            }
1922
            break;
1923
        case PROTOCOL_BINARY_CMD_STAT:
1924
            if (extlen == 0) {
1925
                bin_read_key(c, bin_reading_stat, 0);
1926
            } else {
1927
                protocol_error = 1;
1928
            }
1929
            break;
1930
        case PROTOCOL_BINARY_CMD_QUIT:
1931
            if (keylen == 0 && extlen == 0 && bodylen == 0) {
1932
                write_bin_response(c, NULL, 0, 0, 0);
1933
                c->write_and_go = conn_closing;
1.3.5 by David Martínez Moreno
Import upstream version 1.4.2
1934
                if (c->noreply) {
1935
                    conn_set_state(c, conn_closing);
1936
                }
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
1937
            } else {
1938
                protocol_error = 1;
1939
            }
1940
            break;
1.4.3 by David Martínez Moreno
Import upstream version 1.4.5
1941
        case PROTOCOL_BINARY_CMD_SASL_LIST_MECHS:
1942
            if (extlen == 0 && keylen == 0 && bodylen == 0) {
1943
                bin_list_sasl_mechs(c);
1944
            } else {
1945
                protocol_error = 1;
1946
            }
1947
            break;
1948
        case PROTOCOL_BINARY_CMD_SASL_AUTH:
1949
        case PROTOCOL_BINARY_CMD_SASL_STEP:
1950
            if (extlen == 0 && keylen != 0) {
1951
                bin_read_key(c, bin_reading_sasl_auth, 0);
1952
            } else {
1953
                protocol_error = 1;
1954
            }
1955
            break;
1.1.9 by Scott Kitterman
Import upstream version 1.4.9
1956
        case PROTOCOL_BINARY_CMD_TOUCH:
1957
        case PROTOCOL_BINARY_CMD_GAT:
1958
        case PROTOCOL_BINARY_CMD_GATQ:
1959
        case PROTOCOL_BINARY_CMD_GATK:
1960
        case PROTOCOL_BINARY_CMD_GATKQ:
1961
            if (extlen == 4 && keylen != 0) {
1962
                bin_read_key(c, bin_reading_touch_key, 4);
1963
            } else {
1964
                protocol_error = 1;
1965
            }
1966
            break;
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
1967
        default:
1968
            write_bin_error(c, PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND, bodylen);
1969
    }
1970
1.3.5 by David Martínez Moreno
Import upstream version 1.4.2
1971
    if (protocol_error)
1972
        handle_binary_protocol_error(c);
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
1973
}
1974
1975
static void process_bin_update(conn *c) {
1976
    char *key;
1977
    int nkey;
1978
    int vlen;
1979
    item *it;
1980
    protocol_binary_request_set* req = binary_get_request(c);
1981
1982
    assert(c != NULL);
1983
1984
    key = binary_get_key(c);
1985
    nkey = c->binary_header.request.keylen;
1986
1987
    /* fix byteorder in the request */
1988
    req->message.body.flags = ntohl(req->message.body.flags);
1989
    req->message.body.expiration = ntohl(req->message.body.expiration);
1990
1991
    vlen = c->binary_header.request.bodylen - (nkey + c->binary_header.request.extlen);
1992
1.3.5 by David Martínez Moreno
Import upstream version 1.4.2
1993
    if (settings.verbose > 1) {
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
1994
        int ii;
1995
        if (c->cmd == PROTOCOL_BINARY_CMD_ADD) {
1996
            fprintf(stderr, "<%d ADD ", c->sfd);
1997
        } else if (c->cmd == PROTOCOL_BINARY_CMD_SET) {
1998
            fprintf(stderr, "<%d SET ", c->sfd);
1999
        } else {
2000
            fprintf(stderr, "<%d REPLACE ", c->sfd);
2001
        }
2002
        for (ii = 0; ii < nkey; ++ii) {
2003
            fprintf(stderr, "%c", key[ii]);
2004
        }
2005
1.3.5 by David Martínez Moreno
Import upstream version 1.4.2
2006
        fprintf(stderr, " Value len is %d", vlen);
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
2007
        fprintf(stderr, "\n");
2008
    }
2009
2010
    if (settings.detail_enabled) {
2011
        stats_prefix_record_set(key, nkey);
2012
    }
2013
2014
    it = item_alloc(key, nkey, req->message.body.flags,
2015
            realtime(req->message.body.expiration), vlen+2);
2016
2017
    if (it == 0) {
2018
        if (! item_size_ok(nkey, req->message.body.flags, vlen + 2)) {
2019
            write_bin_error(c, PROTOCOL_BINARY_RESPONSE_E2BIG, vlen);
2020
        } else {
2021
            write_bin_error(c, PROTOCOL_BINARY_RESPONSE_ENOMEM, vlen);
2022
        }
2023
2024
        /* Avoid stale data persisting in cache because we failed alloc.
2025
         * Unacceptable for SET. Anywhere else too? */
2026
        if (c->cmd == PROTOCOL_BINARY_CMD_SET) {
2027
            it = item_get(key, nkey);
2028
            if (it) {
2029
                item_unlink(it);
2030
                item_remove(it);
2031
            }
2032
        }
2033
2034
        /* swallow the data line */
2035
        c->write_and_go = conn_swallow;
2036
        return;
2037
    }
2038
2039
    ITEM_set_cas(it, c->binary_header.request.cas);
2040
2041
    switch (c->cmd) {
2042
        case PROTOCOL_BINARY_CMD_ADD:
2043
            c->cmd = NREAD_ADD;
2044
            break;
2045
        case PROTOCOL_BINARY_CMD_SET:
2046
            c->cmd = NREAD_SET;
2047
            break;
2048
        case PROTOCOL_BINARY_CMD_REPLACE:
2049
            c->cmd = NREAD_REPLACE;
2050
            break;
2051
        default:
2052
            assert(0);
2053
    }
2054
2055
    if (ITEM_get_cas(it) != 0) {
2056
        c->cmd = NREAD_CAS;
2057
    }
2058
2059
    c->item = it;
2060
    c->ritem = ITEM_data(it);
2061
    c->rlbytes = vlen;
2062
    conn_set_state(c, conn_nread);
2063
    c->substate = bin_read_set_value;
2064
}
2065
2066
static void process_bin_append_prepend(conn *c) {
2067
    char *key;
2068
    int nkey;
2069
    int vlen;
2070
    item *it;
2071
2072
    assert(c != NULL);
2073
2074
    key = binary_get_key(c);
2075
    nkey = c->binary_header.request.keylen;
2076
    vlen = c->binary_header.request.bodylen - nkey;
2077
2078
    if (settings.verbose > 1) {
2079
        fprintf(stderr, "Value len is %d\n", vlen);
2080
    }
2081
2082
    if (settings.detail_enabled) {
2083
        stats_prefix_record_set(key, nkey);
2084
    }
2085
2086
    it = item_alloc(key, nkey, 0, 0, vlen+2);
2087
2088
    if (it == 0) {
2089
        if (! item_size_ok(nkey, 0, vlen + 2)) {
2090
            write_bin_error(c, PROTOCOL_BINARY_RESPONSE_E2BIG, vlen);
2091
        } else {
2092
            write_bin_error(c, PROTOCOL_BINARY_RESPONSE_ENOMEM, vlen);
2093
        }
2094
        /* swallow the data line */
2095
        c->write_and_go = conn_swallow;
2096
        return;
2097
    }
2098
2099
    ITEM_set_cas(it, c->binary_header.request.cas);
2100
2101
    switch (c->cmd) {
2102
        case PROTOCOL_BINARY_CMD_APPEND:
2103
            c->cmd = NREAD_APPEND;
2104
            break;
2105
        case PROTOCOL_BINARY_CMD_PREPEND:
2106
            c->cmd = NREAD_PREPEND;
2107
            break;
2108
        default:
2109
            assert(0);
2110
    }
2111
2112
    c->item = it;
2113
    c->ritem = ITEM_data(it);
2114
    c->rlbytes = vlen;
2115
    conn_set_state(c, conn_nread);
2116
    c->substate = bin_read_set_value;
2117
}
2118
2119
static void process_bin_flush(conn *c) {
2120
    time_t exptime = 0;
2121
    protocol_binary_request_flush* req = binary_get_request(c);
2122
2123
    if (c->binary_header.request.extlen == sizeof(req->message.body)) {
2124
        exptime = ntohl(req->message.body.expiration);
2125
    }
2126
2127
    if (exptime > 0) {
2128
        settings.oldest_live = realtime(exptime) - 1;
2129
    } else {
2130
        settings.oldest_live = current_time - 1;
2131
    }
2132
    item_flush_expired();
2133
1.3.4 by David Martínez Moreno
Import upstream version 1.4.1
2134
    pthread_mutex_lock(&c->thread->stats.mutex);
2135
    c->thread->stats.flush_cmds++;
2136
    pthread_mutex_unlock(&c->thread->stats.mutex);
2137
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
2138
    write_bin_response(c, NULL, 0, 0, 0);
2139
}
2140
2141
static void process_bin_delete(conn *c) {
2142
    item *it;
2143
2144
    protocol_binary_request_delete* req = binary_get_request(c);
2145
2146
    char* key = binary_get_key(c);
2147
    size_t nkey = c->binary_header.request.keylen;
2148
2149
    assert(c != NULL);
2150
1.3.5 by David Martínez Moreno
Import upstream version 1.4.2
2151
    if (settings.verbose > 1) {
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
2152
        fprintf(stderr, "Deleting %s\n", key);
2153
    }
2154
2155
    if (settings.detail_enabled) {
2156
        stats_prefix_record_delete(key, nkey);
2157
    }
2158
2159
    it = item_get(key, nkey);
2160
    if (it) {
1.3.5 by David Martínez Moreno
Import upstream version 1.4.2
2161
        uint64_t cas = ntohll(req->message.header.request.cas);
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
2162
        if (cas == 0 || cas == ITEM_get_cas(it)) {
2163
            MEMCACHED_COMMAND_DELETE(c->sfd, ITEM_key(it), it->nkey);
1.1.11 by Scott Kitterman
Import upstream version 1.4.11
2164
            pthread_mutex_lock(&c->thread->stats.mutex);
2165
            c->thread->stats.slab_stats[it->slabs_clsid].delete_hits++;
2166
            pthread_mutex_unlock(&c->thread->stats.mutex);
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
2167
            item_unlink(it);
2168
            write_bin_response(c, NULL, 0, 0, 0);
2169
        } else {
2170
            write_bin_error(c, PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS, 0);
2171
        }
2172
        item_remove(it);      /* release our reference */
2173
    } else {
2174
        write_bin_error(c, PROTOCOL_BINARY_RESPONSE_KEY_ENOENT, 0);
1.1.11 by Scott Kitterman
Import upstream version 1.4.11
2175
        pthread_mutex_lock(&c->thread->stats.mutex);
2176
        c->thread->stats.delete_misses++;
2177
        pthread_mutex_unlock(&c->thread->stats.mutex);
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
2178
    }
2179
}
2180
2181
static void complete_nread_binary(conn *c) {
2182
    assert(c != NULL);
2183
    assert(c->cmd >= 0);
2184
2185
    switch(c->substate) {
2186
    case bin_reading_set_header:
2187
        if (c->cmd == PROTOCOL_BINARY_CMD_APPEND ||
2188
                c->cmd == PROTOCOL_BINARY_CMD_PREPEND) {
2189
            process_bin_append_prepend(c);
2190
        } else {
2191
            process_bin_update(c);
2192
        }
2193
        break;
2194
    case bin_read_set_value:
2195
        complete_update_bin(c);
2196
        break;
2197
    case bin_reading_get_key:
2198
        process_bin_get(c);
2199
        break;
1.1.9 by Scott Kitterman
Import upstream version 1.4.9
2200
    case bin_reading_touch_key:
2201
        process_bin_touch(c);
2202
        break;
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
2203
    case bin_reading_stat:
2204
        process_bin_stat(c);
2205
        break;
2206
    case bin_reading_del_header:
2207
        process_bin_delete(c);
2208
        break;
2209
    case bin_reading_incr_header:
2210
        complete_incr_bin(c);
2211
        break;
2212
    case bin_read_flush_exptime:
2213
        process_bin_flush(c);
2214
        break;
1.4.3 by David Martínez Moreno
Import upstream version 1.4.5
2215
    case bin_reading_sasl_auth:
2216
        process_bin_sasl_auth(c);
2217
        break;
2218
    case bin_reading_sasl_auth_data:
2219
        process_bin_complete_sasl_auth(c);
2220
        break;
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
2221
    default:
2222
        fprintf(stderr, "Not handling substate %d\n", c->substate);
2223
        assert(0);
2224
    }
2225
}
2226
2227
static void reset_cmd_handler(conn *c) {
2228
    c->cmd = -1;
2229
    c->substate = bin_no_state;
2230
    if(c->item != NULL) {
2231
        item_remove(c->item);
2232
        c->item = NULL;
2233
    }
2234
    conn_shrink(c);
2235
    if (c->rbytes > 0) {
2236
        conn_set_state(c, conn_parse_cmd);
2237
    } else {
2238
        conn_set_state(c, conn_waiting);
2239
    }
2240
}
2241
2242
static void complete_nread(conn *c) {
2243
    assert(c != NULL);
2244
    assert(c->protocol == ascii_prot
2245
           || c->protocol == binary_prot);
2246
2247
    if (c->protocol == ascii_prot) {
2248
        complete_nread_ascii(c);
2249
    } else if (c->protocol == binary_prot) {
2250
        complete_nread_binary(c);
2251
    }
1.2.1 by Jay Bonci
Import upstream version 1.2.2
2252
}
2253
2254
/*
2255
 * Stores an item in the cache according to the semantics of one of the set
2256
 * commands. In threaded mode, this is protected by the cache lock.
2257
 *
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
2258
 * Returns the state of storage.
1.2.1 by Jay Bonci
Import upstream version 1.2.2
2259
 */
1.1.10 by Scott Kitterman
Import upstream version 1.4.10
2260
enum store_item_type do_store_item(item *it, int comm, conn *c, const uint32_t hv) {
1.2.1 by Jay Bonci
Import upstream version 1.2.2
2261
    char *key = ITEM_key(it);
1.1.10 by Scott Kitterman
Import upstream version 1.4.10
2262
    item *old_it = do_item_get(key, it->nkey, hv);
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
2263
    enum store_item_type stored = NOT_STORED;
1.2.1 by Jay Bonci
Import upstream version 1.2.2
2264
1.2.3 by David Martínez Moreno
Import upstream version 1.2.4
2265
    item *new_it = NULL;
2266
    int flags;
2267
1.2.1 by Jay Bonci
Import upstream version 1.2.2
2268
    if (old_it != NULL && comm == NREAD_ADD) {
2269
        /* add only adds a nonexistent item, but promote to head of LRU */
2270
        do_item_update(old_it);
1.2.3 by David Martínez Moreno
Import upstream version 1.2.4
2271
    } else if (!old_it && (comm == NREAD_REPLACE
2272
        || comm == NREAD_APPEND || comm == NREAD_PREPEND))
2273
    {
1.2.1 by Jay Bonci
Import upstream version 1.2.2
2274
        /* replace only replaces an existing value; don't store */
1.2.3 by David Martínez Moreno
Import upstream version 1.2.4
2275
    } else if (comm == NREAD_CAS) {
2276
        /* validate cas operation */
2277
        if(old_it == NULL) {
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
2278
            // LRU expired
2279
            stored = NOT_FOUND;
2280
            pthread_mutex_lock(&c->thread->stats.mutex);
2281
            c->thread->stats.cas_misses++;
2282
            pthread_mutex_unlock(&c->thread->stats.mutex);
2283
        }
2284
        else if (ITEM_get_cas(it) == ITEM_get_cas(old_it)) {
2285
            // cas validates
2286
            // it and old_it may belong to different classes.
2287
            // I'm updating the stats for the one that's getting pushed out
2288
            pthread_mutex_lock(&c->thread->stats.mutex);
2289
            c->thread->stats.slab_stats[old_it->slabs_clsid].cas_hits++;
2290
            pthread_mutex_unlock(&c->thread->stats.mutex);
2291
1.1.10 by Scott Kitterman
Import upstream version 1.4.10
2292
            item_replace(old_it, it, hv);
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
2293
            stored = STORED;
2294
        } else {
2295
            pthread_mutex_lock(&c->thread->stats.mutex);
2296
            c->thread->stats.slab_stats[old_it->slabs_clsid].cas_badval++;
2297
            pthread_mutex_unlock(&c->thread->stats.mutex);
2298
2299
            if(settings.verbose > 1) {
2300
                fprintf(stderr, "CAS:  failure: expected %llu, got %llu\n",
2301
                        (unsigned long long)ITEM_get_cas(old_it),
2302
                        (unsigned long long)ITEM_get_cas(it));
2303
            }
2304
            stored = EXISTS;
1.2.3 by David Martínez Moreno
Import upstream version 1.2.4
2305
        }
1.2.1 by Jay Bonci
Import upstream version 1.2.2
2306
    } else {
1.2.3 by David Martínez Moreno
Import upstream version 1.2.4
2307
        /*
2308
         * Append - combine new and old record into single one. Here it's
2309
         * atomic and thread-safe.
2310
         */
2311
        if (comm == NREAD_APPEND || comm == NREAD_PREPEND) {
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
2312
            /*
2313
             * Validate CAS
2314
             */
2315
            if (ITEM_get_cas(it) != 0) {
2316
                // CAS much be equal
2317
                if (ITEM_get_cas(it) != ITEM_get_cas(old_it)) {
2318
                    stored = EXISTS;
2319
                }
2320
            }
2321
2322
            if (stored == NOT_STORED) {
2323
                /* we have it and old_it here - alloc memory to hold both */
2324
                /* flags was already lost - so recover them from ITEM_suffix(it) */
2325
2326
                flags = (int) strtol(ITEM_suffix(old_it), (char **) NULL, 10);
2327
1.1.10 by Scott Kitterman
Import upstream version 1.4.10
2328
                new_it = item_alloc(key, it->nkey, flags, old_it->exptime, it->nbytes + old_it->nbytes - 2 /* CRLF */);
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
2329
2330
                if (new_it == NULL) {
2331
                    /* SERVER_ERROR out of memory */
2332
                    if (old_it != NULL)
2333
                        do_item_remove(old_it);
2334
2335
                    return NOT_STORED;
2336
                }
2337
2338
                /* copy data from it and old_it to new_it */
2339
2340
                if (comm == NREAD_APPEND) {
2341
                    memcpy(ITEM_data(new_it), ITEM_data(old_it), old_it->nbytes);
2342
                    memcpy(ITEM_data(new_it) + old_it->nbytes - 2 /* CRLF */, ITEM_data(it), it->nbytes);
2343
                } else {
2344
                    /* NREAD_PREPEND */
2345
                    memcpy(ITEM_data(new_it), ITEM_data(it), it->nbytes);
2346
                    memcpy(ITEM_data(new_it) + it->nbytes - 2 /* CRLF */, ITEM_data(old_it), old_it->nbytes);
2347
                }
2348
2349
                it = new_it;
2350
            }
2351
        }
2352
2353
        if (stored == NOT_STORED) {
2354
            if (old_it != NULL)
1.1.10 by Scott Kitterman
Import upstream version 1.4.10
2355
                item_replace(old_it, it, hv);
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
2356
            else
1.1.10 by Scott Kitterman
Import upstream version 1.4.10
2357
                do_item_link(it, hv);
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
2358
2359
            c->cas = ITEM_get_cas(it);
2360
2361
            stored = STORED;
2362
        }
1.1.2 by Jay Bonci
Import upstream version 1.2.1
2363
    }
2364
1.2.3 by David Martínez Moreno
Import upstream version 1.2.4
2365
    if (old_it != NULL)
1.2.1 by Jay Bonci
Import upstream version 1.2.2
2366
        do_item_remove(old_it);         /* release our reference */
1.2.3 by David Martínez Moreno
Import upstream version 1.2.4
2367
    if (new_it != NULL)
2368
        do_item_remove(new_it);
2369
1.3.5 by David Martínez Moreno
Import upstream version 1.4.2
2370
    if (stored == STORED) {
2371
        c->cas = ITEM_get_cas(it);
2372
    }
2373
1.2.1 by Jay Bonci
Import upstream version 1.2.2
2374
    return stored;
1.1.2 by Jay Bonci
Import upstream version 1.2.1
2375
}
2376
2377
typedef struct token_s {
1.2.1 by Jay Bonci
Import upstream version 1.2.2
2378
    char *value;
1.1.2 by Jay Bonci
Import upstream version 1.2.1
2379
    size_t length;
2380
} token_t;
2381
2382
#define COMMAND_TOKEN 0
2383
#define SUBCOMMAND_TOKEN 1
2384
#define KEY_TOKEN 1
2385
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
2386
#define MAX_TOKENS 8
1.1.2 by Jay Bonci
Import upstream version 1.2.1
2387
2388
/*
2389
 * Tokenize the command string by replacing whitespace with '\0' and update
2390
 * the token array tokens with pointer to start of each token and length.
2391
 * Returns total number of tokens.  The last valid token is the terminal
2392
 * token (value points to the first unprocessed character of the string and
1.2.1 by Jay Bonci
Import upstream version 1.2.2
2393
 * length zero).
1.1.2 by Jay Bonci
Import upstream version 1.2.1
2394
 *
2395
 * Usage example:
2396
 *
2397
 *  while(tokenize_command(command, ncommand, tokens, max_tokens) > 0) {
2398
 *      for(int ix = 0; tokens[ix].length != 0; ix++) {
2399
 *          ...
2400
 *      }
2401
 *      ncommand = tokens[ix].value - command;
2402
 *      command  = tokens[ix].value;
2403
 *   }
2404
 */
1.2.1 by Jay Bonci
Import upstream version 1.2.2
2405
static size_t tokenize_command(char *command, token_t *tokens, const size_t max_tokens) {
2406
    char *s, *e;
1.1.2 by Jay Bonci
Import upstream version 1.2.1
2407
    size_t ntokens = 0;
1.1.10 by Scott Kitterman
Import upstream version 1.4.10
2408
    size_t len = strlen(command);
2409
    unsigned int i = 0;
1.1.2 by Jay Bonci
Import upstream version 1.2.1
2410
1.2.1 by Jay Bonci
Import upstream version 1.2.2
2411
    assert(command != NULL && tokens != NULL && max_tokens > 1);
2412
1.1.10 by Scott Kitterman
Import upstream version 1.4.10
2413
    s = e = command;
2414
    for (i = 0; i < len; i++) {
1.2.1 by Jay Bonci
Import upstream version 1.2.2
2415
        if (*e == ' ') {
2416
            if (s != e) {
2417
                tokens[ntokens].value = s;
2418
                tokens[ntokens].length = e - s;
2419
                ntokens++;
2420
                *e = '\0';
1.1.10 by Scott Kitterman
Import upstream version 1.4.10
2421
                if (ntokens == max_tokens - 1) {
2422
                    e++;
2423
                    s = e; /* so we don't add an extra token */
2424
                    break;
2425
                }
1.2.1 by Jay Bonci
Import upstream version 1.2.2
2426
            }
2427
            s = e + 1;
2428
        }
1.1.10 by Scott Kitterman
Import upstream version 1.4.10
2429
        e++;
2430
    }
1.2.1 by Jay Bonci
Import upstream version 1.2.2
2431
1.1.10 by Scott Kitterman
Import upstream version 1.4.10
2432
    if (s != e) {
2433
        tokens[ntokens].value = s;
2434
        tokens[ntokens].length = e - s;
2435
        ntokens++;
1.1.2 by Jay Bonci
Import upstream version 1.2.1
2436
    }
2437
2438
    /*
2439
     * If we scanned the whole string, the terminal value pointer is null,
2440
     * otherwise it is the first unprocessed character.
2441
     */
1.2.1 by Jay Bonci
Import upstream version 1.2.2
2442
    tokens[ntokens].value =  *e == '\0' ? NULL : e;
1.1.2 by Jay Bonci
Import upstream version 1.2.1
2443
    tokens[ntokens].length = 0;
2444
    ntokens++;
2445
2446
    return ntokens;
2447
}
2448
1.2.3 by David Martínez Moreno
Import upstream version 1.2.4
2449
/* set up a connection to write a buffer then free it, used for stats */
2450
static void write_and_free(conn *c, char *buf, int bytes) {
2451
    if (buf) {
2452
        c->write_and_free = buf;
2453
        c->wcurr = buf;
2454
        c->wbytes = bytes;
2455
        conn_set_state(c, conn_write);
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
2456
        c->write_and_go = conn_new_cmd;
1.2.3 by David Martínez Moreno
Import upstream version 1.2.4
2457
    } else {
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
2458
        out_string(c, "SERVER_ERROR out of memory writing stats");
2459
    }
2460
}
2461
1.4.3 by David Martínez Moreno
Import upstream version 1.4.5
2462
static inline bool set_noreply_maybe(conn *c, token_t *tokens, size_t ntokens)
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
2463
{
2464
    int noreply_index = ntokens - 2;
2465
2466
    /*
2467
      NOTE: this function is not the first place where we are going to
2468
      send the reply.  We could send it instead from process_command()
2469
      if the request line has wrong number of tokens.  However parsing
2470
      malformed line for "noreply" option is not reliable anyway, so
2471
      it can't be helped.
2472
    */
2473
    if (tokens[noreply_index].value
2474
        && strcmp(tokens[noreply_index].value, "noreply") == 0) {
2475
        c->noreply = true;
1.2.3 by David Martínez Moreno
Import upstream version 1.2.4
2476
    }
1.4.3 by David Martínez Moreno
Import upstream version 1.4.5
2477
    return c->noreply;
1.2.3 by David Martínez Moreno
Import upstream version 1.2.4
2478
}
2479
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
2480
void append_stat(const char *name, ADD_STAT add_stats, conn *c,
2481
                 const char *fmt, ...) {
1.3.4 by David Martínez Moreno
Import upstream version 1.4.1
2482
    char val_str[STAT_VAL_LEN];
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
2483
    int vlen;
2484
    va_list ap;
2485
2486
    assert(name);
2487
    assert(add_stats);
2488
    assert(c);
2489
    assert(fmt);
2490
2491
    va_start(ap, fmt);
2492
    vlen = vsnprintf(val_str, sizeof(val_str) - 1, fmt, ap);
2493
    va_end(ap);
2494
2495
    add_stats(name, strlen(name), val_str, vlen, c);
2496
}
2497
1.2.2 by David Martínez Moreno
Import upstream version 1.2.3
2498
inline static void process_stats_detail(conn *c, const char *command) {
1.2.1 by Jay Bonci
Import upstream version 1.2.2
2499
    assert(c != NULL);
2500
2501
    if (strcmp(command, "on") == 0) {
2502
        settings.detail_enabled = 1;
2503
        out_string(c, "OK");
2504
    }
2505
    else if (strcmp(command, "off") == 0) {
2506
        settings.detail_enabled = 0;
2507
        out_string(c, "OK");
2508
    }
2509
    else if (strcmp(command, "dump") == 0) {
2510
        int len;
2511
        char *stats = stats_prefix_dump(&len);
1.2.3 by David Martínez Moreno
Import upstream version 1.2.4
2512
        write_and_free(c, stats, len);
1.2.1 by Jay Bonci
Import upstream version 1.2.2
2513
    }
2514
    else {
2515
        out_string(c, "CLIENT_ERROR usage: stats detail on|off|dump");
2516
    }
2517
}
2518
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
2519
/* return server specific stats only */
2520
static void server_stats(ADD_STAT add_stats, conn *c) {
2521
    pid_t pid = getpid();
2522
    rel_time_t now = current_time;
2523
2524
    struct thread_stats thread_stats;
2525
    threadlocal_stats_aggregate(&thread_stats);
2526
    struct slab_stats slab_stats;
2527
    slab_stats_aggregate(&thread_stats, &slab_stats);
2528
2529
#ifndef WIN32
2530
    struct rusage usage;
2531
    getrusage(RUSAGE_SELF, &usage);
2532
#endif /* !WIN32 */
2533
2534
    STATS_LOCK();
2535
2536
    APPEND_STAT("pid", "%lu", (long)pid);
2537
    APPEND_STAT("uptime", "%u", now);
2538
    APPEND_STAT("time", "%ld", now + (long)process_started);
2539
    APPEND_STAT("version", "%s", VERSION);
1.4.4 by Arno Töll
Import upstream version 1.4.7
2540
    APPEND_STAT("libevent", "%s", event_get_version());
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
2541
    APPEND_STAT("pointer_size", "%d", (int)(8 * sizeof(void *)));
2542
2543
#ifndef WIN32
2544
    append_stat("rusage_user", add_stats, c, "%ld.%06ld",
2545
                (long)usage.ru_utime.tv_sec,
2546
                (long)usage.ru_utime.tv_usec);
2547
    append_stat("rusage_system", add_stats, c, "%ld.%06ld",
2548
                (long)usage.ru_stime.tv_sec,
2549
                (long)usage.ru_stime.tv_usec);
2550
#endif /* !WIN32 */
2551
2552
    APPEND_STAT("curr_connections", "%u", stats.curr_conns - 1);
2553
    APPEND_STAT("total_connections", "%u", stats.total_conns);
1.1.9 by Scott Kitterman
Import upstream version 1.4.9
2554
    if (settings.maxconns_fast) {
2555
        APPEND_STAT("rejected_connections", "%llu", (unsigned long long)stats.rejected_conns);
2556
    }
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
2557
    APPEND_STAT("connection_structures", "%u", stats.conn_structs);
1.1.9 by Scott Kitterman
Import upstream version 1.4.9
2558
    APPEND_STAT("reserved_fds", "%u", stats.reserved_fds);
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
2559
    APPEND_STAT("cmd_get", "%llu", (unsigned long long)thread_stats.get_cmds);
2560
    APPEND_STAT("cmd_set", "%llu", (unsigned long long)slab_stats.set_cmds);
2561
    APPEND_STAT("cmd_flush", "%llu", (unsigned long long)thread_stats.flush_cmds);
1.1.9 by Scott Kitterman
Import upstream version 1.4.9
2562
    APPEND_STAT("cmd_touch", "%llu", (unsigned long long)thread_stats.touch_cmds);
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
2563
    APPEND_STAT("get_hits", "%llu", (unsigned long long)slab_stats.get_hits);
2564
    APPEND_STAT("get_misses", "%llu", (unsigned long long)thread_stats.get_misses);
2565
    APPEND_STAT("delete_misses", "%llu", (unsigned long long)thread_stats.delete_misses);
2566
    APPEND_STAT("delete_hits", "%llu", (unsigned long long)slab_stats.delete_hits);
2567
    APPEND_STAT("incr_misses", "%llu", (unsigned long long)thread_stats.incr_misses);
2568
    APPEND_STAT("incr_hits", "%llu", (unsigned long long)slab_stats.incr_hits);
2569
    APPEND_STAT("decr_misses", "%llu", (unsigned long long)thread_stats.decr_misses);
2570
    APPEND_STAT("decr_hits", "%llu", (unsigned long long)slab_stats.decr_hits);
2571
    APPEND_STAT("cas_misses", "%llu", (unsigned long long)thread_stats.cas_misses);
2572
    APPEND_STAT("cas_hits", "%llu", (unsigned long long)slab_stats.cas_hits);
2573
    APPEND_STAT("cas_badval", "%llu", (unsigned long long)slab_stats.cas_badval);
1.1.9 by Scott Kitterman
Import upstream version 1.4.9
2574
    APPEND_STAT("touch_hits", "%llu", (unsigned long long)slab_stats.touch_hits);
2575
    APPEND_STAT("touch_misses", "%llu", (unsigned long long)thread_stats.touch_misses);
1.4.3 by David Martínez Moreno
Import upstream version 1.4.5
2576
    APPEND_STAT("auth_cmds", "%llu", (unsigned long long)thread_stats.auth_cmds);
2577
    APPEND_STAT("auth_errors", "%llu", (unsigned long long)thread_stats.auth_errors);
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
2578
    APPEND_STAT("bytes_read", "%llu", (unsigned long long)thread_stats.bytes_read);
2579
    APPEND_STAT("bytes_written", "%llu", (unsigned long long)thread_stats.bytes_written);
2580
    APPEND_STAT("limit_maxbytes", "%llu", (unsigned long long)settings.maxbytes);
2581
    APPEND_STAT("accepting_conns", "%u", stats.accepting_conns);
2582
    APPEND_STAT("listen_disabled_num", "%llu", (unsigned long long)stats.listen_disabled_num);
2583
    APPEND_STAT("threads", "%d", settings.num_threads);
2584
    APPEND_STAT("conn_yields", "%llu", (unsigned long long)thread_stats.conn_yields);
1.1.9 by Scott Kitterman
Import upstream version 1.4.9
2585
    APPEND_STAT("hash_power_level", "%u", stats.hash_power_level);
2586
    APPEND_STAT("hash_bytes", "%llu", (unsigned long long)stats.hash_bytes);
2587
    APPEND_STAT("hash_is_expanding", "%u", stats.hash_is_expanding);
2588
    APPEND_STAT("expired_unfetched", "%llu", stats.expired_unfetched);
2589
    APPEND_STAT("evicted_unfetched", "%llu", stats.evicted_unfetched);
1.1.11 by Scott Kitterman
Import upstream version 1.4.11
2590
    if (settings.slab_reassign) {
2591
        APPEND_STAT("slab_reassign_running", "%u", stats.slab_reassign_running);
2592
        APPEND_STAT("slabs_moved", "%llu", stats.slabs_moved);
2593
    }
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
2594
    STATS_UNLOCK();
2595
}
2596
2597
static void process_stat_settings(ADD_STAT add_stats, void *c) {
2598
    assert(add_stats);
2599
    APPEND_STAT("maxbytes", "%u", (unsigned int)settings.maxbytes);
2600
    APPEND_STAT("maxconns", "%d", settings.maxconns);
2601
    APPEND_STAT("tcpport", "%d", settings.port);
2602
    APPEND_STAT("udpport", "%d", settings.udpport);
2603
    APPEND_STAT("inter", "%s", settings.inter ? settings.inter : "NULL");
2604
    APPEND_STAT("verbosity", "%d", settings.verbose);
2605
    APPEND_STAT("oldest", "%lu", (unsigned long)settings.oldest_live);
2606
    APPEND_STAT("evictions", "%s", settings.evict_to_free ? "on" : "off");
2607
    APPEND_STAT("domain_socket", "%s",
2608
                settings.socketpath ? settings.socketpath : "NULL");
2609
    APPEND_STAT("umask", "%o", settings.access);
2610
    APPEND_STAT("growth_factor", "%.2f", settings.factor);
2611
    APPEND_STAT("chunk_size", "%d", settings.chunk_size);
2612
    APPEND_STAT("num_threads", "%d", settings.num_threads);
1.4.4 by Arno Töll
Import upstream version 1.4.7
2613
    APPEND_STAT("num_threads_per_udp", "%d", settings.num_threads_per_udp);
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
2614
    APPEND_STAT("stat_key_prefix", "%c", settings.prefix_delimiter);
2615
    APPEND_STAT("detail_enabled", "%s",
2616
                settings.detail_enabled ? "yes" : "no");
2617
    APPEND_STAT("reqs_per_event", "%d", settings.reqs_per_event);
2618
    APPEND_STAT("cas_enabled", "%s", settings.use_cas ? "yes" : "no");
2619
    APPEND_STAT("tcp_backlog", "%d", settings.backlog);
2620
    APPEND_STAT("binding_protocol", "%s",
2621
                prot_text(settings.binding_protocol));
1.4.3 by David Martínez Moreno
Import upstream version 1.4.5
2622
    APPEND_STAT("auth_enabled_sasl", "%s", settings.sasl ? "yes" : "no");
1.3.5 by David Martínez Moreno
Import upstream version 1.4.2
2623
    APPEND_STAT("item_size_max", "%d", settings.item_size_max);
1.1.9 by Scott Kitterman
Import upstream version 1.4.9
2624
    APPEND_STAT("maxconns_fast", "%s", settings.maxconns_fast ? "yes" : "no");
2625
    APPEND_STAT("hashpower_init", "%d", settings.hashpower_init);
1.1.11 by Scott Kitterman
Import upstream version 1.4.11
2626
    APPEND_STAT("slab_reassign", "%s", settings.slab_reassign ? "yes" : "no");
2627
    APPEND_STAT("slab_automove", "%s", settings.slab_automove ? "yes" : "no");
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
2628
}
2629
1.2.1 by Jay Bonci
Import upstream version 1.2.2
2630
static void process_stat(conn *c, token_t *tokens, const size_t ntokens) {
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
2631
    const char *subcommand = tokens[SUBCOMMAND_TOKEN].value;
1.2.1 by Jay Bonci
Import upstream version 1.2.2
2632
    assert(c != NULL);
1.1.2 by Jay Bonci
Import upstream version 1.2.1
2633
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
2634
    if (ntokens < 2) {
1.1.2 by Jay Bonci
Import upstream version 1.2.1
2635
        out_string(c, "CLIENT_ERROR bad command line");
1 by Jay Bonci
Import upstream version 1.1.11
2636
        return;
2637
    }
1.1.2 by Jay Bonci
Import upstream version 1.2.1
2638
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
2639
    if (ntokens == 2) {
2640
        server_stats(&append_stats, c);
2641
        (void)get_stats(NULL, 0, &append_stats, c);
2642
    } else if (strcmp(subcommand, "reset") == 0) {
1 by Jay Bonci
Import upstream version 1.1.11
2643
        stats_reset();
2644
        out_string(c, "RESET");
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
2645
        return ;
2646
    } else if (strcmp(subcommand, "detail") == 0) {
2647
        /* NOTE: how to tackle detail with binary? */
2648
        if (ntokens < 4)
2649
            process_stats_detail(c, "");  /* outputs the error message */
2650
        else
2651
            process_stats_detail(c, tokens[2].value);
2652
        /* Output already generated */
2653
        return ;
2654
    } else if (strcmp(subcommand, "settings") == 0) {
2655
        process_stat_settings(&append_stats, c);
2656
    } else if (strcmp(subcommand, "cachedump") == 0) {
1 by Jay Bonci
Import upstream version 1.1.11
2657
        char *buf;
2658
        unsigned int bytes, id, limit = 0;
1.1.2 by Jay Bonci
Import upstream version 1.2.1
2659
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
2660
        if (ntokens < 5) {
1 by Jay Bonci
Import upstream version 1.1.11
2661
            out_string(c, "CLIENT_ERROR bad command line");
2662
            return;
2663
        }
2664
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
2665
        if (!safe_strtoul(tokens[2].value, &id) ||
2666
            !safe_strtoul(tokens[3].value, &limit)) {
1.1.2 by Jay Bonci
Import upstream version 1.2.1
2667
            out_string(c, "CLIENT_ERROR bad command line format");
2668
            return;
2669
        }
2670
1.3.5 by David Martínez Moreno
Import upstream version 1.4.2
2671
        if (id >= POWER_LARGEST) {
2672
            out_string(c, "CLIENT_ERROR Illegal slab id");
2673
            return;
2674
        }
2675
1 by Jay Bonci
Import upstream version 1.1.11
2676
        buf = item_cachedump(id, limit, &bytes);
1.2.3 by David Martínez Moreno
Import upstream version 1.2.4
2677
        write_and_free(c, buf, bytes);
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
2678
        return ;
2679
    } else {
2680
        /* getting here means that the subcommand is either engine specific or
2681
           is invalid. query the engine and see. */
2682
        if (get_stats(subcommand, strlen(subcommand), &append_stats, c)) {
2683
            if (c->stats.buffer == NULL) {
2684
                out_string(c, "SERVER_ERROR out of memory writing stats");
2685
            } else {
2686
                write_and_free(c, c->stats.buffer, c->stats.offset);
2687
                c->stats.buffer = NULL;
2688
            }
2689
        } else {
2690
            out_string(c, "ERROR");
2691
        }
2692
        return ;
2693
    }
2694
2695
    /* append terminator and start the transfer */
2696
    append_stats(NULL, 0, NULL, 0, c);
2697
2698
    if (c->stats.buffer == NULL) {
2699
        out_string(c, "SERVER_ERROR out of memory writing stats");
2700
    } else {
2701
        write_and_free(c, c->stats.buffer, c->stats.offset);
2702
        c->stats.buffer = NULL;
2703
    }
1 by Jay Bonci
Import upstream version 1.1.11
2704
}
2705
1.2.1 by Jay Bonci
Import upstream version 1.2.2
2706
/* ntokens is overwritten here... shrug.. */
1.2.3 by David Martínez Moreno
Import upstream version 1.2.4
2707
static inline void process_get_command(conn *c, token_t *tokens, size_t ntokens, bool return_cas) {
1.1.2 by Jay Bonci
Import upstream version 1.2.1
2708
    char *key;
2709
    size_t nkey;
2710
    int i = 0;
2711
    item *it;
1.2.1 by Jay Bonci
Import upstream version 1.2.2
2712
    token_t *key_token = &tokens[KEY_TOKEN];
1.2.3 by David Martínez Moreno
Import upstream version 1.2.4
2713
    char *suffix;
1.2.1 by Jay Bonci
Import upstream version 1.2.2
2714
    assert(c != NULL);
1.1.2 by Jay Bonci
Import upstream version 1.2.1
2715
2716
    do {
2717
        while(key_token->length != 0) {
1.2.1 by Jay Bonci
Import upstream version 1.2.2
2718
1.1.2 by Jay Bonci
Import upstream version 1.2.1
2719
            key = key_token->value;
2720
            nkey = key_token->length;
1.2.1 by Jay Bonci
Import upstream version 1.2.2
2721
1.1.2 by Jay Bonci
Import upstream version 1.2.1
2722
            if(nkey > KEY_MAX_LENGTH) {
2723
                out_string(c, "CLIENT_ERROR bad command line format");
1 by Jay Bonci
Import upstream version 1.1.11
2724
                return;
2725
            }
1.2.1 by Jay Bonci
Import upstream version 1.2.2
2726
2727
            it = item_get(key, nkey);
2728
            if (settings.detail_enabled) {
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
2729
                stats_prefix_record_get(key, nkey, NULL != it);
1.2.1 by Jay Bonci
Import upstream version 1.2.2
2730
            }
1 by Jay Bonci
Import upstream version 1.1.11
2731
            if (it) {
1.1.1 by Jay Bonci
Import upstream version 1.1.12
2732
                if (i >= c->isize) {
1.2.1 by Jay Bonci
Import upstream version 1.2.2
2733
                    item **new_list = realloc(c->ilist, sizeof(item *) * c->isize * 2);
1.1.1 by Jay Bonci
Import upstream version 1.1.12
2734
                    if (new_list) {
2735
                        c->isize *= 2;
2736
                        c->ilist = new_list;
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
2737
                    } else {
1.3.2 by David Martínez Moreno
Import upstream version 1.2.8
2738
                        item_remove(it);
2739
                        break;
2740
                    }
1.1.1 by Jay Bonci
Import upstream version 1.1.12
2741
                }
1.2.1 by Jay Bonci
Import upstream version 1.2.2
2742
1.1.2 by Jay Bonci
Import upstream version 1.2.1
2743
                /*
2744
                 * Construct the response. Each hit adds three elements to the
2745
                 * outgoing data list:
2746
                 *   "VALUE "
2747
                 *   key
2748
                 *   " " + flags + " " + data length + "\r\n" + data (with \r\n)
2749
                 */
1.2.3 by David Martínez Moreno
Import upstream version 1.2.4
2750
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
2751
                if (return_cas)
1.2.3 by David Martínez Moreno
Import upstream version 1.2.4
2752
                {
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
2753
                  MEMCACHED_COMMAND_GET(c->sfd, ITEM_key(it), it->nkey,
2754
                                        it->nbytes, ITEM_get_cas(it));
1.2.3 by David Martínez Moreno
Import upstream version 1.2.4
2755
                  /* Goofy mid-flight realloc. */
2756
                  if (i >= c->suffixsize) {
2757
                    char **new_suffix_list = realloc(c->suffixlist,
2758
                                           sizeof(char *) * c->suffixsize * 2);
2759
                    if (new_suffix_list) {
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
2760
                        c->suffixsize *= 2;
2761
                        c->suffixlist  = new_suffix_list;
1.3.2 by David Martínez Moreno
Import upstream version 1.2.8
2762
                    } else {
2763
                        item_remove(it);
2764
                        break;
2765
                    }
1.2.3 by David Martínez Moreno
Import upstream version 1.2.4
2766
                  }
2767
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
2768
                  suffix = cache_alloc(c->thread->suffix_cache);
1.2.3 by David Martínez Moreno
Import upstream version 1.2.4
2769
                  if (suffix == NULL) {
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
2770
                    out_string(c, "SERVER_ERROR out of memory making CAS suffix");
1.3.2 by David Martínez Moreno
Import upstream version 1.2.8
2771
                    item_remove(it);
1.2.3 by David Martínez Moreno
Import upstream version 1.2.4
2772
                    return;
2773
                  }
2774
                  *(c->suffixlist + i) = suffix;
1.3.4 by David Martínez Moreno
Import upstream version 1.4.1
2775
                  int suffix_len = snprintf(suffix, SUFFIX_SIZE,
2776
                                            " %llu\r\n",
2777
                                            (unsigned long long)ITEM_get_cas(it));
1.2.3 by David Martínez Moreno
Import upstream version 1.2.4
2778
                  if (add_iov(c, "VALUE ", 6) != 0 ||
2779
                      add_iov(c, ITEM_key(it), it->nkey) != 0 ||
2780
                      add_iov(c, ITEM_suffix(it), it->nsuffix - 2) != 0 ||
1.3.4 by David Martínez Moreno
Import upstream version 1.4.1
2781
                      add_iov(c, suffix, suffix_len) != 0 ||
1.2.3 by David Martínez Moreno
Import upstream version 1.2.4
2782
                      add_iov(c, ITEM_data(it), it->nbytes) != 0)
2783
                      {
1.3.2 by David Martínez Moreno
Import upstream version 1.2.8
2784
                          item_remove(it);
1.2.3 by David Martínez Moreno
Import upstream version 1.2.4
2785
                          break;
2786
                      }
2787
                }
2788
                else
2789
                {
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
2790
                  MEMCACHED_COMMAND_GET(c->sfd, ITEM_key(it), it->nkey,
2791
                                        it->nbytes, ITEM_get_cas(it));
1.2.3 by David Martínez Moreno
Import upstream version 1.2.4
2792
                  if (add_iov(c, "VALUE ", 6) != 0 ||
2793
                      add_iov(c, ITEM_key(it), it->nkey) != 0 ||
2794
                      add_iov(c, ITEM_suffix(it), it->nsuffix + it->nbytes) != 0)
2795
                      {
1.3.2 by David Martínez Moreno
Import upstream version 1.2.8
2796
                          item_remove(it);
1.2.3 by David Martínez Moreno
Import upstream version 1.2.4
2797
                          break;
2798
                      }
2799
                }
2800
2801
1.1.2 by Jay Bonci
Import upstream version 1.2.1
2802
                if (settings.verbose > 1)
2803
                    fprintf(stderr, ">%d sending key %s\n", c->sfd, ITEM_key(it));
2804
1.2.1 by Jay Bonci
Import upstream version 1.2.2
2805
                /* item_get() has incremented it->refcount for us */
1.3.5 by David Martínez Moreno
Import upstream version 1.4.2
2806
                pthread_mutex_lock(&c->thread->stats.mutex);
2807
                c->thread->stats.slab_stats[it->slabs_clsid].get_hits++;
2808
                c->thread->stats.get_cmds++;
2809
                pthread_mutex_unlock(&c->thread->stats.mutex);
1 by Jay Bonci
Import upstream version 1.1.11
2810
                item_update(it);
2811
                *(c->ilist + i) = it;
2812
                i++;
1.2.1 by Jay Bonci
Import upstream version 1.2.2
2813
2814
            } else {
1.3.5 by David Martínez Moreno
Import upstream version 1.4.2
2815
                pthread_mutex_lock(&c->thread->stats.mutex);
2816
                c->thread->stats.get_misses++;
1.4.3 by David Martínez Moreno
Import upstream version 1.4.5
2817
                c->thread->stats.get_cmds++;
1.3.5 by David Martínez Moreno
Import upstream version 1.4.2
2818
                pthread_mutex_unlock(&c->thread->stats.mutex);
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
2819
                MEMCACHED_COMMAND_GET(c->sfd, key, nkey, -1, 0);
1.2.1 by Jay Bonci
Import upstream version 1.2.2
2820
            }
2821
1.1.2 by Jay Bonci
Import upstream version 1.2.1
2822
            key_token++;
2823
        }
2824
2825
        /*
2826
         * If the command string hasn't been fully processed, get the next set
2827
         * of tokens.
2828
         */
2829
        if(key_token->value != NULL) {
1.2.1 by Jay Bonci
Import upstream version 1.2.2
2830
            ntokens = tokenize_command(key_token->value, tokens, MAX_TOKENS);
1.1.2 by Jay Bonci
Import upstream version 1.2.1
2831
            key_token = tokens;
2832
        }
1.2.1 by Jay Bonci
Import upstream version 1.2.2
2833
1.1.2 by Jay Bonci
Import upstream version 1.2.1
2834
    } while(key_token->value != NULL);
2835
2836
    c->icurr = c->ilist;
2837
    c->ileft = i;
1.2.3 by David Martínez Moreno
Import upstream version 1.2.4
2838
    if (return_cas) {
2839
        c->suffixcurr = c->suffixlist;
2840
        c->suffixleft = i;
2841
    }
1.2.1 by Jay Bonci
Import upstream version 1.2.2
2842
1.1.2 by Jay Bonci
Import upstream version 1.2.1
2843
    if (settings.verbose > 1)
2844
        fprintf(stderr, ">%d END\n", c->sfd);
1.2.1 by Jay Bonci
Import upstream version 1.2.2
2845
1.2.3 by David Martínez Moreno
Import upstream version 1.2.4
2846
    /*
2847
        If the loop was terminated because of out-of-memory, it is not
2848
        reliable to add END\r\n to the buffer, because it might not end
2849
        in \r\n. So we send SERVER_ERROR instead.
2850
    */
2851
    if (key_token->value != NULL || add_iov(c, "END\r\n", 5) != 0
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
2852
        || (IS_UDP(c->transport) && build_udp_headers(c) != 0)) {
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
2853
        out_string(c, "SERVER_ERROR out of memory writing get response");
1.1.2 by Jay Bonci
Import upstream version 1.2.1
2854
    }
2855
    else {
2856
        conn_set_state(c, conn_mwrite);
2857
        c->msgcurr = 0;
2858
    }
1.2.3 by David Martínez Moreno
Import upstream version 1.2.4
2859
1.1.2 by Jay Bonci
Import upstream version 1.2.1
2860
    return;
2861
}
2862
1.2.3 by David Martínez Moreno
Import upstream version 1.2.4
2863
static void process_update_command(conn *c, token_t *tokens, const size_t ntokens, int comm, bool handle_cas) {
1.1.2 by Jay Bonci
Import upstream version 1.2.1
2864
    char *key;
2865
    size_t nkey;
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
2866
    unsigned int flags;
2867
    int32_t exptime_int = 0;
1.1.2 by Jay Bonci
Import upstream version 1.2.1
2868
    time_t exptime;
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
2869
    int vlen;
2870
    uint64_t req_cas_id=0;
2871
    item *it;
1.1.2 by Jay Bonci
Import upstream version 1.2.1
2872
1.2.1 by Jay Bonci
Import upstream version 1.2.2
2873
    assert(c != NULL);
2874
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
2875
    set_noreply_maybe(c, tokens, ntokens);
2876
1.1.2 by Jay Bonci
Import upstream version 1.2.1
2877
    if (tokens[KEY_TOKEN].length > KEY_MAX_LENGTH) {
2878
        out_string(c, "CLIENT_ERROR bad command line format");
2879
        return;
2880
    }
2881
2882
    key = tokens[KEY_TOKEN].value;
2883
    nkey = tokens[KEY_TOKEN].length;
2884
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
2885
    if (! (safe_strtoul(tokens[2].value, (uint32_t *)&flags)
2886
           && safe_strtol(tokens[3].value, &exptime_int)
2887
           && safe_strtol(tokens[4].value, (int32_t *)&vlen))) {
2888
        out_string(c, "CLIENT_ERROR bad command line format");
2889
        return;
2890
    }
2891
2892
    /* Ubuntu 8.04 breaks when I pass exptime to safe_strtol */
2893
    exptime = exptime_int;
1.2.1 by Jay Bonci
Import upstream version 1.2.2
2894
1.4.4 by Arno Töll
Import upstream version 1.4.7
2895
    /* Negative exptimes can underflow and end up immortal. realtime() will
2896
       immediately expire values that are greater than REALTIME_MAXDELTA, but less
2897
       than process_started, so lets aim for that. */
2898
    if (exptime < 0)
2899
        exptime = REALTIME_MAXDELTA + 1;
2900
1.2.3 by David Martínez Moreno
Import upstream version 1.2.4
2901
    // does cas value exist?
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
2902
    if (handle_cas) {
1.3.4 by David Martínez Moreno
Import upstream version 1.4.1
2903
        if (!safe_strtoull(tokens[5].value, &req_cas_id)) {
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
2904
            out_string(c, "CLIENT_ERROR bad command line format");
2905
            return;
2906
        }
1.1.2 by Jay Bonci
Import upstream version 1.2.1
2907
    }
1.2.3 by David Martínez Moreno
Import upstream version 1.2.4
2908
1.3.4 by David Martínez Moreno
Import upstream version 1.4.1
2909
    vlen += 2;
2910
    if (vlen < 0 || vlen - 2 < 0) {
1.1.2 by Jay Bonci
Import upstream version 1.2.1
2911
        out_string(c, "CLIENT_ERROR bad command line format");
2912
        return;
2913
    }
1.3.4 by David Martínez Moreno
Import upstream version 1.4.1
2914
1.2.1 by Jay Bonci
Import upstream version 1.2.2
2915
    if (settings.detail_enabled) {
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
2916
        stats_prefix_record_set(key, nkey);
1.2.1 by Jay Bonci
Import upstream version 1.2.2
2917
    }
2918
1.3.4 by David Martínez Moreno
Import upstream version 1.4.1
2919
    it = item_alloc(key, nkey, flags, realtime(exptime), vlen);
1.1.2 by Jay Bonci
Import upstream version 1.2.1
2920
2921
    if (it == 0) {
1.3.4 by David Martínez Moreno
Import upstream version 1.4.1
2922
        if (! item_size_ok(nkey, flags, vlen))
1.1.2 by Jay Bonci
Import upstream version 1.2.1
2923
            out_string(c, "SERVER_ERROR object too large for cache");
2924
        else
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
2925
            out_string(c, "SERVER_ERROR out of memory storing object");
1.1.2 by Jay Bonci
Import upstream version 1.2.1
2926
        /* swallow the data line */
2927
        c->write_and_go = conn_swallow;
1.3.4 by David Martínez Moreno
Import upstream version 1.4.1
2928
        c->sbytes = vlen;
1.3.2 by David Martínez Moreno
Import upstream version 1.2.8
2929
2930
        /* Avoid stale data persisting in cache because we failed alloc.
2931
         * Unacceptable for SET. Anywhere else too? */
2932
        if (comm == NREAD_SET) {
2933
            it = item_get(key, nkey);
2934
            if (it) {
2935
                item_unlink(it);
2936
                item_remove(it);
2937
            }
2938
        }
2939
1.1.2 by Jay Bonci
Import upstream version 1.2.1
2940
        return;
2941
    }
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
2942
    ITEM_set_cas(it, req_cas_id);
1.2.1 by Jay Bonci
Import upstream version 1.2.2
2943
1.1.2 by Jay Bonci
Import upstream version 1.2.1
2944
    c->item = it;
2945
    c->ritem = ITEM_data(it);
2946
    c->rlbytes = it->nbytes;
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
2947
    c->cmd = comm;
1.1.2 by Jay Bonci
Import upstream version 1.2.1
2948
    conn_set_state(c, conn_nread);
2949
}
2950
1.1.9 by Scott Kitterman
Import upstream version 1.4.9
2951
static void process_touch_command(conn *c, token_t *tokens, const size_t ntokens) {
2952
    char *key;
2953
    size_t nkey;
2954
    int32_t exptime_int = 0;
2955
    item *it;
2956
2957
    assert(c != NULL);
2958
2959
    set_noreply_maybe(c, tokens, ntokens);
2960
2961
    if (tokens[KEY_TOKEN].length > KEY_MAX_LENGTH) {
2962
        out_string(c, "CLIENT_ERROR bad command line format");
2963
        return;
2964
    }
2965
2966
    key = tokens[KEY_TOKEN].value;
2967
    nkey = tokens[KEY_TOKEN].length;
2968
2969
    if (!safe_strtol(tokens[2].value, &exptime_int)) {
2970
        out_string(c, "CLIENT_ERROR invalid exptime argument");
2971
        return;
2972
    }
2973
2974
    it = item_touch(key, nkey, realtime(exptime_int));
2975
    if (it) {
2976
        item_update(it);
2977
        pthread_mutex_lock(&c->thread->stats.mutex);
2978
        c->thread->stats.touch_cmds++;
2979
        c->thread->stats.slab_stats[it->slabs_clsid].touch_hits++;
2980
        pthread_mutex_unlock(&c->thread->stats.mutex);
2981
2982
        out_string(c, "TOUCHED");
2983
        item_remove(it);
2984
    } else {
2985
        pthread_mutex_lock(&c->thread->stats.mutex);
2986
        c->thread->stats.touch_cmds++;
2987
        c->thread->stats.touch_misses++;
2988
        pthread_mutex_unlock(&c->thread->stats.mutex);
2989
2990
        out_string(c, "NOT_FOUND");
2991
    }
2992
}
2993
1.2.3 by David Martínez Moreno
Import upstream version 1.2.4
2994
static void process_arithmetic_command(conn *c, token_t *tokens, const size_t ntokens, const bool incr) {
1.3.4 by David Martínez Moreno
Import upstream version 1.4.1
2995
    char temp[INCR_MAX_STORAGE_LEN];
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
2996
    uint64_t delta;
1.1.2 by Jay Bonci
Import upstream version 1.2.1
2997
    char *key;
2998
    size_t nkey;
1.2.1 by Jay Bonci
Import upstream version 1.2.2
2999
3000
    assert(c != NULL);
3001
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
3002
    set_noreply_maybe(c, tokens, ntokens);
3003
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
3004
    if (tokens[KEY_TOKEN].length > KEY_MAX_LENGTH) {
1.2.1 by Jay Bonci
Import upstream version 1.2.2
3005
        out_string(c, "CLIENT_ERROR bad command line format");
3006
        return;
3007
    }
3008
3009
    key = tokens[KEY_TOKEN].value;
3010
    nkey = tokens[KEY_TOKEN].length;
3011
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
3012
    if (!safe_strtoull(tokens[2].value, &delta)) {
3013
        out_string(c, "CLIENT_ERROR invalid numeric delta argument");
1.2.1 by Jay Bonci
Import upstream version 1.2.2
3014
        return;
3015
    }
3016
1.4.4 by Arno Töll
Import upstream version 1.4.7
3017
    switch(add_delta(c, key, nkey, incr, delta, temp, NULL)) {
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
3018
    case OK:
3019
        out_string(c, temp);
3020
        break;
3021
    case NON_NUMERIC:
3022
        out_string(c, "CLIENT_ERROR cannot increment or decrement non-numeric value");
3023
        break;
3024
    case EOM:
3025
        out_string(c, "SERVER_ERROR out of memory");
3026
        break;
1.4.4 by Arno Töll
Import upstream version 1.4.7
3027
    case DELTA_ITEM_NOT_FOUND:
3028
        pthread_mutex_lock(&c->thread->stats.mutex);
3029
        if (incr) {
3030
            c->thread->stats.incr_misses++;
3031
        } else {
3032
            c->thread->stats.decr_misses++;
3033
        }
3034
        pthread_mutex_unlock(&c->thread->stats.mutex);
3035
3036
        out_string(c, "NOT_FOUND");
3037
        break;
3038
    case DELTA_ITEM_CAS_MISMATCH:
3039
        break; /* Should never get here */
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
3040
    }
1.2.1 by Jay Bonci
Import upstream version 1.2.2
3041
}
3042
3043
/*
3044
 * adds a delta value to a numeric item.
3045
 *
1.3.2 by David Martínez Moreno
Import upstream version 1.2.8
3046
 * c     connection requesting the operation
1.2.1 by Jay Bonci
Import upstream version 1.2.2
3047
 * it    item to adjust
3048
 * incr  true to increment value, false to decrement
3049
 * delta amount to adjust value by
3050
 * buf   buffer for response string
3051
 *
3052
 * returns a response string to send back to the client.
3053
 */
1.4.4 by Arno Töll
Import upstream version 1.4.7
3054
enum delta_result_type do_add_delta(conn *c, const char *key, const size_t nkey,
3055
                                    const bool incr, const int64_t delta,
1.1.10 by Scott Kitterman
Import upstream version 1.4.10
3056
                                    char *buf, uint64_t *cas,
3057
                                    const uint32_t hv) {
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3058
    char *ptr;
1.3.2 by David Martínez Moreno
Import upstream version 1.2.8
3059
    uint64_t value;
1.2.1 by Jay Bonci
Import upstream version 1.2.2
3060
    int res;
1.4.4 by Arno Töll
Import upstream version 1.4.7
3061
    item *it;
3062
1.1.10 by Scott Kitterman
Import upstream version 1.4.10
3063
    it = do_item_get(key, nkey, hv);
1.4.4 by Arno Töll
Import upstream version 1.4.7
3064
    if (!it) {
3065
        return DELTA_ITEM_NOT_FOUND;
3066
    }
3067
3068
    if (cas != NULL && *cas != 0 && ITEM_get_cas(it) != *cas) {
3069
        do_item_remove(it);
3070
        return DELTA_ITEM_CAS_MISMATCH;
3071
    }
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3072
3073
    ptr = ITEM_data(it);
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
3074
3075
    if (!safe_strtoull(ptr, &value)) {
1.4.4 by Arno Töll
Import upstream version 1.4.7
3076
        do_item_remove(it);
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
3077
        return NON_NUMERIC;
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3078
    }
1.2.1 by Jay Bonci
Import upstream version 1.2.2
3079
1.3.2 by David Martínez Moreno
Import upstream version 1.2.8
3080
    if (incr) {
1.2.1 by Jay Bonci
Import upstream version 1.2.2
3081
        value += delta;
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
3082
        MEMCACHED_COMMAND_INCR(c->sfd, ITEM_key(it), it->nkey, value);
3083
    } else {
3084
        if(delta > value) {
3085
            value = 0;
3086
        } else {
3087
            value -= delta;
3088
        }
3089
        MEMCACHED_COMMAND_DECR(c->sfd, ITEM_key(it), it->nkey, value);
3090
    }
3091
3092
    pthread_mutex_lock(&c->thread->stats.mutex);
3093
    if (incr) {
3094
        c->thread->stats.slab_stats[it->slabs_clsid].incr_hits++;
3095
    } else {
3096
        c->thread->stats.slab_stats[it->slabs_clsid].decr_hits++;
3097
    }
3098
    pthread_mutex_unlock(&c->thread->stats.mutex);
3099
1.3.4 by David Martínez Moreno
Import upstream version 1.4.1
3100
    snprintf(buf, INCR_MAX_STORAGE_LEN, "%llu", (unsigned long long)value);
1.2.1 by Jay Bonci
Import upstream version 1.2.2
3101
    res = strlen(buf);
1.4.4 by Arno Töll
Import upstream version 1.4.7
3102
    if (res + 2 > it->nbytes || it->refcount != 1) { /* need to realloc */
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3103
        item *new_it;
1.1.10 by Scott Kitterman
Import upstream version 1.4.10
3104
        new_it = item_alloc(ITEM_key(it), it->nkey, atoi(ITEM_suffix(it) + 1), it->exptime, res + 2 );
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3105
        if (new_it == 0) {
1.4.4 by Arno Töll
Import upstream version 1.4.7
3106
            do_item_remove(it);
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
3107
            return EOM;
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3108
        }
1.2.1 by Jay Bonci
Import upstream version 1.2.2
3109
        memcpy(ITEM_data(new_it), buf, res);
1.3.2 by David Martínez Moreno
Import upstream version 1.2.8
3110
        memcpy(ITEM_data(new_it) + res, "\r\n", 2);
1.1.10 by Scott Kitterman
Import upstream version 1.4.10
3111
        item_replace(it, new_it, hv);
1.1.9 by Scott Kitterman
Import upstream version 1.4.9
3112
        // Overwrite the older item's CAS with our new CAS since we're
3113
        // returning the CAS of the old item below.
3114
        ITEM_set_cas(it, (settings.use_cas) ? ITEM_get_cas(new_it) : 0);
1.2.1 by Jay Bonci
Import upstream version 1.2.2
3115
        do_item_remove(new_it);       /* release our reference */
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3116
    } else { /* replace in-place */
1.3.2 by David Martínez Moreno
Import upstream version 1.2.8
3117
        /* When changing the value without replacing the item, we
3118
           need to update the CAS on the existing item. */
1.1.10 by Scott Kitterman
Import upstream version 1.4.10
3119
        mutex_lock(&cache_lock); /* FIXME */
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
3120
        ITEM_set_cas(it, (settings.use_cas) ? get_cas_id() : 0);
1.1.10 by Scott Kitterman
Import upstream version 1.4.10
3121
        pthread_mutex_unlock(&cache_lock);
1.3.2 by David Martínez Moreno
Import upstream version 1.2.8
3122
1.2.1 by Jay Bonci
Import upstream version 1.2.2
3123
        memcpy(ITEM_data(it), buf, res);
3124
        memset(ITEM_data(it) + res, ' ', it->nbytes - res - 2);
1.1.9 by Scott Kitterman
Import upstream version 1.4.9
3125
        do_item_update(it);
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3126
    }
1.2.1 by Jay Bonci
Import upstream version 1.2.2
3127
1.4.4 by Arno Töll
Import upstream version 1.4.7
3128
    if (cas) {
3129
        *cas = ITEM_get_cas(it);    /* swap the incoming CAS value */
3130
    }
3131
    do_item_remove(it);         /* release our reference */
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
3132
    return OK;
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3133
}
3134
1.2.1 by Jay Bonci
Import upstream version 1.2.2
3135
static void process_delete_command(conn *c, token_t *tokens, const size_t ntokens) {
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3136
    char *key;
3137
    size_t nkey;
3138
    item *it;
1.2.1 by Jay Bonci
Import upstream version 1.2.2
3139
3140
    assert(c != NULL);
3141
1.4.3 by David Martínez Moreno
Import upstream version 1.4.5
3142
    if (ntokens > 3) {
3143
        bool hold_is_zero = strcmp(tokens[KEY_TOKEN+1].value, "0") == 0;
3144
        bool sets_noreply = set_noreply_maybe(c, tokens, ntokens);
3145
        bool valid = (ntokens == 4 && (hold_is_zero || sets_noreply))
3146
            || (ntokens == 5 && hold_is_zero && sets_noreply);
3147
        if (!valid) {
3148
            out_string(c, "CLIENT_ERROR bad command line format.  "
3149
                       "Usage: delete <key> [noreply]");
3150
            return;
3151
        }
3152
    }
3153
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
3154
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3155
    key = tokens[KEY_TOKEN].value;
3156
    nkey = tokens[KEY_TOKEN].length;
3157
3158
    if(nkey > KEY_MAX_LENGTH) {
3159
        out_string(c, "CLIENT_ERROR bad command line format");
3160
        return;
3161
    }
3162
1.2.1 by Jay Bonci
Import upstream version 1.2.2
3163
    if (settings.detail_enabled) {
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
3164
        stats_prefix_record_delete(key, nkey);
1.2.1 by Jay Bonci
Import upstream version 1.2.2
3165
    }
3166
3167
    it = item_get(key, nkey);
3168
    if (it) {
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
3169
        MEMCACHED_COMMAND_DELETE(c->sfd, ITEM_key(it), it->nkey);
3170
3171
        pthread_mutex_lock(&c->thread->stats.mutex);
3172
        c->thread->stats.slab_stats[it->slabs_clsid].delete_hits++;
3173
        pthread_mutex_unlock(&c->thread->stats.mutex);
3174
3175
        item_unlink(it);
3176
        item_remove(it);      /* release our reference */
3177
        out_string(c, "DELETED");
1.2.1 by Jay Bonci
Import upstream version 1.2.2
3178
    } else {
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
3179
        pthread_mutex_lock(&c->thread->stats.mutex);
3180
        c->thread->stats.delete_misses++;
3181
        pthread_mutex_unlock(&c->thread->stats.mutex);
3182
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3183
        out_string(c, "NOT_FOUND");
1.2.1 by Jay Bonci
Import upstream version 1.2.2
3184
    }
3185
}
3186
3187
static void process_verbosity_command(conn *c, token_t *tokens, const size_t ntokens) {
3188
    unsigned int level;
3189
3190
    assert(c != NULL);
3191
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
3192
    set_noreply_maybe(c, tokens, ntokens);
3193
1.2.1 by Jay Bonci
Import upstream version 1.2.2
3194
    level = strtoul(tokens[1].value, NULL, 10);
3195
    settings.verbose = level > MAX_VERBOSITY_LEVEL ? MAX_VERBOSITY_LEVEL : level;
3196
    out_string(c, "OK");
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3197
    return;
3198
}
3199
1.1.11 by Scott Kitterman
Import upstream version 1.4.11
3200
static void process_slabs_automove_command(conn *c, token_t *tokens, const size_t ntokens) {
3201
    unsigned int level;
3202
3203
    assert(c != NULL);
3204
3205
    set_noreply_maybe(c, tokens, ntokens);
3206
3207
    level = strtoul(tokens[2].value, NULL, 10);
3208
    if (level == 0) {
3209
        settings.slab_automove = false;
3210
    } else if (level == 1) {
3211
        settings.slab_automove = true;
3212
    } else {
3213
        out_string(c, "ERROR");
3214
        return;
3215
    }
3216
    out_string(c, "OK");
3217
    return;
3218
}
3219
1.2.1 by Jay Bonci
Import upstream version 1.2.2
3220
static void process_command(conn *c, char *command) {
3221
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3222
    token_t tokens[MAX_TOKENS];
3223
    size_t ntokens;
3224
    int comm;
3225
1.2.1 by Jay Bonci
Import upstream version 1.2.2
3226
    assert(c != NULL);
3227
1.3.2 by David Martínez Moreno
Import upstream version 1.2.8
3228
    MEMCACHED_PROCESS_COMMAND_START(c->sfd, c->rcurr, c->rbytes);
3229
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3230
    if (settings.verbose > 1)
3231
        fprintf(stderr, "<%d %s\n", c->sfd, command);
3232
1.2.1 by Jay Bonci
Import upstream version 1.2.2
3233
    /*
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3234
     * for commands set/add/replace, we build an item and read the data
3235
     * directly into it, then continue in nread_complete().
1.2.1 by Jay Bonci
Import upstream version 1.2.2
3236
     */
3237
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3238
    c->msgcurr = 0;
3239
    c->msgused = 0;
3240
    c->iovused = 0;
1.2.1 by Jay Bonci
Import upstream version 1.2.2
3241
    if (add_msghdr(c) != 0) {
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
3242
        out_string(c, "SERVER_ERROR out of memory preparing response");
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3243
        return;
3244
    }
3245
3246
    ntokens = tokenize_command(command, tokens, MAX_TOKENS);
3247
    if (ntokens >= 3 &&
3248
        ((strcmp(tokens[COMMAND_TOKEN].value, "get") == 0) ||
3249
         (strcmp(tokens[COMMAND_TOKEN].value, "bget") == 0))) {
1.2.1 by Jay Bonci
Import upstream version 1.2.2
3250
1.2.3 by David Martínez Moreno
Import upstream version 1.2.4
3251
        process_get_command(c, tokens, ntokens, false);
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3252
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
3253
    } else if ((ntokens == 6 || ntokens == 7) &&
1.2.1 by Jay Bonci
Import upstream version 1.2.2
3254
               ((strcmp(tokens[COMMAND_TOKEN].value, "add") == 0 && (comm = NREAD_ADD)) ||
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3255
                (strcmp(tokens[COMMAND_TOKEN].value, "set") == 0 && (comm = NREAD_SET)) ||
1.2.3 by David Martínez Moreno
Import upstream version 1.2.4
3256
                (strcmp(tokens[COMMAND_TOKEN].value, "replace") == 0 && (comm = NREAD_REPLACE)) ||
3257
                (strcmp(tokens[COMMAND_TOKEN].value, "prepend") == 0 && (comm = NREAD_PREPEND)) ||
3258
                (strcmp(tokens[COMMAND_TOKEN].value, "append") == 0 && (comm = NREAD_APPEND)) )) {
3259
3260
        process_update_command(c, tokens, ntokens, comm, false);
3261
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
3262
    } else if ((ntokens == 7 || ntokens == 8) && (strcmp(tokens[COMMAND_TOKEN].value, "cas") == 0 && (comm = NREAD_CAS))) {
1.2.3 by David Martínez Moreno
Import upstream version 1.2.4
3263
3264
        process_update_command(c, tokens, ntokens, comm, true);
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3265
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
3266
    } else if ((ntokens == 4 || ntokens == 5) && (strcmp(tokens[COMMAND_TOKEN].value, "incr") == 0)) {
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3267
3268
        process_arithmetic_command(c, tokens, ntokens, 1);
3269
1.2.3 by David Martínez Moreno
Import upstream version 1.2.4
3270
    } else if (ntokens >= 3 && (strcmp(tokens[COMMAND_TOKEN].value, "gets") == 0)) {
3271
3272
        process_get_command(c, tokens, ntokens, true);
3273
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
3274
    } else if ((ntokens == 4 || ntokens == 5) && (strcmp(tokens[COMMAND_TOKEN].value, "decr") == 0)) {
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3275
3276
        process_arithmetic_command(c, tokens, ntokens, 0);
3277
1.4.3 by David Martínez Moreno
Import upstream version 1.4.5
3278
    } else if (ntokens >= 3 && ntokens <= 5 && (strcmp(tokens[COMMAND_TOKEN].value, "delete") == 0)) {
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3279
3280
        process_delete_command(c, tokens, ntokens);
3281
1.1.9 by Scott Kitterman
Import upstream version 1.4.9
3282
    } else if ((ntokens == 4 || ntokens == 5) && (strcmp(tokens[COMMAND_TOKEN].value, "touch") == 0)) {
3283
3284
        process_touch_command(c, tokens, ntokens);
3285
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3286
    } else if (ntokens >= 2 && (strcmp(tokens[COMMAND_TOKEN].value, "stats") == 0)) {
1.2.1 by Jay Bonci
Import upstream version 1.2.2
3287
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3288
        process_stat(c, tokens, ntokens);
3289
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
3290
    } else if (ntokens >= 2 && ntokens <= 4 && (strcmp(tokens[COMMAND_TOKEN].value, "flush_all") == 0)) {
1.2.1 by Jay Bonci
Import upstream version 1.2.2
3291
        time_t exptime = 0;
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3292
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
3293
        set_noreply_maybe(c, tokens, ntokens);
3294
1.3.4 by David Martínez Moreno
Import upstream version 1.4.1
3295
        pthread_mutex_lock(&c->thread->stats.mutex);
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
3296
        c->thread->stats.flush_cmds++;
1.3.4 by David Martínez Moreno
Import upstream version 1.4.1
3297
        pthread_mutex_unlock(&c->thread->stats.mutex);
1.3.2 by David Martínez Moreno
Import upstream version 1.2.8
3298
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
3299
        if(ntokens == (c->noreply ? 3 : 2)) {
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3300
            settings.oldest_live = current_time - 1;
3301
            item_flush_expired();
3302
            out_string(c, "OK");
3303
            return;
3304
        }
3305
3306
        exptime = strtol(tokens[1].value, NULL, 10);
3307
        if(errno == ERANGE) {
3308
            out_string(c, "CLIENT_ERROR bad command line format");
3309
            return;
3310
        }
3311
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
3312
        /*
3313
          If exptime is zero realtime() would return zero too, and
3314
          realtime(exptime) - 1 would overflow to the max unsigned
3315
          value.  So we process exptime == 0 the same way we do when
3316
          no delay is given at all.
3317
        */
3318
        if (exptime > 0)
3319
            settings.oldest_live = realtime(exptime) - 1;
3320
        else /* exptime == 0 */
3321
            settings.oldest_live = current_time - 1;
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3322
        item_flush_expired();
1 by Jay Bonci
Import upstream version 1.1.11
3323
        out_string(c, "OK");
3324
        return;
1.2.1 by Jay Bonci
Import upstream version 1.2.2
3325
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3326
    } else if (ntokens == 2 && (strcmp(tokens[COMMAND_TOKEN].value, "version") == 0)) {
1.2.1 by Jay Bonci
Import upstream version 1.2.2
3327
1 by Jay Bonci
Import upstream version 1.1.11
3328
        out_string(c, "VERSION " VERSION);
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3329
3330
    } else if (ntokens == 2 && (strcmp(tokens[COMMAND_TOKEN].value, "quit") == 0)) {
3331
3332
        conn_set_state(c, conn_closing);
1.2.1 by Jay Bonci
Import upstream version 1.2.2
3333
1.1.12 by Clint Byrum
Import upstream version 1.4.13
3334
    } else if (ntokens > 1 && strcmp(tokens[COMMAND_TOKEN].value, "slabs") == 0) {
1.1.11 by Scott Kitterman
Import upstream version 1.4.11
3335
        if (ntokens == 5 && strcmp(tokens[COMMAND_TOKEN + 1].value, "reassign") == 0) {
3336
            int src, dst, rv;
3337
3338
            if (settings.slab_reassign == false) {
3339
                out_string(c, "CLIENT_ERROR slab reassignment disabled");
3340
                return;
3341
            }
3342
3343
            src = strtol(tokens[2].value, NULL, 10);
3344
            dst = strtol(tokens[3].value, NULL, 10);
3345
3346
            if (errno == ERANGE) {
3347
                out_string(c, "CLIENT_ERROR bad command line format");
3348
                return;
3349
            }
3350
3351
            rv = slabs_reassign(src, dst);
3352
            switch (rv) {
3353
            case REASSIGN_OK:
3354
                out_string(c, "OK");
3355
                break;
3356
            case REASSIGN_RUNNING:
3357
                out_string(c, "BUSY currently processing reassign request");
3358
                break;
3359
            case REASSIGN_BADCLASS:
3360
                out_string(c, "BADCLASS invalid src or dst class id");
3361
                break;
3362
            case REASSIGN_NOSPARE:
3363
                out_string(c, "NOSPARE source class has no spare pages");
3364
                break;
3365
            case REASSIGN_DEST_NOT_FULL:
3366
                out_string(c, "NOTFULL dest class has spare memory");
3367
                break;
3368
            case REASSIGN_SRC_NOT_SAFE:
3369
                out_string(c, "UNSAFE src class is in an unsafe state");
3370
                break;
3371
            case REASSIGN_SRC_DST_SAME:
3372
                out_string(c, "SAME src and dst class are identical");
3373
                break;
3374
            }
3375
            return;
3376
        } else if (ntokens == 4 &&
3377
            (strcmp(tokens[COMMAND_TOKEN + 1].value, "automove") == 0)) {
3378
            process_slabs_automove_command(c, tokens, ntokens);
3379
        } else {
3380
            out_string(c, "ERROR");
3381
        }
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
3382
    } else if ((ntokens == 3 || ntokens == 4) && (strcmp(tokens[COMMAND_TOKEN].value, "verbosity") == 0)) {
1.2.1 by Jay Bonci
Import upstream version 1.2.2
3383
        process_verbosity_command(c, tokens, ntokens);
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3384
    } else {
3385
        out_string(c, "ERROR");
3386
    }
1 by Jay Bonci
Import upstream version 1.1.11
3387
    return;
3388
}
3389
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3390
/*
3391
 * if we have a complete line in the buffer, process it.
1 by Jay Bonci
Import upstream version 1.1.11
3392
 */
1.2.1 by Jay Bonci
Import upstream version 1.2.2
3393
static int try_read_command(conn *c) {
3394
    assert(c != NULL);
3395
    assert(c->rcurr <= (c->rbuf + c->rsize));
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
3396
    assert(c->rbytes > 0);
3397
3398
    if (c->protocol == negotiating_prot || c->transport == udp_transport)  {
3399
        if ((unsigned char)c->rbuf[0] == (unsigned char)PROTOCOL_BINARY_REQ) {
3400
            c->protocol = binary_prot;
3401
        } else {
3402
            c->protocol = ascii_prot;
3403
        }
3404
1.3.5 by David Martínez Moreno
Import upstream version 1.4.2
3405
        if (settings.verbose > 1) {
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
3406
            fprintf(stderr, "%d: Client using the %s protocol\n", c->sfd,
3407
                    prot_text(c->protocol));
3408
        }
3409
    }
3410
3411
    if (c->protocol == binary_prot) {
3412
        /* Do we have the complete packet header? */
3413
        if (c->rbytes < sizeof(c->binary_header)) {
3414
            /* need more data! */
3415
            return 0;
3416
        } else {
3417
#ifdef NEED_ALIGN
3418
            if (((long)(c->rcurr)) % 8 != 0) {
3419
                /* must realign input buffer */
3420
                memmove(c->rbuf, c->rcurr, c->rbytes);
3421
                c->rcurr = c->rbuf;
1.3.5 by David Martínez Moreno
Import upstream version 1.4.2
3422
                if (settings.verbose > 1) {
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
3423
                    fprintf(stderr, "%d: Realign input buffer\n", c->sfd);
3424
                }
3425
            }
3426
#endif
3427
            protocol_binary_request_header* req;
3428
            req = (protocol_binary_request_header*)c->rcurr;
3429
3430
            if (settings.verbose > 1) {
3431
                /* Dump the packet before we convert it to host order */
3432
                int ii;
3433
                fprintf(stderr, "<%d Read binary protocol data:", c->sfd);
3434
                for (ii = 0; ii < sizeof(req->bytes); ++ii) {
3435
                    if (ii % 4 == 0) {
3436
                        fprintf(stderr, "\n<%d   ", c->sfd);
3437
                    }
3438
                    fprintf(stderr, " 0x%02x", req->bytes[ii]);
3439
                }
3440
                fprintf(stderr, "\n");
3441
            }
3442
3443
            c->binary_header = *req;
3444
            c->binary_header.request.keylen = ntohs(req->request.keylen);
3445
            c->binary_header.request.bodylen = ntohl(req->request.bodylen);
1.3.5 by David Martínez Moreno
Import upstream version 1.4.2
3446
            c->binary_header.request.cas = ntohll(req->request.cas);
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
3447
3448
            if (c->binary_header.request.magic != PROTOCOL_BINARY_REQ) {
3449
                if (settings.verbose) {
3450
                    fprintf(stderr, "Invalid magic:  %x\n",
3451
                            c->binary_header.request.magic);
3452
                }
3453
                conn_set_state(c, conn_closing);
3454
                return -1;
3455
            }
3456
3457
            c->msgcurr = 0;
3458
            c->msgused = 0;
3459
            c->iovused = 0;
3460
            if (add_msghdr(c) != 0) {
3461
                out_string(c, "SERVER_ERROR out of memory");
3462
                return 0;
3463
            }
3464
3465
            c->cmd = c->binary_header.request.opcode;
3466
            c->keylen = c->binary_header.request.keylen;
3467
            c->opaque = c->binary_header.request.opaque;
3468
            /* clear the returned cas value */
3469
            c->cas = 0;
3470
3471
            dispatch_bin_command(c);
3472
3473
            c->rbytes -= sizeof(c->binary_header);
3474
            c->rcurr += sizeof(c->binary_header);
3475
        }
3476
    } else {
3477
        char *el, *cont;
3478
3479
        if (c->rbytes == 0)
3480
            return 0;
1.4.3 by David Martínez Moreno
Import upstream version 1.4.5
3481
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
3482
        el = memchr(c->rcurr, '\n', c->rbytes);
1.4.3 by David Martínez Moreno
Import upstream version 1.4.5
3483
        if (!el) {
3484
            if (c->rbytes > 1024) {
3485
                /*
3486
                 * We didn't have a '\n' in the first k. This _has_ to be a
3487
                 * large multiget, if not we should just nuke the connection.
3488
                 */
3489
                char *ptr = c->rcurr;
3490
                while (*ptr == ' ') { /* ignore leading whitespaces */
3491
                    ++ptr;
3492
                }
3493
3494
                if (ptr - c->rcurr > 100 ||
3495
                    (strncmp(ptr, "get ", 4) && strncmp(ptr, "gets ", 5))) {
3496
3497
                    conn_set_state(c, conn_closing);
3498
                    return 1;
3499
                }
3500
            }
3501
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
3502
            return 0;
1.4.3 by David Martínez Moreno
Import upstream version 1.4.5
3503
        }
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
3504
        cont = el + 1;
3505
        if ((el - c->rcurr) > 1 && *(el - 1) == '\r') {
3506
            el--;
3507
        }
3508
        *el = '\0';
3509
3510
        assert(cont <= (c->rcurr + c->rbytes));
3511
3512
        process_command(c, c->rcurr);
3513
3514
        c->rbytes -= (cont - c->rcurr);
3515
        c->rcurr = cont;
3516
3517
        assert(c->rcurr <= (c->rbuf + c->rsize));
3518
    }
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3519
3520
    return 1;
3521
}
3522
3523
/*
3524
 * read a UDP request.
3525
 */
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
3526
static enum try_read_result try_read_udp(conn *c) {
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3527
    int res;
3528
1.2.1 by Jay Bonci
Import upstream version 1.2.2
3529
    assert(c != NULL);
3530
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3531
    c->request_addr_size = sizeof(c->request_addr);
3532
    res = recvfrom(c->sfd, c->rbuf, c->rsize,
3533
                   0, &c->request_addr, &c->request_addr_size);
3534
    if (res > 8) {
3535
        unsigned char *buf = (unsigned char *)c->rbuf;
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
3536
        pthread_mutex_lock(&c->thread->stats.mutex);
3537
        c->thread->stats.bytes_read += res;
3538
        pthread_mutex_unlock(&c->thread->stats.mutex);
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3539
3540
        /* Beginning of UDP packet is the request ID; save it. */
3541
        c->request_id = buf[0] * 256 + buf[1];
3542
3543
        /* If this is a multi-packet request, drop it. */
3544
        if (buf[4] != 0 || buf[5] != 1) {
3545
            out_string(c, "SERVER_ERROR multi-packet request not supported");
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
3546
            return READ_NO_DATA_RECEIVED;
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3547
        }
3548
3549
        /* Don't care about any of the rest of the header. */
3550
        res -= 8;
3551
        memmove(c->rbuf, c->rbuf + 8, res);
3552
1.4.4 by Arno Töll
Import upstream version 1.4.7
3553
        c->rbytes = res;
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3554
        c->rcurr = c->rbuf;
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
3555
        return READ_DATA_RECEIVED;
1 by Jay Bonci
Import upstream version 1.1.11
3556
    }
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
3557
    return READ_NO_DATA_RECEIVED;
1 by Jay Bonci
Import upstream version 1.1.11
3558
}
3559
3560
/*
3561
 * read from network as much as we can, handle buffer overflow and connection
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3562
 * close.
3563
 * before reading, move the remaining incomplete fragment of a command
3564
 * (if any) to the beginning of the buffer.
1.4.3 by David Martínez Moreno
Import upstream version 1.4.5
3565
 *
3566
 * To protect us from someone flooding a connection with bogus data causing
3567
 * the connection to eat up all available memory, break out and start looking
3568
 * at the data I've got after a number of reallocs...
3569
 *
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
3570
 * @return enum try_read_result
1 by Jay Bonci
Import upstream version 1.1.11
3571
 */
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
3572
static enum try_read_result try_read_network(conn *c) {
3573
    enum try_read_result gotdata = READ_NO_DATA_RECEIVED;
1 by Jay Bonci
Import upstream version 1.1.11
3574
    int res;
1.4.3 by David Martínez Moreno
Import upstream version 1.4.5
3575
    int num_allocs = 0;
1.2.1 by Jay Bonci
Import upstream version 1.2.2
3576
    assert(c != NULL);
3577
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3578
    if (c->rcurr != c->rbuf) {
3579
        if (c->rbytes != 0) /* otherwise there's nothing to copy */
3580
            memmove(c->rbuf, c->rcurr, c->rbytes);
3581
        c->rcurr = c->rbuf;
3582
    }
3583
1 by Jay Bonci
Import upstream version 1.1.11
3584
    while (1) {
3585
        if (c->rbytes >= c->rsize) {
1.4.3 by David Martínez Moreno
Import upstream version 1.4.5
3586
            if (num_allocs == 4) {
3587
                return gotdata;
3588
            }
3589
            ++num_allocs;
1.2.1 by Jay Bonci
Import upstream version 1.2.2
3590
            char *new_rbuf = realloc(c->rbuf, c->rsize * 2);
1 by Jay Bonci
Import upstream version 1.1.11
3591
            if (!new_rbuf) {
3592
                if (settings.verbose > 0)
3593
                    fprintf(stderr, "Couldn't realloc input buffer\n");
3594
                c->rbytes = 0; /* ignore what we read */
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
3595
                out_string(c, "SERVER_ERROR out of memory reading request");
1 by Jay Bonci
Import upstream version 1.1.11
3596
                c->write_and_go = conn_closing;
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
3597
                return READ_MEMORY_ERROR;
1 by Jay Bonci
Import upstream version 1.1.11
3598
            }
1.2.1 by Jay Bonci
Import upstream version 1.2.2
3599
            c->rcurr = c->rbuf = new_rbuf;
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3600
            c->rsize *= 2;
3601
        }
3602
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
3603
        int avail = c->rsize - c->rbytes;
3604
        res = read(c->sfd, c->rbuf + c->rbytes, avail);
1 by Jay Bonci
Import upstream version 1.1.11
3605
        if (res > 0) {
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
3606
            pthread_mutex_lock(&c->thread->stats.mutex);
3607
            c->thread->stats.bytes_read += res;
3608
            pthread_mutex_unlock(&c->thread->stats.mutex);
3609
            gotdata = READ_DATA_RECEIVED;
1 by Jay Bonci
Import upstream version 1.1.11
3610
            c->rbytes += res;
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
3611
            if (res == avail) {
3612
                continue;
3613
            } else {
3614
                break;
3615
            }
1 by Jay Bonci
Import upstream version 1.1.11
3616
        }
3617
        if (res == 0) {
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
3618
            return READ_ERROR;
1 by Jay Bonci
Import upstream version 1.1.11
3619
        }
3620
        if (res == -1) {
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
3621
            if (errno == EAGAIN || errno == EWOULDBLOCK) {
3622
                break;
3623
            }
3624
            return READ_ERROR;
1 by Jay Bonci
Import upstream version 1.1.11
3625
        }
3626
    }
3627
    return gotdata;
3628
}
3629
1.2.1 by Jay Bonci
Import upstream version 1.2.2
3630
static bool update_event(conn *c, const int new_flags) {
3631
    assert(c != NULL);
3632
3633
    struct event_base *base = c->event.ev_base;
1 by Jay Bonci
Import upstream version 1.1.11
3634
    if (c->ev_flags == new_flags)
1.2.1 by Jay Bonci
Import upstream version 1.2.2
3635
        return true;
3636
    if (event_del(&c->event) == -1) return false;
1 by Jay Bonci
Import upstream version 1.1.11
3637
    event_set(&c->event, c->sfd, new_flags, event_handler, (void *)c);
1.2.1 by Jay Bonci
Import upstream version 1.2.2
3638
    event_base_set(base, &c->event);
1 by Jay Bonci
Import upstream version 1.1.11
3639
    c->ev_flags = new_flags;
1.2.1 by Jay Bonci
Import upstream version 1.2.2
3640
    if (event_add(&c->event, 0) == -1) return false;
3641
    return true;
3642
}
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3643
3644
/*
3645
 * Sets whether we are listening for new connections or not.
3646
 */
1.3.2 by David Martínez Moreno
Import upstream version 1.2.8
3647
void do_accept_new_conns(const bool do_accept) {
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
3648
    conn *next;
3649
3650
    for (next = listen_conn; next; next = next->next) {
3651
        if (do_accept) {
3652
            update_event(next, EV_READ | EV_PERSIST);
1.3.2 by David Martínez Moreno
Import upstream version 1.2.8
3653
            if (listen(next->sfd, settings.backlog) != 0) {
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
3654
                perror("listen");
3655
            }
3656
        }
3657
        else {
3658
            update_event(next, 0);
3659
            if (listen(next->sfd, 0) != 0) {
3660
                perror("listen");
3661
            }
3662
        }
1.3.2 by David Martínez Moreno
Import upstream version 1.2.8
3663
    }
3664
3665
    if (do_accept) {
3666
        STATS_LOCK();
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
3667
        stats.accepting_conns = true;
1.3.2 by David Martínez Moreno
Import upstream version 1.2.8
3668
        STATS_UNLOCK();
3669
    } else {
3670
        STATS_LOCK();
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
3671
        stats.accepting_conns = false;
1.3.2 by David Martínez Moreno
Import upstream version 1.2.8
3672
        stats.listen_disabled_num++;
3673
        STATS_UNLOCK();
1.4.4 by Arno Töll
Import upstream version 1.4.7
3674
        allow_new_conns = false;
3675
        maxconns_handler(-42, 0, 0);
1.3.2 by David Martínez Moreno
Import upstream version 1.2.8
3676
    }
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3677
}
3678
3679
/*
3680
 * Transmit the next chunk of data from our list of msgbuf structures.
3681
 *
3682
 * Returns:
3683
 *   TRANSMIT_COMPLETE   All done writing.
3684
 *   TRANSMIT_INCOMPLETE More data remaining to write.
3685
 *   TRANSMIT_SOFT_ERROR Can't write any more right now.
3686
 *   TRANSMIT_HARD_ERROR Can't write (c->state is set to conn_closing)
3687
 */
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
3688
static enum transmit_result transmit(conn *c) {
1.2.1 by Jay Bonci
Import upstream version 1.2.2
3689
    assert(c != NULL);
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3690
3691
    if (c->msgcurr < c->msgused &&
3692
            c->msglist[c->msgcurr].msg_iovlen == 0) {
3693
        /* Finished writing the current msg; advance to the next. */
3694
        c->msgcurr++;
3695
    }
3696
    if (c->msgcurr < c->msgused) {
1.2.1 by Jay Bonci
Import upstream version 1.2.2
3697
        ssize_t res;
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3698
        struct msghdr *m = &c->msglist[c->msgcurr];
1.2.1 by Jay Bonci
Import upstream version 1.2.2
3699
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3700
        res = sendmsg(c->sfd, m, 0);
3701
        if (res > 0) {
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
3702
            pthread_mutex_lock(&c->thread->stats.mutex);
3703
            c->thread->stats.bytes_written += res;
3704
            pthread_mutex_unlock(&c->thread->stats.mutex);
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3705
3706
            /* We've written some of the data. Remove the completed
3707
               iovec entries from the list of pending writes. */
3708
            while (m->msg_iovlen > 0 && res >= m->msg_iov->iov_len) {
3709
                res -= m->msg_iov->iov_len;
3710
                m->msg_iovlen--;
3711
                m->msg_iov++;
3712
            }
3713
3714
            /* Might have written just part of the last iovec entry;
3715
               adjust it so the next write will do the rest. */
3716
            if (res > 0) {
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
3717
                m->msg_iov->iov_base = (caddr_t)m->msg_iov->iov_base + res;
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3718
                m->msg_iov->iov_len -= res;
3719
            }
3720
            return TRANSMIT_INCOMPLETE;
3721
        }
3722
        if (res == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
3723
            if (!update_event(c, EV_WRITE | EV_PERSIST)) {
3724
                if (settings.verbose > 0)
3725
                    fprintf(stderr, "Couldn't update event\n");
3726
                conn_set_state(c, conn_closing);
3727
                return TRANSMIT_HARD_ERROR;
3728
            }
3729
            return TRANSMIT_SOFT_ERROR;
3730
        }
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
3731
        /* if res == 0 or res == -1 and error is not EAGAIN or EWOULDBLOCK,
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3732
           we have a real error, on which we close the connection */
3733
        if (settings.verbose > 0)
3734
            perror("Failed to write, and not due to blocking");
3735
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
3736
        if (IS_UDP(c->transport))
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3737
            conn_set_state(c, conn_read);
3738
        else
3739
            conn_set_state(c, conn_closing);
3740
        return TRANSMIT_HARD_ERROR;
3741
    } else {
3742
        return TRANSMIT_COMPLETE;
3743
    }
3744
}
3745
1.2.1 by Jay Bonci
Import upstream version 1.2.2
3746
static void drive_machine(conn *c) {
3747
    bool stop = false;
1 by Jay Bonci
Import upstream version 1.1.11
3748
    int sfd, flags = 1;
3749
    socklen_t addrlen;
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
3750
    struct sockaddr_storage addr;
1.3.2 by David Martínez Moreno
Import upstream version 1.2.8
3751
    int nreqs = settings.reqs_per_event;
1 by Jay Bonci
Import upstream version 1.1.11
3752
    int res;
1.1.9 by Scott Kitterman
Import upstream version 1.4.9
3753
    const char *str;
1 by Jay Bonci
Import upstream version 1.1.11
3754
1.2.1 by Jay Bonci
Import upstream version 1.2.2
3755
    assert(c != NULL);
3756
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3757
    while (!stop) {
1.2.1 by Jay Bonci
Import upstream version 1.2.2
3758
1 by Jay Bonci
Import upstream version 1.1.11
3759
        switch(c->state) {
3760
        case conn_listening:
3761
            addrlen = sizeof(addr);
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
3762
            if ((sfd = accept(c->sfd, (struct sockaddr *)&addr, &addrlen)) == -1) {
1 by Jay Bonci
Import upstream version 1.1.11
3763
                if (errno == EAGAIN || errno == EWOULDBLOCK) {
1.2.1 by Jay Bonci
Import upstream version 1.2.2
3764
                    /* these are transient, so don't log anything */
3765
                    stop = true;
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3766
                } else if (errno == EMFILE) {
3767
                    if (settings.verbose > 0)
3768
                        fprintf(stderr, "Too many open connections\n");
1.2.1 by Jay Bonci
Import upstream version 1.2.2
3769
                    accept_new_conns(false);
3770
                    stop = true;
1 by Jay Bonci
Import upstream version 1.1.11
3771
                } else {
3772
                    perror("accept()");
1.2.1 by Jay Bonci
Import upstream version 1.2.2
3773
                    stop = true;
1 by Jay Bonci
Import upstream version 1.1.11
3774
                }
3775
                break;
3776
            }
3777
            if ((flags = fcntl(sfd, F_GETFL, 0)) < 0 ||
3778
                fcntl(sfd, F_SETFL, flags | O_NONBLOCK) < 0) {
3779
                perror("setting O_NONBLOCK");
3780
                close(sfd);
3781
                break;
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3782
            }
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
3783
1.1.9 by Scott Kitterman
Import upstream version 1.4.9
3784
            if (settings.maxconns_fast &&
3785
                stats.curr_conns + stats.reserved_fds >= settings.maxconns - 1) {
3786
                str = "ERROR Too many open connections\r\n";
3787
                res = write(sfd, str, strlen(str));
3788
                close(sfd);
3789
                STATS_LOCK();
3790
                stats.rejected_conns++;
3791
                STATS_UNLOCK();
3792
            } else {
3793
                dispatch_conn_new(sfd, conn_new_cmd, EV_READ | EV_PERSIST,
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
3794
                                     DATA_BUFFER_SIZE, tcp_transport);
1.1.9 by Scott Kitterman
Import upstream version 1.4.9
3795
            }
3796
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
3797
            stop = true;
3798
            break;
3799
3800
        case conn_waiting:
3801
            if (!update_event(c, EV_READ | EV_PERSIST)) {
3802
                if (settings.verbose > 0)
3803
                    fprintf(stderr, "Couldn't update event\n");
3804
                conn_set_state(c, conn_closing);
3805
                break;
3806
            }
3807
3808
            conn_set_state(c, conn_read);
3809
            stop = true;
1 by Jay Bonci
Import upstream version 1.1.11
3810
            break;
3811
3812
        case conn_read:
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
3813
            res = IS_UDP(c->transport) ? try_read_udp(c) : try_read_network(c);
3814
3815
            switch (res) {
3816
            case READ_NO_DATA_RECEIVED:
3817
                conn_set_state(c, conn_waiting);
3818
                break;
3819
            case READ_DATA_RECEIVED:
3820
                conn_set_state(c, conn_parse_cmd);
3821
                break;
3822
            case READ_ERROR:
3823
                conn_set_state(c, conn_closing);
3824
                break;
3825
            case READ_MEMORY_ERROR: /* Failed to allocate more memory */
3826
                /* State already set by try_read_network */
3827
                break;
3828
            }
3829
            break;
3830
3831
        case conn_parse_cmd :
3832
            if (try_read_command(c) == 0) {
3833
                /* wee need more data! */
3834
                conn_set_state(c, conn_waiting);
3835
            }
3836
3837
            break;
3838
3839
        case conn_new_cmd:
1.3.2 by David Martínez Moreno
Import upstream version 1.2.8
3840
            /* Only process nreqs at a time to avoid starving other
3841
               connections */
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
3842
3843
            --nreqs;
3844
            if (nreqs >= 0) {
3845
                reset_cmd_handler(c);
3846
            } else {
3847
                pthread_mutex_lock(&c->thread->stats.mutex);
3848
                c->thread->stats.conn_yields++;
3849
                pthread_mutex_unlock(&c->thread->stats.mutex);
3850
                if (c->rbytes > 0) {
3851
                    /* We have already read in data into the input buffer,
3852
                       so libevent will most likely not signal read events
3853
                       on the socket (unless more data is available. As a
3854
                       hack we should just put in a request to write data,
3855
                       because that should be possible ;-)
3856
                    */
3857
                    if (!update_event(c, EV_WRITE | EV_PERSIST)) {
3858
                        if (settings.verbose > 0)
3859
                            fprintf(stderr, "Couldn't update event\n");
3860
                        conn_set_state(c, conn_closing);
3861
                    }
3862
                }
3863
                stop = true;
3864
            }
1 by Jay Bonci
Import upstream version 1.1.11
3865
            break;
3866
3867
        case conn_nread:
3868
            if (c->rlbytes == 0) {
3869
                complete_nread(c);
3870
                break;
3871
            }
3872
            /* first check if we have leftovers in the conn_read buffer */
3873
            if (c->rbytes > 0) {
3874
                int tocopy = c->rbytes > c->rlbytes ? c->rlbytes : c->rbytes;
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
3875
                if (c->ritem != c->rcurr) {
3876
                    memmove(c->ritem, c->rcurr, tocopy);
3877
                }
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3878
                c->ritem += tocopy;
1 by Jay Bonci
Import upstream version 1.1.11
3879
                c->rlbytes -= tocopy;
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3880
                c->rcurr += tocopy;
1 by Jay Bonci
Import upstream version 1.1.11
3881
                c->rbytes -= tocopy;
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
3882
                if (c->rlbytes == 0) {
3883
                    break;
3884
                }
1 by Jay Bonci
Import upstream version 1.1.11
3885
            }
3886
3887
            /*  now try reading from the socket */
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3888
            res = read(c->sfd, c->ritem, c->rlbytes);
1 by Jay Bonci
Import upstream version 1.1.11
3889
            if (res > 0) {
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
3890
                pthread_mutex_lock(&c->thread->stats.mutex);
3891
                c->thread->stats.bytes_read += res;
3892
                pthread_mutex_unlock(&c->thread->stats.mutex);
3893
                if (c->rcurr == c->ritem) {
3894
                    c->rcurr += res;
3895
                }
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3896
                c->ritem += res;
1 by Jay Bonci
Import upstream version 1.1.11
3897
                c->rlbytes -= res;
3898
                break;
3899
            }
3900
            if (res == 0) { /* end of stream */
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3901
                conn_set_state(c, conn_closing);
1 by Jay Bonci
Import upstream version 1.1.11
3902
                break;
3903
            }
3904
            if (res == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
3905
                if (!update_event(c, EV_READ | EV_PERSIST)) {
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3906
                    if (settings.verbose > 0)
1 by Jay Bonci
Import upstream version 1.1.11
3907
                        fprintf(stderr, "Couldn't update event\n");
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3908
                    conn_set_state(c, conn_closing);
1 by Jay Bonci
Import upstream version 1.1.11
3909
                    break;
3910
                }
1.2.1 by Jay Bonci
Import upstream version 1.2.2
3911
                stop = true;
1 by Jay Bonci
Import upstream version 1.1.11
3912
                break;
3913
            }
3914
            /* otherwise we have a real error, on which we close the connection */
1.3.4 by David Martínez Moreno
Import upstream version 1.4.1
3915
            if (settings.verbose > 0) {
3916
                fprintf(stderr, "Failed to read, and not due to blocking:\n"
3917
                        "errno: %d %s \n"
3918
                        "rcurr=%lx ritem=%lx rbuf=%lx rlbytes=%d rsize=%d\n",
3919
                        errno, strerror(errno),
3920
                        (long)c->rcurr, (long)c->ritem, (long)c->rbuf,
3921
                        (int)c->rlbytes, (int)c->rsize);
3922
            }
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3923
            conn_set_state(c, conn_closing);
1 by Jay Bonci
Import upstream version 1.1.11
3924
            break;
3925
3926
        case conn_swallow:
3927
            /* we are reading sbytes and throwing them away */
3928
            if (c->sbytes == 0) {
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
3929
                conn_set_state(c, conn_new_cmd);
1 by Jay Bonci
Import upstream version 1.1.11
3930
                break;
3931
            }
3932
3933
            /* first check if we have leftovers in the conn_read buffer */
3934
            if (c->rbytes > 0) {
3935
                int tocopy = c->rbytes > c->sbytes ? c->sbytes : c->rbytes;
3936
                c->sbytes -= tocopy;
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3937
                c->rcurr += tocopy;
1 by Jay Bonci
Import upstream version 1.1.11
3938
                c->rbytes -= tocopy;
3939
                break;
3940
            }
3941
3942
            /*  now try reading from the socket */
3943
            res = read(c->sfd, c->rbuf, c->rsize > c->sbytes ? c->sbytes : c->rsize);
3944
            if (res > 0) {
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
3945
                pthread_mutex_lock(&c->thread->stats.mutex);
3946
                c->thread->stats.bytes_read += res;
3947
                pthread_mutex_unlock(&c->thread->stats.mutex);
1 by Jay Bonci
Import upstream version 1.1.11
3948
                c->sbytes -= res;
3949
                break;
3950
            }
3951
            if (res == 0) { /* end of stream */
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3952
                conn_set_state(c, conn_closing);
1 by Jay Bonci
Import upstream version 1.1.11
3953
                break;
3954
            }
3955
            if (res == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
3956
                if (!update_event(c, EV_READ | EV_PERSIST)) {
3957
                    if (settings.verbose > 0)
3958
                        fprintf(stderr, "Couldn't update event\n");
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3959
                    conn_set_state(c, conn_closing);
1 by Jay Bonci
Import upstream version 1.1.11
3960
                    break;
3961
                }
1.2.1 by Jay Bonci
Import upstream version 1.2.2
3962
                stop = true;
1 by Jay Bonci
Import upstream version 1.1.11
3963
                break;
3964
            }
3965
            /* otherwise we have a real error, on which we close the connection */
3966
            if (settings.verbose > 0)
3967
                fprintf(stderr, "Failed to read, and not due to blocking\n");
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3968
            conn_set_state(c, conn_closing);
1 by Jay Bonci
Import upstream version 1.1.11
3969
            break;
3970
3971
        case conn_write:
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3972
            /*
3973
             * We want to write out a simple response. If we haven't already,
3974
             * assemble it into a msgbuf list (this will be a single-entry
3975
             * list for TCP or a two-entry list for UDP).
3976
             */
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
3977
            if (c->iovused == 0 || (IS_UDP(c->transport) && c->iovused == 1)) {
3978
                if (add_iov(c, c->wcurr, c->wbytes) != 0) {
1 by Jay Bonci
Import upstream version 1.1.11
3979
                    if (settings.verbose > 0)
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3980
                        fprintf(stderr, "Couldn't build response\n");
3981
                    conn_set_state(c, conn_closing);
1 by Jay Bonci
Import upstream version 1.1.11
3982
                    break;
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3983
                }
1 by Jay Bonci
Import upstream version 1.1.11
3984
            }
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3985
3986
            /* fall through... */
3987
1 by Jay Bonci
Import upstream version 1.1.11
3988
        case conn_mwrite:
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
3989
          if (IS_UDP(c->transport) && c->msgcurr == 0 && build_udp_headers(c) != 0) {
3990
            if (settings.verbose > 0)
3991
              fprintf(stderr, "Failed to build UDP headers\n");
3992
            conn_set_state(c, conn_closing);
3993
            break;
3994
          }
1.1.2 by Jay Bonci
Import upstream version 1.2.1
3995
            switch (transmit(c)) {
3996
            case TRANSMIT_COMPLETE:
3997
                if (c->state == conn_mwrite) {
3998
                    while (c->ileft > 0) {
3999
                        item *it = *(c->icurr);
4000
                        assert((it->it_flags & ITEM_SLABBED) == 0);
4001
                        item_remove(it);
1 by Jay Bonci
Import upstream version 1.1.11
4002
                        c->icurr++;
1.1.2 by Jay Bonci
Import upstream version 1.2.1
4003
                        c->ileft--;
4004
                    }
1.2.3 by David Martínez Moreno
Import upstream version 1.2.4
4005
                    while (c->suffixleft > 0) {
4006
                        char *suffix = *(c->suffixcurr);
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
4007
                        cache_free(c->thread->suffix_cache, suffix);
1.2.3 by David Martínez Moreno
Import upstream version 1.2.4
4008
                        c->suffixcurr++;
4009
                        c->suffixleft--;
4010
                    }
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
4011
                    /* XXX:  I don't know why this wasn't the general case */
4012
                    if(c->protocol == binary_prot) {
4013
                        conn_set_state(c, c->write_and_go);
4014
                    } else {
4015
                        conn_set_state(c, conn_new_cmd);
4016
                    }
1.1.2 by Jay Bonci
Import upstream version 1.2.1
4017
                } else if (c->state == conn_write) {
4018
                    if (c->write_and_free) {
4019
                        free(c->write_and_free);
4020
                        c->write_and_free = 0;
4021
                    }
4022
                    conn_set_state(c, c->write_and_go);
4023
                } else {
4024
                    if (settings.verbose > 0)
4025
                        fprintf(stderr, "Unexpected state %d\n", c->state);
4026
                    conn_set_state(c, conn_closing);
1 by Jay Bonci
Import upstream version 1.1.11
4027
                }
1.1.2 by Jay Bonci
Import upstream version 1.2.1
4028
                break;
4029
4030
            case TRANSMIT_INCOMPLETE:
4031
            case TRANSMIT_HARD_ERROR:
4032
                break;                   /* Continue in state machine. */
4033
4034
            case TRANSMIT_SOFT_ERROR:
1.2.1 by Jay Bonci
Import upstream version 1.2.2
4035
                stop = true;
1.1.2 by Jay Bonci
Import upstream version 1.2.1
4036
                break;
1 by Jay Bonci
Import upstream version 1.1.11
4037
            }
4038
            break;
4039
4040
        case conn_closing:
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
4041
            if (IS_UDP(c->transport))
1.1.2 by Jay Bonci
Import upstream version 1.2.1
4042
                conn_cleanup(c);
4043
            else
4044
                conn_close(c);
1.2.1 by Jay Bonci
Import upstream version 1.2.2
4045
            stop = true;
1 by Jay Bonci
Import upstream version 1.1.11
4046
            break;
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
4047
4048
        case conn_max_state:
4049
            assert(false);
4050
            break;
1 by Jay Bonci
Import upstream version 1.1.11
4051
        }
4052
    }
4053
4054
    return;
4055
}
4056
1.2.1 by Jay Bonci
Import upstream version 1.2.2
4057
void event_handler(const int fd, const short which, void *arg) {
1 by Jay Bonci
Import upstream version 1.1.11
4058
    conn *c;
1.1.2 by Jay Bonci
Import upstream version 1.2.1
4059
1 by Jay Bonci
Import upstream version 1.1.11
4060
    c = (conn *)arg;
1.2.1 by Jay Bonci
Import upstream version 1.2.2
4061
    assert(c != NULL);
4062
1 by Jay Bonci
Import upstream version 1.1.11
4063
    c->which = which;
4064
4065
    /* sanity */
4066
    if (fd != c->sfd) {
4067
        if (settings.verbose > 0)
4068
            fprintf(stderr, "Catastrophic: event fd doesn't match conn fd!\n");
4069
        conn_close(c);
4070
        return;
4071
    }
4072
4073
    drive_machine(c);
4074
4075
    /* wait for next event */
4076
    return;
4077
}
4078
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
4079
static int new_socket(struct addrinfo *ai) {
1 by Jay Bonci
Import upstream version 1.1.11
4080
    int sfd;
4081
    int flags;
4082
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
4083
    if ((sfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) == -1) {
1 by Jay Bonci
Import upstream version 1.1.11
4084
        return -1;
4085
    }
4086
4087
    if ((flags = fcntl(sfd, F_GETFL, 0)) < 0 ||
4088
        fcntl(sfd, F_SETFL, flags | O_NONBLOCK) < 0) {
4089
        perror("setting O_NONBLOCK");
4090
        close(sfd);
4091
        return -1;
4092
    }
4093
    return sfd;
4094
}
4095
1.1.2 by Jay Bonci
Import upstream version 1.2.1
4096
4097
/*
4098
 * Sets a socket's send buffer size to the maximum allowed by the system.
4099
 */
1.2.1 by Jay Bonci
Import upstream version 1.2.2
4100
static void maximize_sndbuf(const int sfd) {
1.1.2 by Jay Bonci
Import upstream version 1.2.1
4101
    socklen_t intsize = sizeof(int);
4102
    int last_good = 0;
4103
    int min, max, avg;
4104
    int old_size;
4105
4106
    /* Start with the default size. */
1.2.1 by Jay Bonci
Import upstream version 1.2.2
4107
    if (getsockopt(sfd, SOL_SOCKET, SO_SNDBUF, &old_size, &intsize) != 0) {
1.1.2 by Jay Bonci
Import upstream version 1.2.1
4108
        if (settings.verbose > 0)
4109
            perror("getsockopt(SO_SNDBUF)");
4110
        return;
4111
    }
4112
4113
    /* Binary-search for the real maximum. */
4114
    min = old_size;
4115
    max = MAX_SENDBUF_SIZE;
4116
4117
    while (min <= max) {
1.2.1 by Jay Bonci
Import upstream version 1.2.2
4118
        avg = ((unsigned int)(min + max)) / 2;
4119
        if (setsockopt(sfd, SOL_SOCKET, SO_SNDBUF, (void *)&avg, intsize) == 0) {
1.1.2 by Jay Bonci
Import upstream version 1.2.1
4120
            last_good = avg;
4121
            min = avg + 1;
4122
        } else {
4123
            max = avg - 1;
4124
        }
4125
    }
4126
4127
    if (settings.verbose > 1)
4128
        fprintf(stderr, "<%d send buffer was %d, now %d\n", sfd, old_size, last_good);
4129
}
4130
1.3.4 by David Martínez Moreno
Import upstream version 1.4.1
4131
/**
4132
 * Create a socket and bind it to a specific port number
1.4.4 by Arno Töll
Import upstream version 1.4.7
4133
 * @param interface the interface to bind to
1.3.4 by David Martínez Moreno
Import upstream version 1.4.1
4134
 * @param port the port number to bind to
4135
 * @param transport the transport protocol (TCP / UDP)
4136
 * @param portnumber_file A filepointer to write the port numbers to
4137
 *        when they are successfully added to the list of ports we
4138
 *        listen on.
4139
 */
1.4.4 by Arno Töll
Import upstream version 1.4.7
4140
static int server_socket(const char *interface,
4141
                         int port,
4142
                         enum network_transport transport,
1.3.4 by David Martínez Moreno
Import upstream version 1.4.1
4143
                         FILE *portnumber_file) {
1 by Jay Bonci
Import upstream version 1.1.11
4144
    int sfd;
4145
    struct linger ling = {0, 0};
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
4146
    struct addrinfo *ai;
4147
    struct addrinfo *next;
1.3.4 by David Martínez Moreno
Import upstream version 1.4.1
4148
    struct addrinfo hints = { .ai_flags = AI_PASSIVE,
4149
                              .ai_family = AF_UNSPEC };
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
4150
    char port_buf[NI_MAXSERV];
4151
    int error;
4152
    int success = 0;
1 by Jay Bonci
Import upstream version 1.1.11
4153
    int flags =1;
4154
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
4155
    hints.ai_socktype = IS_UDP(transport) ? SOCK_DGRAM : SOCK_STREAM;
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
4156
1.3.4 by David Martínez Moreno
Import upstream version 1.4.1
4157
    if (port == -1) {
4158
        port = 0;
4159
    }
4160
    snprintf(port_buf, sizeof(port_buf), "%d", port);
1.4.4 by Arno Töll
Import upstream version 1.4.7
4161
    error= getaddrinfo(interface, port_buf, &hints, &ai);
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
4162
    if (error != 0) {
1.3.2 by David Martínez Moreno
Import upstream version 1.2.8
4163
        if (error != EAI_SYSTEM)
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
4164
          fprintf(stderr, "getaddrinfo(): %s\n", gai_strerror(error));
1.3.2 by David Martínez Moreno
Import upstream version 1.2.8
4165
        else
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
4166
          perror("getaddrinfo()");
1.3.2 by David Martínez Moreno
Import upstream version 1.2.8
4167
        return 1;
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
4168
    }
4169
4170
    for (next= ai; next; next= next->ai_next) {
4171
        conn *listen_conn_add;
4172
        if ((sfd = new_socket(next)) == -1) {
1.3.2 by David Martínez Moreno
Import upstream version 1.2.8
4173
            /* getaddrinfo can return "junk" addresses,
4174
             * we make sure at least one works before erroring.
4175
             */
1.1.9 by Scott Kitterman
Import upstream version 1.4.9
4176
            if (errno == EMFILE) {
4177
                /* ...unless we're out of fds */
4178
                perror("server_socket");
4179
                exit(EX_OSERR);
4180
            }
1.3.2 by David Martínez Moreno
Import upstream version 1.2.8
4181
            continue;
4182
        }
4183
4184
#ifdef IPV6_V6ONLY
4185
        if (next->ai_family == AF_INET6) {
4186
            error = setsockopt(sfd, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &flags, sizeof(flags));
4187
            if (error != 0) {
4188
                perror("setsockopt");
4189
                close(sfd);
4190
                continue;
4191
            }
4192
        }
4193
#endif
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
4194
4195
        setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (void *)&flags, sizeof(flags));
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
4196
        if (IS_UDP(transport)) {
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
4197
            maximize_sndbuf(sfd);
4198
        } else {
1.3.2 by David Martínez Moreno
Import upstream version 1.2.8
4199
            error = setsockopt(sfd, SOL_SOCKET, SO_KEEPALIVE, (void *)&flags, sizeof(flags));
4200
            if (error != 0)
4201
                perror("setsockopt");
4202
4203
            error = setsockopt(sfd, SOL_SOCKET, SO_LINGER, (void *)&ling, sizeof(ling));
4204
            if (error != 0)
4205
                perror("setsockopt");
4206
4207
            error = setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, (void *)&flags, sizeof(flags));
4208
            if (error != 0)
4209
                perror("setsockopt");
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
4210
        }
4211
4212
        if (bind(sfd, next->ai_addr, next->ai_addrlen) == -1) {
4213
            if (errno != EADDRINUSE) {
4214
                perror("bind()");
4215
                close(sfd);
4216
                freeaddrinfo(ai);
4217
                return 1;
4218
            }
4219
            close(sfd);
4220
            continue;
4221
        } else {
1.3.2 by David Martínez Moreno
Import upstream version 1.2.8
4222
            success++;
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
4223
            if (!IS_UDP(transport) && listen(sfd, settings.backlog) == -1) {
1.3.2 by David Martínez Moreno
Import upstream version 1.2.8
4224
                perror("listen()");
4225
                close(sfd);
4226
                freeaddrinfo(ai);
4227
                return 1;
4228
            }
1.3.4 by David Martínez Moreno
Import upstream version 1.4.1
4229
            if (portnumber_file != NULL &&
4230
                (next->ai_addr->sa_family == AF_INET ||
4231
                 next->ai_addr->sa_family == AF_INET6)) {
4232
                union {
4233
                    struct sockaddr_in in;
4234
                    struct sockaddr_in6 in6;
4235
                } my_sockaddr;
4236
                socklen_t len = sizeof(my_sockaddr);
4237
                if (getsockname(sfd, (struct sockaddr*)&my_sockaddr, &len)==0) {
4238
                    if (next->ai_addr->sa_family == AF_INET) {
4239
                        fprintf(portnumber_file, "%s INET: %u\n",
4240
                                IS_UDP(transport) ? "UDP" : "TCP",
4241
                                ntohs(my_sockaddr.in.sin_port));
4242
                    } else {
4243
                        fprintf(portnumber_file, "%s INET6: %u\n",
4244
                                IS_UDP(transport) ? "UDP" : "TCP",
4245
                                ntohs(my_sockaddr.in6.sin6_port));
4246
                    }
4247
                }
4248
            }
1.3.2 by David Martínez Moreno
Import upstream version 1.2.8
4249
        }
4250
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
4251
        if (IS_UDP(transport)) {
4252
            int c;
1.3.2 by David Martínez Moreno
Import upstream version 1.2.8
4253
1.4.4 by Arno Töll
Import upstream version 1.4.7
4254
            for (c = 0; c < settings.num_threads_per_udp; c++) {
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
4255
                /* this is guaranteed to hit all threads because we round-robin */
4256
                dispatch_conn_new(sfd, conn_read, EV_READ | EV_PERSIST,
4257
                                  UDP_READ_BUFFER_SIZE, transport);
4258
            }
1.3.2 by David Martínez Moreno
Import upstream version 1.2.8
4259
        } else {
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
4260
            if (!(listen_conn_add = conn_new(sfd, conn_listening,
4261
                                             EV_READ | EV_PERSIST, 1,
4262
                                             transport, main_base))) {
4263
                fprintf(stderr, "failed to create listening connection\n");
4264
                exit(EXIT_FAILURE);
4265
            }
4266
            listen_conn_add->next = listen_conn;
4267
            listen_conn = listen_conn_add;
1.3.2 by David Martínez Moreno
Import upstream version 1.2.8
4268
        }
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
4269
    }
4270
4271
    freeaddrinfo(ai);
4272
4273
    /* Return zero iff we detected no errors in starting up connections */
4274
    return success == 0;
1.1.2 by Jay Bonci
Import upstream version 1.2.1
4275
}
4276
1.4.4 by Arno Töll
Import upstream version 1.4.7
4277
static int server_sockets(int port, enum network_transport transport,
4278
                          FILE *portnumber_file) {
4279
    if (settings.inter == NULL) {
4280
        return server_socket(settings.inter, port, transport, portnumber_file);
4281
    } else {
4282
        // tokenize them and bind to each one of them..
4283
        char *b;
4284
        int ret = 0;
4285
        char *list = strdup(settings.inter);
4286
4287
        if (list == NULL) {
4288
            fprintf(stderr, "Failed to allocate memory for parsing server interface string\n");
4289
            return 1;
4290
        }
4291
        for (char *p = strtok_r(list, ";,", &b);
4292
             p != NULL;
4293
             p = strtok_r(NULL, ";,", &b)) {
4294
            int the_port = port;
4295
            char *s = strchr(p, ':');
4296
            if (s != NULL) {
4297
                *s = '\0';
4298
                ++s;
4299
                if (!safe_strtol(s, &the_port)) {
4300
                    fprintf(stderr, "Invalid port number: \"%s\"", s);
4301
                    return 1;
4302
                }
4303
            }
4304
            if (strcmp(p, "*") == 0) {
4305
                p = NULL;
4306
            }
4307
            ret |= server_socket(p, the_port, transport, portnumber_file);
4308
        }
4309
        free(list);
4310
        return ret;
4311
    }
4312
}
4313
1.2.1 by Jay Bonci
Import upstream version 1.2.2
4314
static int new_socket_unix(void) {
1.1.2 by Jay Bonci
Import upstream version 1.2.1
4315
    int sfd;
4316
    int flags;
4317
4318
    if ((sfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
4319
        perror("socket()");
4320
        return -1;
4321
    }
4322
4323
    if ((flags = fcntl(sfd, F_GETFL, 0)) < 0 ||
4324
        fcntl(sfd, F_SETFL, flags | O_NONBLOCK) < 0) {
4325
        perror("setting O_NONBLOCK");
4326
        close(sfd);
4327
        return -1;
4328
    }
4329
    return sfd;
4330
}
4331
1.2.3 by David Martínez Moreno
Import upstream version 1.2.4
4332
static int server_socket_unix(const char *path, int access_mask) {
1.1.2 by Jay Bonci
Import upstream version 1.2.1
4333
    int sfd;
4334
    struct linger ling = {0, 0};
4335
    struct sockaddr_un addr;
4336
    struct stat tstat;
4337
    int flags =1;
1.2.3 by David Martínez Moreno
Import upstream version 1.2.4
4338
    int old_umask;
1.1.2 by Jay Bonci
Import upstream version 1.2.1
4339
4340
    if (!path) {
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
4341
        return 1;
1.1.2 by Jay Bonci
Import upstream version 1.2.1
4342
    }
4343
4344
    if ((sfd = new_socket_unix()) == -1) {
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
4345
        return 1;
1.1.2 by Jay Bonci
Import upstream version 1.2.1
4346
    }
4347
4348
    /*
4349
     * Clean up a previous socket file if we left it around
4350
     */
1.2.1 by Jay Bonci
Import upstream version 1.2.2
4351
    if (lstat(path, &tstat) == 0) {
1.1.2 by Jay Bonci
Import upstream version 1.2.1
4352
        if (S_ISSOCK(tstat.st_mode))
4353
            unlink(path);
4354
    }
4355
1.2.1 by Jay Bonci
Import upstream version 1.2.2
4356
    setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (void *)&flags, sizeof(flags));
4357
    setsockopt(sfd, SOL_SOCKET, SO_KEEPALIVE, (void *)&flags, sizeof(flags));
4358
    setsockopt(sfd, SOL_SOCKET, SO_LINGER, (void *)&ling, sizeof(ling));
1.1.2 by Jay Bonci
Import upstream version 1.2.1
4359
4360
    /*
4361
     * the memset call clears nonstandard fields in some impementations
4362
     * that otherwise mess things up.
4363
     */
4364
    memset(&addr, 0, sizeof(addr));
4365
4366
    addr.sun_family = AF_UNIX;
1.3.4 by David Martínez Moreno
Import upstream version 1.4.1
4367
    strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);
4368
    assert(strcmp(addr.sun_path, path) == 0);
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
4369
    old_umask = umask( ~(access_mask&0777));
1.2.1 by Jay Bonci
Import upstream version 1.2.2
4370
    if (bind(sfd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
1.1.2 by Jay Bonci
Import upstream version 1.2.1
4371
        perror("bind()");
4372
        close(sfd);
1.2.3 by David Martínez Moreno
Import upstream version 1.2.4
4373
        umask(old_umask);
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
4374
        return 1;
1.1.2 by Jay Bonci
Import upstream version 1.2.1
4375
    }
1.2.3 by David Martínez Moreno
Import upstream version 1.2.4
4376
    umask(old_umask);
1.3.2 by David Martínez Moreno
Import upstream version 1.2.8
4377
    if (listen(sfd, settings.backlog) == -1) {
1 by Jay Bonci
Import upstream version 1.1.11
4378
        perror("listen()");
4379
        close(sfd);
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
4380
        return 1;
4381
    }
4382
    if (!(listen_conn = conn_new(sfd, conn_listening,
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
4383
                                 EV_READ | EV_PERSIST, 1,
4384
                                 local_transport, main_base))) {
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
4385
        fprintf(stderr, "failed to create listening connection\n");
4386
        exit(EXIT_FAILURE);
4387
    }
4388
4389
    return 0;
1 by Jay Bonci
Import upstream version 1.1.11
4390
}
4391
1.1.2 by Jay Bonci
Import upstream version 1.2.1
4392
/*
4393
 * We keep the current time of day in a global variable that's updated by a
4394
 * timer event. This saves us a bunch of time() system calls (we really only
4395
 * need to get the time once a second, whereas there can be tens of thousands
4396
 * of requests a second) and allows us to use server-start-relative timestamps
4397
 * rather than absolute UNIX timestamps, a space savings on systems where
4398
 * sizeof(time_t) > sizeof(unsigned int).
4399
 */
4400
volatile rel_time_t current_time;
1.2.1 by Jay Bonci
Import upstream version 1.2.2
4401
static struct event clockevent;
1.1.2 by Jay Bonci
Import upstream version 1.2.1
4402
1.4.4 by Arno Töll
Import upstream version 1.4.7
4403
/* libevent uses a monotonic clock when available for event scheduling. Aside
4404
 * from jitter, simply ticking our internal timer here is accurate enough.
4405
 * Note that users who are setting explicit dates for expiration times *must*
4406
 * ensure their clocks are correct before starting memcached. */
1.2.1 by Jay Bonci
Import upstream version 1.2.2
4407
static void clock_handler(const int fd, const short which, void *arg) {
4408
    struct timeval t = {.tv_sec = 1, .tv_usec = 0};
4409
    static bool initialized = false;
1.4.4 by Arno Töll
Import upstream version 1.4.7
4410
#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
4411
    static bool monotonic = false;
4412
    static time_t monotonic_start;
4413
#endif
1.1.2 by Jay Bonci
Import upstream version 1.2.1
4414
4415
    if (initialized) {
4416
        /* only delete the event if it's actually there. */
4417
        evtimer_del(&clockevent);
4418
    } else {
1.2.1 by Jay Bonci
Import upstream version 1.2.2
4419
        initialized = true;
1.4.4 by Arno Töll
Import upstream version 1.4.7
4420
        /* process_started is initialized to time() - 2. We initialize to 1 so
4421
         * flush_all won't underflow during tests. */
4422
#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
4423
        struct timespec ts;
4424
        if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
4425
            monotonic = true;
4426
            monotonic_start = ts.tv_sec - 2;
4427
        }
4428
#endif
1.1.2 by Jay Bonci
Import upstream version 1.2.1
4429
    }
4430
4431
    evtimer_set(&clockevent, clock_handler, 0);
1.2.1 by Jay Bonci
Import upstream version 1.2.2
4432
    event_base_set(main_base, &clockevent);
1.1.2 by Jay Bonci
Import upstream version 1.2.1
4433
    evtimer_add(&clockevent, &t);
4434
1.4.4 by Arno Töll
Import upstream version 1.4.7
4435
#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
4436
    if (monotonic) {
4437
        struct timespec ts;
4438
        if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1)
4439
            return;
4440
        current_time = (rel_time_t) (ts.tv_sec - monotonic_start);
4441
        return;
4442
    }
4443
#endif
4444
    {
4445
        struct timeval tv;
4446
        gettimeofday(&tv, NULL);
4447
        current_time = (rel_time_t) (tv.tv_sec - process_started);
4448
    }
1.1.2 by Jay Bonci
Import upstream version 1.2.1
4449
}
4450
1.2.1 by Jay Bonci
Import upstream version 1.2.2
4451
static void usage(void) {
1 by Jay Bonci
Import upstream version 1.1.11
4452
    printf(PACKAGE " " VERSION "\n");
1.2.1 by Jay Bonci
Import upstream version 1.2.2
4453
    printf("-p <num>      TCP port number to listen on (default: 11211)\n"
1.3.2 by David Martínez Moreno
Import upstream version 1.2.8
4454
           "-U <num>      UDP port number to listen on (default: 11211, 0 is off)\n"
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
4455
           "-s <file>     UNIX socket path to listen on (disables network support)\n"
4456
           "-a <mask>     access mask for UNIX socket, in octal (default: 0700)\n"
1.4.4 by Arno Töll
Import upstream version 1.4.7
4457
           "-l <addr>     interface to listen on (default: INADDR_ANY, all addresses)\n"
4458
           "              <addr> may be specified as host:port. If you don't specify\n"
4459
           "              a port number, the value you specified with -p or -U is\n"
4460
           "              used. You may specify multiple addresses separated by comma\n"
4461
           "              or by using -l multiple times\n"
4462
1.2.1 by Jay Bonci
Import upstream version 1.2.2
4463
           "-d            run as a daemon\n"
4464
           "-r            maximize core file limit\n"
4465
           "-u <username> assume identity of <username> (only when run as root)\n"
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
4466
           "-m <num>      max memory to use for items in megabytes (default: 64 MB)\n"
1.2.1 by Jay Bonci
Import upstream version 1.2.2
4467
           "-M            return error on memory exhausted (rather than removing items)\n"
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
4468
           "-c <num>      max simultaneous connections (default: 1024)\n"
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
4469
           "-k            lock down all paged memory.  Note that there is a\n"
4470
           "              limit on how much memory you may lock.  Trying to\n"
4471
           "              allocate more than that would fail, so be sure you\n"
4472
           "              set the limit correctly for the user you started\n"
4473
           "              the daemon with (not for -u <username> user;\n"
4474
           "              under sh this is done with 'ulimit -S -l NUM_KB').\n"
1.2.1 by Jay Bonci
Import upstream version 1.2.2
4475
           "-v            verbose (print errors/warnings while in event loop)\n"
4476
           "-vv           very verbose (also print client commands/reponses)\n"
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
4477
           "-vvv          extremely verbose (also print internal state transitions)\n"
1.2.1 by Jay Bonci
Import upstream version 1.2.2
4478
           "-h            print this help and exit\n"
4479
           "-i            print memcached and libevent license\n"
4480
           "-P <file>     save PID in <file>, only used with -d option\n"
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
4481
           "-f <factor>   chunk size growth factor (default: 1.25)\n"
1.3.5 by David Martínez Moreno
Import upstream version 1.4.2
4482
           "-n <bytes>    minimum space allocated for key+value+flags (default: 48)\n");
4483
    printf("-L            Try to use large memory pages (if available). Increasing\n"
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
4484
           "              the memory page size could reduce the number of TLB misses\n"
4485
           "              and improve the performance. In order to get large pages\n"
4486
           "              from the OS, memcached will allocate the total item-cache\n"
1.3.5 by David Martínez Moreno
Import upstream version 1.4.2
4487
           "              in one large chunk.\n");
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
4488
    printf("-D <char>     Use <char> as the delimiter between key prefixes and IDs.\n"
4489
           "              This is used for per-prefix stats reporting. The default is\n"
4490
           "              \":\" (colon). If this option is specified, stats collection\n"
4491
           "              is turned on automatically; if not, then it may be turned on\n"
4492
           "              by sending the \"stats detail on\" command to the server.\n");
4493
    printf("-t <num>      number of threads to use (default: 4)\n");
4494
    printf("-R            Maximum number of requests per event, limits the number of\n"
4495
           "              requests process for a given connection to prevent \n"
4496
           "              starvation (default: 20)\n");
4497
    printf("-C            Disable use of CAS\n");
4498
    printf("-b            Set the backlog queue limit (default: 1024)\n");
4499
    printf("-B            Binding protocol - one of ascii, binary, or auto (default)\n");
1.4.3 by David Martínez Moreno
Import upstream version 1.4.5
4500
    printf("-I            Override the size of each slab page. Adjusts max item size\n"
4501
           "              (default: 1mb, min: 1k, max: 128m)\n");
4502
#ifdef ENABLE_SASL
4503
    printf("-S            Turn on Sasl authentication\n");
4504
#endif
1.1.9 by Scott Kitterman
Import upstream version 1.4.9
4505
    printf("-o            Comma separated list of extended or experimental options\n"
4506
           "              - (EXPERIMENTAL) maxconns_fast: immediately close new\n"
4507
           "                connections if over maxconns limit\n"
4508
           "              - hashpower: An integer multiplier for how large the hash\n"
4509
           "                table should be. Can be grown at runtime if not big enough.\n"
4510
           "                Set this based on \"STAT hash_power_level\" before a \n"
4511
           "                restart.\n"
4512
           );
1 by Jay Bonci
Import upstream version 1.1.11
4513
    return;
4514
}
4515
1.2.1 by Jay Bonci
Import upstream version 1.2.2
4516
static void usage_license(void) {
1 by Jay Bonci
Import upstream version 1.1.11
4517
    printf(PACKAGE " " VERSION "\n\n");
4518
    printf(
1.1.2 by Jay Bonci
Import upstream version 1.2.1
4519
    "Copyright (c) 2003, Danga Interactive, Inc. <http://www.danga.com/>\n"
4520
    "All rights reserved.\n"
4521
    "\n"
4522
    "Redistribution and use in source and binary forms, with or without\n"
4523
    "modification, are permitted provided that the following conditions are\n"
4524
    "met:\n"
4525
    "\n"
4526
    "    * Redistributions of source code must retain the above copyright\n"
4527
    "notice, this list of conditions and the following disclaimer.\n"
4528
    "\n"
4529
    "    * Redistributions in binary form must reproduce the above\n"
4530
    "copyright notice, this list of conditions and the following disclaimer\n"
4531
    "in the documentation and/or other materials provided with the\n"
4532
    "distribution.\n"
4533
    "\n"
4534
    "    * Neither the name of the Danga Interactive nor the names of its\n"
4535
    "contributors may be used to endorse or promote products derived from\n"
4536
    "this software without specific prior written permission.\n"
4537
    "\n"
4538
    "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
4539
    "\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
4540
    "LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
4541
    "A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
4542
    "OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
4543
    "SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
4544
    "LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
4545
    "DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
4546
    "THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
4547
    "(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
4548
    "OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
4549
    "\n"
4550
    "\n"
4551
    "This product includes software developed by Niels Provos.\n"
4552
    "\n"
4553
    "[ libevent ]\n"
4554
    "\n"
4555
    "Copyright 2000-2003 Niels Provos <provos@citi.umich.edu>\n"
4556
    "All rights reserved.\n"
4557
    "\n"
4558
    "Redistribution and use in source and binary forms, with or without\n"
4559
    "modification, are permitted provided that the following conditions\n"
4560
    "are met:\n"
4561
    "1. Redistributions of source code must retain the above copyright\n"
4562
    "   notice, this list of conditions and the following disclaimer.\n"
4563
    "2. Redistributions in binary form must reproduce the above copyright\n"
4564
    "   notice, this list of conditions and the following disclaimer in the\n"
4565
    "   documentation and/or other materials provided with the distribution.\n"
4566
    "3. All advertising materials mentioning features or use of this software\n"
4567
    "   must display the following acknowledgement:\n"
4568
    "      This product includes software developed by Niels Provos.\n"
4569
    "4. The name of the author may not be used to endorse or promote products\n"
4570
    "   derived from this software without specific prior written permission.\n"
4571
    "\n"
4572
    "THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n"
4573
    "IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n"
4574
    "OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n"
4575
    "IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\n"
4576
    "INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n"
4577
    "NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
4578
    "DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
4579
    "THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
4580
    "(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\n"
4581
    "THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
1 by Jay Bonci
Import upstream version 1.1.11
4582
    );
4583
4584
    return;
4585
}
4586
1.4.4 by Arno Töll
Import upstream version 1.4.7
4587
static void save_pid(const char *pid_file) {
1.1.1 by Jay Bonci
Import upstream version 1.1.12
4588
    FILE *fp;
1.4.4 by Arno Töll
Import upstream version 1.4.7
4589
    if (access(pid_file, F_OK) == 0) {
4590
        if ((fp = fopen(pid_file, "r")) != NULL) {
4591
            char buffer[1024];
4592
            if (fgets(buffer, sizeof(buffer), fp) != NULL) {
4593
                unsigned int pid;
4594
                if (safe_strtoul(buffer, &pid) && kill((pid_t)pid, 0) == 0) {
4595
                    fprintf(stderr, "WARNING: The pid file contained the following (running) pid: %u\n", pid);
4596
                }
4597
            }
4598
            fclose(fp);
4599
        }
4600
    }
1.1.1 by Jay Bonci
Import upstream version 1.1.12
4601
1.2.3 by David Martínez Moreno
Import upstream version 1.2.4
4602
    if ((fp = fopen(pid_file, "w")) == NULL) {
1.4.3 by David Martínez Moreno
Import upstream version 1.4.5
4603
        vperror("Could not open the pid file %s for writing", pid_file);
1.1.1 by Jay Bonci
Import upstream version 1.1.12
4604
        return;
4605
    }
4606
1.4.4 by Arno Töll
Import upstream version 1.4.7
4607
    fprintf(fp,"%ld\n", (long)getpid());
1.1.1 by Jay Bonci
Import upstream version 1.1.12
4608
    if (fclose(fp) == -1) {
1.4.3 by David Martínez Moreno
Import upstream version 1.4.5
4609
        vperror("Could not close the pid file %s", pid_file);
1.1.1 by Jay Bonci
Import upstream version 1.1.12
4610
    }
4611
}
4612
1.2.1 by Jay Bonci
Import upstream version 1.2.2
4613
static void remove_pidfile(const char *pid_file) {
4614
  if (pid_file == NULL)
1.1.1 by Jay Bonci
Import upstream version 1.1.12
4615
      return;
4616
1.2.1 by Jay Bonci
Import upstream version 1.2.2
4617
  if (unlink(pid_file) != 0) {
1.4.3 by David Martínez Moreno
Import upstream version 1.4.5
4618
      vperror("Could not remove the pid file %s", pid_file);
1.1.1 by Jay Bonci
Import upstream version 1.1.12
4619
  }
4620
4621
}
4622
1.2.1 by Jay Bonci
Import upstream version 1.2.2
4623
static void sig_handler(const int sig) {
1.1.2 by Jay Bonci
Import upstream version 1.2.1
4624
    printf("SIGINT handled.\n");
1.2.1 by Jay Bonci
Import upstream version 1.2.2
4625
    exit(EXIT_SUCCESS);
1.1.2 by Jay Bonci
Import upstream version 1.2.1
4626
}
1 by Jay Bonci
Import upstream version 1.1.11
4627
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
4628
#ifndef HAVE_SIGIGNORE
4629
static int sigignore(int sig) {
4630
    struct sigaction sa = { .sa_handler = SIG_IGN, .sa_flags = 0 };
4631
4632
    if (sigemptyset(&sa.sa_mask) == -1 || sigaction(sig, &sa, 0) == -1) {
4633
        return -1;
4634
    }
4635
    return 0;
4636
}
4637
#endif
4638
4639
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
4640
/*
4641
 * On systems that supports multiple page sizes we may reduce the
4642
 * number of TLB-misses by using the biggest available page size
4643
 */
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
4644
static int enable_large_pages(void) {
1.3.5 by David Martínez Moreno
Import upstream version 1.4.2
4645
#if defined(HAVE_GETPAGESIZES) && defined(HAVE_MEMCNTL)
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
4646
    int ret = -1;
4647
    size_t sizes[32];
4648
    int avail = getpagesizes(sizes, 32);
4649
    if (avail != -1) {
4650
        size_t max = sizes[0];
4651
        struct memcntl_mha arg = {0};
4652
        int ii;
4653
4654
        for (ii = 1; ii < avail; ++ii) {
4655
            if (max < sizes[ii]) {
4656
                max = sizes[ii];
4657
            }
4658
        }
4659
4660
        arg.mha_flags   = 0;
4661
        arg.mha_pagesize = max;
4662
        arg.mha_cmd = MHA_MAPSIZE_BSSBRK;
4663
4664
        if (memcntl(0, 0, MC_HAT_ADVISE, (caddr_t)&arg, 0, 0) == -1) {
4665
            fprintf(stderr, "Failed to set large pages: %s\n",
4666
                    strerror(errno));
4667
            fprintf(stderr, "Will use default page size\n");
4668
        } else {
4669
            ret = 0;
4670
        }
4671
    } else {
4672
        fprintf(stderr, "Failed to get supported pagesizes: %s\n",
4673
                strerror(errno));
4674
        fprintf(stderr, "Will use default page size\n");
4675
    }
4676
4677
    return ret;
1.3.5 by David Martínez Moreno
Import upstream version 1.4.2
4678
#else
4679
    return 0;
4680
#endif
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
4681
}
4682
1.4.4 by Arno Töll
Import upstream version 1.4.7
4683
/**
4684
 * Do basic sanity check of the runtime environment
4685
 * @return true if no errors found, false if we can't use this env
4686
 */
4687
static bool sanitycheck(void) {
4688
    /* One of our biggest problems is old and bogus libevents */
4689
    const char *ever = event_get_version();
4690
    if (ever != NULL) {
4691
        if (strncmp(ever, "1.", 2) == 0) {
4692
            /* Require at least 1.3 (that's still a couple of years old) */
4693
            if ((ever[2] == '1' || ever[2] == '2') && !isdigit(ever[3])) {
4694
                fprintf(stderr, "You are using libevent %s.\nPlease upgrade to"
4695
                        " a more recent version (1.3 or newer)\n",
4696
                        event_get_version());
4697
                return false;
4698
            }
4699
        }
4700
    }
4701
4702
    return true;
4703
}
4704
1 by Jay Bonci
Import upstream version 1.1.11
4705
int main (int argc, char **argv) {
4706
    int c;
1.2.1 by Jay Bonci
Import upstream version 1.2.2
4707
    bool lock_memory = false;
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
4708
    bool do_daemonize = false;
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
4709
    bool preallocate = false;
1 by Jay Bonci
Import upstream version 1.1.11
4710
    int maxcore = 0;
1.2.1 by Jay Bonci
Import upstream version 1.2.2
4711
    char *username = NULL;
4712
    char *pid_file = NULL;
1 by Jay Bonci
Import upstream version 1.1.11
4713
    struct passwd *pw;
4714
    struct rlimit rlim;
1.3.5 by David Martínez Moreno
Import upstream version 1.4.2
4715
    char unit = '\0';
4716
    int size_max = 0;
1.1.9 by Scott Kitterman
Import upstream version 1.4.9
4717
    int retval = EXIT_SUCCESS;
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
4718
    /* listening sockets */
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
4719
    static int *l_socket = NULL;
4720
4721
    /* udp socket */
4722
    static int *u_socket = NULL;
1.4.3 by David Martínez Moreno
Import upstream version 1.4.5
4723
    bool protocol_specified = false;
4724
    bool tcp_specified = false;
4725
    bool udp_specified = false;
1.2.1 by Jay Bonci
Import upstream version 1.2.2
4726
1.1.9 by Scott Kitterman
Import upstream version 1.4.9
4727
    char *subopts;
4728
    char *subopts_value;
4729
    enum {
4730
        MAXCONNS_FAST = 0,
1.1.11 by Scott Kitterman
Import upstream version 1.4.11
4731
        HASHPOWER_INIT,
4732
        SLAB_REASSIGN,
4733
        SLAB_AUTOMOVE
1.1.9 by Scott Kitterman
Import upstream version 1.4.9
4734
    };
4735
    char *const subopts_tokens[] = {
4736
        [MAXCONNS_FAST] = "maxconns_fast",
4737
        [HASHPOWER_INIT] = "hashpower",
1.1.11 by Scott Kitterman
Import upstream version 1.4.11
4738
        [SLAB_REASSIGN] = "slab_reassign",
4739
        [SLAB_AUTOMOVE] = "slab_automove",
1.1.9 by Scott Kitterman
Import upstream version 1.4.9
4740
        NULL
4741
    };
4742
1.4.4 by Arno Töll
Import upstream version 1.4.7
4743
    if (!sanitycheck()) {
4744
        return EX_OSERR;
4745
    }
4746
1.1.2 by Jay Bonci
Import upstream version 1.2.1
4747
    /* handle SIGINT */
4748
    signal(SIGINT, sig_handler);
4749
1 by Jay Bonci
Import upstream version 1.1.11
4750
    /* init settings */
4751
    settings_init();
4752
1.1.2 by Jay Bonci
Import upstream version 1.2.1
4753
    /* set stderr non-buffering (for running under, say, daemontools) */
4754
    setbuf(stderr, NULL);
4755
1 by Jay Bonci
Import upstream version 1.1.11
4756
    /* process arguments */
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
4757
    while (-1 != (c = getopt(argc, argv,
4758
          "a:"  /* access mask for unix socket */
4759
          "p:"  /* TCP port number to listen on */
4760
          "s:"  /* unix socket path to listen on */
4761
          "U:"  /* UDP port number to listen on */
4762
          "m:"  /* max memory to use for items in megabytes */
4763
          "M"   /* return error on memory exhausted */
4764
          "c:"  /* max simultaneous connections */
4765
          "k"   /* lock down all paged memory */
4766
          "hi"  /* help, licence info */
4767
          "r"   /* maximize core file limit */
4768
          "v"   /* verbose */
4769
          "d"   /* daemon mode */
4770
          "l:"  /* interface to listen on */
4771
          "u:"  /* user identity to run as */
4772
          "P:"  /* save PID in file */
4773
          "f:"  /* factor? */
4774
          "n:"  /* minimum space allocated for key+value+flags */
4775
          "t:"  /* threads */
4776
          "D:"  /* prefix delimiter? */
4777
          "L"   /* Large memory pages */
4778
          "R:"  /* max requests per event */
4779
          "C"   /* Disable use of CAS */
4780
          "b:"  /* backlog queue limit */
4781
          "B:"  /* Binding protocol */
1.3.5 by David Martínez Moreno
Import upstream version 1.4.2
4782
          "I:"  /* Max item size */
1.4.3 by David Martínez Moreno
Import upstream version 1.4.5
4783
          "S"   /* Sasl ON */
1.1.9 by Scott Kitterman
Import upstream version 1.4.9
4784
          "o:"  /* Extended generic options */
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
4785
        ))) {
1 by Jay Bonci
Import upstream version 1.1.11
4786
        switch (c) {
1.2.3 by David Martínez Moreno
Import upstream version 1.2.4
4787
        case 'a':
4788
            /* access for unix domain socket, as octal mask (like chmod)*/
4789
            settings.access= strtol(optarg,NULL,8);
4790
            break;
4791
1.1.2 by Jay Bonci
Import upstream version 1.2.1
4792
        case 'U':
4793
            settings.udpport = atoi(optarg);
1.4.3 by David Martínez Moreno
Import upstream version 1.4.5
4794
            udp_specified = true;
1.1.2 by Jay Bonci
Import upstream version 1.2.1
4795
            break;
1 by Jay Bonci
Import upstream version 1.1.11
4796
        case 'p':
4797
            settings.port = atoi(optarg);
1.4.3 by David Martínez Moreno
Import upstream version 1.4.5
4798
            tcp_specified = true;
1 by Jay Bonci
Import upstream version 1.1.11
4799
            break;
1.1.2 by Jay Bonci
Import upstream version 1.2.1
4800
        case 's':
4801
            settings.socketpath = optarg;
4802
            break;
1 by Jay Bonci
Import upstream version 1.1.11
4803
        case 'm':
1.2.1 by Jay Bonci
Import upstream version 1.2.2
4804
            settings.maxbytes = ((size_t)atoi(optarg)) * 1024 * 1024;
1 by Jay Bonci
Import upstream version 1.1.11
4805
            break;
4806
        case 'M':
4807
            settings.evict_to_free = 0;
4808
            break;
4809
        case 'c':
4810
            settings.maxconns = atoi(optarg);
4811
            break;
4812
        case 'h':
4813
            usage();
1.2.1 by Jay Bonci
Import upstream version 1.2.2
4814
            exit(EXIT_SUCCESS);
1 by Jay Bonci
Import upstream version 1.1.11
4815
        case 'i':
4816
            usage_license();
1.2.1 by Jay Bonci
Import upstream version 1.2.2
4817
            exit(EXIT_SUCCESS);
1 by Jay Bonci
Import upstream version 1.1.11
4818
        case 'k':
1.2.1 by Jay Bonci
Import upstream version 1.2.2
4819
            lock_memory = true;
1 by Jay Bonci
Import upstream version 1.1.11
4820
            break;
4821
        case 'v':
4822
            settings.verbose++;
4823
            break;
4824
        case 'l':
1.4.4 by Arno Töll
Import upstream version 1.4.7
4825
            if (settings.inter != NULL) {
4826
                size_t len = strlen(settings.inter) + strlen(optarg) + 2;
4827
                char *p = malloc(len);
4828
                if (p == NULL) {
4829
                    fprintf(stderr, "Failed to allocate memory\n");
4830
                    return 1;
4831
                }
4832
                snprintf(p, len, "%s,%s", settings.inter, optarg);
4833
                free(settings.inter);
4834
                settings.inter = p;
4835
            } else {
4836
                settings.inter= strdup(optarg);
4837
            }
1 by Jay Bonci
Import upstream version 1.1.11
4838
            break;
4839
        case 'd':
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
4840
            do_daemonize = true;
1 by Jay Bonci
Import upstream version 1.1.11
4841
            break;
4842
        case 'r':
4843
            maxcore = 1;
4844
            break;
1.3.2 by David Martínez Moreno
Import upstream version 1.2.8
4845
        case 'R':
4846
            settings.reqs_per_event = atoi(optarg);
4847
            if (settings.reqs_per_event == 0) {
4848
                fprintf(stderr, "Number of requests per event must be greater than 0\n");
4849
                return 1;
4850
            }
4851
            break;
1 by Jay Bonci
Import upstream version 1.1.11
4852
        case 'u':
4853
            username = optarg;
4854
            break;
1.1.1 by Jay Bonci
Import upstream version 1.1.12
4855
        case 'P':
4856
            pid_file = optarg;
4857
            break;
1.1.2 by Jay Bonci
Import upstream version 1.2.1
4858
        case 'f':
4859
            settings.factor = atof(optarg);
4860
            if (settings.factor <= 1.0) {
4861
                fprintf(stderr, "Factor must be greater than 1\n");
4862
                return 1;
4863
            }
4864
            break;
4865
        case 'n':
4866
            settings.chunk_size = atoi(optarg);
4867
            if (settings.chunk_size == 0) {
4868
                fprintf(stderr, "Chunk size must be greater than 0\n");
4869
                return 1;
4870
            }
4871
            break;
1.2.1 by Jay Bonci
Import upstream version 1.2.2
4872
        case 't':
1.3.5 by David Martínez Moreno
Import upstream version 1.4.2
4873
            settings.num_threads = atoi(optarg);
4874
            if (settings.num_threads <= 0) {
1.2.1 by Jay Bonci
Import upstream version 1.2.2
4875
                fprintf(stderr, "Number of threads must be greater than 0\n");
4876
                return 1;
4877
            }
1.3.5 by David Martínez Moreno
Import upstream version 1.4.2
4878
            /* There're other problems when you get above 64 threads.
4879
             * In the future we should portably detect # of cores for the
4880
             * default.
4881
             */
4882
            if (settings.num_threads > 64) {
4883
                fprintf(stderr, "WARNING: Setting a high number of worker"
4884
                                "threads is not recommended.\n"
4885
                                " Set this value to the number of cores in"
4886
                                " your machine or less.\n");
4887
            }
1.2.1 by Jay Bonci
Import upstream version 1.2.2
4888
            break;
4889
        case 'D':
4890
            if (! optarg || ! optarg[0]) {
4891
                fprintf(stderr, "No delimiter specified\n");
4892
                return 1;
4893
            }
4894
            settings.prefix_delimiter = optarg[0];
4895
            settings.detail_enabled = 1;
4896
            break;
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
4897
        case 'L' :
4898
            if (enable_large_pages() == 0) {
4899
                preallocate = true;
4900
            }
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
4901
            break;
4902
        case 'C' :
4903
            settings.use_cas = false;
4904
            break;
1.3.2 by David Martínez Moreno
Import upstream version 1.2.8
4905
        case 'b' :
4906
            settings.backlog = atoi(optarg);
4907
            break;
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
4908
        case 'B':
1.4.3 by David Martínez Moreno
Import upstream version 1.4.5
4909
            protocol_specified = true;
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
4910
            if (strcmp(optarg, "auto") == 0) {
4911
                settings.binding_protocol = negotiating_prot;
4912
            } else if (strcmp(optarg, "binary") == 0) {
4913
                settings.binding_protocol = binary_prot;
4914
            } else if (strcmp(optarg, "ascii") == 0) {
4915
                settings.binding_protocol = ascii_prot;
4916
            } else {
4917
                fprintf(stderr, "Invalid value for binding protocol: %s\n"
4918
                        " -- should be one of auto, binary, or ascii\n", optarg);
4919
                exit(EX_USAGE);
4920
            }
4921
            break;
1.3.5 by David Martínez Moreno
Import upstream version 1.4.2
4922
        case 'I':
4923
            unit = optarg[strlen(optarg)-1];
4924
            if (unit == 'k' || unit == 'm' ||
4925
                unit == 'K' || unit == 'M') {
4926
                optarg[strlen(optarg)-1] = '\0';
4927
                size_max = atoi(optarg);
4928
                if (unit == 'k' || unit == 'K')
4929
                    size_max *= 1024;
4930
                if (unit == 'm' || unit == 'M')
4931
                    size_max *= 1024 * 1024;
4932
                settings.item_size_max = size_max;
4933
            } else {
4934
                settings.item_size_max = atoi(optarg);
4935
            }
4936
            if (settings.item_size_max < 1024) {
4937
                fprintf(stderr, "Item max size cannot be less than 1024 bytes.\n");
4938
                return 1;
4939
            }
4940
            if (settings.item_size_max > 1024 * 1024 * 128) {
4941
                fprintf(stderr, "Cannot set item size limit higher than 128 mb.\n");
4942
                return 1;
4943
            }
4944
            if (settings.item_size_max > 1024 * 1024) {
4945
                fprintf(stderr, "WARNING: Setting item max size above 1MB is not"
4946
                    " recommended!\n"
4947
                    " Raising this limit increases the minimum memory requirements\n"
4948
                    " and will decrease your memory efficiency.\n"
4949
                );
4950
            }
4951
            break;
1.4.3 by David Martínez Moreno
Import upstream version 1.4.5
4952
        case 'S': /* set Sasl authentication to true. Default is false */
4953
#ifndef ENABLE_SASL
4954
            fprintf(stderr, "This server is not built with SASL support.\n");
4955
            exit(EX_USAGE);
4956
#endif
4957
            settings.sasl = true;
4958
            break;
1.1.9 by Scott Kitterman
Import upstream version 1.4.9
4959
        case 'o': /* It's sub-opts time! */
4960
            subopts = optarg;
4961
4962
            while (*subopts != '\0') {
4963
4964
            switch (getsubopt(&subopts, subopts_tokens, &subopts_value)) {
4965
            case MAXCONNS_FAST:
4966
                settings.maxconns_fast = true;
4967
                break;
4968
            case HASHPOWER_INIT:
4969
                if (subopts_value == NULL) {
4970
                    fprintf(stderr, "Missing numeric argument for hashpower\n");
4971
                    return 1;
4972
                }
4973
                settings.hashpower_init = atoi(subopts_value);
4974
                if (settings.hashpower_init < 12) {
4975
                    fprintf(stderr, "Initial hashtable multiplier of %d is too low\n",
4976
                        settings.hashpower_init);
4977
                    return 1;
4978
                } else if (settings.hashpower_init > 64) {
4979
                    fprintf(stderr, "Initial hashtable multiplier of %d is too high\n"
4980
                        "Choose a value based on \"STAT hash_power_level\" from a running instance\n",
4981
                        settings.hashpower_init);
4982
                    return 1;
4983
                }
4984
                break;
1.1.11 by Scott Kitterman
Import upstream version 1.4.11
4985
            case SLAB_REASSIGN:
4986
                settings.slab_reassign = true;
4987
                break;
4988
            case SLAB_AUTOMOVE:
4989
                settings.slab_automove = true;
4990
                break;
1.1.9 by Scott Kitterman
Import upstream version 1.4.9
4991
            default:
4992
                printf("Illegal suboption \"%s\"\n", subopts_value);
4993
                return 1;
4994
            }
4995
4996
            }
4997
            break;
1 by Jay Bonci
Import upstream version 1.1.11
4998
        default:
4999
            fprintf(stderr, "Illegal argument \"%c\"\n", c);
5000
            return 1;
5001
        }
5002
    }
5003
1.4.4 by Arno Töll
Import upstream version 1.4.7
5004
    /*
5005
     * Use one workerthread to serve each UDP port if the user specified
5006
     * multiple ports
5007
     */
5008
    if (settings.inter != NULL && strchr(settings.inter, ',')) {
5009
        settings.num_threads_per_udp = 1;
5010
    } else {
5011
        settings.num_threads_per_udp = settings.num_threads;
5012
    }
5013
1.4.3 by David Martínez Moreno
Import upstream version 1.4.5
5014
    if (settings.sasl) {
5015
        if (!protocol_specified) {
5016
            settings.binding_protocol = binary_prot;
5017
        } else {
5018
            if (settings.binding_protocol != binary_prot) {
5019
                fprintf(stderr, "ERROR: You cannot allow the ASCII protocol while using SASL.\n");
5020
                exit(EX_USAGE);
5021
            }
5022
        }
5023
    }
5024
5025
    if (tcp_specified && !udp_specified) {
5026
        settings.udpport = settings.port;
5027
    } else if (udp_specified && !tcp_specified) {
5028
        settings.port = settings.udpport;
5029
    }
5030
1.2.1 by Jay Bonci
Import upstream version 1.2.2
5031
    if (maxcore != 0) {
1 by Jay Bonci
Import upstream version 1.1.11
5032
        struct rlimit rlim_new;
1.1.2 by Jay Bonci
Import upstream version 1.2.1
5033
        /*
1 by Jay Bonci
Import upstream version 1.1.11
5034
         * First try raising to infinity; if that fails, try bringing
1.1.2 by Jay Bonci
Import upstream version 1.2.1
5035
         * the soft limit to the hard.
1 by Jay Bonci
Import upstream version 1.1.11
5036
         */
1.2.1 by Jay Bonci
Import upstream version 1.2.2
5037
        if (getrlimit(RLIMIT_CORE, &rlim) == 0) {
1 by Jay Bonci
Import upstream version 1.1.11
5038
            rlim_new.rlim_cur = rlim_new.rlim_max = RLIM_INFINITY;
1.2.1 by Jay Bonci
Import upstream version 1.2.2
5039
            if (setrlimit(RLIMIT_CORE, &rlim_new)!= 0) {
1 by Jay Bonci
Import upstream version 1.1.11
5040
                /* failed. try raising just to the old max */
1.2.1 by Jay Bonci
Import upstream version 1.2.2
5041
                rlim_new.rlim_cur = rlim_new.rlim_max = rlim.rlim_max;
5042
                (void)setrlimit(RLIMIT_CORE, &rlim_new);
1 by Jay Bonci
Import upstream version 1.1.11
5043
            }
5044
        }
1.1.2 by Jay Bonci
Import upstream version 1.2.1
5045
        /*
5046
         * getrlimit again to see what we ended up with. Only fail if
5047
         * the soft limit ends up 0, because then no core files will be
1 by Jay Bonci
Import upstream version 1.1.11
5048
         * created at all.
5049
         */
1.1.2 by Jay Bonci
Import upstream version 1.2.1
5050
1.2.1 by Jay Bonci
Import upstream version 1.2.2
5051
        if ((getrlimit(RLIMIT_CORE, &rlim) != 0) || rlim.rlim_cur == 0) {
1 by Jay Bonci
Import upstream version 1.1.11
5052
            fprintf(stderr, "failed to ensure corefile creation\n");
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
5053
            exit(EX_OSERR);
1 by Jay Bonci
Import upstream version 1.1.11
5054
        }
5055
    }
1.1.2 by Jay Bonci
Import upstream version 1.2.1
5056
5057
    /*
1 by Jay Bonci
Import upstream version 1.1.11
5058
     * If needed, increase rlimits to allow as many connections
5059
     * as needed.
5060
     */
1.1.2 by Jay Bonci
Import upstream version 1.2.1
5061
1 by Jay Bonci
Import upstream version 1.1.11
5062
    if (getrlimit(RLIMIT_NOFILE, &rlim) != 0) {
5063
        fprintf(stderr, "failed to getrlimit number of files\n");
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
5064
        exit(EX_OSERR);
1 by Jay Bonci
Import upstream version 1.1.11
5065
    } else {
1.1.9 by Scott Kitterman
Import upstream version 1.4.9
5066
        rlim.rlim_cur = settings.maxconns;
5067
        rlim.rlim_max = settings.maxconns;
1 by Jay Bonci
Import upstream version 1.1.11
5068
        if (setrlimit(RLIMIT_NOFILE, &rlim) != 0) {
1.1.9 by Scott Kitterman
Import upstream version 1.4.9
5069
            fprintf(stderr, "failed to set rlimit for open files. Try starting as root or requesting smaller maxconns value.\n");
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
5070
            exit(EX_OSERR);
5071
        }
5072
    }
5073
5074
    /* lose root privileges if we have them */
5075
    if (getuid() == 0 || geteuid() == 0) {
5076
        if (username == 0 || *username == '\0') {
5077
            fprintf(stderr, "can't run as root without the -u switch\n");
5078
            exit(EX_USAGE);
5079
        }
5080
        if ((pw = getpwnam(username)) == 0) {
5081
            fprintf(stderr, "can't find the user %s to switch to\n", username);
5082
            exit(EX_NOUSER);
5083
        }
5084
        if (setgid(pw->pw_gid) < 0 || setuid(pw->pw_uid) < 0) {
5085
            fprintf(stderr, "failed to assume identity of user %s\n", username);
5086
            exit(EX_OSERR);
1 by Jay Bonci
Import upstream version 1.1.11
5087
        }
5088
    }
5089
1.4.3 by David Martínez Moreno
Import upstream version 1.4.5
5090
    /* Initialize Sasl if -S was specified */
5091
    if (settings.sasl) {
5092
        init_sasl();
5093
    }
5094
1.3.2 by David Martínez Moreno
Import upstream version 1.2.8
5095
    /* daemonize if requested */
5096
    /* if we want to ensure our ability to dump core, don't chdir to / */
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
5097
    if (do_daemonize) {
5098
        if (sigignore(SIGHUP) == -1) {
5099
            perror("Failed to ignore SIGHUP");
5100
        }
5101
        if (daemonize(maxcore, settings.verbose) == -1) {
1.3.2 by David Martínez Moreno
Import upstream version 1.2.8
5102
            fprintf(stderr, "failed to daemon() in order to daemonize\n");
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
5103
            exit(EXIT_FAILURE);
1.3.2 by David Martínez Moreno
Import upstream version 1.2.8
5104
        }
5105
    }
5106
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
5107
    /* lock paged memory if needed */
5108
    if (lock_memory) {
5109
#ifdef HAVE_MLOCKALL
5110
        int res = mlockall(MCL_CURRENT | MCL_FUTURE);
5111
        if (res != 0) {
5112
            fprintf(stderr, "warning: -k invalid, mlockall() failed: %s\n",
5113
                    strerror(errno));
5114
        }
5115
#else
5116
        fprintf(stderr, "warning: -k invalid, mlockall() not supported on this platform.  proceeding without.\n");
5117
#endif
1 by Jay Bonci
Import upstream version 1.1.11
5118
    }
5119
1.2.1 by Jay Bonci
Import upstream version 1.2.2
5120
    /* initialize main thread libevent instance */
5121
    main_base = event_init();
1 by Jay Bonci
Import upstream version 1.1.11
5122
5123
    /* initialize other stuff */
5124
    stats_init();
1.1.9 by Scott Kitterman
Import upstream version 1.4.9
5125
    assoc_init(settings.hashpower_init);
1 by Jay Bonci
Import upstream version 1.1.11
5126
    conn_init();
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
5127
    slabs_init(settings.maxbytes, settings.factor, preallocate);
1.1.2 by Jay Bonci
Import upstream version 1.2.1
5128
1 by Jay Bonci
Import upstream version 1.1.11
5129
    /*
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
5130
     * ignore SIGPIPE signals; we can use errno == EPIPE if we
1 by Jay Bonci
Import upstream version 1.1.11
5131
     * need that information
5132
     */
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
5133
    if (sigignore(SIGPIPE) == -1) {
1 by Jay Bonci
Import upstream version 1.1.11
5134
        perror("failed to ignore SIGPIPE; sigaction");
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
5135
        exit(EX_OSERR);
1 by Jay Bonci
Import upstream version 1.1.11
5136
    }
1.2.1 by Jay Bonci
Import upstream version 1.2.2
5137
    /* start up worker threads if MT mode */
5138
    thread_init(settings.num_threads, main_base);
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
5139
5140
    if (start_assoc_maintenance_thread() == -1) {
5141
        exit(EXIT_FAILURE);
5142
    }
5143
1.1.11 by Scott Kitterman
Import upstream version 1.4.11
5144
    if (settings.slab_reassign &&
5145
        start_slab_maintenance_thread() == -1) {
5146
        exit(EXIT_FAILURE);
5147
    }
5148
1.1.2 by Jay Bonci
Import upstream version 1.2.1
5149
    /* initialise clock event */
1.2.1 by Jay Bonci
Import upstream version 1.2.2
5150
    clock_handler(0, 0, 0);
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
5151
5152
    /* create unix mode sockets after dropping privileges */
5153
    if (settings.socketpath != NULL) {
1.3.2 by David Martínez Moreno
Import upstream version 1.2.8
5154
        errno = 0;
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
5155
        if (server_socket_unix(settings.socketpath,settings.access)) {
1.3.4 by David Martínez Moreno
Import upstream version 1.4.1
5156
            vperror("failed to listen on UNIX socket: %s", settings.socketpath);
5157
            exit(EX_OSERR);
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
5158
        }
5159
    }
5160
5161
    /* create the listening socket, bind it, and init */
5162
    if (settings.socketpath == NULL) {
1.3.4 by David Martínez Moreno
Import upstream version 1.4.1
5163
        const char *portnumber_filename = getenv("MEMCACHED_PORT_FILENAME");
5164
        char temp_portnumber_filename[PATH_MAX];
5165
        FILE *portnumber_file = NULL;
5166
5167
        if (portnumber_filename != NULL) {
5168
            snprintf(temp_portnumber_filename,
5169
                     sizeof(temp_portnumber_filename),
5170
                     "%s.lck", portnumber_filename);
5171
5172
            portnumber_file = fopen(temp_portnumber_filename, "a");
5173
            if (portnumber_file == NULL) {
5174
                fprintf(stderr, "Failed to open \"%s\": %s\n",
5175
                        temp_portnumber_filename, strerror(errno));
5176
            }
5177
        }
5178
1.3.2 by David Martínez Moreno
Import upstream version 1.2.8
5179
        errno = 0;
1.4.4 by Arno Töll
Import upstream version 1.4.7
5180
        if (settings.port && server_sockets(settings.port, tcp_transport,
1.3.4 by David Martínez Moreno
Import upstream version 1.4.1
5181
                                           portnumber_file)) {
5182
            vperror("failed to listen on TCP port %d", settings.port);
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
5183
            exit(EX_OSERR);
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
5184
        }
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
5185
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
5186
        /*
5187
         * initialization order: first create the listening sockets
5188
         * (may need root on low ports), then drop root if needed,
5189
         * then daemonise if needed, then init libevent (in some cases
5190
         * descriptors created by libevent wouldn't survive forking).
5191
         */
5192
5193
        /* create the UDP listening socket and bind it */
1.3.2 by David Martínez Moreno
Import upstream version 1.2.8
5194
        errno = 0;
1.4.4 by Arno Töll
Import upstream version 1.4.7
5195
        if (settings.udpport && server_sockets(settings.udpport, udp_transport,
1.3.4 by David Martínez Moreno
Import upstream version 1.4.1
5196
                                              portnumber_file)) {
5197
            vperror("failed to listen on UDP port %d", settings.udpport);
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
5198
            exit(EX_OSERR);
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
5199
        }
1.3.4 by David Martínez Moreno
Import upstream version 1.4.1
5200
5201
        if (portnumber_file) {
5202
            fclose(portnumber_file);
5203
            rename(temp_portnumber_filename, portnumber_filename);
5204
        }
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
5205
    }
5206
1.1.9 by Scott Kitterman
Import upstream version 1.4.9
5207
    /* Give the sockets a moment to open. I know this is dumb, but the error
5208
     * is only an advisory.
5209
     */
5210
    usleep(1000);
5211
    if (stats.curr_conns + stats.reserved_fds >= settings.maxconns - 1) {
5212
        fprintf(stderr, "Maxconns setting is too low, use -c to increase.\n");
5213
        exit(EXIT_FAILURE);
5214
    }
5215
1.4.4 by Arno Töll
Import upstream version 1.4.7
5216
    if (pid_file != NULL) {
5217
        save_pid(pid_file);
5218
    }
5219
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
5220
    /* Drop privileges no longer needed */
5221
    drop_privileges();
5222
1.2.1 by Jay Bonci
Import upstream version 1.2.2
5223
    /* enter the event loop */
1.1.9 by Scott Kitterman
Import upstream version 1.4.9
5224
    if (event_base_loop(main_base, 0) != 0) {
5225
        retval = EXIT_FAILURE;
5226
    }
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
5227
5228
    stop_assoc_maintenance_thread();
5229
1.1.1 by Jay Bonci
Import upstream version 1.1.12
5230
    /* remove the PID file if we're a daemon */
1.3.3 by David Martínez Moreno
Import upstream version 1.4.0
5231
    if (do_daemonize)
1.1.1 by Jay Bonci
Import upstream version 1.1.12
5232
        remove_pidfile(pid_file);
1.3.1 by David Martínez Moreno
Import upstream version 1.2.5
5233
    /* Clean up strdup() call for bind() address */
5234
    if (settings.inter)
5235
      free(settings.inter);
5236
    if (l_socket)
5237
      free(l_socket);
5238
    if (u_socket)
5239
      free(u_socket);
5240
1.1.9 by Scott Kitterman
Import upstream version 1.4.9
5241
    return retval;
1 by Jay Bonci
Import upstream version 1.1.11
5242
}