Add lttng URI support and default network ports
[lttng-tools.git] / src / common / uri.c
CommitLineData
3a5713da
DG
1/*
2 * Copyright (C) 2012 - David Goulet <dgoulet@efficios.com>
3 *
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.
7 *
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
11 * more details.
12 *
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.
16 */
17
18#define _GNU_SOURCE
19#include <arpa/inet.h>
20#include <netdb.h>
21#include <stdlib.h>
22#include <string.h>
23#include <sys/socket.h>
24
25#include <common/common.h>
26#include <common/defaults.h>
27
28#include "uri.h"
29
30enum uri_proto_code {
31 P_NET, P_NET6, P_FILE, P_TCP, P_TCP6,
32};
33
34struct uri_proto {
35 char *name;
36 enum uri_proto_code code;
37 enum lttng_proto_type type;
38 enum lttng_dst_type dtype;
39};
40
41/* Supported protocols */
42static 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 },
48 { .name = NULL }
49};
50
51/*
52 * Validate if proto is a supported protocol from proto_uri array.
53 */
54static const struct uri_proto *validate_protocol(char *proto)
55{
56 const struct uri_proto *supported;
57
58 /* Safety net */
59 if (proto == NULL) {
60 goto end;
61 }
62
63 for (supported = &proto_uri[0];
64 supported->name != NULL; ++supported) {
65 if (strncmp(proto, supported->name, strlen(proto)) == 0) {
66 goto end;
67 }
68 }
69
70 /* Proto not found */
71 return NULL;
72
73end:
74 return supported;
75}
76
77/*
78 * Compare two URIs.
79 *
80 * Return 0 if equal else 1.
81 */
82int uri_compare(struct lttng_uri *uri1, struct lttng_uri *uri2)
83{
84 return memcmp(uri1, uri2, sizeof(struct lttng_uri));
85}
86
87/*
88 * Free URI memory.
89 */
90void uri_free(struct lttng_uri *uri)
91{
92 /* Safety check */
93 if (uri != NULL) {
94 free(uri);
95 }
96}
97
98/*
99 * Return an allocated URI.
100 */
101struct lttng_uri *uri_create(void)
102{
103 struct lttng_uri *uri;
104
105 uri = zmalloc(sizeof(struct lttng_uri));
106 if (uri == NULL) {
107 PERROR("zmalloc uri");
108 }
109
110 return uri;
111}
112
113static int set_ip_address(const char *addr, int af, char *dst, size_t size)
114{
115 int ret;
116 unsigned char buf[sizeof(struct in6_addr)];
117 struct hostent *record;
118
119 /* Network protocol */
120 ret = inet_pton(af, addr, buf);
121 if (ret < 1) {
122 /* We consider the dst to be an hostname or an invalid IP char */
123 record = gethostbyname2(addr, af);
124 if (record == NULL) {
125 /* At this point, the IP or the hostname is bad */
126 printf("bad hostname\n");
127 goto error;
128 }
129
130 /* Translate IP to string */
131 (void) inet_ntop(af, record->h_addr_list[0], dst, size);
132 } else {
133 memcpy(dst, addr, size);
134 }
135
136 return 0;
137
138error:
139 return -1;
140}
141
142ssize_t uri_parse(const char *str_uri, struct lttng_uri **uris)
143{
144 int ret;
145 /* Size of the uris array. Default is 1 */
146 ssize_t size = 1;
147 char net[6], dst[LTTNG_MAX_DNNAME + 1];
148 unsigned int ctrl_port = DEFAULT_NETWORK_CONTROL_PORT;
149 unsigned int data_port = DEFAULT_NETWORK_DATA_PORT;
150 struct lttng_uri *uri;
151 const struct uri_proto *proto;
152
153 /*
154 * The first part is the protocol portion of a maximum of 5 bytes for now.
155 * (tcp, tcp6, udp, udp6, file, net). The second part is the hostname or IP
156 * address. The 255 bytes size is the limit found in the RFC 1035 for the
157 * total length of a domain name (https://www.ietf.org/rfc/rfc1035.txt).
158 * Finally, with the net:// protocol, two ports can be specified.
159 */
160
161 ret = sscanf(str_uri, "%5[^:]://", net);
162 if (ret < 1) {
163 printf("bad protocol\n");
164 goto error;
165 }
166
167 DBG3("URI protocol : %s", str_uri);
168
169 proto = validate_protocol(net);
170 if (proto == NULL) {
171 printf("no protocol\n");
172 ret = -1;
173 goto error;
174 }
175
176 if (proto->code == P_NET || proto->code == P_NET6) {
177 /* Special case for net:// which requires two URI object */
178 size = 2;
179 }
180
181 /* Parse the rest of the URI */
182 ret = sscanf(str_uri + strlen(net), "://%255[^:]:%u:%u", dst,
183 &ctrl_port, &data_port);
184 if (ret < 0) {
185 printf("bad URI\n");
186 goto error;
187 }
188
189 /* We have enough valid information to create URI(s) object */
190
191 /* Allocate URI array */
192 uri = zmalloc(sizeof(struct lttng_uri) * size);
193 if (uri == NULL) {
194 PERROR("zmalloc uri");
195 goto error;
196 }
197
198 /* Copy generic information */
199 uri[0].dtype = proto->dtype;
200 uri[0].proto = proto->type;
201 uri[0].port = ctrl_port;
202
203 DBG3("URI dtype: %d, proto: %d, port: %d", proto->dtype, proto->type,
204 ctrl_port);
205
206 switch (proto->code) {
207 case P_FILE:
208 memcpy(uri[0].dst.path, dst, sizeof(uri[0].dst.path));
209 /* Reset port for the file:// URI */
210 uri[0].port = 0;
211 DBG3("URI file destination: %s", dst);
212 break;
213 case P_NET:
214 ret = set_ip_address(dst, AF_INET, uri[0].dst.ipv4,
215 sizeof(uri[0].dst.ipv4));
216 if (ret < 0) {
217 goto free_error;
218 }
219
220 memcpy(uri[1].dst.ipv4, uri[0].dst.ipv4, sizeof(uri[1].dst.ipv4));
221
222 uri[1].dtype = proto->dtype;
223 uri[1].proto = proto->type;
224 uri[1].port = data_port;
225 break;
226 case P_NET6:
227 ret = set_ip_address(dst, AF_INET6, uri[0].dst.ipv6,
228 sizeof(uri[0].dst.ipv6));
229 if (ret < 0) {
230 goto free_error;
231 }
232
233 memcpy(uri[1].dst.ipv6, uri[0].dst.ipv6, sizeof(uri[1].dst.ipv6));
234
235 uri[1].dtype = proto->dtype;
236 uri[1].proto = proto->type;
237 uri[1].port = data_port;
238 break;
239 case P_TCP:
240 ret = set_ip_address(dst, AF_INET, uri[0].dst.ipv4,
241 sizeof(uri[0].dst.ipv4));
242 if (ret < 0) {
243 goto free_error;
244 }
245 break;
246 case P_TCP6:
247 ret = set_ip_address(dst, AF_INET6, uri[0].dst.ipv6,
248 sizeof(uri[0].dst.ipv6));
249 if (ret < 0) {
250 goto free_error;
251 }
252 break;
253 default:
254 goto free_error;
255 }
256
257 *uris = uri;
258
259 return size;
260
261free_error:
262 free(uri);
263error:
264 return -1;
265}
This page took 0.047981 seconds and 4 git commands to generate.