| /** |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include "core/span_id.h" |
| #include "util/cmp.h" |
| #include "util/log.h" |
| #include "util/rand.h" |
| #include "util/string.h" |
| #include "util/time.h" |
| |
| #include <errno.h> |
| #include <inttypes.h> |
| #include <stdint.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| |
| /** |
| * @file span_id.c |
| * |
| * Implementation of HTrace span IDs. |
| * |
| * Span IDs are 128 bits in total. The upper 64 bits of a span ID is the same |
| * as the upper 64 bits of the first parent span, if there is one. The lower 64 |
| * bits are always random. |
| */ |
| |
| const struct htrace_span_id INVALID_SPAN_ID; |
| |
| static uint64_t parse_hex_range(const char *str, int start, int end, |
| char *err, size_t err_len) |
| { |
| char *endptr = NULL; |
| uint64_t ret; |
| char substr[HTRACE_SPAN_ID_STRING_LENGTH + 1]; |
| |
| err[0] = '\0'; |
| if (end - start >= HTRACE_SPAN_ID_STRING_LENGTH) { |
| snprintf(err, err_len, "parse_hex_range buffer too short."); |
| return 0; |
| } |
| memcpy(substr, str + start, end - start); |
| substr[end - start] = '\0'; |
| errno = 0; |
| ret = strtoull(substr, &endptr, 16); |
| if (errno) { |
| int e = errno; |
| snprintf(err, err_len, "parse_hex_range error: %s", terror(e)); |
| return 0; |
| } |
| while (1) { |
| char c = *endptr; |
| if (c == '\0') { |
| break; |
| } |
| if ((c != ' ') || (c != '\t')) { |
| snprintf(err, err_len, "parse_hex_range error: garbage at end " |
| "of string."); |
| return 0; |
| } |
| endptr++; |
| } |
| return ret; |
| } |
| |
| void htrace_span_id_parse(struct htrace_span_id *id, const char *str, |
| char *err, size_t err_len) |
| { |
| size_t len; |
| |
| err[0] = '\0'; |
| len = strlen(str); |
| if (len < HTRACE_SPAN_ID_STRING_LENGTH) { |
| snprintf(err, err_len, "too short: must be %d characters.", |
| HTRACE_SPAN_ID_STRING_LENGTH); |
| return; |
| } |
| id->high = (parse_hex_range(str, 0, 8, err, err_len) << 32); |
| if (err[0]) { |
| return; |
| } |
| id->high |= (parse_hex_range(str, 8, 16, err, err_len)); |
| if (err[0]) { |
| return; |
| } |
| id->low = (parse_hex_range(str, 16, 24, err, err_len) << 32); |
| if (err[0]) { |
| return; |
| } |
| id->low |= (parse_hex_range(str, 24, 32, err, err_len)); |
| if (err[0]) { |
| return; |
| } |
| } |
| |
| int htrace_span_id_to_str(const struct htrace_span_id *id, |
| char *str, size_t len) |
| { |
| int res = snprintf(str, len, |
| "%08"PRIx32"%08"PRIx32"%08"PRIx32"%08"PRIx32, |
| (uint32_t)(0xffffffffUL & (id->high >> 32)), |
| (uint32_t)(0xffffffffUL & id->high), |
| (uint32_t)(0xffffffffUL & (id->low >> 32)), |
| (uint32_t)(0xffffffffUL & id->low)); |
| return (res == HTRACE_SPAN_ID_STRING_LENGTH); |
| } |
| |
| void htrace_span_id_copy(struct htrace_span_id *dst, |
| const struct htrace_span_id *src) |
| { |
| memmove(dst, src, sizeof(*dst)); |
| } |
| |
| int htrace_span_id_write_msgpack(const struct htrace_span_id *id, |
| struct cmp_ctx_s *ctx) |
| { |
| uint8_t buf[HTRACE_SPAN_ID_NUM_BYTES]; |
| buf[0] = (id->high >> 56) & 0xff; |
| buf[1] = (id->high >> 48) & 0xff; |
| buf[2] = (id->high >> 40) & 0xff; |
| buf[3] = (id->high >> 32) & 0xff; |
| buf[4] = (id->high >> 24) & 0xff; |
| buf[5] = (id->high >> 16) & 0xff; |
| buf[6] = (id->high >> 8) & 0xff; |
| buf[7] = (id->high >> 0) & 0xff; |
| buf[8] = (id->low >> 56) & 0xff; |
| buf[9] = (id->low >> 48) & 0xff; |
| buf[10] = (id->low >> 40) & 0xff; |
| buf[11] = (id->low >> 32) & 0xff; |
| buf[12] = (id->low >> 24) & 0xff; |
| buf[13] = (id->low >> 16) & 0xff; |
| buf[14] = (id->low >> 8) & 0xff; |
| buf[15] = (id->low >> 0) & 0xff; |
| return cmp_write_bin(ctx, buf, HTRACE_SPAN_ID_NUM_BYTES); |
| } |
| |
| int htrace_span_id_read_msgpack(struct htrace_span_id *id, |
| struct cmp_ctx_s *ctx) |
| { |
| uint8_t buf[HTRACE_SPAN_ID_NUM_BYTES]; |
| uint32_t size = HTRACE_SPAN_ID_NUM_BYTES; |
| |
| if (!cmp_read_bin(ctx, buf, &size)) { |
| return 0; |
| } |
| if (size != HTRACE_SPAN_ID_NUM_BYTES) { |
| return 0; |
| } |
| id->high = |
| (((uint64_t)buf[0]) << 56) | |
| (((uint64_t)buf[1]) << 48) | |
| (((uint64_t)buf[2]) << 40) | |
| (((uint64_t)buf[3]) << 32) | |
| (((uint64_t)buf[4]) << 24) | |
| (((uint64_t)buf[5]) << 16) | |
| (((uint64_t)buf[6]) << 8) | |
| (((uint64_t)buf[7]) << 0); |
| id->low = |
| (((uint64_t)buf[8]) << 56) | |
| (((uint64_t)buf[9]) << 48) | |
| (((uint64_t)buf[10]) << 40) | |
| (((uint64_t)buf[11]) << 32) | |
| (((uint64_t)buf[12]) << 24) | |
| (((uint64_t)buf[13]) << 16) | |
| (((uint64_t)buf[14]) << 8) | |
| (((uint64_t)buf[15]) << 0); |
| return 1; |
| } |
| |
| void htrace_span_id_generate(struct htrace_span_id *id, struct random_src *rnd, |
| const struct htrace_span_id *parent) |
| { |
| if (parent) { |
| id->high = parent->high; |
| } else { |
| do { |
| id->high = random_u64(rnd); |
| } while (id->high == 0); |
| } |
| do { |
| id->low = random_u64(rnd); |
| } while (id->low == 0); |
| } |
| |
| void htrace_span_id_clear(struct htrace_span_id *id) |
| { |
| memset(id, 0, sizeof(*id)); |
| } |
| |
| int htrace_span_id_compare(const struct htrace_span_id *a, |
| const struct htrace_span_id *b) |
| { |
| if (a->high < b->high) { |
| return -1; |
| } else if (a->high > b->high) { |
| return 1; |
| } else if (a->low < b->low) { |
| return -1; |
| } else if (a->low > b->low) { |
| return 1; |
| } else { |
| return 0; |
| } |
| } |
| |
| // vim:ts=4:sw=4:et |