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 |
}
|