1 /*
2  * libiio - Library for interfacing industrial I/O (IIO) devices
3  *
4  * Copyright (C) 2014-2020 Analog Devices, Inc.
5  * Author: Paul Cercueil <paul.cercueil@analog.com>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  */
18 
19 #include "debug.h"
20 #include "iiod-client.h"
21 #include "iio-lock.h"
22 #include "iio-private.h"
23 
24 #include <errno.h>
25 #include <inttypes.h>
26 #include <string.h>
27 #include <stdio.h>
28 
29 struct iiod_client {
30 	struct iio_context_pdata *pdata;
31 	const struct iiod_client_ops *ops;
32 	struct iio_mutex *lock;
33 };
34 
iiod_client_read_integer(struct iiod_client * client,void * desc,int * val)35 static ssize_t iiod_client_read_integer(struct iiod_client *client,
36 		void *desc, int *val)
37 {
38 	unsigned int i;
39 	char buf[1024], *ptr = NULL, *end;
40 	ssize_t ret;
41 	int value;
42 
43 	do {
44 		ret = client->ops->read_line(client->pdata,
45 				desc, buf, sizeof(buf));
46 		if (ret < 0) {
47 			IIO_ERROR("READ LINE: %zd\n", ret);
48 			return ret;
49 		}
50 
51 		for (i = 0; i < (unsigned int) ret; i++) {
52 			if (buf[i] != '\n') {
53 				if (!ptr)
54 					ptr = &buf[i];
55 			} else if (!!ptr) {
56 				break;
57 			}
58 		}
59 	} while (!ptr);
60 
61 	buf[i] = '\0';
62 
63 	errno = 0;
64 	value = (int) strtol(ptr, &end, 10);
65 	if (ptr == end || errno == ERANGE)
66 		return -EINVAL;
67 
68 	*val = value;
69 	return 0;
70 }
71 
iiod_client_exec_command(struct iiod_client * client,void * desc,const char * cmd)72 static int iiod_client_exec_command(struct iiod_client *client,
73 		void *desc, const char *cmd)
74 {
75 	int resp;
76 	ssize_t ret;
77 
78 	ret = client->ops->write(client->pdata, desc, cmd, strlen(cmd));
79 	if (ret < 0)
80 		return (int) ret;
81 
82 	ret = iiod_client_read_integer(client, desc, &resp);
83 	return ret < 0 ? (int) ret : resp;
84 }
85 
iiod_client_write_all(struct iiod_client * client,void * desc,const void * src,size_t len)86 static ssize_t iiod_client_write_all(struct iiod_client *client,
87 		void *desc, const void *src, size_t len)
88 {
89 	struct iio_context_pdata *pdata = client->pdata;
90 	const struct iiod_client_ops *ops = client->ops;
91 	uintptr_t ptr = (uintptr_t) src;
92 
93 	while (len) {
94 		ssize_t ret = ops->write(pdata, desc, (const void *) ptr, len);
95 
96 		if (ret < 0) {
97 			if (ret == -EINTR)
98 				continue;
99 			else
100 				return ret;
101 		}
102 
103 		if (ret == 0)
104 			return -EPIPE;
105 
106 		ptr += ret;
107 		len -= ret;
108 	}
109 
110 	return (ssize_t) (ptr - (uintptr_t) src);
111 }
112 
iiod_client_read_all(struct iiod_client * client,void * desc,void * dst,size_t len)113 static ssize_t iiod_client_read_all(struct iiod_client *client,
114 		void *desc, void *dst, size_t len)
115 {
116 	struct iio_context_pdata *pdata = client->pdata;
117 	const struct iiod_client_ops *ops = client->ops;
118 	uintptr_t ptr = (uintptr_t) dst;
119 
120 	while (len) {
121 		ssize_t ret = ops->read(pdata, desc, (void *) ptr, len);
122 
123 		if (ret < 0) {
124 			if (ret == -EINTR)
125 				continue;
126 			else
127 				return ret;
128 		}
129 
130 		if (ret == 0)
131 			return -EPIPE;
132 
133 		ptr += ret;
134 		len -= ret;
135 	}
136 
137 	return (ssize_t) (ptr - (uintptr_t) dst);
138 }
139 
iiod_client_new(struct iio_context_pdata * pdata,struct iio_mutex * lock,const struct iiod_client_ops * ops)140 struct iiod_client * iiod_client_new(struct iio_context_pdata *pdata,
141 		struct iio_mutex *lock, const struct iiod_client_ops *ops)
142 {
143 	struct iiod_client *client;
144 
145 	client = malloc(sizeof(*client));
146 	if (!client) {
147 		errno = ENOMEM;
148 		return NULL;
149 	}
150 
151 	client->lock = lock;
152 	client->pdata = pdata;
153 	client->ops = ops;
154 	return client;
155 }
156 
iiod_client_destroy(struct iiod_client * client)157 void iiod_client_destroy(struct iiod_client *client)
158 {
159 	free(client);
160 }
161 
iiod_client_get_version(struct iiod_client * client,void * desc,unsigned int * major,unsigned int * minor,char * git_tag)162 int iiod_client_get_version(struct iiod_client *client, void *desc,
163 		unsigned int *major, unsigned int *minor, char *git_tag)
164 {
165 	struct iio_context_pdata *pdata = client->pdata;
166 	const struct iiod_client_ops *ops = client->ops;
167 	char buf[256], *ptr = buf, *end;
168 	long maj, min;
169 	int ret;
170 
171 	iio_mutex_lock(client->lock);
172 
173 	ret = (int) ops->write(pdata, desc, "VERSION\r\n", sizeof("VERSION\r\n") - 1);
174 	if (ret < 0) {
175 		iio_mutex_unlock(client->lock);
176 		return ret;
177 	}
178 
179 	ret = (int) ops->read_line(pdata, desc, buf, sizeof(buf));
180 	iio_mutex_unlock(client->lock);
181 
182 	if (ret < 0)
183 		return ret;
184 
185 	errno = 0;
186 	maj = strtol(ptr, &end, 10);
187 	if (ptr == end || errno == ERANGE)
188 		return -EIO;
189 
190 	ptr = end + 1;
191 	errno = 0;
192 	min = strtol(ptr, &end, 10);
193 	if (ptr == end || errno == ERANGE)
194 		return -EIO;
195 
196 	ptr = end + 1;
197 	if (buf + ret < ptr + 8)
198 		return -EIO;
199 
200 	/* Strip the \n */
201 	ptr[buf + ret - ptr - 1] = '\0';
202 
203 	if (major)
204 		*major = (unsigned int) maj;
205 	if (minor)
206 		*minor = (unsigned int) min;
207 	if (git_tag)
208 		iio_strlcpy(git_tag, ptr, 8);
209 	return 0;
210 }
211 
iiod_client_get_trigger(struct iiod_client * client,void * desc,const struct iio_device * dev,const struct iio_device ** trigger)212 int iiod_client_get_trigger(struct iiod_client *client, void *desc,
213 		const struct iio_device *dev, const struct iio_device **trigger)
214 {
215 	const struct iio_context *ctx = iio_device_get_context(dev);
216 	unsigned int i, nb_devices = iio_context_get_devices_count(ctx);
217 	char buf[1024];
218 	unsigned int name_len;
219 	int ret;
220 
221 	iio_snprintf(buf, sizeof(buf), "GETTRIG %s\r\n",
222 			iio_device_get_id(dev));
223 
224 	iio_mutex_lock(client->lock);
225 	ret = iiod_client_exec_command(client, desc, buf);
226 
227 	if (ret == 0)
228 		*trigger = NULL;
229 	if (ret <= 0)
230 		goto out_unlock;
231 
232 	if ((unsigned int) ret > sizeof(buf) - 1) {
233 		ret = -EIO;
234 		goto out_unlock;
235 	}
236 
237 	name_len = ret;
238 
239 	ret = (int) iiod_client_read_all(client, desc, buf, name_len + 1);
240 	if (ret < 0)
241 		goto out_unlock;
242 
243 	ret = -ENXIO;
244 
245 	for (i = 0; i < nb_devices; i++) {
246 		struct iio_device *cur = iio_context_get_device(ctx, i);
247 
248 		if (iio_device_is_trigger(cur)) {
249 			const char *name = iio_device_get_name(cur);
250 
251 			if (!name)
252 				continue;
253 
254 			if (!strncmp(name, buf, name_len)) {
255 				*trigger = cur;
256 				ret = 0;
257 				goto out_unlock;
258 			}
259 		}
260 	}
261 
262 out_unlock:
263 	iio_mutex_unlock(client->lock);
264 	return ret;
265 }
266 
iiod_client_set_trigger(struct iiod_client * client,void * desc,const struct iio_device * dev,const struct iio_device * trigger)267 int iiod_client_set_trigger(struct iiod_client *client, void *desc,
268 		const struct iio_device *dev, const struct iio_device *trigger)
269 {
270 	char buf[1024];
271 	int ret;
272 
273 	if (trigger) {
274 		iio_snprintf(buf, sizeof(buf), "SETTRIG %s %s\r\n",
275 				iio_device_get_id(dev),
276 				iio_device_get_id(trigger));
277 	} else {
278 		iio_snprintf(buf, sizeof(buf), "SETTRIG %s\r\n",
279 				iio_device_get_id(dev));
280 	}
281 
282 	iio_mutex_lock(client->lock);
283 	ret = iiod_client_exec_command(client, desc, buf);
284 	iio_mutex_unlock(client->lock);
285 	return ret;
286 }
287 
iiod_client_set_kernel_buffers_count(struct iiod_client * client,void * desc,const struct iio_device * dev,unsigned int nb_blocks)288 int iiod_client_set_kernel_buffers_count(struct iiod_client *client, void *desc,
289 		const struct iio_device *dev, unsigned int nb_blocks)
290 {
291 	int ret;
292 	char buf[1024];
293 
294 	iio_snprintf(buf, sizeof(buf), "SET %s BUFFERS_COUNT %u\r\n",
295 			iio_device_get_id(dev), nb_blocks);
296 
297 	iio_mutex_lock(client->lock);
298 	ret = iiod_client_exec_command(client, desc, buf);
299 	iio_mutex_unlock(client->lock);
300 	return ret;
301 }
302 
iiod_client_set_timeout(struct iiod_client * client,void * desc,unsigned int timeout)303 int iiod_client_set_timeout(struct iiod_client *client,
304 		void *desc, unsigned int timeout)
305 {
306 	int ret;
307 	char buf[1024];
308 
309 	iio_snprintf(buf, sizeof(buf), "TIMEOUT %u\r\n", timeout);
310 
311 	iio_mutex_lock(client->lock);
312 	ret = iiod_client_exec_command(client, desc, buf);
313 	iio_mutex_unlock(client->lock);
314 	return ret;
315 }
316 
iiod_client_discard(struct iiod_client * client,void * desc,char * buf,size_t buf_len,size_t to_discard)317 static int iiod_client_discard(struct iiod_client *client, void *desc,
318 		char *buf, size_t buf_len, size_t to_discard)
319 {
320 	do {
321 		size_t read_len;
322 		ssize_t ret;
323 
324 		if (to_discard > buf_len)
325 			read_len = buf_len;
326 		else
327 			read_len = to_discard;
328 
329 		ret = iiod_client_read_all(client, desc, buf, read_len);
330 		if (ret < 0)
331 			return (int) ret;
332 
333 		to_discard -= (size_t) ret;
334 	} while (to_discard);
335 
336 	return 0;
337 }
338 
iiod_client_read_attr(struct iiod_client * client,void * desc,const struct iio_device * dev,const struct iio_channel * chn,const char * attr,char * dest,size_t len,enum iio_attr_type type)339 ssize_t iiod_client_read_attr(struct iiod_client *client, void *desc,
340 		const struct iio_device *dev, const struct iio_channel *chn,
341 		const char *attr, char *dest, size_t len, enum iio_attr_type type)
342 {
343 	const char *id = iio_device_get_id(dev);
344 	char buf[1024];
345 	ssize_t ret;
346 
347 	if (attr) {
348 		if (chn) {
349 			if (!iio_channel_find_attr(chn, attr))
350 				return -ENOENT;
351 		} else {
352 			switch (type) {
353 				case IIO_ATTR_TYPE_DEVICE:
354 					if (!iio_device_find_attr(dev, attr))
355 						return -ENOENT;
356 					break;
357 				case IIO_ATTR_TYPE_DEBUG:
358 					if (!iio_device_find_debug_attr(dev, attr))
359 						return -ENOENT;
360 					break;
361 				case IIO_ATTR_TYPE_BUFFER:
362 					if (!iio_device_find_buffer_attr(dev, attr))
363 						return -ENOENT;
364 					break;
365 				default:
366 					return -EINVAL;
367 			}
368 		}
369 	}
370 
371 	if (chn) {
372 		iio_snprintf(buf, sizeof(buf), "READ %s %s %s %s\r\n", id,
373 				iio_channel_is_output(chn) ? "OUTPUT" : "INPUT",
374 				iio_channel_get_id(chn), attr ? attr : "");
375 	} else {
376 		switch (type) {
377 			case IIO_ATTR_TYPE_DEVICE:
378 				iio_snprintf(buf, sizeof(buf), "READ %s %s\r\n",
379 						id, attr ? attr : "");
380 				break;
381 			case IIO_ATTR_TYPE_DEBUG:
382 				iio_snprintf(buf, sizeof(buf), "READ %s DEBUG %s\r\n",
383 						id, attr ? attr : "");
384 				break;
385 			case IIO_ATTR_TYPE_BUFFER:
386 				iio_snprintf(buf, sizeof(buf), "READ %s BUFFER %s\r\n",
387 						id, attr ? attr : "");
388 				break;
389 		}
390 	}
391 
392 	iio_mutex_lock(client->lock);
393 
394 	ret = (ssize_t) iiod_client_exec_command(client, desc, buf);
395 	if (ret < 0)
396 		goto out_unlock;
397 
398 	if ((size_t) ret + 1 > len) {
399 		iiod_client_discard(client, desc, dest, len, ret + 1);
400 		ret = -EIO;
401 		goto out_unlock;
402 	}
403 
404 	/* +1: Also read the trailing \n */
405 	ret = iiod_client_read_all(client, desc, dest, ret + 1);
406 
407 	if (ret > 0) {
408 		/* Discard the trailing \n */
409 		ret--;
410 
411 		/* Replace it with a \0 just in case */
412 		dest[ret] = '\0';
413 	}
414 
415 out_unlock:
416 	iio_mutex_unlock(client->lock);
417 	return ret;
418 }
419 
iiod_client_write_attr(struct iiod_client * client,void * desc,const struct iio_device * dev,const struct iio_channel * chn,const char * attr,const char * src,size_t len,enum iio_attr_type type)420 ssize_t iiod_client_write_attr(struct iiod_client *client, void *desc,
421 		const struct iio_device *dev, const struct iio_channel *chn,
422 		const char *attr, const char *src, size_t len, enum iio_attr_type type)
423 {
424 	struct iio_context_pdata *pdata = client->pdata;
425 	const struct iiod_client_ops *ops = client->ops;
426 	const char *id = iio_device_get_id(dev);
427 	char buf[1024];
428 	ssize_t ret;
429 	int resp;
430 
431 	if (attr) {
432 		if (chn) {
433 			if (!iio_channel_find_attr(chn, attr))
434 				return -ENOENT;
435 		} else {
436 			switch (type) {
437 				case IIO_ATTR_TYPE_DEVICE:
438 					if (!iio_device_find_attr(dev, attr))
439 						return -ENOENT;
440 					break;
441 				case IIO_ATTR_TYPE_DEBUG:
442 					if (!iio_device_find_debug_attr(dev, attr))
443 						return -ENOENT;
444 					break;
445 				case IIO_ATTR_TYPE_BUFFER:
446 					if (!iio_device_find_buffer_attr(dev, attr))
447 						return -ENOENT;
448 					break;
449 				default:
450 					return -EINVAL;
451 			}
452 		}
453 	}
454 
455 	if (chn) {
456 		iio_snprintf(buf, sizeof(buf), "WRITE %s %s %s %s %lu\r\n", id,
457 				iio_channel_is_output(chn) ? "OUTPUT" : "INPUT",
458 				iio_channel_get_id(chn), attr ? attr : "",
459 				(unsigned long) len);
460 	} else {
461 		switch (type) {
462 			case IIO_ATTR_TYPE_DEVICE:
463 				iio_snprintf(buf, sizeof(buf), "WRITE %s %s %lu\r\n",
464 						id, attr ? attr : "", (unsigned long) len);
465 				break;
466 			case IIO_ATTR_TYPE_DEBUG:
467 				iio_snprintf(buf, sizeof(buf), "WRITE %s DEBUG %s %lu\r\n",
468 						id, attr ? attr : "", (unsigned long) len);
469 				break;
470 			case IIO_ATTR_TYPE_BUFFER:
471 				iio_snprintf(buf, sizeof(buf), "WRITE %s BUFFER %s %lu\r\n",
472 						id, attr ? attr : "", (unsigned long) len);
473 				break;
474 		}
475 	}
476 
477 	iio_mutex_lock(client->lock);
478 	ret = ops->write(pdata, desc, buf, strlen(buf));
479 	if (ret < 0)
480 		goto out_unlock;
481 
482 	ret = iiod_client_write_all(client, desc, src, len);
483 	if (ret < 0)
484 		goto out_unlock;
485 
486 	ret = iiod_client_read_integer(client, desc, &resp);
487 	if (ret < 0)
488 		goto out_unlock;
489 
490 	ret = (ssize_t) resp;
491 
492 out_unlock:
493 	iio_mutex_unlock(client->lock);
494 	return ret;
495 }
496 
iiod_client_create_context(struct iiod_client * client,void * desc)497 struct iio_context * iiod_client_create_context(
498 		struct iiod_client *client, void *desc)
499 {
500 	struct iio_context *ctx = NULL;
501 	size_t xml_len;
502 	char *xml;
503 	int ret;
504 
505 	iio_mutex_lock(client->lock);
506 	ret = iiod_client_exec_command(client, desc, "PRINT\r\n");
507 	if (ret < 0)
508 		goto out_unlock;
509 
510 	xml_len = (size_t) ret;
511 	xml = malloc(xml_len + 1);
512 	if (!xml) {
513 		ret = -ENOMEM;
514 		goto out_unlock;
515 	}
516 
517 	/* +1: Also read the trailing \n */
518 	ret = (int) iiod_client_read_all(client, desc, xml, xml_len + 1);
519 	if (ret < 0)
520 		goto out_free_xml;
521 
522 	ctx = iio_create_xml_context_mem(xml, xml_len);
523 	if (!ctx)
524 		ret = -errno;
525 
526 out_free_xml:
527 	free(xml);
528 out_unlock:
529 	iio_mutex_unlock(client->lock);
530 	if (!ctx)
531 		errno = -ret;
532 	return ctx;
533 }
534 
iiod_client_open_unlocked(struct iiod_client * client,void * desc,const struct iio_device * dev,size_t samples_count,bool cyclic)535 int iiod_client_open_unlocked(struct iiod_client *client, void *desc,
536 		const struct iio_device *dev, size_t samples_count, bool cyclic)
537 {
538 	char buf[1024], *ptr;
539 	size_t i;
540 	ssize_t len;
541 
542 	len = sizeof(buf);
543 	len -= iio_snprintf(buf, len, "OPEN %s %lu ",
544 			iio_device_get_id(dev), (unsigned long) samples_count);
545 	ptr = buf + strlen(buf);
546 
547 	for (i = dev->words; i > 0; i--, ptr += 8) {
548 		len -= iio_snprintf(ptr, len, "%08" PRIx32,
549 				dev->mask[i - 1]);
550 	}
551 
552 	len -= iio_strlcpy(ptr, cyclic ? " CYCLIC\r\n" : "\r\n", len);
553 
554 	if (len < 0) {
555 		IIO_ERROR("strlength problem in iiod_client_open_unlocked\n");
556 		return -ENOMEM;
557 	}
558 
559 	return iiod_client_exec_command(client, desc, buf);
560 }
561 
iiod_client_close_unlocked(struct iiod_client * client,void * desc,const struct iio_device * dev)562 int iiod_client_close_unlocked(struct iiod_client *client, void *desc,
563 		const struct iio_device *dev)
564 {
565 	char buf[1024];
566 
567 	iio_snprintf(buf, sizeof(buf), "CLOSE %s\r\n", iio_device_get_id(dev));
568 	return iiod_client_exec_command(client, desc, buf);
569 }
570 
iiod_client_read_mask(struct iiod_client * client,void * desc,uint32_t * mask,size_t words)571 static int iiod_client_read_mask(struct iiod_client *client,
572 		void *desc, uint32_t *mask, size_t words)
573 {
574 	size_t i;
575 	ssize_t ret;
576 	char *buf, *ptr;
577 
578 	buf = malloc(words * 8 + 1);
579 	if (!buf)
580 		return -ENOMEM;
581 
582 	ret = iiod_client_read_all(client, desc, buf, words * 8 + 1);
583 	if (ret < 0) {
584 		IIO_ERROR("READ ALL: %zd\n", ret);
585 		goto out_buf_free;
586 	} else
587 		ret = 0;
588 
589 	buf[words*8] = '\0';
590 
591 	IIO_DEBUG("Reading mask\n");
592 
593 	for (i = words, ptr = buf; i > 0; i--) {
594 		iio_sscanf(ptr, "%08" PRIx32, &mask[i - 1]);
595 		IIO_DEBUG("mask[%lu] = 0x%08" PRIx32 "\n",
596 				(unsigned long)(i - 1), mask[i - 1]);
597 
598 		ptr = (char *) ((uintptr_t) ptr + 8);
599 	}
600 
601 out_buf_free:
602 	free(buf);
603 	return (int) ret;
604 }
605 
iiod_client_read_unlocked(struct iiod_client * client,void * desc,const struct iio_device * dev,void * dst,size_t len,uint32_t * mask,size_t words)606 ssize_t iiod_client_read_unlocked(struct iiod_client *client, void *desc,
607 		const struct iio_device *dev, void *dst, size_t len,
608 		uint32_t *mask, size_t words)
609 {
610 	unsigned int nb_channels = iio_device_get_channels_count(dev);
611 	uintptr_t ptr = (uintptr_t) dst;
612 	char buf[1024];
613 	ssize_t ret, read = 0;
614 
615 	if (!len || words != (nb_channels + 31) / 32)
616 		return -EINVAL;
617 
618 	iio_snprintf(buf, sizeof(buf), "READBUF %s %lu\r\n",
619 			iio_device_get_id(dev), (unsigned long) len);
620 
621 	ret = iiod_client_write_all(client, desc, buf, strlen(buf));
622 	if (ret < 0) {
623 		IIO_ERROR("WRITE ALL: %zd\n", ret);
624 		return ret;
625 	}
626 
627 	do {
628 		int to_read;
629 
630 		ret = iiod_client_read_integer(client, desc, &to_read);
631 		if (ret < 0) {
632 			IIO_ERROR("READ INTEGER: %zd\n", ret);
633 			return ret;
634 		}
635 		if (to_read < 0)
636 			return (ssize_t) to_read;
637 		if (!to_read)
638 			break;
639 
640 		if (mask) {
641 			ret = iiod_client_read_mask(client, desc, mask, words);
642 			if (ret < 0) {
643 				IIO_ERROR("READ ALL: %zd\n", ret);
644 				return ret;
645 			}
646 
647 			mask = NULL; /* We read the mask only once */
648 		}
649 
650 		ret = iiod_client_read_all(client, desc, (char *) ptr, to_read);
651 		if (ret < 0)
652 			return ret;
653 
654 		ptr += ret;
655 		read += ret;
656 		len -= ret;
657 	} while (len);
658 
659 	return read;
660 }
661 
iiod_client_write_unlocked(struct iiod_client * client,void * desc,const struct iio_device * dev,const void * src,size_t len)662 ssize_t iiod_client_write_unlocked(struct iiod_client *client, void *desc,
663 		const struct iio_device *dev, const void *src, size_t len)
664 {
665 	ssize_t ret;
666 	char buf[1024];
667 	int val;
668 
669 	iio_snprintf(buf, sizeof(buf), "WRITEBUF %s %lu\r\n",
670 			dev->id, (unsigned long) len);
671 
672 	ret = iiod_client_write_all(client, desc, buf, strlen(buf));
673 	if (ret < 0)
674 		return ret;
675 
676 	ret = iiod_client_read_integer(client, desc, &val);
677 	if (ret < 0)
678 		return ret;
679 	if (val < 0)
680 		return (ssize_t) val;
681 
682 	ret = iiod_client_write_all(client, desc, src, len);
683 	if (ret < 0)
684 		return ret;
685 
686 	ret = iiod_client_read_integer(client, desc, &val);
687 	if (ret < 0)
688 		return ret;
689 	if (val < 0)
690 		return (ssize_t) val;
691 
692 	return (ssize_t) len;
693 }
694