2 * Copyright (C) 2012 - David Goulet <dgoulet@efficios.com>
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License, version 2 only, as
6 * published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * You should have received a copy of the GNU General Public License along with
14 * this program; if not, write to the Free Software Foundation, Inc., 51
15 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 #include <arpa/inet.h>
23 #include <sys/socket.h>
25 #include <common/common.h>
26 #include <common/defaults.h>
31 P_NET
, P_NET6
, P_FILE
, P_TCP
, P_TCP6
,
36 enum uri_proto_code code
;
37 enum lttng_proto_type type
;
38 enum lttng_dst_type dtype
;
41 /* Supported protocols */
42 static const struct uri_proto proto_uri
[] = {
43 { .name
= "file", .code
= P_FILE
, .type
= 0, .dtype
= LTTNG_DST_PATH
},
44 { .name
= "net", .code
= P_NET
, .type
= LTTNG_TCP
, .dtype
= LTTNG_DST_IPV4
},
45 { .name
= "net6", .code
= P_NET6
, .type
= LTTNG_TCP
, .dtype
= LTTNG_DST_IPV6
},
46 { .name
= "tcp", .code
= P_TCP
, .type
= LTTNG_TCP
, .dtype
= LTTNG_DST_IPV4
},
47 { .name
= "tcp6", .code
= P_TCP6
, .type
= LTTNG_TCP
, .dtype
= LTTNG_DST_IPV6
},
52 * Validate if proto is a supported protocol from proto_uri array.
54 static const struct uri_proto
*validate_protocol(char *proto
)
56 const struct uri_proto
*supported
;
63 for (supported
= &proto_uri
[0];
64 supported
->name
!= NULL
; ++supported
) {
65 if (strncmp(proto
, supported
->name
, strlen(proto
)) == 0) {
78 * Set network address from string into dst. Supports both IP string and
81 static int set_ip_address(const char *addr
, int af
, char *dst
, size_t size
)
84 unsigned char buf
[sizeof(struct in6_addr
)];
85 struct hostent
*record
;
87 /* Network protocol */
88 ret
= inet_pton(af
, addr
, buf
);
90 /* We consider the dst to be an hostname or an invalid IP char */
91 record
= gethostbyname2(addr
, af
);
93 /* At this point, the IP or the hostname is bad */
94 ERR("URI parse bad hostname %s for af %d", addr
, af
);
98 /* Translate IP to string */
99 (void) inet_ntop(af
, record
->h_addr_list
[0], dst
, size
);
101 memcpy(dst
, addr
, size
);
113 * Return 0 if equal else 1.
115 int uri_compare(struct lttng_uri
*uri1
, struct lttng_uri
*uri2
)
117 return memcmp(uri1
, uri2
, sizeof(struct lttng_uri
));
123 void uri_free(struct lttng_uri
*uri
)
132 * Return an allocated URI.
134 struct lttng_uri
*uri_create(void)
136 struct lttng_uri
*uri
;
138 uri
= zmalloc(sizeof(struct lttng_uri
));
140 PERROR("zmalloc uri");
147 * Parses a string URI to a lttng_uri. This function can potentially return
148 * more than one URI in uris so the size of the array is returned and uris is
149 * allocated and populated. Caller must free(3) the array.
151 * This function can not detect the stream type of the URI so the caller has to
152 * make sure the correct type (stype) is set on the return URI(s). The default
153 * port must also be set by the caller if the returned URI has its port set to
156 ssize_t
uri_parse(const char *str_uri
, struct lttng_uri
**uris
)
159 size_t str_offset
= 0;
160 /* Size of the uris array. Default is 1 */
162 char net
[6], dst
[LTTNG_MAX_DNNAME
+ 1], subdir
[PATH_MAX
];
163 unsigned int ctrl_port
= 0;
164 unsigned int data_port
= 0;
165 struct lttng_uri
*uri
;
166 const struct uri_proto
*proto
;
169 * The first part is the protocol portion of a maximum of 5 bytes for now.
170 * The second part is the hostname or IP address. The 255 bytes size is the
171 * limit found in the RFC 1035 for the total length of a domain name
172 * (https://www.ietf.org/rfc/rfc1035.txt). Finally, for the net://
173 * protocol, two ports CAN be specified.
176 ret
= sscanf(str_uri
, "%5[^:]://", net
);
178 ERR("URI parse bad protocol %s", str_uri
);
182 DBG3("URI string: %s", str_uri
);
184 proto
= validate_protocol(net
);
186 ERR("URI parse unknown protocol %s", net
);
191 if (proto
->code
== P_NET
|| proto
->code
== P_NET6
) {
192 /* Special case for net:// which requires two URI object */
196 memset(subdir
, 0, sizeof(subdir
));
197 str_offset
+= strlen(net
);
199 /* Parse the rest of the URI */
200 if (sscanf(str_uri
+ str_offset
, "://%255[^:]:%u:%u/%s", dst
, &ctrl_port
,
201 &data_port
, subdir
) == 4) {
203 } else if (sscanf(str_uri
+ str_offset
, "://%255[^:]:%u:%u", dst
,
204 &ctrl_port
, &data_port
) == 3) {
205 } else if (sscanf(str_uri
+ str_offset
, "://%255[^:]:%u/%s", dst
,
206 &ctrl_port
, subdir
) == 3) {
207 } else if (sscanf(str_uri
+ str_offset
, "://%255[^:]:%u", dst
,
209 } else if (sscanf(str_uri
+ str_offset
, "://%255[^/]/%s", dst
,
212 ret
= sscanf(str_uri
+ str_offset
, "://%255[^:]", dst
);
219 /* We have enough valid information to create URI(s) object */
221 /* Allocate URI array */
222 uri
= zmalloc(sizeof(struct lttng_uri
) * size
);
224 PERROR("zmalloc uri");
228 /* Copy generic information */
229 uri
[0].dtype
= proto
->dtype
;
230 uri
[0].proto
= proto
->type
;
231 uri
[0].port
= ctrl_port
;
232 strncpy(uri
[0].subdir
, subdir
, sizeof(uri
[0].subdir
));
234 DBG3("URI dtype: %d, proto: %d, host: %s, subdir: %s, ctrl: %d, data: %d",
235 proto
->dtype
, proto
->type
, dst
, subdir
, ctrl_port
, data_port
);
237 switch (proto
->code
) {
239 memcpy(uri
[0].dst
.path
, dst
, sizeof(uri
[0].dst
.path
));
240 /* Reset port for the file:// URI */
242 DBG3("URI file destination: %s", dst
);
245 ret
= set_ip_address(dst
, AF_INET
, uri
[0].dst
.ipv4
,
246 sizeof(uri
[0].dst
.ipv4
));
251 memcpy(uri
[1].dst
.ipv4
, uri
[0].dst
.ipv4
, sizeof(uri
[1].dst
.ipv4
));
253 uri
[1].dtype
= proto
->dtype
;
254 uri
[1].proto
= proto
->type
;
255 uri
[1].port
= data_port
;
258 ret
= set_ip_address(dst
, AF_INET6
, uri
[0].dst
.ipv6
,
259 sizeof(uri
[0].dst
.ipv6
));
264 memcpy(uri
[1].dst
.ipv6
, uri
[0].dst
.ipv6
, sizeof(uri
[1].dst
.ipv6
));
266 uri
[1].dtype
= proto
->dtype
;
267 uri
[1].proto
= proto
->type
;
268 uri
[1].port
= data_port
;
271 ret
= set_ip_address(dst
, AF_INET
, uri
[0].dst
.ipv4
,
272 sizeof(uri
[0].dst
.ipv4
));
278 ret
= set_ip_address(dst
, AF_INET6
, uri
[0].dst
.ipv6
,
279 sizeof(uri
[0].dst
.ipv6
));
This page took 0.040562 seconds and 4 git commands to generate.