nutcracker 0.3.0.12 → 0.4.0.13
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -13
- data/README.md +3 -3
- data/Rakefile +12 -10
- data/ext/nutcracker/Makefile.in +215 -162
- data/ext/nutcracker/README.md +16 -4
- data/ext/nutcracker/aclocal.m4 +432 -254
- data/ext/nutcracker/{contrib/yaml-0.1.4/configure → autom4te.cache/output.0} +11367 -4545
- data/ext/nutcracker/autom4te.cache/output.1 +19907 -0
- data/ext/nutcracker/autom4te.cache/output.2 +19907 -0
- data/ext/nutcracker/autom4te.cache/requests +518 -0
- data/ext/nutcracker/autom4te.cache/traces.0 +2715 -0
- data/ext/nutcracker/autom4te.cache/traces.1 +967 -0
- data/ext/nutcracker/autom4te.cache/traces.2 +2715 -0
- data/ext/nutcracker/config/compile +347 -0
- data/ext/nutcracker/config/config.guess +116 -78
- data/ext/nutcracker/config/config.sub +65 -45
- data/ext/nutcracker/config/depcomp +295 -192
- data/ext/nutcracker/config/install-sh +7 -7
- data/ext/nutcracker/config/ltmain.sh +15 -20
- data/ext/nutcracker/config/missing +149 -265
- data/ext/nutcracker/configure +493 -367
- data/ext/nutcracker/contrib/Makefile.in +158 -116
- data/ext/nutcracker/extconf.rb +0 -1
- data/ext/nutcracker/m4/libtool.m4 +4 -23
- data/ext/nutcracker/m4/ltoptions.m4 +0 -0
- data/ext/nutcracker/m4/ltsugar.m4 +0 -0
- data/ext/nutcracker/m4/ltversion.m4 +0 -0
- data/ext/nutcracker/m4/lt~obsolete.m4 +0 -0
- data/ext/nutcracker/notes/recommendation.md +1 -1
- data/ext/nutcracker/notes/redis.md +35 -3
- data/ext/nutcracker/scripts/benchmark-mget.py +43 -0
- data/ext/nutcracker/scripts/nutcracker.spec +61 -3
- data/ext/nutcracker/scripts/redis-check.sh +43 -0
- data/ext/nutcracker/src/Makefile.in +205 -142
- data/ext/nutcracker/src/event/Makefile.in +164 -66
- data/ext/nutcracker/src/hashkit/Makefile.in +164 -66
- data/ext/nutcracker/src/nc_conf.c +2 -0
- data/ext/nutcracker/src/nc_connection.c +31 -0
- data/ext/nutcracker/src/nc_connection.h +3 -0
- data/ext/nutcracker/src/nc_core.c +38 -2
- data/ext/nutcracker/src/nc_core.h +11 -0
- data/ext/nutcracker/src/nc_log.c +90 -12
- data/ext/nutcracker/src/nc_log.h +11 -0
- data/ext/nutcracker/src/nc_mbuf.h +1 -1
- data/ext/nutcracker/src/nc_message.c +162 -116
- data/ext/nutcracker/src/nc_message.h +161 -129
- data/ext/nutcracker/src/nc_proxy.c +34 -4
- data/ext/nutcracker/src/nc_request.c +158 -32
- data/ext/nutcracker/src/nc_server.c +59 -5
- data/ext/nutcracker/src/nc_server.h +1 -0
- data/ext/nutcracker/src/nc_signal.c +2 -2
- data/ext/nutcracker/src/nc_stats.c +21 -0
- data/ext/nutcracker/src/nc_stats.h +28 -26
- data/ext/nutcracker/src/nc_string.c +176 -1
- data/ext/nutcracker/src/nc_string.h +26 -0
- data/ext/nutcracker/src/nc_util.c +12 -0
- data/ext/nutcracker/src/nc_util.h +1 -0
- data/ext/nutcracker/src/proto/Makefile.in +164 -66
- data/ext/nutcracker/src/proto/nc_memcache.c +279 -88
- data/ext/nutcracker/src/proto/nc_proto.h +3 -4
- data/ext/nutcracker/src/proto/nc_redis.c +561 -134
- data/lib/nutcracker/version.rb +1 -1
- metadata +31 -67
- data/ext/nutcracker/contrib/yaml-0.1.4/LICENSE +0 -19
- data/ext/nutcracker/contrib/yaml-0.1.4/Makefile.am +0 -20
- data/ext/nutcracker/contrib/yaml-0.1.4/Makefile.in +0 -736
- data/ext/nutcracker/contrib/yaml-0.1.4/README +0 -27
- data/ext/nutcracker/contrib/yaml-0.1.4/aclocal.m4 +0 -956
- data/ext/nutcracker/contrib/yaml-0.1.4/config.h.in +0 -80
- data/ext/nutcracker/contrib/yaml-0.1.4/config/config.guess +0 -1561
- data/ext/nutcracker/contrib/yaml-0.1.4/config/config.sub +0 -1686
- data/ext/nutcracker/contrib/yaml-0.1.4/config/depcomp +0 -630
- data/ext/nutcracker/contrib/yaml-0.1.4/config/install-sh +0 -520
- data/ext/nutcracker/contrib/yaml-0.1.4/config/ltmain.sh +0 -8406
- data/ext/nutcracker/contrib/yaml-0.1.4/config/missing +0 -376
- data/ext/nutcracker/contrib/yaml-0.1.4/configure.ac +0 -75
- data/ext/nutcracker/contrib/yaml-0.1.4/doc/doxygen.cfg +0 -222
- data/ext/nutcracker/contrib/yaml-0.1.4/include/yaml.h +0 -1971
- data/ext/nutcracker/contrib/yaml-0.1.4/m4/libtool.m4 +0 -7357
- data/ext/nutcracker/contrib/yaml-0.1.4/m4/ltoptions.m4 +0 -368
- data/ext/nutcracker/contrib/yaml-0.1.4/m4/ltsugar.m4 +0 -123
- data/ext/nutcracker/contrib/yaml-0.1.4/m4/ltversion.m4 +0 -23
- data/ext/nutcracker/contrib/yaml-0.1.4/m4/lt~obsolete.m4 +0 -92
- data/ext/nutcracker/contrib/yaml-0.1.4/src/Makefile.am +0 -4
- data/ext/nutcracker/contrib/yaml-0.1.4/src/Makefile.in +0 -484
- data/ext/nutcracker/contrib/yaml-0.1.4/src/api.c +0 -1392
- data/ext/nutcracker/contrib/yaml-0.1.4/src/dumper.c +0 -394
- data/ext/nutcracker/contrib/yaml-0.1.4/src/emitter.c +0 -2329
- data/ext/nutcracker/contrib/yaml-0.1.4/src/loader.c +0 -432
- data/ext/nutcracker/contrib/yaml-0.1.4/src/parser.c +0 -1374
- data/ext/nutcracker/contrib/yaml-0.1.4/src/reader.c +0 -465
- data/ext/nutcracker/contrib/yaml-0.1.4/src/scanner.c +0 -3570
- data/ext/nutcracker/contrib/yaml-0.1.4/src/writer.c +0 -141
- data/ext/nutcracker/contrib/yaml-0.1.4/src/yaml_private.h +0 -640
- data/ext/nutcracker/contrib/yaml-0.1.4/tests/Makefile.am +0 -8
- data/ext/nutcracker/contrib/yaml-0.1.4/tests/Makefile.in +0 -675
- data/ext/nutcracker/contrib/yaml-0.1.4/tests/example-deconstructor-alt.c +0 -800
- data/ext/nutcracker/contrib/yaml-0.1.4/tests/example-deconstructor.c +0 -1130
- data/ext/nutcracker/contrib/yaml-0.1.4/tests/example-reformatter-alt.c +0 -217
- data/ext/nutcracker/contrib/yaml-0.1.4/tests/example-reformatter.c +0 -202
- data/ext/nutcracker/contrib/yaml-0.1.4/tests/run-dumper.c +0 -311
- data/ext/nutcracker/contrib/yaml-0.1.4/tests/run-emitter.c +0 -327
- data/ext/nutcracker/contrib/yaml-0.1.4/tests/run-loader.c +0 -63
- data/ext/nutcracker/contrib/yaml-0.1.4/tests/run-parser.c +0 -63
- data/ext/nutcracker/contrib/yaml-0.1.4/tests/run-scanner.c +0 -63
- data/ext/nutcracker/contrib/yaml-0.1.4/tests/test-reader.c +0 -354
- data/ext/nutcracker/contrib/yaml-0.1.4/tests/test-version.c +0 -29
@@ -368,6 +368,10 @@ server_close(struct context *ctx, struct conn *conn)
|
|
368
368
|
msg->error = 1;
|
369
369
|
msg->err = conn->err;
|
370
370
|
|
371
|
+
if (msg->frag_owner != NULL) {
|
372
|
+
msg->frag_owner->nfrag_done++;
|
373
|
+
}
|
374
|
+
|
371
375
|
if (req_done(c_conn, TAILQ_FIRST(&c_conn->omsg_q))) {
|
372
376
|
event_add_out(ctx->evb, msg->owner);
|
373
377
|
}
|
@@ -397,6 +401,9 @@ server_close(struct context *ctx, struct conn *conn)
|
|
397
401
|
msg->done = 1;
|
398
402
|
msg->error = 1;
|
399
403
|
msg->err = conn->err;
|
404
|
+
if (msg->frag_owner != NULL) {
|
405
|
+
msg->frag_owner->nfrag_done++;
|
406
|
+
}
|
400
407
|
|
401
408
|
if (req_done(c_conn, TAILQ_FIRST(&c_conn->omsg_q))) {
|
402
409
|
event_add_out(ctx->evb, msg->owner);
|
@@ -464,7 +471,7 @@ server_connect(struct context *ctx, struct server *server, struct conn *conn)
|
|
464
471
|
status = nc_set_nonblocking(conn->sd);
|
465
472
|
if (status != NC_OK) {
|
466
473
|
log_error("set nonblock on s %d for server '%.*s' failed: %s",
|
467
|
-
conn->sd,
|
474
|
+
conn->sd, server->pname.len, server->pname.data,
|
468
475
|
strerror(errno));
|
469
476
|
goto error;
|
470
477
|
}
|
@@ -608,15 +615,33 @@ server_pool_hash(struct server_pool *pool, uint8_t *key, uint32_t keylen)
|
|
608
615
|
return pool->key_hash((char *)key, keylen);
|
609
616
|
}
|
610
617
|
|
611
|
-
|
612
|
-
|
618
|
+
uint32_t
|
619
|
+
server_pool_idx(struct server_pool *pool, uint8_t *key, uint32_t keylen)
|
613
620
|
{
|
614
|
-
struct server *server;
|
615
621
|
uint32_t hash, idx;
|
616
622
|
|
617
623
|
ASSERT(array_n(&pool->server) != 0);
|
618
624
|
ASSERT(key != NULL && keylen != 0);
|
619
625
|
|
626
|
+
/*
|
627
|
+
* If hash_tag: is configured for this server pool, we use the part of
|
628
|
+
* the key within the hash tag as an input to the distributor. Otherwise
|
629
|
+
* we use the full key
|
630
|
+
*/
|
631
|
+
if (!string_empty(&pool->hash_tag)) {
|
632
|
+
struct string *tag = &pool->hash_tag;
|
633
|
+
uint8_t *tag_start, *tag_end;
|
634
|
+
|
635
|
+
tag_start = nc_strchr(key, key + keylen, tag->data[0]);
|
636
|
+
if (tag_start != NULL) {
|
637
|
+
tag_end = nc_strchr(tag_start + 1, key + keylen, tag->data[1]);
|
638
|
+
if ((tag_end != NULL) && (tag_end - tag_start > 1)) {
|
639
|
+
key = tag_start + 1;
|
640
|
+
keylen = (uint32_t)(tag_end - key);
|
641
|
+
}
|
642
|
+
}
|
643
|
+
}
|
644
|
+
|
620
645
|
switch (pool->dist_type) {
|
621
646
|
case DIST_KETAMA:
|
622
647
|
hash = server_pool_hash(pool, key, keylen);
|
@@ -634,10 +659,19 @@ server_pool_server(struct server_pool *pool, uint8_t *key, uint32_t keylen)
|
|
634
659
|
|
635
660
|
default:
|
636
661
|
NOT_REACHED();
|
637
|
-
return
|
662
|
+
return 0;
|
638
663
|
}
|
639
664
|
ASSERT(idx < array_n(&pool->server));
|
665
|
+
return idx;
|
666
|
+
}
|
640
667
|
|
668
|
+
static struct server *
|
669
|
+
server_pool_server(struct server_pool *pool, uint8_t *key, uint32_t keylen)
|
670
|
+
{
|
671
|
+
struct server *server;
|
672
|
+
uint32_t idx;
|
673
|
+
|
674
|
+
idx = server_pool_idx(pool, key, keylen);
|
641
675
|
server = array_get(&pool->server, idx);
|
642
676
|
|
643
677
|
log_debug(LOG_VERB, "key '%.*s' on dist %d maps to server '%.*s'", keylen,
|
@@ -742,6 +776,18 @@ server_pool_each_set_owner(void *elem, void *data)
|
|
742
776
|
return NC_OK;
|
743
777
|
}
|
744
778
|
|
779
|
+
static rstatus_t
|
780
|
+
server_pool_each_calc_connections(void *elem, void *data)
|
781
|
+
{
|
782
|
+
struct server_pool *sp = elem;
|
783
|
+
struct context *ctx = data;
|
784
|
+
|
785
|
+
ctx->max_nsconn += sp->server_connections * array_n(&sp->server);
|
786
|
+
ctx->max_nsconn += 1; /* pool listening socket */
|
787
|
+
|
788
|
+
return NC_OK;
|
789
|
+
}
|
790
|
+
|
745
791
|
rstatus_t
|
746
792
|
server_pool_run(struct server_pool *pool)
|
747
793
|
{
|
@@ -802,6 +848,14 @@ server_pool_init(struct array *server_pool, struct array *conf_pool,
|
|
802
848
|
return status;
|
803
849
|
}
|
804
850
|
|
851
|
+
/* compute max server connections */
|
852
|
+
ctx->max_nsconn = 0;
|
853
|
+
status = array_each(server_pool, server_pool_each_calc_connections, ctx);
|
854
|
+
if (status != NC_OK) {
|
855
|
+
server_pool_deinit(server_pool);
|
856
|
+
return status;
|
857
|
+
}
|
858
|
+
|
805
859
|
/* update server pool continuum */
|
806
860
|
status = array_each(server_pool, server_pool_each_run, NULL);
|
807
861
|
if (status != NC_OK) {
|
@@ -133,6 +133,7 @@ void server_close(struct context *ctx, struct conn *conn);
|
|
133
133
|
void server_connected(struct context *ctx, struct conn *conn);
|
134
134
|
void server_ok(struct context *ctx, struct conn *conn);
|
135
135
|
|
136
|
+
uint32_t server_pool_idx(struct server_pool *pool, uint8_t *key, uint32_t keylen);
|
136
137
|
struct conn *server_pool_conn(struct context *ctx, struct server_pool *pool, uint8_t *key, uint32_t keylen);
|
137
138
|
rstatus_t server_pool_run(struct server_pool *pool);
|
138
139
|
rstatus_t server_pool_preconnect(struct context *ctx);
|
@@ -110,7 +110,7 @@ signal_handler(int signo)
|
|
110
110
|
break;
|
111
111
|
|
112
112
|
case SIGSEGV:
|
113
|
-
|
113
|
+
log_stacktrace();
|
114
114
|
actionstr = ", core dumping";
|
115
115
|
raise(SIGSEGV);
|
116
116
|
break;
|
@@ -119,7 +119,7 @@ signal_handler(int signo)
|
|
119
119
|
NOT_REACHED();
|
120
120
|
}
|
121
121
|
|
122
|
-
|
122
|
+
log_safe("signal %d (%s) received%s", signo, sig->signame, actionstr);
|
123
123
|
|
124
124
|
if (action != NULL) {
|
125
125
|
action();
|
@@ -361,6 +361,14 @@ stats_create_buf(struct stats *st)
|
|
361
361
|
size += int64_max_digits;
|
362
362
|
size += key_value_extra;
|
363
363
|
|
364
|
+
size += st->ntotal_conn_str.len;
|
365
|
+
size += int64_max_digits;
|
366
|
+
size += key_value_extra;
|
367
|
+
|
368
|
+
size += st->ncurr_conn_str.len;
|
369
|
+
size += int64_max_digits;
|
370
|
+
size += key_value_extra;
|
371
|
+
|
364
372
|
/* server pools */
|
365
373
|
for (i = 0; i < array_n(&st->sum); i++) {
|
366
374
|
struct stats_pool *stp = array_get(&st->sum, i);
|
@@ -508,6 +516,16 @@ stats_add_header(struct stats *st)
|
|
508
516
|
return status;
|
509
517
|
}
|
510
518
|
|
519
|
+
status = stats_add_num(st, &st->ntotal_conn_str, conn_ntotal_conn());
|
520
|
+
if (status != NC_OK) {
|
521
|
+
return status;
|
522
|
+
}
|
523
|
+
|
524
|
+
status = stats_add_num(st, &st->ncurr_conn_str, conn_ncurr_conn());
|
525
|
+
if (status != NC_OK) {
|
526
|
+
return status;
|
527
|
+
}
|
528
|
+
|
511
529
|
return NC_OK;
|
512
530
|
}
|
513
531
|
|
@@ -909,6 +927,9 @@ stats_create(uint16_t stats_port, char *stats_ip, int stats_interval,
|
|
909
927
|
string_set_text(&st->uptime_str, "uptime");
|
910
928
|
string_set_text(&st->timestamp_str, "timestamp");
|
911
929
|
|
930
|
+
string_set_text(&st->ntotal_conn_str, "total_connections");
|
931
|
+
string_set_text(&st->ncurr_conn_str, "curr_connections");
|
932
|
+
|
912
933
|
st->updated = 0;
|
913
934
|
st->aggregate = 0;
|
914
935
|
|
@@ -41,7 +41,7 @@
|
|
41
41
|
/* data behavior */ \
|
42
42
|
ACTION( requests, STATS_COUNTER, "# requests") \
|
43
43
|
ACTION( request_bytes, STATS_COUNTER, "total request bytes") \
|
44
|
-
ACTION( responses, STATS_COUNTER, "#
|
44
|
+
ACTION( responses, STATS_COUNTER, "# responses") \
|
45
45
|
ACTION( response_bytes, STATS_COUNTER, "total response bytes") \
|
46
46
|
ACTION( in_queue, STATS_GAUGE, "# requests in incoming queue") \
|
47
47
|
ACTION( in_queue_bytes, STATS_GAUGE, "current request bytes in incoming queue") \
|
@@ -87,31 +87,33 @@ struct stats_buffer {
|
|
87
87
|
};
|
88
88
|
|
89
89
|
struct stats {
|
90
|
-
uint16_t port;
|
91
|
-
int interval;
|
92
|
-
struct string addr;
|
93
|
-
|
94
|
-
int64_t start_ts;
|
95
|
-
struct stats_buffer buf;
|
96
|
-
|
97
|
-
struct array current;
|
98
|
-
struct array shadow;
|
99
|
-
struct array sum;
|
100
|
-
|
101
|
-
pthread_t tid;
|
102
|
-
int sd;
|
103
|
-
|
104
|
-
struct string service_str;
|
105
|
-
struct string service;
|
106
|
-
struct string source_str;
|
107
|
-
struct string source;
|
108
|
-
struct string version_str;
|
109
|
-
struct string version;
|
110
|
-
struct string uptime_str;
|
111
|
-
struct string timestamp_str;
|
112
|
-
|
113
|
-
|
114
|
-
|
90
|
+
uint16_t port; /* stats monitoring port */
|
91
|
+
int interval; /* stats aggregation interval */
|
92
|
+
struct string addr; /* stats monitoring address */
|
93
|
+
|
94
|
+
int64_t start_ts; /* start timestamp of nutcracker */
|
95
|
+
struct stats_buffer buf; /* output buffer */
|
96
|
+
|
97
|
+
struct array current; /* stats_pool[] (a) */
|
98
|
+
struct array shadow; /* stats_pool[] (b) */
|
99
|
+
struct array sum; /* stats_pool[] (c = a + b) */
|
100
|
+
|
101
|
+
pthread_t tid; /* stats aggregator thread */
|
102
|
+
int sd; /* stats descriptor */
|
103
|
+
|
104
|
+
struct string service_str; /* service string */
|
105
|
+
struct string service; /* service */
|
106
|
+
struct string source_str; /* source string */
|
107
|
+
struct string source; /* source */
|
108
|
+
struct string version_str; /* version string */
|
109
|
+
struct string version; /* version */
|
110
|
+
struct string uptime_str; /* uptime string */
|
111
|
+
struct string timestamp_str; /* timestamp string */
|
112
|
+
struct string ntotal_conn_str; /* total connections string */
|
113
|
+
struct string ncurr_conn_str; /* curr connections string */
|
114
|
+
|
115
|
+
volatile int aggregate; /* shadow (b) aggregate? */
|
116
|
+
volatile int updated; /* current (a) updated? */
|
115
117
|
};
|
116
118
|
|
117
119
|
#define DEFINE_ACTION(_name, _type, _desc) STATS_POOL_##_name,
|
@@ -102,8 +102,183 @@ int
|
|
102
102
|
string_compare(const struct string *s1, const struct string *s2)
|
103
103
|
{
|
104
104
|
if (s1->len != s2->len) {
|
105
|
-
return s1->len
|
105
|
+
return s1->len > s2->len ? 1 : -1;
|
106
106
|
}
|
107
107
|
|
108
108
|
return nc_strncmp(s1->data, s2->data, s1->len);
|
109
109
|
}
|
110
|
+
|
111
|
+
static char *
|
112
|
+
_safe_utoa(int _base, uint64_t val, char *buf)
|
113
|
+
{
|
114
|
+
char hex[] = "0123456789abcdef";
|
115
|
+
uint32_t base = (uint32_t) _base;
|
116
|
+
*buf-- = 0;
|
117
|
+
do {
|
118
|
+
*buf-- = hex[val % base];
|
119
|
+
} while ((val /= base) != 0);
|
120
|
+
return buf + 1;
|
121
|
+
}
|
122
|
+
|
123
|
+
static char *
|
124
|
+
_safe_itoa(int base, int64_t val, char *buf)
|
125
|
+
{
|
126
|
+
char hex[] = "0123456789abcdef";
|
127
|
+
char *orig_buf = buf;
|
128
|
+
const int32_t is_neg = (val < 0);
|
129
|
+
*buf-- = 0;
|
130
|
+
|
131
|
+
if (is_neg) {
|
132
|
+
val = -val;
|
133
|
+
}
|
134
|
+
if (is_neg && base == 16) {
|
135
|
+
int ix;
|
136
|
+
val -= 1;
|
137
|
+
for (ix = 0; ix < 16; ++ix)
|
138
|
+
buf[-ix] = '0';
|
139
|
+
}
|
140
|
+
|
141
|
+
do {
|
142
|
+
*buf-- = hex[val % base];
|
143
|
+
} while ((val /= base) != 0);
|
144
|
+
|
145
|
+
if (is_neg && base == 10) {
|
146
|
+
*buf-- = '-';
|
147
|
+
}
|
148
|
+
|
149
|
+
if (is_neg && base == 16) {
|
150
|
+
int ix;
|
151
|
+
buf = orig_buf - 1;
|
152
|
+
for (ix = 0; ix < 16; ++ix, --buf) {
|
153
|
+
/* *INDENT-OFF* */
|
154
|
+
switch (*buf) {
|
155
|
+
case '0': *buf = 'f'; break;
|
156
|
+
case '1': *buf = 'e'; break;
|
157
|
+
case '2': *buf = 'd'; break;
|
158
|
+
case '3': *buf = 'c'; break;
|
159
|
+
case '4': *buf = 'b'; break;
|
160
|
+
case '5': *buf = 'a'; break;
|
161
|
+
case '6': *buf = '9'; break;
|
162
|
+
case '7': *buf = '8'; break;
|
163
|
+
case '8': *buf = '7'; break;
|
164
|
+
case '9': *buf = '6'; break;
|
165
|
+
case 'a': *buf = '5'; break;
|
166
|
+
case 'b': *buf = '4'; break;
|
167
|
+
case 'c': *buf = '3'; break;
|
168
|
+
case 'd': *buf = '2'; break;
|
169
|
+
case 'e': *buf = '1'; break;
|
170
|
+
case 'f': *buf = '0'; break;
|
171
|
+
}
|
172
|
+
/* *INDENT-ON* */
|
173
|
+
}
|
174
|
+
}
|
175
|
+
return buf + 1;
|
176
|
+
}
|
177
|
+
|
178
|
+
static const char *
|
179
|
+
_safe_check_longlong(const char *fmt, int32_t * have_longlong)
|
180
|
+
{
|
181
|
+
*have_longlong = false;
|
182
|
+
if (*fmt == 'l') {
|
183
|
+
fmt++;
|
184
|
+
if (*fmt != 'l') {
|
185
|
+
*have_longlong = (sizeof(long) == sizeof(int64_t));
|
186
|
+
} else {
|
187
|
+
fmt++;
|
188
|
+
*have_longlong = true;
|
189
|
+
}
|
190
|
+
}
|
191
|
+
return fmt;
|
192
|
+
}
|
193
|
+
|
194
|
+
int
|
195
|
+
_safe_vsnprintf(char *to, size_t size, const char *format, va_list ap)
|
196
|
+
{
|
197
|
+
char *start = to;
|
198
|
+
char *end = start + size - 1;
|
199
|
+
for (; *format; ++format) {
|
200
|
+
int32_t have_longlong = false;
|
201
|
+
if (*format != '%') {
|
202
|
+
if (to == end) { /* end of buffer */
|
203
|
+
break;
|
204
|
+
}
|
205
|
+
*to++ = *format; /* copy ordinary char */
|
206
|
+
continue;
|
207
|
+
}
|
208
|
+
++format; /* skip '%' */
|
209
|
+
|
210
|
+
format = _safe_check_longlong(format, &have_longlong);
|
211
|
+
|
212
|
+
switch (*format) {
|
213
|
+
case 'd':
|
214
|
+
case 'i':
|
215
|
+
case 'u':
|
216
|
+
case 'x':
|
217
|
+
case 'p':
|
218
|
+
{
|
219
|
+
int64_t ival = 0;
|
220
|
+
uint64_t uval = 0;
|
221
|
+
if (*format == 'p')
|
222
|
+
have_longlong = (sizeof(void *) == sizeof(uint64_t));
|
223
|
+
if (have_longlong) {
|
224
|
+
if (*format == 'u') {
|
225
|
+
uval = va_arg(ap, uint64_t);
|
226
|
+
} else {
|
227
|
+
ival = va_arg(ap, int64_t);
|
228
|
+
}
|
229
|
+
} else {
|
230
|
+
if (*format == 'u') {
|
231
|
+
uval = va_arg(ap, uint32_t);
|
232
|
+
} else {
|
233
|
+
ival = va_arg(ap, int32_t);
|
234
|
+
}
|
235
|
+
}
|
236
|
+
|
237
|
+
{
|
238
|
+
char buff[22];
|
239
|
+
const int base = (*format == 'x' || *format == 'p') ? 16 : 10;
|
240
|
+
|
241
|
+
/* *INDENT-OFF* */
|
242
|
+
char *val_as_str = (*format == 'u') ?
|
243
|
+
_safe_utoa(base, uval, &buff[sizeof(buff) - 1]) :
|
244
|
+
_safe_itoa(base, ival, &buff[sizeof(buff) - 1]);
|
245
|
+
/* *INDENT-ON* */
|
246
|
+
|
247
|
+
/* Strip off "ffffffff" if we have 'x' format without 'll' */
|
248
|
+
if (*format == 'x' && !have_longlong && ival < 0) {
|
249
|
+
val_as_str += 8;
|
250
|
+
}
|
251
|
+
|
252
|
+
while (*val_as_str && to < end) {
|
253
|
+
*to++ = *val_as_str++;
|
254
|
+
}
|
255
|
+
continue;
|
256
|
+
}
|
257
|
+
}
|
258
|
+
case 's':
|
259
|
+
{
|
260
|
+
const char *val = va_arg(ap, char *);
|
261
|
+
if (!val) {
|
262
|
+
val = "(null)";
|
263
|
+
}
|
264
|
+
while (*val && to < end) {
|
265
|
+
*to++ = *val++;
|
266
|
+
}
|
267
|
+
continue;
|
268
|
+
}
|
269
|
+
}
|
270
|
+
}
|
271
|
+
*to = 0;
|
272
|
+
return (int)(to - start);
|
273
|
+
}
|
274
|
+
|
275
|
+
int
|
276
|
+
_safe_snprintf(char *to, size_t n, const char *fmt, ...)
|
277
|
+
{
|
278
|
+
int result;
|
279
|
+
va_list args;
|
280
|
+
va_start(args, fmt);
|
281
|
+
result = _safe_vsnprintf(to, n, fmt, args);
|
282
|
+
va_end(args);
|
283
|
+
return result;
|
284
|
+
}
|
@@ -19,6 +19,9 @@
|
|
19
19
|
#define _NC_STRING_H_
|
20
20
|
|
21
21
|
#include <string.h>
|
22
|
+
#include <sys/types.h>
|
23
|
+
#include <stdarg.h>
|
24
|
+
|
22
25
|
#include <nc_core.h>
|
23
26
|
|
24
27
|
struct string {
|
@@ -83,6 +86,29 @@ int string_compare(const struct string *s1, const struct string *s2);
|
|
83
86
|
#define nc_vscnprintf(_s, _n, _f, _a) \
|
84
87
|
_vscnprintf((char *)(_s), (size_t)(_n), _f, _a)
|
85
88
|
|
89
|
+
#define nc_strftime(_s, _n, fmt, tm) \
|
90
|
+
(int)strftime((char *)(_s), (size_t)(_n), fmt, tm)
|
91
|
+
|
92
|
+
/*
|
93
|
+
* A (very) limited version of snprintf
|
94
|
+
* @param to Destination buffer
|
95
|
+
* @param n Size of destination buffer
|
96
|
+
* @param fmt printf() style format string
|
97
|
+
* @returns Number of bytes written, including terminating '\0'
|
98
|
+
* Supports 'd' 'i' 'u' 'x' 'p' 's' conversion
|
99
|
+
* Supports 'l' and 'll' modifiers for integral types
|
100
|
+
* Does not support any width/precision
|
101
|
+
* Implemented with simplicity, and async-signal-safety in mind
|
102
|
+
*/
|
103
|
+
int _safe_vsnprintf(char *to, size_t size, const char *format, va_list ap);
|
104
|
+
int _safe_snprintf(char *to, size_t n, const char *fmt, ...);
|
105
|
+
|
106
|
+
#define nc_safe_snprintf(_s, _n, ...) \
|
107
|
+
_safe_snprintf((char *)(_s), (size_t)(_n), __VA_ARGS__)
|
108
|
+
|
109
|
+
#define nc_safe_vsnprintf(_s, _n, _f, _a) \
|
110
|
+
_safe_vsnprintf((char *)(_s), (size_t)(_n), _f, _a)
|
111
|
+
|
86
112
|
static inline uint8_t *
|
87
113
|
_nc_strchr(uint8_t *p, uint8_t *last, uint8_t c)
|
88
114
|
{
|