+/*
+ * Set network address from string into dst. Supports both IP string and
+ * hostname.
+ */
+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;
+
+ assert(addr);
+ assert(dst);
+
+ memset(dst, 0, size);
+
+ /* 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 = lttng_gethostbyname2(addr, af);
+ if (record) {
+ /* Translate IP to string */
+ if (!inet_ntop(af, record->h_addr_list[0], dst, size)) {
+ PERROR("inet_ntop");
+ goto error;
+ }
+ } else if (!strcmp(addr, "localhost") &&
+ (af == AF_INET || af == AF_INET6)) {
+ /*
+ * Some systems may not have "localhost" defined in
+ * accordance with IETF RFC 6761. According to this RFC,
+ * applications may recognize "localhost" names as
+ * special and resolve to the appropriate loopback
+ * address.
+ *
+ * We choose to use the system name resolution API first
+ * to honor its network configuration. If this fails, we
+ * resolve to the appropriate loopback address. This is
+ * done to accomodate systems which may want to start
+ * tracing before their network configured.
+ */
+ const char *loopback_addr = af == AF_INET ?
+ LOOPBACK_ADDR_IPV4 : LOOPBACK_ADDR_IPV6;
+ const size_t loopback_addr_len = af == AF_INET ?
+ sizeof(LOOPBACK_ADDR_IPV4) :
+ sizeof(LOOPBACK_ADDR_IPV6);
+
+ DBG2("Could not resolve localhost address, using fallback");
+ if (loopback_addr_len > size) {
+ ERR("Could not resolve localhost address; destination string is too short");
+ goto error;
+ }
+ strcpy(dst, loopback_addr);
+ } else {
+ /* At this point, the IP or the hostname is bad */
+ goto error;
+ }
+ } else {
+ if (size > 0) {
+ strncpy(dst, addr, size);
+ dst[size - 1] = '\0';
+ }
+ }
+
+ DBG2("IP address resolved to %s", dst);
+ return 0;
+
+error:
+ ERR("URI parse bad hostname %s for af %d", addr, af);
+ return -1;
+}
+
+/*
+ * Set default URI attribute which is basically the given stream type and the
+ * default port if none is set in the URI.
+ */
+static void set_default_uri_attr(struct lttng_uri *uri,
+ enum lttng_stream_type stype)
+{
+ uri->stype = stype;
+ if (uri->dtype != LTTNG_DST_PATH && uri->port == 0) {
+ uri->port = (stype == LTTNG_STREAM_CONTROL) ?
+ DEFAULT_NETWORK_CONTROL_PORT : DEFAULT_NETWORK_DATA_PORT;
+ }
+}
+
+/*
+ * Compare two URL destination.
+ *
+ * Return 0 is equal else is not equal.
+ */
+static int compare_destination(struct lttng_uri *ctrl, struct lttng_uri *data)
+{
+ int ret;
+
+ assert(ctrl);
+ assert(data);
+
+ switch (ctrl->dtype) {
+ case LTTNG_DST_IPV4:
+ ret = strncmp(ctrl->dst.ipv4, data->dst.ipv4, sizeof(ctrl->dst.ipv4));
+ break;
+ case LTTNG_DST_IPV6:
+ ret = strncmp(ctrl->dst.ipv6, data->dst.ipv6, sizeof(ctrl->dst.ipv6));
+ break;
+ default:
+ ret = -1;
+ break;
+ }
+
+ return ret;
+}
+
+/*
+ * Build a string URL from a lttng_uri object.
+ */
+LTTNG_HIDDEN
+int uri_to_str_url(struct lttng_uri *uri, char *dst, size_t size)
+{
+ int ipver, ret;
+ const char *addr;
+ char proto[5], port[7];
+
+ assert(uri);
+ assert(dst);
+
+ if (uri->dtype == LTTNG_DST_PATH) {
+ ipver = 0;
+ addr = uri->dst.path;
+ (void) snprintf(proto, sizeof(proto), "file");
+ (void) snprintf(port, sizeof(port), "%s", "");
+ } else {
+ ipver = (uri->dtype == LTTNG_DST_IPV4) ? 4 : 6;
+ addr = (ipver == 4) ? uri->dst.ipv4 : uri->dst.ipv6;
+ (void) snprintf(proto, sizeof(proto), "tcp%d", ipver);
+ (void) snprintf(port, sizeof(port), ":%d", uri->port);
+ }
+
+ ret = snprintf(dst, size, "%s://%s%s%s%s/%s", proto,
+ (ipver == 6) ? "[" : "", addr, (ipver == 6) ? "]" : "",
+ port, uri->subdir);
+ if (ret < 0) {
+ PERROR("snprintf uri to url");
+ }
+
+ return ret;
+}
+