nutcracker 0.2.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +22 -0
- data/Rakefile +55 -0
- data/bin/nutcracker +2 -0
- data/ext/nutcracker/ChangeLog +66 -0
- data/ext/nutcracker/LICENSE +177 -0
- data/ext/nutcracker/Makefile.am +7 -0
- data/ext/nutcracker/Makefile.in +726 -0
- data/ext/nutcracker/NOTICE +124 -0
- data/ext/nutcracker/README.md +240 -0
- data/ext/nutcracker/aclocal.m4 +956 -0
- data/ext/nutcracker/conf/nutcracker.leaf.yml +10 -0
- data/ext/nutcracker/conf/nutcracker.root.yml +8 -0
- data/ext/nutcracker/conf/nutcracker.yml +67 -0
- data/ext/nutcracker/config.h.in +316 -0
- data/ext/nutcracker/config/config.guess +1561 -0
- data/ext/nutcracker/config/config.sub +1686 -0
- data/ext/nutcracker/config/depcomp +630 -0
- data/ext/nutcracker/config/install-sh +520 -0
- data/ext/nutcracker/config/ltmain.sh +8413 -0
- data/ext/nutcracker/config/missing +376 -0
- data/ext/nutcracker/configure +18862 -0
- data/ext/nutcracker/configure.ac +155 -0
- data/ext/nutcracker/contrib/Makefile.am +3 -0
- data/ext/nutcracker/contrib/Makefile.in +560 -0
- data/ext/nutcracker/contrib/yaml-0.1.4.tar.gz +0 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/LICENSE +19 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/Makefile.am +20 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/Makefile.in +736 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/README +27 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/aclocal.m4 +956 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/config.h.in +80 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/config/config.guess +1561 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/config/config.sub +1686 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/config/depcomp +630 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/config/install-sh +520 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/config/ltmain.sh +8406 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/config/missing +376 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/configure +13085 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/configure.ac +75 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/doc/doxygen.cfg +222 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/include/yaml.h +1971 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/m4/libtool.m4 +7357 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/m4/ltoptions.m4 +368 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/m4/ltsugar.m4 +123 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/m4/ltversion.m4 +23 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/m4/lt~obsolete.m4 +92 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/src/Makefile.am +4 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/src/Makefile.in +484 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/src/api.c +1392 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/src/dumper.c +394 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/src/emitter.c +2329 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/src/loader.c +432 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/src/parser.c +1374 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/src/reader.c +465 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/src/scanner.c +3570 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/src/writer.c +141 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/src/yaml_private.h +640 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/tests/Makefile.am +8 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/tests/Makefile.in +675 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/tests/example-deconstructor-alt.c +800 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/tests/example-deconstructor.c +1130 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/tests/example-reformatter-alt.c +217 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/tests/example-reformatter.c +202 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/tests/run-dumper.c +311 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/tests/run-emitter.c +327 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/tests/run-loader.c +63 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/tests/run-parser.c +63 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/tests/run-scanner.c +63 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/tests/test-reader.c +354 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/tests/test-version.c +29 -0
- data/ext/nutcracker/extconf.rb +5 -0
- data/ext/nutcracker/m4/libtool.m4 +7376 -0
- data/ext/nutcracker/m4/ltoptions.m4 +368 -0
- data/ext/nutcracker/m4/ltsugar.m4 +123 -0
- data/ext/nutcracker/m4/ltversion.m4 +23 -0
- data/ext/nutcracker/m4/lt~obsolete.m4 +92 -0
- data/ext/nutcracker/notes/c-styleguide.txt +425 -0
- data/ext/nutcracker/notes/debug.txt +96 -0
- data/ext/nutcracker/notes/memcache.txt +123 -0
- data/ext/nutcracker/notes/recommendation.md +118 -0
- data/ext/nutcracker/notes/redis.md +415 -0
- data/ext/nutcracker/notes/socket.txt +131 -0
- data/ext/nutcracker/scripts/multi_get.sh +26 -0
- data/ext/nutcracker/scripts/nutcracker.init +73 -0
- data/ext/nutcracker/scripts/nutcracker.spec +52 -0
- data/ext/nutcracker/scripts/pipelined_read.sh +23 -0
- data/ext/nutcracker/scripts/pipelined_write.sh +29 -0
- data/ext/nutcracker/scripts/populate_memcached.sh +24 -0
- data/ext/nutcracker/scripts/redis-check.py +23 -0
- data/ext/nutcracker/scripts/redis-check.sh +564 -0
- data/ext/nutcracker/src/Makefile.am +46 -0
- data/ext/nutcracker/src/Makefile.in +726 -0
- data/ext/nutcracker/src/hashkit/Makefile.am +22 -0
- data/ext/nutcracker/src/hashkit/Makefile.in +501 -0
- data/ext/nutcracker/src/hashkit/nc_crc32.c +105 -0
- data/ext/nutcracker/src/hashkit/nc_fnv.c +82 -0
- data/ext/nutcracker/src/hashkit/nc_hashkit.h +74 -0
- data/ext/nutcracker/src/hashkit/nc_hsieh.c +93 -0
- data/ext/nutcracker/src/hashkit/nc_jenkins.c +230 -0
- data/ext/nutcracker/src/hashkit/nc_ketama.c +240 -0
- data/ext/nutcracker/src/hashkit/nc_md5.c +379 -0
- data/ext/nutcracker/src/hashkit/nc_modula.c +144 -0
- data/ext/nutcracker/src/hashkit/nc_murmur.c +99 -0
- data/ext/nutcracker/src/hashkit/nc_one_at_a_time.c +51 -0
- data/ext/nutcracker/src/hashkit/nc_random.c +146 -0
- data/ext/nutcracker/src/nc.c +573 -0
- data/ext/nutcracker/src/nc_array.c +204 -0
- data/ext/nutcracker/src/nc_array.h +73 -0
- data/ext/nutcracker/src/nc_client.c +189 -0
- data/ext/nutcracker/src/nc_client.h +28 -0
- data/ext/nutcracker/src/nc_conf.c +1766 -0
- data/ext/nutcracker/src/nc_conf.h +134 -0
- data/ext/nutcracker/src/nc_connection.c +392 -0
- data/ext/nutcracker/src/nc_connection.h +99 -0
- data/ext/nutcracker/src/nc_core.c +334 -0
- data/ext/nutcracker/src/nc_core.h +131 -0
- data/ext/nutcracker/src/nc_event.c +214 -0
- data/ext/nutcracker/src/nc_event.h +39 -0
- data/ext/nutcracker/src/nc_log.c +254 -0
- data/ext/nutcracker/src/nc_log.h +120 -0
- data/ext/nutcracker/src/nc_mbuf.c +285 -0
- data/ext/nutcracker/src/nc_mbuf.h +67 -0
- data/ext/nutcracker/src/nc_message.c +828 -0
- data/ext/nutcracker/src/nc_message.h +253 -0
- data/ext/nutcracker/src/nc_proxy.c +359 -0
- data/ext/nutcracker/src/nc_proxy.h +34 -0
- data/ext/nutcracker/src/nc_queue.h +788 -0
- data/ext/nutcracker/src/nc_rbtree.c +348 -0
- data/ext/nutcracker/src/nc_rbtree.h +47 -0
- data/ext/nutcracker/src/nc_request.c +588 -0
- data/ext/nutcracker/src/nc_response.c +332 -0
- data/ext/nutcracker/src/nc_server.c +841 -0
- data/ext/nutcracker/src/nc_server.h +143 -0
- data/ext/nutcracker/src/nc_signal.c +131 -0
- data/ext/nutcracker/src/nc_signal.h +34 -0
- data/ext/nutcracker/src/nc_stats.c +1188 -0
- data/ext/nutcracker/src/nc_stats.h +206 -0
- data/ext/nutcracker/src/nc_string.c +109 -0
- data/ext/nutcracker/src/nc_string.h +112 -0
- data/ext/nutcracker/src/nc_util.c +619 -0
- data/ext/nutcracker/src/nc_util.h +214 -0
- data/ext/nutcracker/src/proto/Makefile.am +14 -0
- data/ext/nutcracker/src/proto/Makefile.in +482 -0
- data/ext/nutcracker/src/proto/nc_memcache.c +1306 -0
- data/ext/nutcracker/src/proto/nc_proto.h +155 -0
- data/ext/nutcracker/src/proto/nc_redis.c +2102 -0
- data/lib/nutcracker.rb +7 -0
- data/lib/nutcracker/version.rb +3 -0
- metadata +194 -0
@@ -0,0 +1,206 @@
|
|
1
|
+
/*
|
2
|
+
* twemproxy - A fast and lightweight proxy for memcached protocol.
|
3
|
+
* Copyright (C) 2011 Twitter, Inc.
|
4
|
+
*
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
* you may not use this file except in compliance with the License.
|
7
|
+
* You may obtain a copy of the License at
|
8
|
+
*
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
*
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
* See the License for the specific language governing permissions and
|
15
|
+
* limitations under the License.
|
16
|
+
*/
|
17
|
+
|
18
|
+
#ifndef _NC_STATS_H_
|
19
|
+
#define _NC_STATS_H_
|
20
|
+
|
21
|
+
#include <sys/epoll.h>
|
22
|
+
|
23
|
+
#include <nc_core.h>
|
24
|
+
|
25
|
+
#define STATS_POOL_CODEC(ACTION) \
|
26
|
+
/* client behavior */ \
|
27
|
+
ACTION( client_eof, STATS_COUNTER, "# eof on client connections") \
|
28
|
+
ACTION( client_err, STATS_COUNTER, "# errors on client connections") \
|
29
|
+
ACTION( client_connections, STATS_GAUGE, "# active client connections") \
|
30
|
+
/* pool behavior */ \
|
31
|
+
ACTION( server_ejects, STATS_COUNTER, "# times backend server was ejected") \
|
32
|
+
/* forwarder behavior */ \
|
33
|
+
ACTION( forward_error, STATS_COUNTER, "# times we encountered a forwarding error") \
|
34
|
+
ACTION( fragments, STATS_COUNTER, "# fragments created from a multi-vector request") \
|
35
|
+
|
36
|
+
#define STATS_SERVER_CODEC(ACTION) \
|
37
|
+
/* server behavior */ \
|
38
|
+
ACTION( server_eof, STATS_COUNTER, "# eof on server connections") \
|
39
|
+
ACTION( server_err, STATS_COUNTER, "# errors on server connections") \
|
40
|
+
ACTION( server_timedout, STATS_COUNTER, "# timeouts on server connections") \
|
41
|
+
ACTION( server_connections, STATS_GAUGE, "# active server connections") \
|
42
|
+
/* data behavior */ \
|
43
|
+
ACTION( requests, STATS_COUNTER, "# requests") \
|
44
|
+
ACTION( request_bytes, STATS_COUNTER, "total request bytes") \
|
45
|
+
ACTION( responses, STATS_COUNTER, "# respones") \
|
46
|
+
ACTION( response_bytes, STATS_COUNTER, "total response bytes") \
|
47
|
+
ACTION( in_queue, STATS_GAUGE, "# requests in incoming queue") \
|
48
|
+
ACTION( in_queue_bytes, STATS_GAUGE, "current request bytes in incoming queue") \
|
49
|
+
ACTION( out_queue, STATS_GAUGE, "# requests in outgoing queue") \
|
50
|
+
ACTION( out_queue_bytes, STATS_GAUGE, "current request bytes in outgoing queue") \
|
51
|
+
|
52
|
+
#define STATS_ADDR "0.0.0.0"
|
53
|
+
#define STATS_PORT 22222
|
54
|
+
#define STATS_INTERVAL (30 * 1000) /* in msec */
|
55
|
+
|
56
|
+
typedef enum stats_type {
|
57
|
+
STATS_INVALID,
|
58
|
+
STATS_COUNTER, /* monotonic accumulator */
|
59
|
+
STATS_GAUGE, /* non-monotonic accumulator */
|
60
|
+
STATS_TIMESTAMP, /* monotonic timestamp (in nsec) */
|
61
|
+
STATS_SENTINEL
|
62
|
+
} stats_type_t;
|
63
|
+
|
64
|
+
struct stats_metric {
|
65
|
+
stats_type_t type; /* type */
|
66
|
+
struct string name; /* name (ref) */
|
67
|
+
union {
|
68
|
+
int64_t counter; /* accumulating counter */
|
69
|
+
int64_t timestamp; /* monotonic timestamp */
|
70
|
+
} value;
|
71
|
+
};
|
72
|
+
|
73
|
+
struct stats_server {
|
74
|
+
struct string name; /* server name (ref) */
|
75
|
+
struct array metric; /* stats_metric[] for server codec */
|
76
|
+
};
|
77
|
+
|
78
|
+
struct stats_pool {
|
79
|
+
struct string name; /* pool name (ref) */
|
80
|
+
struct array metric; /* stats_metric[] for pool codec */
|
81
|
+
struct array server; /* stats_server[] */
|
82
|
+
};
|
83
|
+
|
84
|
+
struct stats_buffer {
|
85
|
+
size_t len; /* buffer length */
|
86
|
+
uint8_t *data; /* buffer data */
|
87
|
+
size_t size; /* buffer alloc size */
|
88
|
+
};
|
89
|
+
|
90
|
+
struct stats {
|
91
|
+
uint16_t port; /* stats monitoring port */
|
92
|
+
int interval; /* stats aggregation interval */
|
93
|
+
struct string addr; /* stats monitoring address */
|
94
|
+
|
95
|
+
int64_t start_ts; /* start timestamp of nutcracker */
|
96
|
+
struct stats_buffer buf; /* output buffer */
|
97
|
+
|
98
|
+
struct array current; /* stats_pool[] (a) */
|
99
|
+
struct array shadow; /* stats_pool[] (b) */
|
100
|
+
struct array sum; /* stats_pool[] (c = a + b) */
|
101
|
+
|
102
|
+
pthread_t tid; /* stats aggregator thread */
|
103
|
+
int sd; /* stats descriptor */
|
104
|
+
int ep; /* epoll device */
|
105
|
+
struct epoll_event event; /* epoll event */
|
106
|
+
|
107
|
+
struct string service_str; /* service string */
|
108
|
+
struct string service; /* service */
|
109
|
+
struct string source_str; /* source string */
|
110
|
+
struct string source; /* source */
|
111
|
+
struct string version_str; /* version string */
|
112
|
+
struct string version; /* version */
|
113
|
+
struct string uptime_str; /* uptime string */
|
114
|
+
struct string timestamp_str; /* timestamp string */
|
115
|
+
|
116
|
+
volatile int aggregate; /* shadow (b) aggregate? */
|
117
|
+
volatile int updated; /* current (a) updated? */
|
118
|
+
};
|
119
|
+
|
120
|
+
#define DEFINE_ACTION(_name, _type, _desc) STATS_POOL_##_name,
|
121
|
+
typedef enum stats_pool_field {
|
122
|
+
STATS_POOL_CODEC(DEFINE_ACTION)
|
123
|
+
STATS_POOL_NFIELD
|
124
|
+
} stats_pool_field_t;
|
125
|
+
#undef DEFINE_ACTION
|
126
|
+
|
127
|
+
#define DEFINE_ACTION(_name, _type, _desc) STATS_SERVER_##_name,
|
128
|
+
typedef enum stats_server_field {
|
129
|
+
STATS_SERVER_CODEC(DEFINE_ACTION)
|
130
|
+
STATS_SERVER_NFIELD
|
131
|
+
} stats_server_field_t;
|
132
|
+
#undef DEFINE_ACTION
|
133
|
+
|
134
|
+
#if defined NC_STATS && NC_STATS == 1
|
135
|
+
|
136
|
+
#define stats_pool_incr(_ctx, _pool, _name) do { \
|
137
|
+
_stats_pool_incr(_ctx, _pool, STATS_POOL_##_name); \
|
138
|
+
} while (0)
|
139
|
+
|
140
|
+
#define stats_pool_decr(_ctx, _pool, _name) do { \
|
141
|
+
_stats_pool_decr(_ctx, _pool, STATS_POOL_##_name); \
|
142
|
+
} while (0)
|
143
|
+
|
144
|
+
#define stats_pool_incr_by(_ctx, _pool, _name, _val) do { \
|
145
|
+
_stats_pool_incr_by(_ctx, _pool, STATS_POOL_##_name, _val); \
|
146
|
+
} while (0)
|
147
|
+
|
148
|
+
#define stats_pool_decr_by(_ctx, _pool, _name, _val) do { \
|
149
|
+
_stats_pool_decr_by(_ctx, _pool, STATS_POOL_##_name, _val); \
|
150
|
+
} while (0)
|
151
|
+
|
152
|
+
#define stats_server_incr(_ctx, _server, _name) do { \
|
153
|
+
_stats_server_incr(_ctx, _server, STATS_SERVER_##_name); \
|
154
|
+
} while (0)
|
155
|
+
|
156
|
+
#define stats_server_decr(_ctx, _server, _name) do { \
|
157
|
+
_stats_server_decr(_ctx, _server, STATS_SERVER_##_name); \
|
158
|
+
} while (0)
|
159
|
+
|
160
|
+
#define stats_server_incr_by(_ctx, _server, _name, _val) do { \
|
161
|
+
_stats_server_incr_by(_ctx, _server, STATS_SERVER_##_name, _val); \
|
162
|
+
} while (0)
|
163
|
+
|
164
|
+
#define stats_server_decr_by(_ctx, _server, _name, _val) do { \
|
165
|
+
_stats_server_decr_by(_ctx, _server, STATS_SERVER_##_name, _val); \
|
166
|
+
} while (0)
|
167
|
+
|
168
|
+
#else
|
169
|
+
|
170
|
+
#define stats_pool_incr(_ctx, _pool, _name)
|
171
|
+
|
172
|
+
#define stats_pool_decr(_ctx, _pool, _name)
|
173
|
+
|
174
|
+
#define stats_pool_incr_by(_ctx, _pool, _name, _val)
|
175
|
+
|
176
|
+
#define stats_pool_decr_by(_ctx, _pool, _name, _val)
|
177
|
+
|
178
|
+
#define stats_server_incr(_ctx, _server, _name)
|
179
|
+
|
180
|
+
#define stats_server_decr(_ctx, _server, _name)
|
181
|
+
|
182
|
+
#define stats_server_incr_by(_ctx, _server, _name, _val)
|
183
|
+
|
184
|
+
#define stats_server_decr_by(_ctx, _server, _name, _val)
|
185
|
+
|
186
|
+
#endif
|
187
|
+
|
188
|
+
#define stats_enabled NC_STATS
|
189
|
+
|
190
|
+
void stats_describe(void);
|
191
|
+
|
192
|
+
void _stats_pool_incr(struct context *ctx, struct server_pool *pool, stats_pool_field_t fidx);
|
193
|
+
void _stats_pool_decr(struct context *ctx, struct server_pool *pool, stats_pool_field_t fidx);
|
194
|
+
void _stats_pool_incr_by(struct context *ctx, struct server_pool *pool, stats_pool_field_t fidx, int64_t val);
|
195
|
+
void _stats_pool_decr_by(struct context *ctx, struct server_pool *pool, stats_pool_field_t fidx, int64_t val);
|
196
|
+
|
197
|
+
void _stats_server_incr(struct context *ctx, struct server *server, stats_server_field_t fidx);
|
198
|
+
void _stats_server_decr(struct context *ctx, struct server *server, stats_server_field_t fidx);
|
199
|
+
void _stats_server_incr_by(struct context *ctx, struct server *server, stats_server_field_t fidx, int64_t val);
|
200
|
+
void _stats_server_decr_by(struct context *ctx, struct server *server, stats_server_field_t fidx, int64_t val);
|
201
|
+
|
202
|
+
struct stats *stats_create(uint16_t stats_port, char *stats_ip, int stats_interval, char *source, struct array *server_pool);
|
203
|
+
void stats_destroy(struct stats *stats);
|
204
|
+
void stats_swap(struct stats *stats);
|
205
|
+
|
206
|
+
#endif
|
@@ -0,0 +1,109 @@
|
|
1
|
+
/*
|
2
|
+
* twemproxy - A fast and lightweight proxy for memcached protocol.
|
3
|
+
* Copyright (C) 2011 Twitter, Inc.
|
4
|
+
*
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
* you may not use this file except in compliance with the License.
|
7
|
+
* You may obtain a copy of the License at
|
8
|
+
*
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
*
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
* See the License for the specific language governing permissions and
|
15
|
+
* limitations under the License.
|
16
|
+
*/
|
17
|
+
|
18
|
+
#include <stdlib.h>
|
19
|
+
#include <string.h>
|
20
|
+
|
21
|
+
#include <nc_core.h>
|
22
|
+
|
23
|
+
/*
|
24
|
+
* String (struct string) is a sequence of unsigned char objects terminated
|
25
|
+
* by the null character '\0'. The length of the string is pre-computed and
|
26
|
+
* made available explicitly as an additional field. This means that we don't
|
27
|
+
* have to walk the entire character sequence until the null terminating
|
28
|
+
* character everytime that the length of the String is requested
|
29
|
+
*
|
30
|
+
* The only way to create a String is to initialize it using, string_init()
|
31
|
+
* and duplicate an existing String - string_duplicate() or copy an existing
|
32
|
+
* raw sequence of character bytes - string_copy(). Such String's must be
|
33
|
+
* freed using string_deinit()
|
34
|
+
*
|
35
|
+
* We can also create String as reference to raw string - string_set_raw()
|
36
|
+
* or to text string - string_set_text() or string(). Such String don't have
|
37
|
+
* to be freed.
|
38
|
+
*/
|
39
|
+
|
40
|
+
void
|
41
|
+
string_init(struct string *str)
|
42
|
+
{
|
43
|
+
str->len = 0;
|
44
|
+
str->data = NULL;
|
45
|
+
}
|
46
|
+
|
47
|
+
void
|
48
|
+
string_deinit(struct string *str)
|
49
|
+
{
|
50
|
+
ASSERT((str->len == 0 && str->data == NULL) ||
|
51
|
+
(str->len != 0 && str->data != NULL));
|
52
|
+
|
53
|
+
if (str->data != NULL) {
|
54
|
+
nc_free(str->data);
|
55
|
+
string_init(str);
|
56
|
+
}
|
57
|
+
}
|
58
|
+
|
59
|
+
bool
|
60
|
+
string_empty(const struct string *str)
|
61
|
+
{
|
62
|
+
ASSERT((str->len == 0 && str->data == NULL) ||
|
63
|
+
(str->len != 0 && str->data != NULL));
|
64
|
+
return str->len == 0 ? true : false;
|
65
|
+
}
|
66
|
+
|
67
|
+
rstatus_t
|
68
|
+
string_duplicate(struct string *dst, const struct string *src)
|
69
|
+
{
|
70
|
+
ASSERT(dst->len == 0 && dst->data == NULL);
|
71
|
+
ASSERT(src->len != 0 && src->data != NULL);
|
72
|
+
|
73
|
+
dst->data = nc_strndup(src->data, src->len + 1);
|
74
|
+
if (dst->data == NULL) {
|
75
|
+
return NC_ENOMEM;
|
76
|
+
}
|
77
|
+
|
78
|
+
dst->len = src->len;
|
79
|
+
dst->data[dst->len] = '\0';
|
80
|
+
|
81
|
+
return NC_OK;
|
82
|
+
}
|
83
|
+
|
84
|
+
rstatus_t
|
85
|
+
string_copy(struct string *dst, const uint8_t *src, uint32_t srclen)
|
86
|
+
{
|
87
|
+
ASSERT(dst->len == 0 && dst->data == NULL);
|
88
|
+
ASSERT(src != NULL && srclen != 0);
|
89
|
+
|
90
|
+
dst->data = nc_strndup(src, srclen + 1);
|
91
|
+
if (dst->data == NULL) {
|
92
|
+
return NC_ENOMEM;
|
93
|
+
}
|
94
|
+
|
95
|
+
dst->len = srclen;
|
96
|
+
dst->data[dst->len] = '\0';
|
97
|
+
|
98
|
+
return NC_OK;
|
99
|
+
}
|
100
|
+
|
101
|
+
int
|
102
|
+
string_compare(const struct string *s1, const struct string *s2)
|
103
|
+
{
|
104
|
+
if (s1->len != s2->len) {
|
105
|
+
return s1->len - s2->len > 0 ? 1 : -1;
|
106
|
+
}
|
107
|
+
|
108
|
+
return nc_strncmp(s1->data, s2->data, s1->len);
|
109
|
+
}
|
@@ -0,0 +1,112 @@
|
|
1
|
+
/*
|
2
|
+
* twemproxy - A fast and lightweight proxy for memcached protocol.
|
3
|
+
* Copyright (C) 2011 Twitter, Inc.
|
4
|
+
*
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
* you may not use this file except in compliance with the License.
|
7
|
+
* You may obtain a copy of the License at
|
8
|
+
*
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
*
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
* See the License for the specific language governing permissions and
|
15
|
+
* limitations under the License.
|
16
|
+
*/
|
17
|
+
|
18
|
+
#ifndef _NC_STRING_H_
|
19
|
+
#define _NC_STRING_H_
|
20
|
+
|
21
|
+
#include <string.h>
|
22
|
+
#include <nc_core.h>
|
23
|
+
|
24
|
+
struct string {
|
25
|
+
uint32_t len; /* string length */
|
26
|
+
uint8_t *data; /* string data */
|
27
|
+
};
|
28
|
+
|
29
|
+
#define string(_str) { sizeof(_str) - 1, (uint8_t *)(_str) }
|
30
|
+
#define null_string { 0, NULL }
|
31
|
+
|
32
|
+
#define string_set_text(_str, _text) do { \
|
33
|
+
(_str)->len = (uint32_t)(sizeof(_text) - 1);\
|
34
|
+
(_str)->data = (uint8_t *)(_text); \
|
35
|
+
} while (0);
|
36
|
+
|
37
|
+
#define string_set_raw(_str, _raw) do { \
|
38
|
+
(_str)->len = (uint32_t)(nc_strlen(_raw)); \
|
39
|
+
(_str)->data = (uint8_t *)(_raw); \
|
40
|
+
} while (0);
|
41
|
+
|
42
|
+
void string_init(struct string *str);
|
43
|
+
void string_deinit(struct string *str);
|
44
|
+
bool string_empty(const struct string *str);
|
45
|
+
rstatus_t string_duplicate(struct string *dst, const struct string *src);
|
46
|
+
rstatus_t string_copy(struct string *dst, const uint8_t *src, uint32_t srclen);
|
47
|
+
int string_compare(const struct string *s1, const struct string *s2);
|
48
|
+
|
49
|
+
/*
|
50
|
+
* Wrapper around common routines for manipulating C character
|
51
|
+
* strings
|
52
|
+
*/
|
53
|
+
#define nc_memcpy(_d, _c, _n) \
|
54
|
+
memcpy(_d, _c, (size_t)(_n))
|
55
|
+
|
56
|
+
#define nc_memmove(_d, _c, _n) \
|
57
|
+
memmove(_d, _c, (size_t)(_n))
|
58
|
+
|
59
|
+
#define nc_memchr(_d, _c, _n) \
|
60
|
+
memchr(_d, _c, (size_t)(_n))
|
61
|
+
|
62
|
+
#define nc_strlen(_s) \
|
63
|
+
strlen((char *)(_s))
|
64
|
+
|
65
|
+
#define nc_strncmp(_s1, _s2, _n) \
|
66
|
+
strncmp((char *)(_s1), (char *)(_s2), (size_t)(_n))
|
67
|
+
|
68
|
+
#define nc_strchr(_p, _l, _c) \
|
69
|
+
_nc_strchr((uint8_t *)(_p), (uint8_t *)(_l), (uint8_t)(_c))
|
70
|
+
|
71
|
+
#define nc_strrchr(_p, _s, _c) \
|
72
|
+
_nc_strrchr((uint8_t *)(_p),(uint8_t *)(_s), (uint8_t)(_c))
|
73
|
+
|
74
|
+
#define nc_strndup(_s, _n) \
|
75
|
+
(uint8_t *)strndup((char *)(_s), (size_t)(_n));
|
76
|
+
|
77
|
+
#define nc_snprintf(_s, _n, ...) \
|
78
|
+
snprintf((char *)(_s), (size_t)(_n), __VA_ARGS__)
|
79
|
+
|
80
|
+
#define nc_scnprintf(_s, _n, ...) \
|
81
|
+
_scnprintf((char *)(_s), (size_t)(_n), __VA_ARGS__)
|
82
|
+
|
83
|
+
#define nc_vscnprintf(_s, _n, _f, _a) \
|
84
|
+
_vscnprintf((char *)(_s), (size_t)(_n), _f, _a)
|
85
|
+
|
86
|
+
static inline uint8_t *
|
87
|
+
_nc_strchr(uint8_t *p, uint8_t *last, uint8_t c)
|
88
|
+
{
|
89
|
+
while (p < last) {
|
90
|
+
if (*p == c) {
|
91
|
+
return p;
|
92
|
+
}
|
93
|
+
p++;
|
94
|
+
}
|
95
|
+
|
96
|
+
return NULL;
|
97
|
+
}
|
98
|
+
|
99
|
+
static inline uint8_t *
|
100
|
+
_nc_strrchr(uint8_t *p, uint8_t *start, uint8_t c)
|
101
|
+
{
|
102
|
+
while (p >= start) {
|
103
|
+
if (*p == c) {
|
104
|
+
return p;
|
105
|
+
}
|
106
|
+
p--;
|
107
|
+
}
|
108
|
+
|
109
|
+
return NULL;
|
110
|
+
}
|
111
|
+
|
112
|
+
#endif
|
@@ -0,0 +1,619 @@
|
|
1
|
+
/*
|
2
|
+
* twemproxy - A fast and lightweight proxy for memcached protocol.
|
3
|
+
* Copyright (C) 2011 Twitter, Inc.
|
4
|
+
*
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
* you may not use this file except in compliance with the License.
|
7
|
+
* You may obtain a copy of the License at
|
8
|
+
*
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
*
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
* See the License for the specific language governing permissions and
|
15
|
+
* limitations under the License.
|
16
|
+
*/
|
17
|
+
|
18
|
+
#include <stdio.h>
|
19
|
+
#include <stdlib.h>
|
20
|
+
#include <stdarg.h>
|
21
|
+
#include <string.h>
|
22
|
+
#include <unistd.h>
|
23
|
+
#include <fcntl.h>
|
24
|
+
#include <netdb.h>
|
25
|
+
#include <execinfo.h>
|
26
|
+
|
27
|
+
#include <sys/time.h>
|
28
|
+
#include <sys/types.h>
|
29
|
+
#include <sys/socket.h>
|
30
|
+
#include <sys/ioctl.h>
|
31
|
+
|
32
|
+
#include <netinet/in.h>
|
33
|
+
#include <netinet/tcp.h>
|
34
|
+
|
35
|
+
#include <nc_core.h>
|
36
|
+
|
37
|
+
int
|
38
|
+
nc_set_blocking(int sd)
|
39
|
+
{
|
40
|
+
int flags;
|
41
|
+
|
42
|
+
flags = fcntl(sd, F_GETFL, 0);
|
43
|
+
if (flags < 0) {
|
44
|
+
return flags;
|
45
|
+
}
|
46
|
+
|
47
|
+
return fcntl(sd, F_SETFL, flags & ~O_NONBLOCK);
|
48
|
+
}
|
49
|
+
|
50
|
+
int
|
51
|
+
nc_set_nonblocking(int sd)
|
52
|
+
{
|
53
|
+
int flags;
|
54
|
+
|
55
|
+
flags = fcntl(sd, F_GETFL, 0);
|
56
|
+
if (flags < 0) {
|
57
|
+
return flags;
|
58
|
+
}
|
59
|
+
|
60
|
+
return fcntl(sd, F_SETFL, flags | O_NONBLOCK);
|
61
|
+
}
|
62
|
+
|
63
|
+
int
|
64
|
+
nc_set_reuseaddr(int sd)
|
65
|
+
{
|
66
|
+
int reuse;
|
67
|
+
socklen_t len;
|
68
|
+
|
69
|
+
reuse = 1;
|
70
|
+
len = sizeof(reuse);
|
71
|
+
|
72
|
+
return setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &reuse, len);
|
73
|
+
}
|
74
|
+
|
75
|
+
/*
|
76
|
+
* Disable Nagle algorithm on TCP socket.
|
77
|
+
*
|
78
|
+
* This option helps to minimize transmit latency by disabling coalescing
|
79
|
+
* of data to fill up a TCP segment inside the kernel. Sockets with this
|
80
|
+
* option must use readv() or writev() to do data transfer in bulk and
|
81
|
+
* hence avoid the overhead of small packets.
|
82
|
+
*/
|
83
|
+
int
|
84
|
+
nc_set_tcpnodelay(int sd)
|
85
|
+
{
|
86
|
+
int nodelay;
|
87
|
+
socklen_t len;
|
88
|
+
|
89
|
+
nodelay = 1;
|
90
|
+
len = sizeof(nodelay);
|
91
|
+
|
92
|
+
return setsockopt(sd, IPPROTO_TCP, TCP_NODELAY, &nodelay, len);
|
93
|
+
}
|
94
|
+
|
95
|
+
int
|
96
|
+
nc_set_linger(int sd, int timeout)
|
97
|
+
{
|
98
|
+
struct linger linger;
|
99
|
+
socklen_t len;
|
100
|
+
|
101
|
+
linger.l_onoff = 1;
|
102
|
+
linger.l_linger = timeout;
|
103
|
+
|
104
|
+
len = sizeof(linger);
|
105
|
+
|
106
|
+
return setsockopt(sd, SOL_SOCKET, SO_LINGER, &linger, len);
|
107
|
+
}
|
108
|
+
|
109
|
+
int
|
110
|
+
nc_set_sndbuf(int sd, int size)
|
111
|
+
{
|
112
|
+
socklen_t len;
|
113
|
+
|
114
|
+
len = sizeof(size);
|
115
|
+
|
116
|
+
return setsockopt(sd, SOL_SOCKET, SO_SNDBUF, &size, len);
|
117
|
+
}
|
118
|
+
|
119
|
+
int
|
120
|
+
nc_set_rcvbuf(int sd, int size)
|
121
|
+
{
|
122
|
+
socklen_t len;
|
123
|
+
|
124
|
+
len = sizeof(size);
|
125
|
+
|
126
|
+
return setsockopt(sd, SOL_SOCKET, SO_RCVBUF, &size, len);
|
127
|
+
}
|
128
|
+
|
129
|
+
int
|
130
|
+
nc_get_soerror(int sd)
|
131
|
+
{
|
132
|
+
int status, err;
|
133
|
+
socklen_t len;
|
134
|
+
|
135
|
+
err = 0;
|
136
|
+
len = sizeof(err);
|
137
|
+
|
138
|
+
status = getsockopt(sd, SOL_SOCKET, SO_ERROR, &err, &len);
|
139
|
+
if (status == 0) {
|
140
|
+
errno = err;
|
141
|
+
}
|
142
|
+
|
143
|
+
return status;
|
144
|
+
}
|
145
|
+
|
146
|
+
int
|
147
|
+
nc_get_sndbuf(int sd)
|
148
|
+
{
|
149
|
+
int status, size;
|
150
|
+
socklen_t len;
|
151
|
+
|
152
|
+
size = 0;
|
153
|
+
len = sizeof(size);
|
154
|
+
|
155
|
+
status = getsockopt(sd, SOL_SOCKET, SO_SNDBUF, &size, &len);
|
156
|
+
if (status < 0) {
|
157
|
+
return status;
|
158
|
+
}
|
159
|
+
|
160
|
+
return size;
|
161
|
+
}
|
162
|
+
|
163
|
+
int
|
164
|
+
nc_get_rcvbuf(int sd)
|
165
|
+
{
|
166
|
+
int status, size;
|
167
|
+
socklen_t len;
|
168
|
+
|
169
|
+
size = 0;
|
170
|
+
len = sizeof(size);
|
171
|
+
|
172
|
+
status = getsockopt(sd, SOL_SOCKET, SO_RCVBUF, &size, &len);
|
173
|
+
if (status < 0) {
|
174
|
+
return status;
|
175
|
+
}
|
176
|
+
|
177
|
+
return size;
|
178
|
+
}
|
179
|
+
|
180
|
+
int
|
181
|
+
_nc_atoi(uint8_t *line, size_t n)
|
182
|
+
{
|
183
|
+
int value;
|
184
|
+
|
185
|
+
if (n == 0) {
|
186
|
+
return -1;
|
187
|
+
}
|
188
|
+
|
189
|
+
for (value = 0; n--; line++) {
|
190
|
+
if (*line < '0' || *line > '9') {
|
191
|
+
return -1;
|
192
|
+
}
|
193
|
+
|
194
|
+
value = value * 10 + (*line - '0');
|
195
|
+
}
|
196
|
+
|
197
|
+
if (value < 0) {
|
198
|
+
return -1;
|
199
|
+
}
|
200
|
+
|
201
|
+
return value;
|
202
|
+
}
|
203
|
+
|
204
|
+
bool
|
205
|
+
nc_valid_port(int n)
|
206
|
+
{
|
207
|
+
if (n < 1 || n > UINT16_MAX) {
|
208
|
+
return false;
|
209
|
+
}
|
210
|
+
|
211
|
+
return true;
|
212
|
+
}
|
213
|
+
|
214
|
+
void *
|
215
|
+
_nc_alloc(size_t size, const char *name, int line)
|
216
|
+
{
|
217
|
+
void *p;
|
218
|
+
|
219
|
+
ASSERT(size != 0);
|
220
|
+
|
221
|
+
p = malloc(size);
|
222
|
+
if (p == NULL) {
|
223
|
+
log_error("malloc(%zu) failed @ %s:%d", size, name, line);
|
224
|
+
} else {
|
225
|
+
log_debug(LOG_VVERB, "malloc(%zu) at %p @ %s:%d", size, p, name, line);
|
226
|
+
}
|
227
|
+
|
228
|
+
return p;
|
229
|
+
}
|
230
|
+
|
231
|
+
void *
|
232
|
+
_nc_zalloc(size_t size, const char *name, int line)
|
233
|
+
{
|
234
|
+
void *p;
|
235
|
+
|
236
|
+
p = _nc_alloc(size, name, line);
|
237
|
+
if (p != NULL) {
|
238
|
+
memset(p, 0, size);
|
239
|
+
}
|
240
|
+
|
241
|
+
return p;
|
242
|
+
}
|
243
|
+
|
244
|
+
void *
|
245
|
+
_nc_calloc(size_t nmemb, size_t size, const char *name, int line)
|
246
|
+
{
|
247
|
+
return _nc_zalloc(nmemb * size, name, line);
|
248
|
+
}
|
249
|
+
|
250
|
+
void *
|
251
|
+
_nc_realloc(void *ptr, size_t size, const char *name, int line)
|
252
|
+
{
|
253
|
+
void *p;
|
254
|
+
|
255
|
+
ASSERT(size != 0);
|
256
|
+
|
257
|
+
p = realloc(ptr, size);
|
258
|
+
if (p == NULL) {
|
259
|
+
log_error("realloc(%zu) failed @ %s:%d", size, name, line);
|
260
|
+
} else {
|
261
|
+
log_debug(LOG_VVERB, "realloc(%zu) at %p @ %s:%d", size, p, name, line);
|
262
|
+
}
|
263
|
+
|
264
|
+
return p;
|
265
|
+
}
|
266
|
+
|
267
|
+
void
|
268
|
+
_nc_free(void *ptr, const char *name, int line)
|
269
|
+
{
|
270
|
+
ASSERT(ptr != NULL);
|
271
|
+
log_debug(LOG_VVERB, "free(%p) @ %s:%d", ptr, name, line);
|
272
|
+
free(ptr);
|
273
|
+
}
|
274
|
+
|
275
|
+
void
|
276
|
+
nc_stacktrace(int skip_count)
|
277
|
+
{
|
278
|
+
void *stack[64];
|
279
|
+
char **symbols;
|
280
|
+
int size, i, j;
|
281
|
+
|
282
|
+
size = backtrace(stack, 64);
|
283
|
+
symbols = backtrace_symbols(stack, size);
|
284
|
+
if (symbols == NULL) {
|
285
|
+
return;
|
286
|
+
}
|
287
|
+
|
288
|
+
skip_count++; /* skip the current frame also */
|
289
|
+
|
290
|
+
for (i = skip_count, j = 0; i < size; i++, j++) {
|
291
|
+
loga("[%d] %s", j, symbols[i]);
|
292
|
+
}
|
293
|
+
|
294
|
+
free(symbols);
|
295
|
+
}
|
296
|
+
|
297
|
+
void
|
298
|
+
nc_assert(const char *cond, const char *file, int line, int panic)
|
299
|
+
{
|
300
|
+
log_error("assert '%s' failed @ (%s, %d)", cond, file, line);
|
301
|
+
if (panic) {
|
302
|
+
nc_stacktrace(1);
|
303
|
+
abort();
|
304
|
+
}
|
305
|
+
}
|
306
|
+
|
307
|
+
int
|
308
|
+
_vscnprintf(char *buf, size_t size, const char *fmt, va_list args)
|
309
|
+
{
|
310
|
+
int n;
|
311
|
+
|
312
|
+
n = vsnprintf(buf, size, fmt, args);
|
313
|
+
|
314
|
+
/*
|
315
|
+
* The return value is the number of characters which would be written
|
316
|
+
* into buf not including the trailing '\0'. If size is == 0 the
|
317
|
+
* function returns 0.
|
318
|
+
*
|
319
|
+
* On error, the function also returns 0. This is to allow idiom such
|
320
|
+
* as len += _vscnprintf(...)
|
321
|
+
*
|
322
|
+
* See: http://lwn.net/Articles/69419/
|
323
|
+
*/
|
324
|
+
if (n <= 0) {
|
325
|
+
return 0;
|
326
|
+
}
|
327
|
+
|
328
|
+
if (n < (int) size) {
|
329
|
+
return n;
|
330
|
+
}
|
331
|
+
|
332
|
+
return (int)(size - 1);
|
333
|
+
}
|
334
|
+
|
335
|
+
int
|
336
|
+
_scnprintf(char *buf, size_t size, const char *fmt, ...)
|
337
|
+
{
|
338
|
+
va_list args;
|
339
|
+
int n;
|
340
|
+
|
341
|
+
va_start(args, fmt);
|
342
|
+
n = _vscnprintf(buf, size, fmt, args);
|
343
|
+
va_end(args);
|
344
|
+
|
345
|
+
return n;
|
346
|
+
}
|
347
|
+
|
348
|
+
/*
|
349
|
+
* Send n bytes on a blocking descriptor
|
350
|
+
*/
|
351
|
+
ssize_t
|
352
|
+
_nc_sendn(int sd, const void *vptr, size_t n)
|
353
|
+
{
|
354
|
+
size_t nleft;
|
355
|
+
ssize_t nsend;
|
356
|
+
const char *ptr;
|
357
|
+
|
358
|
+
ptr = vptr;
|
359
|
+
nleft = n;
|
360
|
+
while (nleft > 0) {
|
361
|
+
nsend = send(sd, ptr, nleft, 0);
|
362
|
+
if (nsend < 0) {
|
363
|
+
if (errno == EINTR) {
|
364
|
+
continue;
|
365
|
+
}
|
366
|
+
return nsend;
|
367
|
+
}
|
368
|
+
if (nsend == 0) {
|
369
|
+
return -1;
|
370
|
+
}
|
371
|
+
|
372
|
+
nleft -= (size_t)nsend;
|
373
|
+
ptr += nsend;
|
374
|
+
}
|
375
|
+
|
376
|
+
return (ssize_t)n;
|
377
|
+
}
|
378
|
+
|
379
|
+
/*
|
380
|
+
* Recv n bytes from a blocking descriptor
|
381
|
+
*/
|
382
|
+
ssize_t
|
383
|
+
_nc_recvn(int sd, void *vptr, size_t n)
|
384
|
+
{
|
385
|
+
size_t nleft;
|
386
|
+
ssize_t nrecv;
|
387
|
+
char *ptr;
|
388
|
+
|
389
|
+
ptr = vptr;
|
390
|
+
nleft = n;
|
391
|
+
while (nleft > 0) {
|
392
|
+
nrecv = recv(sd, ptr, nleft, 0);
|
393
|
+
if (nrecv < 0) {
|
394
|
+
if (errno == EINTR) {
|
395
|
+
continue;
|
396
|
+
}
|
397
|
+
return nrecv;
|
398
|
+
}
|
399
|
+
if (nrecv == 0) {
|
400
|
+
break;
|
401
|
+
}
|
402
|
+
|
403
|
+
nleft -= (size_t)nrecv;
|
404
|
+
ptr += nrecv;
|
405
|
+
}
|
406
|
+
|
407
|
+
return (ssize_t)(n - nleft);
|
408
|
+
}
|
409
|
+
|
410
|
+
/*
|
411
|
+
* Return the current time in microseconds since Epoch
|
412
|
+
*/
|
413
|
+
int64_t
|
414
|
+
nc_usec_now(void)
|
415
|
+
{
|
416
|
+
struct timeval now;
|
417
|
+
int64_t usec;
|
418
|
+
int status;
|
419
|
+
|
420
|
+
status = gettimeofday(&now, NULL);
|
421
|
+
if (status < 0) {
|
422
|
+
log_error("gettimeofday failed: %s", strerror(errno));
|
423
|
+
return -1;
|
424
|
+
}
|
425
|
+
|
426
|
+
usec = (int64_t)now.tv_sec * 1000000LL + (int64_t)now.tv_usec;
|
427
|
+
|
428
|
+
return usec;
|
429
|
+
}
|
430
|
+
|
431
|
+
/*
|
432
|
+
* Return the current time in milliseconds since Epoch
|
433
|
+
*/
|
434
|
+
int64_t
|
435
|
+
nc_msec_now(void)
|
436
|
+
{
|
437
|
+
return nc_usec_now() / 1000LL;
|
438
|
+
}
|
439
|
+
|
440
|
+
static int
|
441
|
+
nc_resolve_inet(struct string *name, int port, struct sockinfo *si)
|
442
|
+
{
|
443
|
+
int status;
|
444
|
+
struct addrinfo *ai, *cai; /* head and current addrinfo */
|
445
|
+
struct addrinfo hints;
|
446
|
+
char *node, service[NC_UINTMAX_MAXLEN];
|
447
|
+
bool found;
|
448
|
+
|
449
|
+
ASSERT(nc_valid_port(port));
|
450
|
+
|
451
|
+
memset(&hints, 0, sizeof(hints));
|
452
|
+
hints.ai_flags = AI_NUMERICSERV;
|
453
|
+
hints.ai_family = AF_UNSPEC; /* AF_INET or AF_INET6 */
|
454
|
+
hints.ai_socktype = SOCK_STREAM;
|
455
|
+
hints.ai_protocol = 0;
|
456
|
+
hints.ai_addrlen = 0;
|
457
|
+
hints.ai_addr = NULL;
|
458
|
+
hints.ai_canonname = NULL;
|
459
|
+
|
460
|
+
if (name != NULL) {
|
461
|
+
node = (char *)name->data;
|
462
|
+
} else {
|
463
|
+
/*
|
464
|
+
* If AI_PASSIVE flag is specified in hints.ai_flags, and node is
|
465
|
+
* NULL, then the returned socket addresses will be suitable for
|
466
|
+
* bind(2)ing a socket that will accept(2) connections. The returned
|
467
|
+
* socket address will contain the wildcard IP address.
|
468
|
+
*/
|
469
|
+
node = NULL;
|
470
|
+
hints.ai_flags |= AI_PASSIVE;
|
471
|
+
}
|
472
|
+
|
473
|
+
nc_snprintf(service, NC_UINTMAX_MAXLEN, "%d", port);
|
474
|
+
|
475
|
+
status = getaddrinfo(node, service, &hints, &ai);
|
476
|
+
if (status < 0) {
|
477
|
+
log_error("address resolution of node '%s' service '%s' failed: %s",
|
478
|
+
node, service, gai_strerror(status));
|
479
|
+
return -1;
|
480
|
+
}
|
481
|
+
|
482
|
+
/*
|
483
|
+
* getaddrinfo() can return a linked list of more than one addrinfo,
|
484
|
+
* since we requested for both AF_INET and AF_INET6 addresses and the
|
485
|
+
* host itself can be multi-homed. Since we don't care whether we are
|
486
|
+
* using ipv4 or ipv6, we just use the first address from this collection
|
487
|
+
* in the order in which it was returned.
|
488
|
+
*
|
489
|
+
* The sorting function used within getaddrinfo() is defined in RFC 3484;
|
490
|
+
* the order can be tweaked for a particular system by editing
|
491
|
+
* /etc/gai.conf
|
492
|
+
*/
|
493
|
+
for (cai = ai, found = false; cai != NULL; cai = cai->ai_next) {
|
494
|
+
si->family = cai->ai_family;
|
495
|
+
si->addrlen = cai->ai_addrlen;
|
496
|
+
nc_memcpy(&si->addr, cai->ai_addr, si->addrlen);
|
497
|
+
found = true;
|
498
|
+
break;
|
499
|
+
}
|
500
|
+
|
501
|
+
freeaddrinfo(ai);
|
502
|
+
|
503
|
+
return !found ? -1 : 0;
|
504
|
+
}
|
505
|
+
|
506
|
+
static int
|
507
|
+
nc_resolve_unix(struct string *name, struct sockinfo *si)
|
508
|
+
{
|
509
|
+
struct sockaddr_un *un;
|
510
|
+
|
511
|
+
if (name->len >= NC_UNIX_ADDRSTRLEN) {
|
512
|
+
return -1;
|
513
|
+
}
|
514
|
+
|
515
|
+
un = &si->addr.un;
|
516
|
+
|
517
|
+
un->sun_family = AF_UNIX;
|
518
|
+
nc_memcpy(un->sun_path, name->data, name->len);
|
519
|
+
un->sun_path[name->len] = '\0';
|
520
|
+
|
521
|
+
si->family = AF_UNIX;
|
522
|
+
si->addrlen = sizeof(*un);
|
523
|
+
/* si->addr is an alias of un */
|
524
|
+
|
525
|
+
return 0;
|
526
|
+
}
|
527
|
+
|
528
|
+
/*
|
529
|
+
* Resolve a hostname and service by translating it to socket address and
|
530
|
+
* return it in si
|
531
|
+
*
|
532
|
+
* This routine is reentrant
|
533
|
+
*/
|
534
|
+
int
|
535
|
+
nc_resolve(struct string *name, int port, struct sockinfo *si)
|
536
|
+
{
|
537
|
+
if (name != NULL && name->data[0] == '/') {
|
538
|
+
return nc_resolve_unix(name, si);
|
539
|
+
}
|
540
|
+
|
541
|
+
return nc_resolve_inet(name, port, si);
|
542
|
+
}
|
543
|
+
|
544
|
+
/*
|
545
|
+
* Unresolve the socket address by translating it to a character string
|
546
|
+
* describing the host and service
|
547
|
+
*
|
548
|
+
* This routine is not reentrant
|
549
|
+
*/
|
550
|
+
char *
|
551
|
+
nc_unresolve_addr(struct sockaddr *addr, socklen_t addrlen)
|
552
|
+
{
|
553
|
+
static char unresolve[NI_MAXHOST + NI_MAXSERV];
|
554
|
+
static char host[NI_MAXHOST], service[NI_MAXSERV];
|
555
|
+
int status;
|
556
|
+
|
557
|
+
status = getnameinfo(addr, addrlen, host, sizeof(host),
|
558
|
+
service, sizeof(service),
|
559
|
+
NI_NUMERICHOST | NI_NUMERICSERV);
|
560
|
+
if (status < 0) {
|
561
|
+
return "unknown";
|
562
|
+
}
|
563
|
+
|
564
|
+
nc_snprintf(unresolve, sizeof(unresolve), "%s:%s", host, service);
|
565
|
+
|
566
|
+
return unresolve;
|
567
|
+
}
|
568
|
+
|
569
|
+
/*
|
570
|
+
* Unresolve the socket descriptor peer address by translating it to a
|
571
|
+
* character string describing the host and service
|
572
|
+
*
|
573
|
+
* This routine is not reentrant
|
574
|
+
*/
|
575
|
+
char *
|
576
|
+
nc_unresolve_peer_desc(int sd)
|
577
|
+
{
|
578
|
+
static struct sockinfo si;
|
579
|
+
struct sockaddr *addr;
|
580
|
+
socklen_t addrlen;
|
581
|
+
int status;
|
582
|
+
|
583
|
+
memset(&si, 0, sizeof(si));
|
584
|
+
addr = (struct sockaddr *)&si.addr;
|
585
|
+
addrlen = sizeof(si.addr);
|
586
|
+
|
587
|
+
status = getpeername(sd, addr, &addrlen);
|
588
|
+
if (status < 0) {
|
589
|
+
return "unknown";
|
590
|
+
}
|
591
|
+
|
592
|
+
return nc_unresolve_addr(addr, addrlen);
|
593
|
+
}
|
594
|
+
|
595
|
+
/*
|
596
|
+
* Unresolve the socket descriptor address by translating it to a
|
597
|
+
* character string describing the host and service
|
598
|
+
*
|
599
|
+
* This routine is not reentrant
|
600
|
+
*/
|
601
|
+
char *
|
602
|
+
nc_unresolve_desc(int sd)
|
603
|
+
{
|
604
|
+
static struct sockinfo si;
|
605
|
+
struct sockaddr *addr;
|
606
|
+
socklen_t addrlen;
|
607
|
+
int status;
|
608
|
+
|
609
|
+
memset(&si, 0, sizeof(si));
|
610
|
+
addr = (struct sockaddr *)&si.addr;
|
611
|
+
addrlen = sizeof(si.addr);
|
612
|
+
|
613
|
+
status = getsockname(sd, addr, &addrlen);
|
614
|
+
if (status < 0) {
|
615
|
+
return "unknown";
|
616
|
+
}
|
617
|
+
|
618
|
+
return nc_unresolve_addr(addr, addrlen);
|
619
|
+
}
|