16d74e134SBrad Fitzpatrick/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2977dfd19SBrad Fitzpatrick/*
3977dfd19SBrad Fitzpatrick *  memcached - memory caching daemon
4977dfd19SBrad Fitzpatrick *
5977dfd19SBrad Fitzpatrick *       http://www.danga.com/memcached/
6977dfd19SBrad Fitzpatrick *
7977dfd19SBrad Fitzpatrick *  Copyright 2003 Danga Interactive, Inc.  All rights reserved.
8977dfd19SBrad Fitzpatrick *
90c3b47f4SBrad Fitzpatrick *  Use and distribution licensed under the BSD license.  See
100c3b47f4SBrad Fitzpatrick *  the LICENSE file for full text.
11977dfd19SBrad Fitzpatrick *
12977dfd19SBrad Fitzpatrick *  Authors:
13977dfd19SBrad Fitzpatrick *      Anatoly Vorobey <mellon@pobox.com>
14977dfd19SBrad Fitzpatrick *      Brad Fitzpatrick <brad@danga.com>
15977dfd19SBrad Fitzpatrick */
1658df6f95STrond Norbye#include "config.h"
1756b8339eSSteven Grimm#include "memcached.h"
18d3f20d74SEric Lambert#include "memcached/extension_loggers.h"
19e1175713SMike Wiederhold#include "alloc_hooks.h"
20123184c0STrond Norbye#include "utilities/engine_loader.h"
21bd1ef70eSTrond Norbye#include "timings.h"
22c00c8665STrond Norbye#include "cmdline.h"
23e73832dcSjim#include "mc_time.h"
2495c3be87SPatrick Galbraith
25731c34beSTrond Norbye#include <signal.h>
2632f382b6SBrad Fitzpatrick#include <fcntl.h>
2732f382b6SBrad Fitzpatrick#include <errno.h>
28c6975ef4SPaul Lindner#include <stdlib.h>
29c6975ef4SPaul Lindner#include <stdio.h>
30c6975ef4SPaul Lindner#include <string.h>
311b533267SBrad Fitzpatrick#include <time.h>
32c9607c6dSBrad Fitzpatrick#include <limits.h>
3395c3be87SPatrick Galbraith#include <ctype.h>
3495c3be87SPatrick Galbraith#include <stdarg.h>
357bb82191STrond Norbye#include <stddef.h>
36f606252bSTrond Norbye#include <snappy-c.h>
37c8e1a47dSTrond Norbye#include <JSON_checker.h>
3886969ea4SBrad Fitzpatrick
39288d1a8bSTrond Norbyestatic bool grow_dynamic_buffer(conn *c, size_t needed);
408667210cSTrond Norbyestatic void cookie_set_admin(const void *cookie);
418667210cSTrond Norbyestatic bool cookie_is_admin(const void *cookie);
42288d1a8bSTrond Norbye
436fd31b63STrond Norbyetypedef union {
446fd31b63STrond Norbye    item_info info;
456fd31b63STrond Norbye    char bytes[sizeof(item_info) + ((IOV_MAX - 1) * sizeof(struct iovec))];
466fd31b63STrond Norbye} item_info_holder;
476fd31b63STrond Norbye
48f603fdb6STrond Norbyestatic void item_set_cas(const void *cookie, item *it, uint64_t cas) {
498d94d235SDustin Sallings    settings.engine.v1->item_set_cas(settings.engine.v0, cookie, it, cas);
50758b107cSTrond Norbye}
51758b107cSTrond Norbye
523d93bcf6STrond Norbye#define MAX_SASL_MECH_LEN 32
533d93bcf6STrond Norbye
54a5479c51SSean Lynch/* The item must always be called "it" */
55a5479c51SSean Lynch#define SLAB_GUTS(conn, thread_stats, slab_op, thread_op) \
566fd31b63STrond Norbye    thread_stats->slab_stats[info.info.clsid].slab_op++;
57a5479c51SSean Lynch
58a5479c51SSean Lynch#define THREAD_GUTS(conn, thread_stats, slab_op, thread_op) \
59a5479c51SSean Lynch    thread_stats->thread_op++;
60a5479c51SSean Lynch
61a5479c51SSean Lynch#define THREAD_GUTS2(conn, thread_stats, slab_op, thread_op) \
62a5479c51SSean Lynch    thread_stats->slab_op++; \
63a5479c51SSean Lynch    thread_stats->thread_op++;
64a5479c51SSean Lynch
65a5479c51SSean Lynch#define SLAB_THREAD_GUTS(conn, thread_stats, slab_op, thread_op) \
66a5479c51SSean Lynch    SLAB_GUTS(conn, thread_stats, slab_op, thread_op) \
67a5479c51SSean Lynch    THREAD_GUTS(conn, thread_stats, slab_op, thread_op)
68a5479c51SSean Lynch
69a5479c51SSean Lynch#define STATS_INCR1(GUTS, conn, slab_op, thread_op, key, nkey) { \
70d9be1f23STrond Norbye    struct thread_stats *thread_stats = get_thread_stats(conn); \
71f603fdb6STrond Norbye    cb_mutex_enter(&thread_stats->mutex); \
72a5479c51SSean Lynch    GUTS(conn, thread_stats, slab_op, thread_op); \
73f603fdb6STrond Norbye    cb_mutex_exit(&thread_stats->mutex); \
74a5479c51SSean Lynch}
75a5479c51SSean Lynch
76a5479c51SSean Lynch#define STATS_INCR(conn, op, key, nkey) \
77a5479c51SSean Lynch    STATS_INCR1(THREAD_GUTS, conn, op, op, key, nkey)
78a5479c51SSean Lynch
79a5479c51SSean Lynch#define SLAB_INCR(conn, op, key, nkey) \
80a5479c51SSean Lynch    STATS_INCR1(SLAB_GUTS, conn, op, op, key, nkey)
81a5479c51SSean Lynch
82a5479c51SSean Lynch#define STATS_TWO(conn, slab_op, thread_op, key, nkey) \
83a5479c51SSean Lynch    STATS_INCR1(THREAD_GUTS2, conn, slab_op, thread_op, key, nkey)
84a5479c51SSean Lynch
85a5479c51SSean Lynch#define SLAB_TWO(conn, slab_op, thread_op, key, nkey) \
86a5479c51SSean Lynch    STATS_INCR1(SLAB_THREAD_GUTS, conn, slab_op, thread_op, key, nkey)
87a5479c51SSean Lynch
88a5479c51SSean Lynch#define STATS_HIT(conn, op, key, nkey) \
89a5479c51SSean Lynch    SLAB_TWO(conn, op##_hits, cmd_##op, key, nkey)
90a5479c51SSean Lynch
91a5479c51SSean Lynch#define STATS_MISS(conn, op, key, nkey) \
92a5479c51SSean Lynch    STATS_TWO(conn, op##_misses, cmd_##op, key, nkey)
93a5479c51SSean Lynch
94a5479c51SSean Lynch#define STATS_NOKEY(conn, op) { \
95a5479c51SSean Lynch    struct thread_stats *thread_stats = \
96a5479c51SSean Lynch        get_thread_stats(conn); \
97f603fdb6STrond Norbye    cb_mutex_enter(&thread_stats->mutex); \
98a5479c51SSean Lynch    thread_stats->op++; \
99f603fdb6STrond Norbye    cb_mutex_exit(&thread_stats->mutex); \
100a5479c51SSean Lynch}
101a5479c51SSean Lynch
102a5479c51SSean Lynch#define STATS_NOKEY2(conn, op1, op2) { \
103a5479c51SSean Lynch    struct thread_stats *thread_stats = \
104a5479c51SSean Lynch        get_thread_stats(conn); \
105f603fdb6STrond Norbye    cb_mutex_enter(&thread_stats->mutex); \
106a5479c51SSean Lynch    thread_stats->op1++; \
107a5479c51SSean Lynch    thread_stats->op2++; \
108f603fdb6STrond Norbye    cb_mutex_exit(&thread_stats->mutex); \
109a5479c51SSean Lynch}
110a5479c51SSean Lynch
111a5479c51SSean Lynch#define STATS_ADD(conn, op, amt) { \
112a5479c51SSean Lynch    struct thread_stats *thread_stats = \
113a5479c51SSean Lynch        get_thread_stats(conn); \
114f603fdb6STrond Norbye    cb_mutex_enter(&thread_stats->mutex); \
115a5479c51SSean Lynch    thread_stats->op += amt; \
116f603fdb6STrond Norbye    cb_mutex_exit(&thread_stats->mutex); \
117a5479c51SSean Lynch}
118a5479c51SSean Lynch
1196d860fb3STrond Norbyevolatile sig_atomic_t memcached_shutdown;
12084d6c30cSTrond Norbye
121f603fdb6STrond Norbye/* Lock for global stats */
122f603fdb6STrond Norbyestatic cb_mutex_t stats_lock;
123f603fdb6STrond Norbye
1252c217587Sabhinavdangeti * Structure to save ns_server's session cas token.
1262c217587Sabhinavdangeti */
1272c217587Sabhinavdangetistatic struct session_cas {
1282c217587Sabhinavdangeti    uint64_t value;
1294f426e26Sabhinavdangeti    uint64_t ctr;
1302c217587Sabhinavdangeti    cb_mutex_t mutex;
1312c217587Sabhinavdangeti} session_cas;
133f603fdb6STrond Norbyevoid STATS_LOCK() {
134f603fdb6STrond Norbye    cb_mutex_enter(&stats_lock);
135f603fdb6STrond Norbye}
136f603fdb6STrond Norbye
137f603fdb6STrond Norbyevoid STATS_UNLOCK() {
138f603fdb6STrond Norbye    cb_mutex_exit(&stats_lock);
139f603fdb6STrond Norbye}
140f603fdb6STrond Norbye
141f603fdb6STrond Norbye#ifdef WIN32
142f603fdb6STrond Norbyestatic int is_blocking(DWORD dw) {
143f603fdb6STrond Norbye    return (dw == WSAEWOULDBLOCK);
144f603fdb6STrond Norbye}
145f603fdb6STrond Norbyestatic int is_emfile(DWORD dw) {
146f603fdb6STrond Norbye    return (dw == WSAEMFILE);
147f603fdb6STrond Norbye}
148f603fdb6STrond Norbyestatic int is_closed_conn(DWORD dw) {
149f603fdb6STrond Norbye    return (dw == WSAENOTCONN || WSAECONNRESET);
150f603fdb6STrond Norbye}
151f603fdb6STrond Norbyestatic int is_addrinuse(DWORD dw) {
152f603fdb6STrond Norbye    return (dw == WSAEADDRINUSE);
153f603fdb6STrond Norbye}
154b5273359STrond Norbyestatic void set_ewouldblock(void) {
155b5273359STrond Norbye    WSASetLastError(WSAEWOULDBLOCK);
156b5273359STrond Norbye}
157b5273359STrond Norbyestatic void set_econnreset(void) {
158b5273359STrond Norbye    WSASetLastError(WSAECONNRESET);
159b5273359STrond Norbye}
160f603fdb6STrond Norbye#else
161f603fdb6STrond Norbyestatic int is_blocking(int dw) {
162f603fdb6STrond Norbye    return (dw == EAGAIN || dw == EWOULDBLOCK);
163f603fdb6STrond Norbye}
164f603fdb6STrond Norbyestatic int is_emfile(int dw) {
165f603fdb6STrond Norbye    return (dw == EMFILE);
166f603fdb6STrond Norbye}
167f603fdb6STrond Norbyestatic int is_closed_conn(int dw) {
168f603fdb6STrond Norbye    return  (dw == ENOTCONN || dw != ECONNRESET);
169f603fdb6STrond Norbye}
170f603fdb6STrond Norbyestatic int is_addrinuse(int dw) {
171f603fdb6STrond Norbye    return (dw == EADDRINUSE);
172f603fdb6STrond Norbye}
173b5273359STrond Norbyestatic void set_ewouldblock(void) {
174b5273359STrond Norbye    errno = EWOULDBLOCK;
175b5273359STrond Norbye}
176b5273359STrond Norbyestatic void set_econnreset(void) {
177b5273359STrond Norbye    errno = ECONNRESET;
178b5273359STrond Norbye}
179f603fdb6STrond Norbye#endif
180f603fdb6STrond Norbye
18177dde9f9SPaul Lindner/*
182b80ab7cfSPaul Lindner * forward declarations
18377dde9f9SPaul Lindner */
18400999f69STrond Norbyestatic SOCKET new_socket(struct addrinfo *ai);
18577dde9f9SPaul Lindnerstatic int try_read_command(conn *c);
186f603fdb6STrond Norbyestatic struct thread_stats* get_independent_stats(conn *c);
187f603fdb6STrond Norbyestatic struct thread_stats* get_thread_stats(conn *c);
188fc06711bSDustin Sallingsstatic void register_callback(ENGINE_HANDLE *eh,
189fc06711bSDustin Sallings                              ENGINE_EVENT_TYPE type,
19084d6c30cSTrond Norbye                              EVENT_CALLBACK cb, const void *cb_data);
191b449bca0SDave Rigbystatic SERVER_HANDLE_V1 *get_server_api(void);
19284d6c30cSTrond Norbye
193496384caSSteve Yen
194496384caSSteve Yenenum try_read_result {
195496384caSSteve Yen    READ_DATA_RECEIVED,
196496384caSSteve Yen    READ_NO_DATA_RECEIVED,
197496384caSSteve Yen    READ_ERROR,            /** an error occured (on the socket) (or client closed connection) */
198496384caSSteve Yen    READ_MEMORY_ERROR      /** failed to allocate more memory */
199496384caSSteve Yen};
200496384caSSteve Yen
201496384caSSteve Yenstatic enum try_read_result try_read_network(conn *c);
202496384caSSteve Yen
20377dde9f9SPaul Lindner/* stats */
20477dde9f9SPaul Lindnerstatic void stats_init(void);
205ca605ebbSSean Lynchstatic void server_stats(ADD_STAT add_stats, conn *c, bool aggregate);
20617df5c0eSTrond Norbyestatic void process_stat_settings(ADD_STAT add_stats, void *c);
20752778791SDustin Sallings
20877dde9f9SPaul Lindner
20977dde9f9SPaul Lindner/* defaults */
21077dde9f9SPaul Lindnerstatic void settings_init(void);
21177dde9f9SPaul Lindner
21277dde9f9SPaul Lindner/* event handling, network IO */
213ce9a18d0STrond Norbyestatic void event_handler(evutil_socket_t fd, short which, void *arg);
21477dde9f9SPaul Lindnerstatic void complete_nread(conn *c);
215ce9a18d0STrond Norbyestatic void write_and_free(conn *c, char *buf, size_t bytes);
21677dde9f9SPaul Lindnerstatic int ensure_iov_space(conn *c);
217ce9a18d0STrond Norbyestatic int add_iov(conn *c, const void *buf, size_t len);
21877dde9f9SPaul Lindnerstatic int add_msghdr(conn *c);
21977dde9f9SPaul Lindner
22077dde9f9SPaul Lindner/** exported globals **/
22160d70942SAnatoly Vorobeystruct stats stats;
22260d70942SAnatoly Vorobeystruct settings settings;
22386969ea4SBrad Fitzpatrick
22477dde9f9SPaul Lindner/** file scope variables **/
2259150c85bSBrian Akerstatic conn *listen_conn = NULL;
22656b8339eSSteven Grimmstatic struct event_base *main_base;
227d9be1f23STrond Norbyestatic struct thread_stats *default_independent_stats;
22886969ea4SBrad Fitzpatrick
2293dbf729cSDustin Sallingsstatic struct engine_event_handler *engine_event_handlers[MAX_ENGINE_EVENT_TYPE + 1];
2303dbf729cSDustin Sallings
231f30083c7SSteve Yenenum transmit_result {
232f30083c7SSteve Yen    TRANSMIT_COMPLETE,   /** All done writing. */
233f30083c7SSteve Yen    TRANSMIT_INCOMPLETE, /** More data remaining to write. */
234f30083c7SSteve Yen    TRANSMIT_SOFT_ERROR, /** Can't write any more right now. */
235f30083c7SSteve Yen    TRANSMIT_HARD_ERROR  /** Can't write (c->state is set to conn_closing) */
236f30083c7SSteve Yen};
237f30083c7SSteve Yen
238f30083c7SSteve Yenstatic enum transmit_result transmit(conn *c);
23986969ea4SBrad Fitzpatrick
241eda68b70STrond Norbye
242f603fdb6STrond Norbye/* Perform all callbacks of a given type for the given connection. */
243595bef70STrond Norbyevoid perform_callbacks(ENGINE_EVENT_TYPE type,
244595bef70STrond Norbye                       const void *data,
245595bef70STrond Norbye                       const void *c) {
246f603fdb6STrond Norbye    struct engine_event_handler *h;
247f603fdb6STrond Norbye    for (h = engine_event_handlers[type]; h; h = h->next) {
248289d2e57SDustin Sallings        h->cb(c, type, data, h->cb_data);
249289d2e57SDustin Sallings    }
250289d2e57SDustin Sallings}
251289d2e57SDustin Sallings
25268040a48SChiyoung Seo/**
25368040a48SChiyoung Seo * Return the TCP or domain socket listening_port structure that
25468040a48SChiyoung Seo * has a given port number
25568040a48SChiyoung Seo */
25668040a48SChiyoung Seostatic struct listening_port *get_listening_port_instance(const int port) {
25768040a48SChiyoung Seo    struct listening_port *port_ins = NULL;
258f603fdb6STrond Norbye    int i;
259595bef70STrond Norbye    for (i = 0; i < settings.num_interfaces; ++i) {
26068040a48SChiyoung Seo        if (stats.listening_ports[i].port == port) {
26168040a48SChiyoung Seo            port_ins = &stats.listening_ports[i];
26268040a48SChiyoung Seo        }
26368040a48SChiyoung Seo    }
26468040a48SChiyoung Seo    return port_ins;
26568040a48SChiyoung Seo}
26668040a48SChiyoung Seo
26777dde9f9SPaul Lindnerstatic void stats_init(void) {
2684dce457fSTrond Norbye    stats.daemon_conns = 0;
2694dce457fSTrond Norbye    stats.rejected_conns = 0;
2707401ce60STrond Norbye    stats.curr_conns = stats.total_conns = 0;
271595bef70STrond Norbye    stats.listening_ports = calloc(settings.num_interfaces, sizeof(struct listening_port));
27260267758SBrad Fitzpatrick
27356b8339eSSteven Grimm    stats_prefix_init();
27432f382b6SBrad Fitzpatrick}
275217dcce0SSteven Grimm
2766c869215SDustin Sallingsstatic void stats_reset(const void *cookie) {
277c3fd96d9SSean Lynch    struct conn *conn = (struct conn*)cookie;
27856b8339eSSteven Grimm    STATS_LOCK();
2794dce457fSTrond Norbye    stats.rejected_conns = 0;
2804dce457fSTrond Norbye    stats.total_conns = 0;
28156b8339eSSteven Grimm    stats_prefix_clear();
28256b8339eSSteven Grimm    STATS_UNLOCK();
283d9be1f23STrond Norbye    threadlocal_stats_reset(get_independent_stats(conn));
2846c869215SDustin Sallings    settings.engine.v1->reset_stats(settings.engine.v0, cookie);
28532f382b6SBrad Fitzpatrick}
28686969ea4SBrad Fitzpatrick
287fc344bc4STrond Norbyestatic int get_number_of_worker_threads(void) {
288fc344bc4STrond Norbye    int ret;
289fc344bc4STrond Norbye    char *override = getenv("MEMCACHED_NUM_CPUS");
290fc344bc4STrond Norbye    if (override == NULL) {
291446d5e88STrond Norbye#ifdef WIN32
292fc344bc4STrond Norbye        SYSTEM_INFO sysinfo;
293fc344bc4STrond Norbye        GetSystemInfo(&sysinfo);
294fc344bc4STrond Norbye        ret = (int)sysinfo.dwNumberOfProcessors;
295fc344bc4STrond Norbye#else
296fc344bc4STrond Norbye        ret = (int)sysconf(_SC_NPROCESSORS_ONLN);
297fc344bc4STrond Norbye#endif
298fc344bc4STrond Norbye        if (ret > 4) {
299ce9a18d0STrond Norbye            ret = (int)(ret * 0.75f);
300977f85fbSpavel-paulau        }
301977f85fbSpavel-paulau        if (ret < 4) {
302977f85fbSpavel-paulau            ret = 4;
303fc344bc4STrond Norbye        }
304fc344bc4STrond Norbye    } else {
305fc344bc4STrond Norbye        ret = atoi(override);
306fc344bc4STrond Norbye        if (ret == 0) {
307fc344bc4STrond Norbye            ret = 4;
308fc344bc4STrond Norbye        }
309fc344bc4STrond Norbye    }
310fc344bc4STrond Norbye
311fc344bc4STrond Norbye    return ret;
312fc344bc4STrond Norbye}
313fc344bc4STrond Norbye
31477dde9f9SPaul Lindnerstatic void settings_init(void) {
315595bef70STrond Norbye    static struct interface default_interface;
316595bef70STrond Norbye    default_interface.port = 11211;
317595bef70STrond Norbye    default_interface.maxconn = 1000;
318595bef70STrond Norbye    default_interface.backlog = 1024;
319595bef70STrond Norbye
320595bef70STrond Norbye    settings.num_interfaces = 1;
321595bef70STrond Norbye    settings.interfaces = &default_interface;
322595bef70STrond Norbye    settings.daemonize = false;
323595bef70STrond Norbye    settings.pid_file = NULL;
324b5273359STrond Norbye    settings.bio_drain_buffer_sz = 8192;
325595bef70STrond Norbye
32660d70942SAnatoly Vorobey    settings.verbose = 0;
327fc344bc4STrond Norbye    settings.num_threads = get_number_of_worker_threads();
32856b8339eSSteven Grimm    settings.prefix_delimiter = ':';
32956b8339eSSteven Grimm    settings.detail_enabled = 0;
3304aa1bd48SSean Lynch    settings.allow_detailed = true;
33128e825f7STrond Norbye    settings.reqs_per_event_high_priority = 50;
33228e825f7STrond Norbye    settings.reqs_per_event_med_priority = 5;
33328e825f7STrond Norbye    settings.reqs_per_event_low_priority = 1;
33428e825f7STrond Norbye    settings.default_reqs_per_event = 20;
3353435c08dSSean Lynch    settings.require_sasl = false;
336d3f20d74SEric Lambert    settings.extensions.logger = get_stderr_logger();
33730647e66STrond Norbye    settings.tcp_nodelay = getenv("MEMCACHED_DISABLE_TCP_NODELAY") == NULL;
338595bef70STrond Norbye    settings.engine_module = "default_engine.so";
339595bef70STrond Norbye    settings.engine_config = NULL;
3405a1e75deSTrond Norbye    settings.config = NULL;
3418667210cSTrond Norbye    settings.admin = NULL;
3428667210cSTrond Norbye    settings.disable_admin = false;
34371c3fd66STrond Norbye    settings.datatype = false;
344c9607c6dSBrad Fitzpatrick}
34520892be0SBrad Fitzpatrick
346c9607c6dSBrad Fitzpatrick/*
347c9607c6dSBrad Fitzpatrick * Adds a message header to a connection.
348c9607c6dSBrad Fitzpatrick *
349c9607c6dSBrad Fitzpatrick * Returns 0 on success, -1 on out-of-memory.
350c9607c6dSBrad Fitzpatrick */
35177dde9f9SPaul Lindnerstatic int add_msghdr(conn *c)
352c9607c6dSBrad Fitzpatrick{
353c9607c6dSBrad Fitzpatrick    struct msghdr *msg;
35486969ea4SBrad Fitzpatrick
355464d6f0bSTrond Norbye    cb_assert(c != NULL);
35678955139STim Yardley
357c9607c6dSBrad Fitzpatrick    if (c->msgsize == c->msgused) {
358f4372ea1SDave Rigby        cb_assert(c->msgsize > 0);
359c9607c6dSBrad Fitzpatrick        msg = realloc(c->msglist, c->msgsize * 2 * sizeof(struct msghdr));
360c9607c6dSBrad Fitzpatrick        if (! msg)
361c9607c6dSBrad Fitzpatrick            return -1;
362c9607c6dSBrad Fitzpatrick        c->msglist = msg;
363c9607c6dSBrad Fitzpatrick        c->msgsize *= 2;
364c9607c6dSBrad Fitzpatrick    }
36586969ea4SBrad Fitzpatrick
366c9607c6dSBrad Fitzpatrick    msg = c->msglist + c->msgused;
367edbccb0fSBrad Fitzpatrick
368edbccb0fSBrad Fitzpatrick    /* this wipes msg_iovlen, msg_control, msg_controllen, and
369edbccb0fSBrad Fitzpatrick       msg_flags, the last 3 of which aren't defined on solaris: */
370edbccb0fSBrad Fitzpatrick    memset(msg, 0, sizeof(struct msghdr));
371edbccb0fSBrad Fitzpatrick
372c9607c6dSBrad Fitzpatrick    msg->msg_iov = &c->iov[c->iovused];
37352d1cf20SMaxim Dounin
37452d1cf20SMaxim Dounin    if (c->request_addr_size > 0) {
37552d1cf20SMaxim Dounin        msg->msg_name = &c->request_addr;
37652d1cf20SMaxim Dounin        msg->msg_namelen = c->request_addr_size;
37752d1cf20SMaxim Dounin    }
378edbccb0fSBrad Fitzpatrick
379c9607c6dSBrad Fitzpatrick    c->msgbytes = 0;
380c9607c6dSBrad Fitzpatrick    c->msgused++;
38186969ea4SBrad Fitzpatrick
382c9607c6dSBrad Fitzpatrick    return 0;
38332f382b6SBrad Fitzpatrick}
38486969ea4SBrad Fitzpatrick
38526470267STrond Norbyestruct {
386f603fdb6STrond Norbye    cb_mutex_t mutex;
38726470267STrond Norbye    bool disabled;
38826470267STrond Norbye    ssize_t count;
38926470267STrond Norbye    uint64_t num_disable;
390f603fdb6STrond Norbye} listen_state;
39126470267STrond Norbye
39226470267STrond Norbyestatic bool is_listen_disabled(void) {
39326470267STrond Norbye    bool ret;
394f603fdb6STrond Norbye    cb_mutex_enter(&listen_state.mutex);
39526470267STrond Norbye    ret = listen_state.disabled;
396f603fdb6STrond Norbye    cb_mutex_exit(&listen_state.mutex);
39726470267STrond Norbye    return ret;
39826470267STrond Norbye}
39926470267STrond Norbye
40026470267STrond Norbyestatic uint64_t get_listen_disabled_num(void) {
40126470267STrond Norbye    uint64_t ret;
402f603fdb6STrond Norbye    cb_mutex_enter(&listen_state.mutex);
40326470267STrond Norbye    ret = listen_state.num_disable;
404f603fdb6STrond Norbye    cb_mutex_exit(&listen_state.mutex);
40526470267STrond Norbye    return ret;
40626470267STrond Norbye}
40726470267STrond Norbye
40826470267STrond Norbyestatic void disable_listen(void) {
409f603fdb6STrond Norbye    conn *next;
410f603fdb6STrond Norbye    cb_mutex_enter(&listen_state.mutex);
41126470267STrond Norbye    listen_state.disabled = true;
41226470267STrond Norbye    listen_state.count = 10;
41326470267STrond Norbye    ++listen_state.num_disable;
414f603fdb6STrond Norbye    cb_mutex_exit(&listen_state.mutex);
41526470267STrond Norbye
41626470267STrond Norbye    for (next = listen_conn; next; next = next->next) {
41726470267STrond Norbye        update_event(next, 0);
41826470267STrond Norbye        if (listen(next->sfd, 1) != 0) {
419f603fdb6STrond Norbye            log_socket_error(EXTENSION_LOG_WARNING, NULL,
420f603fdb6STrond Norbye                             "listen() failed: %s");
42126470267STrond Norbye        }
42226470267STrond Norbye    }
42326470267STrond Norbye}
42426470267STrond Norbye
42500999f69STrond Norbyevoid safe_close(SOCKET sfd) {
42600999f69STrond Norbye    if (sfd != INVALID_SOCKET) {
427e804ecd5STrond Norbye        int rval;
42800999f69STrond Norbye        while ((rval = closesocket(sfd)) == SOCKET_ERROR &&
429e804ecd5STrond Norbye               (errno == EINTR || errno == EAGAIN)) {
430e804ecd5STrond Norbye            /* go ahead and retry */
431e804ecd5STrond Norbye        }
432e804ecd5STrond Norbye
43300999f69STrond Norbye        if (rval == SOCKET_ERROR) {
434f603fdb6STrond Norbye            char msg[80];
435f603fdb6STrond Norbye            snprintf(msg, sizeof(msg), "Failed to close socket %d (%%s)!!", (int)sfd);
436f603fdb6STrond Norbye            log_socket_error(EXTENSION_LOG_WARNING, NULL,
437f603fdb6STrond Norbye                             msg);
4387c76b06dSTrond Norbye        } else {
4397c76b06dSTrond Norbye            STATS_LOCK();
4407c76b06dSTrond Norbye            stats.curr_conns--;
4417c76b06dSTrond Norbye            STATS_UNLOCK();
44226470267STrond Norbye
44326470267STrond Norbye            if (is_listen_disabled()) {
44426470267STrond Norbye                notify_dispatcher();
44526470267STrond Norbye            }
446e804ecd5STrond Norbye        }
447e804ecd5STrond Norbye    }
448e804ecd5STrond Norbye}
449e804ecd5STrond Norbye
450fffdb8e6STrond Norbye/**
451fffdb8e6STrond Norbye * Reset all of the dynamic buffers used by a connection back to their
452fffdb8e6STrond Norbye * default sizes. The strategy for resizing the buffers is to allocate a
453fffdb8e6STrond Norbye * new one of the correct size and free the old one if the allocation succeeds
454fffdb8e6STrond Norbye * instead of using realloc to change the buffer size (because realloc may
455fffdb8e6STrond Norbye * not shrink the buffers, and will also copy the memory). If the allocation
456fffdb8e6STrond Norbye * fails the buffer will be unchanged.
457fffdb8e6STrond Norbye *
458fffdb8e6STrond Norbye * @param c the connection to resize the buffers for
459fffdb8e6STrond Norbye * @return true if all allocations succeeded, false if one or more of the
460fffdb8e6STrond Norbye *         allocations failed.
461fffdb8e6STrond Norbye */
462fffdb8e6STrond Norbyestatic bool conn_reset_buffersize(conn *c) {
463fffdb8e6STrond Norbye    bool ret = true;
46486969ea4SBrad Fitzpatrick
465fffdb8e6STrond Norbye    if (c->rsize != DATA_BUFFER_SIZE) {
466fffdb8e6STrond Norbye        void *ptr = malloc(DATA_BUFFER_SIZE);
467fffdb8e6STrond Norbye        if (ptr != NULL) {
468fffdb8e6STrond Norbye            free(c->rbuf);
469fffdb8e6STrond Norbye            c->rbuf = ptr;
470fffdb8e6STrond Norbye            c->rsize = DATA_BUFFER_SIZE;
471fffdb8e6STrond Norbye        } else {
472fffdb8e6STrond Norbye            ret = false;
473fffdb8e6STrond Norbye        }
474fffdb8e6STrond Norbye    }
47556b8339eSSteven Grimm
476fffdb8e6STrond Norbye    if (c->wsize != DATA_BUFFER_SIZE) {
477fffdb8e6STrond Norbye        void *ptr = malloc(DATA_BUFFER_SIZE);
478fffdb8e6STrond Norbye        if (ptr != NULL) {
479fffdb8e6STrond Norbye            free(c->wbuf);
480fffdb8e6STrond Norbye            c->wbuf = ptr;
481fffdb8e6STrond Norbye            c->wsize = DATA_BUFFER_SIZE;
482fffdb8e6STrond Norbye        } else {
483fffdb8e6STrond Norbye            ret = false;
484fffdb8e6STrond Norbye        }
48578955139STim Yardley    }
48686969ea4SBrad Fitzpatrick
487fffdb8e6STrond Norbye    if (c->isize != ITEM_LIST_INITIAL) {
488fffdb8e6STrond Norbye        void *ptr = malloc(sizeof(item *) * ITEM_LIST_INITIAL);
489fffdb8e6STrond Norbye        if (ptr != NULL) {
490fffdb8e6STrond Norbye            free(c->ilist);
491fffdb8e6STrond Norbye            c->ilist = ptr;
492fffdb8e6STrond Norbye            c->isize = ITEM_LIST_INITIAL;
493fffdb8e6STrond Norbye        } else {
494fffdb8e6STrond Norbye            ret = false;
495fffdb8e6STrond Norbye        }
496fffdb8e6STrond Norbye    }
49786969ea4SBrad Fitzpatrick
498c0f75a64STrond Norbye    if (c->temp_alloc_size != TEMP_ALLOC_LIST_INITIAL) {
499c0f75a64STrond Norbye        void *ptr = malloc(sizeof(char *) * TEMP_ALLOC_LIST_INITIAL);
500fffdb8e6STrond Norbye        if (ptr != NULL) {
501c0f75a64STrond Norbye            free(c->temp_alloc_list);
502c0f75a64STrond Norbye            c->temp_alloc_list = ptr;
503c0f75a64STrond Norbye            c->temp_alloc_size = TEMP_ALLOC_LIST_INITIAL;
504fffdb8e6STrond Norbye        } else {
505fffdb8e6STrond Norbye            ret = false;
506fffdb8e6STrond Norbye        }
50756b8339eSSteven Grimm    }
50856b8339eSSteven Grimm
509fffdb8e6STrond Norbye    if (c->iovsize != IOV_LIST_INITIAL) {
510fffdb8e6STrond Norbye        void *ptr = malloc(sizeof(struct iovec) * IOV_LIST_INITIAL);
511fffdb8e6STrond Norbye        if (ptr != NULL) {
512fffdb8e6STrond Norbye            free(c->iov);
513fffdb8e6STrond Norbye            c->iov = ptr;
514fffdb8e6STrond Norbye            c->iovsize = IOV_LIST_INITIAL;
515fffdb8e6STrond Norbye        } else {
516fffdb8e6STrond Norbye            ret = false;
517fffdb8e6STrond Norbye        }
518fffdb8e6STrond Norbye    }
51956b8339eSSteven Grimm
520fffdb8e6STrond Norbye    if (c->msgsize != MSG_LIST_INITIAL) {
521fffdb8e6STrond Norbye        void *ptr = malloc(sizeof(struct msghdr) * MSG_LIST_INITIAL);
522fffdb8e6STrond Norbye        if (ptr != NULL) {
523fffdb8e6STrond Norbye            free(c->msglist);
524fffdb8e6STrond Norbye            c->msglist = ptr;
525fffdb8e6STrond Norbye            c->msgsize = MSG_LIST_INITIAL;
526fffdb8e6STrond Norbye        } else {
527a4562105STrond Norbye            ret = false;
52856b8339eSSteven Grimm        }
52956b8339eSSteven Grimm    }
530fffdb8e6STrond Norbye
531a4562105STrond Norbye    return ret;
53256b8339eSSteven Grimm}
53356b8339eSSteven Grimm
534fffdb8e6STrond Norbye/**
535fffdb8e6STrond Norbye * Constructor for all memory allocations of connection objects. Initialize
536fffdb8e6STrond Norbye * all members and allocate the transfer buffers.
537fffdb8e6STrond Norbye *
538fffdb8e6STrond Norbye * @param buffer The memory allocated by the object cache
539fffdb8e6STrond Norbye * @return 0 on success, 1 if we failed to allocate memory
540fffdb8e6STrond Norbye */
5413797ae07STrond Norbyestatic int conn_constructor(conn *c) {
542fffdb8e6STrond Norbye    memset(c, 0, sizeof(*c));
543fffdb8e6STrond Norbye    MEMCACHED_CONN_CREATE(c);
544fffdb8e6STrond Norbye
5457401ce60STrond Norbye    c->state = conn_immediate_close;
5463797ae07STrond Norbye    c->sfd = INVALID_SOCKET;
547fffdb8e6STrond Norbye    if (!conn_reset_buffersize(c)) {
548fffdb8e6STrond Norbye        free(c->rbuf);
549fffdb8e6STrond Norbye        free(c->wbuf);
550fffdb8e6STrond Norbye        free(c->ilist);
551c0f75a64STrond Norbye        free(c->temp_alloc_list);
552fffdb8e6STrond Norbye        free(c->iov);
553fffdb8e6STrond Norbye        free(c->msglist);
55488d28697STrond Norbye        settings.extensions.logger->log(EXTENSION_LOG_WARNING,
55588d28697STrond Norbye                                        NULL,
55688d28697STrond Norbye                                        "Failed to allocate buffers for connection\n");
557fffdb8e6STrond Norbye        return 1;
5580a3f8c74SDustin Sallings    }
559fffdb8e6STrond Norbye
560fffdb8e6STrond Norbye    STATS_LOCK();
561fffdb8e6STrond Norbye    stats.conn_structs++;
562fffdb8e6STrond Norbye    STATS_UNLOCK();
563fffdb8e6STrond Norbye
564fffdb8e6STrond Norbye    return 0;
565fffdb8e6STrond Norbye}
566fffdb8e6STrond Norbye
567fffdb8e6STrond Norbye/**
568fffdb8e6STrond Norbye * Destructor for all connection objects. Release all allocated resources.
569fffdb8e6STrond Norbye *
570fffdb8e6STrond Norbye * @param buffer The memory allocated by the objec cache
571fffdb8e6STrond Norbye */
5723797ae07STrond Norbyestatic void conn_destructor(conn *c) {
573fffdb8e6STrond Norbye    free(c->rbuf);
574fffdb8e6STrond Norbye    free(c->wbuf);
575fffdb8e6STrond Norbye    free(c->ilist);
576c0f75a64STrond Norbye    free(c->temp_alloc_list);
577fffdb8e6STrond Norbye    free(c->iov);
578fffdb8e6STrond Norbye    free(c->msglist);
579fffdb8e6STrond Norbye
580fffdb8e6STrond Norbye    STATS_LOCK();
581fffdb8e6STrond Norbye    stats.conn_structs--;
582fffdb8e6STrond Norbye    STATS_UNLOCK();
5830a3f8c74SDustin Sallings}
5840a3f8c74SDustin Sallings
5853797ae07STrond Norbye/*
5863797ae07STrond Norbye * Free list management for connections.
5873797ae07STrond Norbye */
5883797ae07STrond Norbyestruct connections {
5893797ae07STrond Norbye    conn* free;
5903797ae07STrond Norbye    conn** all;
591f603fdb6STrond Norbye    cb_mutex_t mutex;
5923797ae07STrond Norbye    int next;
593f603fdb6STrond Norbye} connections;
5943797ae07STrond Norbye
5953797ae07STrond Norbyestatic void initialize_connections(void)
5963797ae07STrond Norbye{
597f603fdb6STrond Norbye    int preallocate;
598f603fdb6STrond Norbye
599f603fdb6STrond Norbye    cb_mutex_initialize(&connections.mutex);
6003797ae07STrond Norbye    connections.all = calloc(settings.maxconns, sizeof(conn*));
6013797ae07STrond Norbye    if (connections.all == NULL) {
6023797ae07STrond Norbye        settings.extensions.logger->log(EXTENSION_LOG_WARNING, NULL,
6033797ae07STrond Norbye                                        "Failed to allocate memory for connections");
6043797ae07STrond Norbye        exit(EX_OSERR);
6053797ae07STrond Norbye    }
6063797ae07STrond Norbye
607f603fdb6STrond Norbye    preallocate = settings.maxconns / 2;
6083797ae07STrond Norbye    if (preallocate < 1000) {
6093797ae07STrond Norbye        preallocate = settings.maxconns;
61032a0e222STrond Norbye    } else if (preallocate > 5000) {
61132a0e222STrond Norbye        preallocate = 5000;
6123797ae07STrond Norbye    }
6133797ae07STrond Norbye
6143797ae07STrond Norbye    for (connections.next = 0; connections.next < preallocate; ++connections.next) {
6153797ae07STrond Norbye        connections.all[connections.next] = malloc(sizeof(conn));
6163797ae07STrond Norbye        if (conn_constructor(connections.all[connections.next]) != 0) {
6173797ae07STrond Norbye            settings.extensions.logger->log(EXTENSION_LOG_WARNING, NULL,
6183797ae07STrond Norbye                                            "Failed to allocate memory for connections");
6193797ae07STrond Norbye            exit(EX_OSERR);
6203797ae07STrond Norbye        }
6213797ae07STrond Norbye        connections.all[connections.next]->next = connections.free;
6223797ae07STrond Norbye        connections.free = connections.all[connections.next];
6233797ae07STrond Norbye    }
6243797ae07STrond Norbye}
6253797ae07STrond Norbye
626a7ff8252STrond Norbyestatic void destroy_connections(void)
627a7ff8252STrond Norbye{
628f603fdb6STrond Norbye    int ii;
629f603fdb6STrond Norbye    for (ii = 0; ii < settings.maxconns; ++ii) {
630a7ff8252STrond Norbye        if (connections.all[ii]) {
631a7ff8252STrond Norbye            conn *c = connections.all[ii];
632a7ff8252STrond Norbye            conn_destructor(c);
633a7ff8252STrond Norbye            free(c);
634a7ff8252STrond Norbye        }
635a7ff8252STrond Norbye    }
636a7ff8252STrond Norbye
637a7ff8252STrond Norbye    free(connections.all);
638a7ff8252STrond Norbye}
639a7ff8252STrond Norbye
6403797ae07STrond Norbyestatic conn *allocate_connection(void) {
6413797ae07STrond Norbye    conn *ret;
6423797ae07STrond Norbye
643f603fdb6STrond Norbye    cb_mutex_enter(&connections.mutex);
6443797ae07STrond Norbye    ret = connections.free;
6453797ae07STrond Norbye    if (ret != NULL) {
6463797ae07STrond Norbye        connections.free = connections.free->next;
6473797ae07STrond Norbye        ret->next = NULL;
6483797ae07STrond Norbye    }
649f603fdb6STrond Norbye    cb_mutex_exit(&connections.mutex);
6503797ae07STrond Norbye
6513797ae07STrond Norbye    if (ret == NULL) {
6523797ae07STrond Norbye        ret = malloc(sizeof(conn));
6533797ae07STrond Norbye        if (ret == NULL) {
6543797ae07STrond Norbye            settings.extensions.logger->log(EXTENSION_LOG_WARNING, NULL,
6553797ae07STrond Norbye                                            "Failed to allocate memory for connection");
6563797ae07STrond Norbye            return NULL;
6573797ae07STrond Norbye        }
6583797ae07STrond Norbye
6593797ae07STrond Norbye        if (conn_constructor(ret) != 0) {
6603797ae07STrond Norbye            free(ret);
6613797ae07STrond Norbye            settings.extensions.logger->log(EXTENSION_LOG_WARNING, NULL,
6623797ae07STrond Norbye                                            "Failed to allocate memory for connection");
6633797ae07STrond Norbye            return NULL;
6643797ae07STrond Norbye        }
6653797ae07STrond Norbye
666f603fdb6STrond Norbye        cb_mutex_enter(&connections.mutex);
6673797ae07STrond Norbye        if (connections.next == settings.maxconns) {
6683797ae07STrond Norbye            free(ret);
6693797ae07STrond Norbye            ret = NULL;
6703797ae07STrond Norbye        } else {
6713797ae07STrond Norbye            connections.all[connections.next++] = ret;
6723797ae07STrond Norbye        }
673f603fdb6STrond Norbye        cb_mutex_exit(&connections.mutex);
6743797ae07STrond Norbye    }
6753797ae07STrond Norbye
6763797ae07STrond Norbye    return ret;
6773797ae07STrond Norbye}
6783797ae07STrond Norbye
6793797ae07STrond Norbyestatic void release_connection(conn *c) {
6803797ae07STrond Norbye    c->sfd = INVALID_SOCKET;
681f603fdb6STrond Norbye    cb_mutex_enter(&connections.mutex);
6823797ae07STrond Norbye    c->next = connections.free;
6833797ae07STrond Norbye    connections.free = c;
684f603fdb6STrond Norbye    cb_mutex_exit(&connections.mutex);
6853797ae07STrond Norbye}
6863797ae07STrond Norbye
6873797ae07STrond Norbyestatic const char *substate_text(enum bin_substates state) {
6883797ae07STrond Norbye    switch (state) {
6893797ae07STrond Norbye    case bin_no_state: return "bin_no_state";
6903797ae07STrond Norbye    case bin_reading_set_header: return "bin_reading_set_header";
6913797ae07STrond Norbye    case bin_reading_cas_header: return "bin_reading_cas_header";
6923797ae07STrond Norbye    case bin_read_set_value: return "bin_read_set_value";
6933797ae07STrond Norbye    case bin_reading_sasl_auth: return "bin_reading_sasl_auth";
6943797ae07STrond Norbye    case bin_reading_sasl_auth_data: return "bin_reading_sasl_auth_data";
6953797ae07STrond Norbye    case bin_reading_packet: return "bin_reading_packet";
6963797ae07STrond Norbye    default:
6973797ae07STrond Norbye        return "illegal";
6983797ae07STrond Norbye    }
6993797ae07STrond Norbye}
7003797ae07STrond Norbye
7013797ae07STrond Norbyestatic void add_connection_stats(ADD_STAT add_stats, conn *d, conn *c) {
7023797ae07STrond Norbye    append_stat("conn", add_stats, d, "%p", c);
7033797ae07STrond Norbye    if (c->sfd == INVALID_SOCKET) {
7043797ae07STrond Norbye        append_stat("socket", add_stats, d, "disconnected");
7053797ae07STrond Norbye    } else {
7063797ae07STrond Norbye        append_stat("socket", add_stats, d, "%lu", (long)c->sfd);
70752f949f1STrond Norbye        append_stat("protocol", add_stats, d, "%s", "binary");
708f603fdb6STrond Norbye        append_stat("transport", add_stats, d, "TCP");
7093797ae07STrond Norbye        append_stat("nevents", add_stats, d, "%u", c->nevents);
7103797ae07STrond Norbye        if (c->sasl_conn != NULL) {
7113797ae07STrond Norbye            append_stat("sasl_conn", add_stats, d, "%p", c->sasl_conn);
7123797ae07STrond Norbye        }
7133797ae07STrond Norbye        append_stat("state", add_stats, d, "%s", state_text(c->state));
71452f949f1STrond Norbye        append_stat("substate", add_stats, d, "%s", substate_text(c->substate));
7153797ae07STrond Norbye        append_stat("registered_in_libevent", add_stats, d, "%d",
7163797ae07STrond Norbye                    (int)c->registered_in_libevent);
7173797ae07STrond Norbye        append_stat("ev_flags", add_stats, d, "%x", c->ev_flags);
7183797ae07STrond Norbye        append_stat("which", add_stats, d, "%x", c->which);
7193797ae07STrond Norbye        append_stat("rbuf", add_stats, d, "%p", c->rbuf);
7203797ae07STrond Norbye        append_stat("rcurr", add_stats, d, "%p", c->rcurr);
7213797ae07STrond Norbye        append_stat("rsize", add_stats, d, "%u", c->rsize);
7223797ae07STrond Norbye        append_stat("rbytes", add_stats, d, "%u", c->rbytes);
7233797ae07STrond Norbye        append_stat("wbuf", add_stats, d, "%p", c->wbuf);
7243797ae07STrond Norbye        append_stat("wcurr", add_stats, d, "%p", c->wcurr);
7253797ae07STrond Norbye        append_stat("wsize", add_stats, d, "%u", c->wsize);
7263797ae07STrond Norbye        append_stat("wbytes", add_stats, d, "%u", c->wbytes);
7273797ae07STrond Norbye        append_stat("write_and_go", add_stats, d, "%p", c->write_and_go);
7283797ae07STrond Norbye        append_stat("write_and_free", add_stats, d, "%p", c->write_and_free);
7293797ae07STrond Norbye        append_stat("ritem", add_stats, d, "%p", c->ritem);
7303797ae07STrond Norbye        append_stat("rlbytes", add_stats, d, "%u", c->rlbytes);
7313797ae07STrond Norbye        append_stat("item", add_stats, d, "%p", c->item);
7323797ae07STrond Norbye        append_stat("store_op", add_stats, d, "%u", c->store_op);
7333797ae07STrond Norbye        append_stat("sbytes", add_stats, d, "%u", c->sbytes);
7343797ae07STrond Norbye        append_stat("iov", add_stats, d, "%p", c->iov);
7353797ae07STrond Norbye        append_stat("iovsize", add_stats, d, "%u", c->iovsize);
7363797ae07STrond Norbye        append_stat("iovused", add_stats, d, "%u", c->iovused);
7373797ae07STrond Norbye        append_stat("msglist", add_stats, d, "%p", c->msglist);
7383797ae07STrond Norbye        append_stat("msgsize", add_stats, d, "%u", c->msgsize);
7393797ae07STrond Norbye        append_stat("msgused", add_stats, d, "%u", c->msgused);
7403797ae07STrond Norbye        append_stat("msgcurr", add_stats, d, "%u", c->msgcurr);
7413797ae07STrond Norbye        append_stat("msgbytes", add_stats, d, "%u", c->msgbytes);
7423797ae07STrond Norbye        append_stat("ilist", add_stats, d, "%p", c->ilist);
7433797ae07STrond Norbye        append_stat("isize", add_stats, d, "%u", c->isize);
7443797ae07STrond Norbye        append_stat("icurr", add_stats, d, "%p", c->icurr);
7453797ae07STrond Norbye        append_stat("ileft", add_stats, d, "%u", c->ileft);
746c0f75a64STrond Norbye        append_stat("temp_alloc_list", add_stats, d, "%p", c->temp_alloc_list);
747c0f75a64STrond Norbye        append_stat("temp_alloc_size", add_stats, d, "%u", c->temp_alloc_size);
748c0f75a64STrond Norbye        append_stat("temp_alloc_curr", add_stats, d, "%p", c->temp_alloc_curr);
749c0f75a64STrond Norbye        append_stat("temp_alloc_left", add_stats, d, "%u", c->temp_alloc_left);
7503797ae07STrond Norbye
7513797ae07STrond Norbye        append_stat("noreply", add_stats, d, "%d", c->noreply);
7523797ae07STrond Norbye        append_stat("refcount", add_stats, d, "%u", (int)c->refcount);
7533797ae07STrond Norbye        append_stat("dynamic_buffer.buffer", add_stats, d, "%p",
7543797ae07STrond Norbye                    c->dynamic_buffer.buffer);
7553797ae07STrond Norbye        append_stat("dynamic_buffer.size", add_stats, d, "%zu",
7563797ae07STrond Norbye                    c->dynamic_buffer.size);
7573797ae07STrond Norbye        append_stat("dynamic_buffer.offset", add_stats, d, "%zu",
7583797ae07STrond Norbye                    c->dynamic_buffer.offset);
7593797ae07STrond Norbye        append_stat("engine_storage", add_stats, d, "%p", c->engine_storage);
76052f949f1STrond Norbye        /* @todo we should decode the binary header */
76152f949f1STrond Norbye        append_stat("cas", add_stats, d, "%"PRIu64, c->cas);
76252f949f1STrond Norbye        append_stat("cmd", add_stats, d, "%u", c->cmd);
76352f949f1STrond Norbye        append_stat("opaque", add_stats, d, "%u", c->opaque);
76452f949f1STrond Norbye        append_stat("keylen", add_stats, d, "%u", c->keylen);
7653797ae07STrond Norbye        append_stat("list_state", add_stats, d, "%u", c->list_state);
7663797ae07STrond Norbye        append_stat("next", add_stats, d, "%p", c->next);
7673797ae07STrond Norbye        append_stat("thread", add_stats, d, "%p", c->thread);
7683797ae07STrond Norbye        append_stat("aiostat", add_stats, d, "%u", c->aiostat);
7693797ae07STrond Norbye        append_stat("ewouldblock", add_stats, d, "%u", c->ewouldblock);
7703797ae07STrond Norbye        append_stat("tap_iterator", add_stats, d, "%p", c->tap_iterator);
7713797ae07STrond Norbye    }
7723797ae07STrond Norbye}
7733797ae07STrond Norbye
7743797ae07STrond Norbye/**
7753797ae07STrond Norbye * Do a full stats of all of the connections.
7763797ae07STrond Norbye * Do _NOT_ try to follow _ANY_ of the pointers in the conn structure
7773797ae07STrond Norbye * because we read all of the values _DIRTY_. We preallocated the array
7783797ae07STrond Norbye * of all of the connection pointers during startup, so we _KNOW_ that
7793797ae07STrond Norbye * we can iterate through all of them. All of the conn structs will
7803797ae07STrond Norbye * only appear in the connections.all array when we've allocated them,
7813797ae07STrond Norbye * and we don't release them so it's safe to look at them.
7823797ae07STrond Norbye */
7833797ae07STrond Norbyestatic void connection_stats(ADD_STAT add_stats, conn *c) {
784f603fdb6STrond Norbye    int ii;
785f603fdb6STrond Norbye    for (ii = 0; ii < settings.maxconns && connections.all[ii]; ++ii) {
7863797ae07STrond Norbye        add_connection_stats(add_stats, c, connections.all[ii]);
7873797ae07STrond Norbye    }
7883797ae07STrond Norbye}
7893797ae07STrond Norbye
790ce9a18d0STrond Norbyeconn *conn_new(const SOCKET sfd, in_port_t parent_port,
791ce9a18d0STrond Norbye               STATE_FUNC init_state, int event_flags,