X-Git-Url: http://git.efficios.com/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fcommon%2Furi.c;h=4af94072cb6100ab99e70228087022a20840e560;hp=740a6d5c50fc6d7fad8e027bb024d9ff9527f8c5;hb=07b86b528dc279d59cdf16e6cb946c144fe773f2;hpb=90e535ef0d0433d31e805775f85e4d187b1cf82c diff --git a/src/common/uri.c b/src/common/uri.c index 740a6d5c5..4af94072c 100644 --- a/src/common/uri.c +++ b/src/common/uri.c @@ -137,6 +137,47 @@ error: 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. */ @@ -145,7 +186,7 @@ int uri_to_str_url(struct lttng_uri *uri, char *dst, size_t size) { int ipver, ret; const char *addr; - char proto[4], port[7]; + char proto[5], port[7]; assert(uri); assert(dst); @@ -153,13 +194,13 @@ int uri_to_str_url(struct lttng_uri *uri, char *dst, size_t size) if (uri->dtype == LTTNG_DST_PATH) { ipver = 0; addr = uri->dst.path; - (void) snprintf(proto, sizeof(proto), "file"); - (void) snprintf(port, sizeof(port), "%s", ""); + (void) snprintf(proto, sizeof(proto) + 1, "file"); + (void) snprintf(port, sizeof(port) + 1, "%s", ""); } else { ipver = (uri->dtype == LTTNG_DST_IPV4) ? 4 : 6; addr = (ipver == 4) ? uri->dst.ipv4 : uri->dst.ipv6; - (void) snprintf(proto, sizeof(proto), "net%d", ipver); - (void) snprintf(port, sizeof(port), ":%d", uri->port); + (void) snprintf(proto, sizeof(proto) + 1, "net%d", ipver); + (void) snprintf(port, sizeof(port) + 1, ":%d", uri->port); } ret = snprintf(dst, size, "%s://%s%s%s%s/%s", proto, @@ -474,3 +515,134 @@ free_error: error: return -1; } + +/* + * Parse a string URL and creates URI(s) returning the size of the populated + * array. + */ +LTTNG_HIDDEN +ssize_t uri_parse_str_urls(const char *ctrl_url, const char *data_url, + struct lttng_uri **uris) +{ + unsigned int equal = 1, idx = 0; + /* Add the "file://" size to the URL maximum size */ + char url[PATH_MAX + 7]; + ssize_t size_ctrl = 0, size_data = 0, size; + struct lttng_uri *ctrl_uris = NULL, *data_uris = NULL; + struct lttng_uri *tmp_uris = NULL; + + /* No URL(s) is allowed. This means that the consumer will be disabled. */ + if (ctrl_url == NULL && data_url == NULL) { + return 0; + } + + /* Check if URLs are equal and if so, only use the control URL */ + if ((ctrl_url && *ctrl_url != '\0') && (data_url && *data_url != '\0')) { + equal = !strcmp(ctrl_url, data_url); + } + + /* + * Since we allow the str_url to be a full local filesystem path, we are + * going to create a valid file:// URL if it's the case. + * + * Check if first character is a '/' or else reject the URL. + */ + if (ctrl_url && ctrl_url[0] == '/') { + int ret; + + ret = snprintf(url, sizeof(url), "file://%s", ctrl_url); + if (ret < 0) { + PERROR("snprintf file url"); + goto parse_error; + } + ctrl_url = url; + } + + /* Parse the control URL if there is one */ + if (ctrl_url && *ctrl_url != '\0') { + size_ctrl = uri_parse(ctrl_url, &ctrl_uris); + if (size_ctrl < 1) { + ERR("Unable to parse the URL %s", ctrl_url); + goto parse_error; + } + + /* At this point, we know there is at least one URI in the array */ + set_default_uri_attr(&ctrl_uris[0], LTTNG_STREAM_CONTROL); + + if (ctrl_uris[0].dtype == LTTNG_DST_PATH && + (data_url && *data_url != '\0')) { + ERR("Can not have a data URL when destination is file://"); + goto error; + } + + /* URL are not equal but the control URL uses a net:// protocol */ + if (size_ctrl == 2) { + if (!equal) { + ERR("Control URL uses the net:// protocol and the data URL is " + "different. Not allowed."); + goto error; + } else { + set_default_uri_attr(&ctrl_uris[1], LTTNG_STREAM_DATA); + /* + * The data_url and ctrl_url are equal and the ctrl_url + * contains a net:// protocol so we just skip the data part. + */ + data_url = NULL; + } + } + } + + if (data_url && *data_url != '\0') { + int ret; + + /* We have to parse the data URL in this case */ + size_data = uri_parse(data_url, &data_uris); + if (size_data < 1) { + ERR("Unable to parse the URL %s", data_url); + goto error; + } else if (size_data == 2) { + ERR("Data URL can not be set with the net[4|6]:// protocol"); + goto error; + } + + set_default_uri_attr(&data_uris[0], LTTNG_STREAM_DATA); + + ret = compare_destination(&ctrl_uris[0], &data_uris[0]); + if (ret != 0) { + ERR("Control and data destination mismatch"); + goto error; + } + } + + /* Compute total size */ + size = size_ctrl + size_data; + + tmp_uris = zmalloc(sizeof(struct lttng_uri) * size); + if (tmp_uris == NULL) { + PERROR("zmalloc uris"); + goto error; + } + + if (ctrl_uris) { + /* It's possible the control URIs array contains more than one URI */ + memcpy(tmp_uris, ctrl_uris, sizeof(struct lttng_uri) * size_ctrl); + ++idx; + free(ctrl_uris); + } + + if (data_uris) { + memcpy(&tmp_uris[idx], data_uris, sizeof(struct lttng_uri)); + free(data_uris); + } + + *uris = tmp_uris; + + return size; + +error: + free(ctrl_uris); + free(data_uris); + free(tmp_uris); +parse_error: + return -1; +}