/src/dbus-broker/src/dbus/address.c
Line | Count | Source |
1 | | /* |
2 | | * D-Bus Peer Addresses |
3 | | * |
4 | | * The D-Bus message broker requires peers to always address the destination of |
5 | | * their messages. Those addresses can come in different styles. The 'Address' |
6 | | * type implemented here parses or writes such addresses, hiding the details |
7 | | * behind a simple API. |
8 | | * |
9 | | * The 'Address' type is supposed to live on the stack. It can be initialized |
10 | | * either from one of the source addresses (a unique ID, a well-known name, ..) |
11 | | * or it can parse a user-supplied string. |
12 | | * The structure is open-coded and can be accesses directly. It consists of a |
13 | | * 'type' field that identifies the address type, and a union carrying the |
14 | | * parsed data. |
15 | | */ |
16 | | |
17 | | #include <c-stdaux.h> |
18 | | #include <stdlib.h> |
19 | | #include "dbus/address.h" |
20 | | |
21 | | /** |
22 | | * address_init_from_id() - initialize ID address |
23 | | * @address: address to operate on |
24 | | * @id: ID to use |
25 | | * |
26 | | * This initializes the address @address to be of type ADDRESS_TYPE_ID with ID |
27 | | * @id. |
28 | | */ |
29 | 0 | void address_init_from_id(Address *address, uint64_t id) { |
30 | 0 | *address = (Address)ADDRESS_INIT_ID(id); |
31 | 0 | } |
32 | | |
33 | | /** |
34 | | * address_init_from_name() - initialize name address |
35 | | * @address: address to operate on |
36 | | * @name: name to use |
37 | | * |
38 | | * This initializes the address @address to be of type ADDRESS_TYPE_NAME with |
39 | | * name @name. |
40 | | * |
41 | | * Note that @name is *NOT* copied into @address. That is, the lifetime of |
42 | | * @address is bound to @name. |
43 | | */ |
44 | 0 | void address_init_from_name(Address *address, const char *name) { |
45 | 0 | *address = (Address)ADDRESS_INIT_NAME(name); |
46 | 0 | } |
47 | | |
48 | | /** |
49 | | * address_from_string() - initialize address from string representation |
50 | | * @address: address to operate on |
51 | | * @string: string to use |
52 | | * |
53 | | * This initializes @address from the string representation of an address, |
54 | | * given as @string. On return, @address->type will contain the type of the |
55 | | * address that was given as @string. Note that this might be |
56 | | * ADDRESS_TYPE_OTHER, in case the parser couldn't detect the address type. |
57 | | * |
58 | | * Note that @string is *NOT* copied into @address, but might be referenced |
59 | | * from it. Hence, the lifetime of @address is bound to @string. |
60 | | * |
61 | | * This function does not fully validate the address! All it does is to detect |
62 | | * the type of address, but the address might still be invalid. In other words, |
63 | | * this function correctly assigns a type to all valid addresses. However, in |
64 | | * case of invalid addresses, it might give false positives. That is, for the |
65 | | * sake of distinguishing addresses, this is sufficient. However, for the sake |
66 | | * of data validation when creating/acquiring names, you need to further verify |
67 | | * the validity of the name. |
68 | | */ |
69 | 0 | void address_from_string(Address *address, const char *string) { |
70 | 0 | uint64_t id; |
71 | 0 | char *end; |
72 | |
|
73 | 0 | address->type = ADDRESS_TYPE_OTHER; |
74 | |
|
75 | 0 | if (!string[0]) { |
76 | 0 | return; |
77 | 0 | } else if (string[0] == ':') { |
78 | 0 | if (strncmp(string, ":1.", strlen(":1."))) |
79 | 0 | return; |
80 | | |
81 | 0 | string += strlen(":1."); |
82 | 0 | errno = 0; |
83 | 0 | id = strtoull(string, &end, 10); |
84 | 0 | if (end == string || *end || errno || id == ULLONG_MAX) |
85 | 0 | return; |
86 | | |
87 | 0 | address->type = ADDRESS_TYPE_ID; |
88 | 0 | address->id = id; |
89 | 0 | } else { |
90 | 0 | address->type = ADDRESS_TYPE_NAME; |
91 | 0 | address->name = string; |
92 | 0 | } |
93 | 0 | } |
94 | | |
95 | | /** |
96 | | * address_to_string() - return string representation of an address |
97 | | * @address: address to operate on |
98 | | * |
99 | | * This returns a pointer to the string representation of @address. Note that |
100 | | * the caller must make sure @address is a valid address. If @address is of |
101 | | * type ADDRESS_TYPE_OTHER, this will raise a fatal exception. |
102 | | * |
103 | | * Note that the address buffer is bound to @address. That is, whenever |
104 | | * @address is modified, the returned pointer will become invalid. |
105 | | * |
106 | | * Return: Pointer to string representation of @address. |
107 | | */ |
108 | 362 | const char *address_to_string(Address *address) { |
109 | 362 | int r; |
110 | | |
111 | 362 | switch (address->type) { |
112 | 362 | case ADDRESS_TYPE_ID: |
113 | 362 | r = snprintf(address->buffer, sizeof(address->buffer), ":1.%"PRIu64, address->id); |
114 | 362 | c_assert(r >= 0 && r < (ssize_t)sizeof(address->buffer)); |
115 | 362 | return address->buffer; |
116 | 0 | case ADDRESS_TYPE_NAME: |
117 | 0 | return address->name; |
118 | 0 | default: |
119 | 0 | c_assert(0); |
120 | 0 | return ":<garbage>"; |
121 | 362 | } |
122 | 362 | } |
123 | | |
124 | | /** |
125 | | * address_write() - write string representation of an address |
126 | | * @address: address to operate on |
127 | | * @buffer: buffer to write into |
128 | | * @n_buffer: size of @buffer |
129 | | * |
130 | | * This is similar to address_to_string(), but rather than returning a pointer |
131 | | * to an internal buffer, it writes the address to a caller-supplied buffer. |
132 | | * |
133 | | * Note that the caller must provide a suitably sized buffer. If the buffer is |
134 | | * not big enough to hold the string representation, this will raise a fatal |
135 | | * exception. |
136 | | */ |
137 | 0 | void address_write(Address *address, char *buffer, size_t n_buffer) { |
138 | 0 | int r; |
139 | |
|
140 | 0 | switch (address->type) { |
141 | 0 | case ADDRESS_TYPE_ID: |
142 | 0 | r = snprintf(buffer, n_buffer, ":1.%"PRIu64, address->id); |
143 | 0 | c_assert(r >= 0 && r < (ssize_t)n_buffer); |
144 | 0 | break; |
145 | 0 | case ADDRESS_TYPE_NAME: |
146 | 0 | c_assert(n_buffer > strlen(address->name)); |
147 | 0 | strcpy(buffer, address->name); |
148 | 0 | break; |
149 | 0 | default: |
150 | 0 | c_assert(0); |
151 | 0 | strcpy(buffer, ":<garbage>"); |
152 | 0 | break; |
153 | 0 | } |
154 | 0 | } |