From 3a5713dad195a7cfa3f4866ad2c75f3a83d73a2f Mon Sep 17 00:00:00 2001 From: David Goulet Date: Wed, 13 Jun 2012 17:08:05 -0400 Subject: [PATCH] Add lttng URI support and default network ports This commit simply adds the lttng_uri API/ABI to the upstream branch. Three functions are provided by common/uri.h and are usable by linking with libcommon. The default network ports are also added for network streaming for both control and data stream. Signed-off-by: David Goulet --- include/lttng/lttng.h | 63 ++++++++++ src/common/Makefile.am | 4 +- src/common/defaults.h | 4 + src/common/uri.c | 265 +++++++++++++++++++++++++++++++++++++++++ src/common/uri.h | 27 +++++ 5 files changed, 361 insertions(+), 2 deletions(-) create mode 100644 src/common/uri.c create mode 100644 src/common/uri.h diff --git a/include/lttng/lttng.h b/include/lttng/lttng.h index c80e2827e..73f291466 100644 --- a/include/lttng/lttng.h +++ b/include/lttng/lttng.h @@ -23,6 +23,7 @@ #define _LTTNG_H #include +#include #include #include @@ -31,6 +32,12 @@ */ #define LTTNG_SYMBOL_NAME_LEN 256 +/* + * Maximum length of a domain name. This is the limit for the total length of a + * domain name specified by the RFC 1035 (https://www.ietf.org/rfc/rfc1035.txt) + */ +#define LTTNG_MAX_DNNAME 255 + /* * Every lttng_event_* structure both apply to kernel event and user-space * event. @@ -124,6 +131,62 @@ enum lttng_calibrate_type { LTTNG_CALIBRATE_FUNCTION = 0, }; +/* Destination type of lttng URI */ +enum lttng_dst_type { + LTTNG_DST_IPV4, /* IPv4 protocol */ + LTTNG_DST_IPV6, /* IPv6 protocol */ + LTTNG_DST_PATH, /* Local file system */ +}; + +/* Type of lttng URI where it is a final destination or a hop */ +enum lttng_uri_type { + LTTNG_URI_DST, /* The URI is a final destination */ + /* + * Hop are not supported yet but planned for a future release. + * + LTTNG_URI_HOP, + */ +}; + +/* Communication stream type of a lttng URI */ +enum lttng_stream_type { + LTTNG_STREAM_CONTROL, + LTTNG_STREAM_DATA, +}; + +/* + * Protocol type of a lttng URI. The value 0 indicate that the proto_type field + * should be ignored. + */ +enum lttng_proto_type { + LTTNG_TCP = 1, + /* + * UDP protocol is not supported for now. + * + LTTNG_UDP = 2, + */ +}; + +/* + * Structure representing an URI supported by lttng. + */ +#define LTTNG_URI_PADDING1_LEN 16 +#define LTTNG_URI_PADDING2_LEN LTTNG_SYMBOL_NAME_LEN + 32 +struct lttng_uri { + enum lttng_dst_type dtype; + enum lttng_uri_type utype; + enum lttng_stream_type stype; + enum lttng_proto_type proto; + in_port_t port; + char padding[LTTNG_URI_PADDING1_LEN]; + union { + char ipv4[INET_ADDRSTRLEN]; + char ipv6[INET6_ADDRSTRLEN]; + char path[PATH_MAX]; + char padding[LTTNG_URI_PADDING2_LEN]; + } dst; +}; + /* * The structures should be initialized to zero before use. */ diff --git a/src/common/Makefile.am b/src/common/Makefile.am index 460f2a2de..1cf707204 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -4,11 +4,11 @@ SUBDIRS = compat hashtable kernel-ctl sessiond-comm kernel-consumer ust-consumer AM_CFLAGS = -fno-strict-aliasing -noinst_HEADERS = lttng-kernel.h defaults.h macros.h error.h futex.h +noinst_HEADERS = lttng-kernel.h defaults.h macros.h error.h futex.h uri.h noinst_LTLIBRARIES = libcommon.la -libcommon_la_SOURCES = runas.c runas.h common.h futex.c futex.h +libcommon_la_SOURCES = runas.c runas.h common.h futex.c futex.h uri.c uri.h # Consumer library noinst_LTLIBRARIES += libconsumer.la diff --git a/src/common/defaults.h b/src/common/defaults.h index 5ee6562d9..53caf62ac 100644 --- a/src/common/defaults.h +++ b/src/common/defaults.h @@ -117,4 +117,8 @@ */ #define DEFAULT_SEM_WAIT_TIMEOUT 30 /* in seconds */ +/* Default network ports for trace streaming support */ +#define DEFAULT_NETWORK_CONTROL_PORT 5342 +#define DEFAULT_NETWORK_DATA_PORT 5343 + #endif /* _DEFAULTS_H */ diff --git a/src/common/uri.c b/src/common/uri.c new file mode 100644 index 000000000..3a58aedca --- /dev/null +++ b/src/common/uri.c @@ -0,0 +1,265 @@ +/* + * Copyright (C) 2012 - David Goulet + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License, version 2 only, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include + +#include +#include + +#include "uri.h" + +enum uri_proto_code { + P_NET, P_NET6, P_FILE, P_TCP, P_TCP6, +}; + +struct uri_proto { + char *name; + enum uri_proto_code code; + enum lttng_proto_type type; + enum lttng_dst_type dtype; +}; + +/* Supported protocols */ +static const struct uri_proto proto_uri[] = { + { .name = "file", .code = P_FILE, .type = 0, .dtype = LTTNG_DST_PATH}, + { .name = "net", .code = P_NET, .type = LTTNG_TCP, .dtype = LTTNG_DST_IPV4 }, + { .name = "net6", .code = P_NET6, .type = LTTNG_TCP, .dtype = LTTNG_DST_IPV6 }, + { .name = "tcp", .code = P_TCP, .type = LTTNG_TCP, .dtype = LTTNG_DST_IPV4 }, + { .name = "tcp6", .code = P_TCP6, .type = LTTNG_TCP, .dtype = LTTNG_DST_IPV6 }, + { .name = NULL } +}; + +/* + * Validate if proto is a supported protocol from proto_uri array. + */ +static const struct uri_proto *validate_protocol(char *proto) +{ + const struct uri_proto *supported; + + /* Safety net */ + if (proto == NULL) { + goto end; + } + + for (supported = &proto_uri[0]; + supported->name != NULL; ++supported) { + if (strncmp(proto, supported->name, strlen(proto)) == 0) { + goto end; + } + } + + /* Proto not found */ + return NULL; + +end: + return supported; +} + +/* + * Compare two URIs. + * + * Return 0 if equal else 1. + */ +int uri_compare(struct lttng_uri *uri1, struct lttng_uri *uri2) +{ + return memcmp(uri1, uri2, sizeof(struct lttng_uri)); +} + +/* + * Free URI memory. + */ +void uri_free(struct lttng_uri *uri) +{ + /* Safety check */ + if (uri != NULL) { + free(uri); + } +} + +/* + * Return an allocated URI. + */ +struct lttng_uri *uri_create(void) +{ + struct lttng_uri *uri; + + uri = zmalloc(sizeof(struct lttng_uri)); + if (uri == NULL) { + PERROR("zmalloc uri"); + } + + return uri; +} + +static int set_ip_address(const char *addr, int af, char *dst, size_t size) +{ + int ret; + unsigned char buf[sizeof(struct in6_addr)]; + struct hostent *record; + + /* Network protocol */ + ret = inet_pton(af, addr, buf); + if (ret < 1) { + /* We consider the dst to be an hostname or an invalid IP char */ + record = gethostbyname2(addr, af); + if (record == NULL) { + /* At this point, the IP or the hostname is bad */ + printf("bad hostname\n"); + goto error; + } + + /* Translate IP to string */ + (void) inet_ntop(af, record->h_addr_list[0], dst, size); + } else { + memcpy(dst, addr, size); + } + + return 0; + +error: + return -1; +} + +ssize_t uri_parse(const char *str_uri, struct lttng_uri **uris) +{ + int ret; + /* Size of the uris array. Default is 1 */ + ssize_t size = 1; + char net[6], dst[LTTNG_MAX_DNNAME + 1]; + unsigned int ctrl_port = DEFAULT_NETWORK_CONTROL_PORT; + unsigned int data_port = DEFAULT_NETWORK_DATA_PORT; + struct lttng_uri *uri; + const struct uri_proto *proto; + + /* + * The first part is the protocol portion of a maximum of 5 bytes for now. + * (tcp, tcp6, udp, udp6, file, net). The second part is the hostname or IP + * address. The 255 bytes size is the limit found in the RFC 1035 for the + * total length of a domain name (https://www.ietf.org/rfc/rfc1035.txt). + * Finally, with the net:// protocol, two ports can be specified. + */ + + ret = sscanf(str_uri, "%5[^:]://", net); + if (ret < 1) { + printf("bad protocol\n"); + goto error; + } + + DBG3("URI protocol : %s", str_uri); + + proto = validate_protocol(net); + if (proto == NULL) { + printf("no protocol\n"); + ret = -1; + goto error; + } + + if (proto->code == P_NET || proto->code == P_NET6) { + /* Special case for net:// which requires two URI object */ + size = 2; + } + + /* Parse the rest of the URI */ + ret = sscanf(str_uri + strlen(net), "://%255[^:]:%u:%u", dst, + &ctrl_port, &data_port); + if (ret < 0) { + printf("bad URI\n"); + goto error; + } + + /* We have enough valid information to create URI(s) object */ + + /* Allocate URI array */ + uri = zmalloc(sizeof(struct lttng_uri) * size); + if (uri == NULL) { + PERROR("zmalloc uri"); + goto error; + } + + /* Copy generic information */ + uri[0].dtype = proto->dtype; + uri[0].proto = proto->type; + uri[0].port = ctrl_port; + + DBG3("URI dtype: %d, proto: %d, port: %d", proto->dtype, proto->type, + ctrl_port); + + switch (proto->code) { + case P_FILE: + memcpy(uri[0].dst.path, dst, sizeof(uri[0].dst.path)); + /* Reset port for the file:// URI */ + uri[0].port = 0; + DBG3("URI file destination: %s", dst); + break; + case P_NET: + ret = set_ip_address(dst, AF_INET, uri[0].dst.ipv4, + sizeof(uri[0].dst.ipv4)); + if (ret < 0) { + goto free_error; + } + + memcpy(uri[1].dst.ipv4, uri[0].dst.ipv4, sizeof(uri[1].dst.ipv4)); + + uri[1].dtype = proto->dtype; + uri[1].proto = proto->type; + uri[1].port = data_port; + break; + case P_NET6: + ret = set_ip_address(dst, AF_INET6, uri[0].dst.ipv6, + sizeof(uri[0].dst.ipv6)); + if (ret < 0) { + goto free_error; + } + + memcpy(uri[1].dst.ipv6, uri[0].dst.ipv6, sizeof(uri[1].dst.ipv6)); + + uri[1].dtype = proto->dtype; + uri[1].proto = proto->type; + uri[1].port = data_port; + break; + case P_TCP: + ret = set_ip_address(dst, AF_INET, uri[0].dst.ipv4, + sizeof(uri[0].dst.ipv4)); + if (ret < 0) { + goto free_error; + } + break; + case P_TCP6: + ret = set_ip_address(dst, AF_INET6, uri[0].dst.ipv6, + sizeof(uri[0].dst.ipv6)); + if (ret < 0) { + goto free_error; + } + break; + default: + goto free_error; + } + + *uris = uri; + + return size; + +free_error: + free(uri); +error: + return -1; +} diff --git a/src/common/uri.h b/src/common/uri.h new file mode 100644 index 000000000..959b9a66c --- /dev/null +++ b/src/common/uri.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2012 - David Goulet + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License, version 2 only, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef _LTT_URI_H +#define _LTT_URI_H + +#include + +int uri_compare(struct lttng_uri *uri1, struct lttng_uri *uri2); +void uri_free(struct lttng_uri *uri); +ssize_t uri_parse(const char *str_uri, struct lttng_uri **uris); + +#endif /* _LTT_URI_H */ -- 2.34.1