nutcracker 0.3.0.12 → 0.4.0.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
{
|