1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
| | // SPDX-License-Identifier: GPL-2.0-or-later
/* PASST - Plug A Simple Socket Transport
* for qemu/UNIX domain socket mode
*
* PASTA - Pack A Subtle Tap Abstraction
* for network namespace/tap device mode
*
* PESTO - Programmable Extensible Socket Translation Orchestrator
* front-end for passt(1) and pasta(1) forwarding configuration
*
* serialise.c - Serialisation of data structures over bytestreams
*
* Copyright Red Hat
* Author: David Gibson <david@gibson.dropbear.id.au>
*/
#include <assert.h>
#include <endian.h>
#include <errno.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include "serialise.h"
/**
* seread_buf() - Fill a whole buffer from a file descriptor
* @fd: File descriptor
* @buf: Pointer to base of buffer
* @len: Length of buffer
*
* Return: 0 on success, -1 on error (with errno set)
*
* #syscalls read
*/
int seread_buf(int fd, void *buf, size_t len)
{
size_t left = len;
char *p = buf;
while (left) {
ssize_t rc;
assert(left <= len);
do
rc = read(fd, p, left);
while ((rc < 0) && errno == EINTR);
if (rc < 0)
return -1;
if (rc == 0) {
errno = ENODATA;
return -1;
}
p += rc;
left -= rc;
}
return 0;
}
/**
* sewrite_buf() - write all of a buffer to an fd
* @fd: File descriptor
* @buf: Pointer to base of buffer
* @len: Length of buffer
*
* Return: 0 on success, -1 on error (with errno set)
*
* #syscalls write
*/
int sewrite_buf(int fd, const void *buf, size_t len)
{
const char *p = buf;
size_t left = len;
while (left) {
ssize_t rc;
do
rc = write(fd, p, left);
while ((rc < 0) && errno == EINTR);
if (rc < 0)
return -1;
p += rc;
left -= rc;
}
return 0;
}
/**
* seread_uXXX() - Receive a uXXX value from an fd
* @fd: File descriptor to read from
* @valp: Pointer to variable to update with read value
*
* Return: 0 on success, -1 on error
*/
/**
* sewrite_uXXX() - Send a uXXX value to an fd
* @fd: File descriptor to write to
* @val: Value to send
*
* Return: 0 on success, -1 on error
*/
#define SERIALISE_UINT(bits) \
int seread_u##bits(int fd, uint##bits##_t *val) \
{ \
uint##bits##_t beval; \
if (seread_var(fd, &beval) < 0) \
return -1; \
*val = be##bits##toh(beval); \
return 0; \
} \
int sewrite_u##bits(int fd, uint##bits##_t val) \
{ \
uint##bits##_t beval = htobe##bits(val); \
return sewrite_var(fd, &beval); \
}
#define be8toh(x) (x)
#define htobe8(x) (x)
SERIALISE_UINT(8)
SERIALISE_UINT(32)
#undef SERIALISE_UNIT
/**
* sewrite_str() - Write a string to an fd in length/value format
* @fd: Socket to the client
* @s: String to send
*
* Return: 0 on success, -1 on error
*/
int sewrite_str(int fd, const char *s)
{
uint32_t len = strlen(s) + 1; /* Include \0 */
if (sewrite_u32(fd, len) < 0)
return -1;
return sewrite_buf(fd, s, len);
}
|