Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-3.0-or-later
2 : : // SPDX-FileCopyrightText: Andy Holmes <andrew.g.r.holmes@gmail.com>
3 : :
4 : : #define G_LOG_DOMAIN "valent-lan-channel"
5 : :
6 : : #include "config.h"
7 : :
8 : : #include <gio/gio.h>
9 : : #include <gio/gnetworking.h>
10 : : #include <json-glib/json-glib.h>
11 : : #include <valent.h>
12 : :
13 : : #include "valent-lan-channel.h"
14 : : #include "valent-lan-utils.h"
15 : :
16 : :
17 : : struct _ValentLanChannel
18 : : {
19 : : ValentChannel parent_instance;
20 : :
21 : : char *host;
22 : : uint16_t port;
23 : : };
24 : :
25 [ + + + - ]: 13 : G_DEFINE_FINAL_TYPE (ValentLanChannel, valent_lan_channel, VALENT_TYPE_CHANNEL)
26 : :
27 : : typedef enum {
28 : : PROP_HOST = 1,
29 : : PROP_PORT,
30 : : } ValentLanChannelProperty;
31 : :
32 : : static GParamSpec *properties[PROP_PORT + 1] = { NULL, };
33 : :
34 : :
35 : : /*
36 : : * ValentChannel
37 : : */
38 : : static GIOStream *
39 : 1 : valent_lan_channel_download (ValentChannel *channel,
40 : : JsonNode *packet,
41 : : GCancellable *cancellable,
42 : : GError **error)
43 : : {
44 : 1 : ValentLanChannel *self = VALENT_LAN_CHANNEL (channel);
45 : 1 : JsonObject *info;
46 : 1 : int64_t port;
47 : 1 : goffset size;
48 : 2 : g_autoptr (GSocketClient) client = NULL;
49 [ + - ]: 1 : g_autoptr (GSocketConnection) connection = NULL;
50 : 1 : GTlsCertificate *certificate = NULL;
51 : 1 : GTlsCertificate *peer_certificate = NULL;
52 [ + - ]: 1 : g_autofree char *host = NULL;
53 : 1 : g_autoptr (GIOStream) tls_stream = NULL;
54 : :
55 [ + - ]: 1 : g_assert (VALENT_IS_CHANNEL (channel));
56 [ - + ]: 1 : g_assert (VALENT_IS_PACKET (packet));
57 [ - + - - : 1 : g_assert (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
- - - - ]
58 [ + - - + ]: 1 : g_assert (error == NULL || *error == NULL);
59 : :
60 : : /* Get the payload information */
61 [ + - ]: 1 : if ((info = valent_packet_get_payload_full (packet, &size, error)) == NULL)
62 : : return NULL;
63 : :
64 [ + - ]: 1 : if ((port = json_object_get_int_member (info, "port")) == 0 ||
65 [ - + ]: 1 : (port < VALENT_LAN_TRANSFER_PORT_MIN || port > VALENT_LAN_TRANSFER_PORT_MAX))
66 : : {
67 : 0 : g_set_error (error,
68 : : VALENT_PACKET_ERROR,
69 : : VALENT_PACKET_ERROR_INVALID_FIELD,
70 : : "expected \"port\" field holding a uint16 between %u-%u",
71 : : VALENT_LAN_TRANSFER_PORT_MIN,
72 : : VALENT_LAN_TRANSFER_PORT_MAX);
73 : 0 : return NULL;
74 : : }
75 : :
76 : : /* Open the outgoing connection */
77 : 1 : host = valent_lan_channel_dup_host (self);
78 : 1 : client = g_object_new (G_TYPE_SOCKET_CLIENT,
79 : : "enable-proxy", FALSE,
80 : : NULL);
81 : 1 : connection = g_socket_client_connect_to_host (client,
82 : : host,
83 : : (uint16_t)port,
84 : : cancellable,
85 : : error);
86 : :
87 [ + - ]: 1 : if (connection == NULL)
88 : : return NULL;
89 : :
90 : : /* We're the TLS client when downloading */
91 : 1 : certificate = valent_channel_get_certificate (channel);
92 : 1 : peer_certificate = valent_channel_get_peer_certificate (channel);
93 : 1 : tls_stream = valent_lan_encrypt_client (connection,
94 : : certificate,
95 : : peer_certificate,
96 : : cancellable,
97 : : error);
98 : :
99 [ - + ]: 1 : if (tls_stream == NULL)
100 : : {
101 : 0 : g_io_stream_close (G_IO_STREAM (connection), NULL, NULL);
102 : 0 : return NULL;
103 : : }
104 : :
105 : : return g_steal_pointer (&tls_stream);
106 : : }
107 : :
108 : : static GIOStream *
109 : 1 : valent_lan_channel_upload (ValentChannel *channel,
110 : : JsonNode *packet,
111 : : GCancellable *cancellable,
112 : : GError **error)
113 : : {
114 : 1 : JsonObject *info;
115 : 2 : g_autoptr (GSocketListener) listener = NULL;
116 [ + - ]: 1 : g_autoptr (GSocketConnection) connection = NULL;
117 : 1 : uint16_t port = VALENT_LAN_TRANSFER_PORT_MIN;
118 : 1 : GTlsCertificate *certificate = NULL;
119 : 1 : GTlsCertificate *peer_certificate = NULL;
120 [ + - ]: 1 : g_autoptr (GIOStream) tls_stream = NULL;
121 : :
122 [ + - ]: 1 : g_assert (VALENT_IS_CHANNEL (channel));
123 [ - + ]: 1 : g_assert (VALENT_IS_PACKET (packet));
124 [ - + - - : 1 : g_assert (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
- - - - ]
125 [ + - - + ]: 1 : g_assert (error == NULL || *error == NULL);
126 : :
127 : : /* Find an open port */
128 : 1 : listener = g_socket_listener_new ();
129 : :
130 [ - + ]: 1 : while (!g_socket_listener_add_inet_port (listener, port, NULL, error))
131 : : {
132 [ # # ]: 0 : if (port >= VALENT_LAN_TRANSFER_PORT_MAX)
133 : : return NULL;
134 : :
135 : 0 : port++;
136 : 0 : g_clear_error (error);
137 : : }
138 : :
139 : : /* Set the payload information */
140 : 1 : info = json_object_new();
141 : 1 : json_object_set_int_member (info, "port", (int64_t)port);
142 : 1 : valent_packet_set_payload_info (packet, info);
143 : :
144 : : /* Notify the device and accept the incoming connection */
145 : 1 : valent_channel_write_packet (channel, packet, cancellable, NULL, NULL);
146 : :
147 : 1 : connection = g_socket_listener_accept (listener, NULL, cancellable, error);
148 : 1 : g_socket_listener_close (listener);
149 : :
150 [ - + ]: 1 : if (connection == NULL)
151 : : return NULL;
152 : :
153 : : /* We're the TLS server when uploading */
154 : 1 : certificate = valent_channel_get_certificate (channel);
155 : 1 : peer_certificate = valent_channel_get_peer_certificate (channel);
156 : 1 : tls_stream = valent_lan_encrypt_server (connection,
157 : : certificate,
158 : : peer_certificate,
159 : : cancellable,
160 : : error);
161 : :
162 [ - + ]: 1 : if (tls_stream == NULL)
163 : : {
164 : 0 : g_io_stream_close (G_IO_STREAM (connection), NULL, NULL);
165 : 0 : return NULL;
166 : : }
167 : :
168 : : return g_steal_pointer (&tls_stream);
169 : : }
170 : :
171 : : /*
172 : : * GObject
173 : : */
174 : : static void
175 : 6 : valent_lan_channel_finalize (GObject *object)
176 : : {
177 : 6 : ValentLanChannel *self = VALENT_LAN_CHANNEL (object);
178 : :
179 : 6 : valent_object_lock (VALENT_OBJECT (self));
180 [ + - ]: 6 : g_clear_pointer (&self->host, g_free);
181 : 6 : valent_object_unlock (VALENT_OBJECT (self));
182 : :
183 : 6 : G_OBJECT_CLASS (valent_lan_channel_parent_class)->finalize (object);
184 : 6 : }
185 : :
186 : : static void
187 : 2 : valent_lan_channel_get_property (GObject *object,
188 : : guint prop_id,
189 : : GValue *value,
190 : : GParamSpec *pspec)
191 : : {
192 : 2 : ValentLanChannel *self = VALENT_LAN_CHANNEL (object);
193 : :
194 [ + + - ]: 2 : switch ((ValentLanChannelProperty)prop_id)
195 : : {
196 : 1 : case PROP_HOST:
197 : 1 : g_value_take_string (value, valent_lan_channel_dup_host (self));
198 : 1 : break;
199 : :
200 : 1 : case PROP_PORT:
201 : 1 : g_value_set_uint (value, valent_lan_channel_get_port (self));
202 : 1 : break;
203 : :
204 : 0 : default:
205 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
206 : : }
207 : 2 : }
208 : :
209 : : static void
210 : 12 : valent_lan_channel_set_property (GObject *object,
211 : : guint prop_id,
212 : : const GValue *value,
213 : : GParamSpec *pspec)
214 : : {
215 : 12 : ValentLanChannel *self = VALENT_LAN_CHANNEL (object);
216 : :
217 [ + + - ]: 12 : switch ((ValentLanChannelProperty)prop_id)
218 : : {
219 : : case PROP_HOST:
220 : 6 : valent_object_lock (VALENT_OBJECT (self));
221 : 6 : self->host = g_value_dup_string (value);
222 : 6 : valent_object_unlock (VALENT_OBJECT (self));
223 : 6 : break;
224 : :
225 : : case PROP_PORT:
226 : 6 : valent_object_lock (VALENT_OBJECT (self));
227 : 6 : self->port = g_value_get_uint (value);
228 : 6 : valent_object_unlock (VALENT_OBJECT (self));
229 : 6 : break;
230 : :
231 : 0 : default:
232 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
233 : : }
234 : 12 : }
235 : :
236 : : static void
237 : 1 : valent_lan_channel_class_init (ValentLanChannelClass *klass)
238 : : {
239 : 1 : GObjectClass *object_class = G_OBJECT_CLASS (klass);
240 : 1 : ValentChannelClass *channel_class = VALENT_CHANNEL_CLASS (klass);
241 : :
242 : 1 : object_class->finalize = valent_lan_channel_finalize;
243 : 1 : object_class->get_property = valent_lan_channel_get_property;
244 : 1 : object_class->set_property = valent_lan_channel_set_property;
245 : :
246 : 1 : channel_class->download = valent_lan_channel_download;
247 : 1 : channel_class->upload = valent_lan_channel_upload;
248 : :
249 : : /**
250 : : * ValentLanChannel:host:
251 : : *
252 : : * The remote TCP/IP address for the channel.
253 : : */
254 : 2 : properties [PROP_HOST] =
255 : 1 : g_param_spec_string ("host", NULL, NULL,
256 : : NULL,
257 : : (G_PARAM_READWRITE |
258 : : G_PARAM_CONSTRUCT_ONLY |
259 : : G_PARAM_EXPLICIT_NOTIFY |
260 : : G_PARAM_STATIC_STRINGS));
261 : :
262 : : /**
263 : : * ValentLanChannel:port:
264 : : *
265 : : * The remote TCP/IP port for the channel.
266 : : */
267 : 2 : properties [PROP_PORT] =
268 : 1 : g_param_spec_uint ("port", NULL, NULL,
269 : : 0, G_MAXUINT16,
270 : : VALENT_LAN_PROTOCOL_PORT,
271 : : (G_PARAM_READWRITE |
272 : : G_PARAM_CONSTRUCT_ONLY |
273 : : G_PARAM_EXPLICIT_NOTIFY |
274 : : G_PARAM_STATIC_STRINGS));
275 : :
276 : 1 : g_object_class_install_properties (object_class, G_N_ELEMENTS (properties), properties);
277 : 1 : }
278 : :
279 : : static void
280 : 6 : valent_lan_channel_init (ValentLanChannel *self)
281 : : {
282 : 6 : }
283 : :
284 : : /**
285 : : * valent_lan_channel_dup_host:
286 : : * @self: a `ValentLanChannel`
287 : : *
288 : : * Get the host address.
289 : : *
290 : : * Returns: (transfer full) (nullable): the remote host address
291 : : */
292 : : char *
293 : 2 : valent_lan_channel_dup_host (ValentLanChannel *self)
294 : : {
295 : 2 : char *ret = NULL;
296 : :
297 [ + - ]: 2 : g_return_val_if_fail (VALENT_LAN_CHANNEL (self), NULL);
298 : :
299 : 2 : valent_object_lock (VALENT_OBJECT (self));
300 [ - + ]: 2 : ret = g_strdup (self->host);
301 : 2 : valent_object_unlock (VALENT_OBJECT (self));
302 : :
303 : 2 : return g_steal_pointer (&ret);
304 : : }
305 : :
306 : : /**
307 : : * valent_lan_channel_get_port:
308 : : * @self: a `ValentLanChannel`
309 : : *
310 : : * Get the host port.
311 : : *
312 : : * Returns: the remote host port
313 : : */
314 : : uint16_t
315 : 1 : valent_lan_channel_get_port (ValentLanChannel *self)
316 : : {
317 : 1 : uint16_t ret;
318 : :
319 [ + - ]: 1 : g_return_val_if_fail (VALENT_IS_LAN_CHANNEL (self), 0);
320 : :
321 : 1 : valent_object_lock (VALENT_OBJECT (self));
322 : 1 : ret = self->port;
323 : 1 : valent_object_unlock (VALENT_OBJECT (self));
324 : :
325 : 1 : return ret;
326 : : }
327 : :
|