]> git.ipfire.org Git - thirdparty/squid.git/blob - src/ipc/TypedMsgHdr.cc
Source Format Enforcement (#532)
[thirdparty/squid.git] / src / ipc / TypedMsgHdr.cc
1 /*
2 * Copyright (C) 1996-2020 The Squid Software Foundation and contributors
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7 */
8
9 /* DEBUG: section 54 Interprocess Communication */
10
11 #include "squid.h"
12 #include "base/TextException.h"
13 #include "ipc/TypedMsgHdr.h"
14 #include "SquidString.h"
15 #include "tools.h"
16
17 #include <cstring>
18
19 Ipc::TypedMsgHdr::TypedMsgHdr()
20 {
21 clear();
22 sync();
23 }
24
25 Ipc::TypedMsgHdr::TypedMsgHdr(const TypedMsgHdr &tmh)
26 {
27 clear();
28 operator =(tmh);
29 }
30
31 Ipc::TypedMsgHdr &Ipc::TypedMsgHdr::operator =(const TypedMsgHdr &tmh)
32 {
33 if (this != &tmh) { // skip assignment to self
34 memcpy(static_cast<msghdr*>(this), static_cast<const msghdr*>(&tmh), sizeof(msghdr));
35 name = tmh.name;
36 memcpy(&ios, &tmh.ios, sizeof(ios));
37 data = tmh.data;
38 ctrl = tmh.ctrl;
39 offset = tmh.offset;
40 sync();
41 }
42 return *this;
43 }
44
45 void
46 Ipc::TypedMsgHdr::clear()
47 {
48 // may be called from the constructor, with object fields uninitialized
49 memset(static_cast<msghdr*>(this), 0, sizeof(msghdr));
50 memset(&name, 0, sizeof(name));
51 memset(&ios, 0, sizeof(ios));
52 data = DataBuffer();
53 ctrl = CtrlBuffer();
54 offset = 0;
55 }
56
57 // update msghdr and ios pointers based on msghdr counters
58 void Ipc::TypedMsgHdr::sync()
59 {
60 if (msg_name) { // we have a name
61 msg_name = &name;
62 } else {
63 Must(!msg_namelen && !msg_name);
64 }
65
66 if (msg_iov) { // we have a data component
67 Must(msg_iovlen == 1);
68 msg_iov = ios;
69 ios[0].iov_base = &data;
70 Must(ios[0].iov_len == sizeof(data));
71 } else {
72 Must(!msg_iovlen && !msg_iov);
73 }
74
75 if (msg_control) { // we have a control component
76 Must(msg_controllen > 0);
77 msg_control = &ctrl;
78 } else {
79 Must(!msg_controllen && !msg_control);
80 }
81 offset = 0;
82 }
83
84 int
85 Ipc::TypedMsgHdr::type() const
86 {
87 Must(msg_iovlen == 1);
88 return data.type_;
89 }
90
91 void
92 Ipc::TypedMsgHdr::address(const struct sockaddr_un& addr)
93 {
94 allocName();
95 name = addr;
96 msg_name = &name;
97 msg_namelen = SUN_LEN(&name);
98 }
99
100 void
101 Ipc::TypedMsgHdr::checkType(int destType) const
102 {
103 Must(type() == destType);
104 }
105
106 void
107 Ipc::TypedMsgHdr::setType(int aType)
108 {
109 if (data.type_) {
110 Must(data.type_ == aType);
111 } else {
112 allocData();
113 data.type_ = aType;
114 }
115 }
116
117 int
118 Ipc::TypedMsgHdr::getInt() const
119 {
120 int n = 0;
121 getPod(n);
122 return n;
123 }
124
125 void
126 Ipc::TypedMsgHdr::putInt(const int n)
127 {
128 putPod(n);
129 }
130
131 void
132 Ipc::TypedMsgHdr::getString(String &s) const
133 {
134 const int length = getInt();
135 Must(length >= 0);
136 // String uses memcpy uncoditionally; TODO: SBuf eliminates this check
137 if (!length) {
138 s.clean();
139 return;
140 }
141
142 Must(length <= maxSize);
143 // TODO: use SBuf.reserve() instead of a temporary buffer
144 char buf[maxSize];
145 getRaw(&buf, length);
146 s.assign(buf, length);
147 }
148
149 void
150 Ipc::TypedMsgHdr::putString(const String &s)
151 {
152 Must(s.psize() <= maxSize);
153 putInt(s.psize());
154 putRaw(s.rawBuf(), s.psize());
155 }
156
157 void
158 Ipc::TypedMsgHdr::getFixed(void *rawBuf, size_t rawSize) const
159 {
160 // no need to load size because it is constant
161 getRaw(rawBuf, rawSize);
162 }
163
164 void
165 Ipc::TypedMsgHdr::putFixed(const void *rawBuf, size_t rawSize)
166 {
167 // no need to store size because it is constant
168 putRaw(rawBuf, rawSize);
169 }
170
171 /// low-level loading of exactly size bytes of raw data
172 void
173 Ipc::TypedMsgHdr::getRaw(void *rawBuf, size_t rawSize) const
174 {
175 if (rawSize > 0) {
176 Must(rawSize <= data.size - offset);
177 memcpy(rawBuf, data.raw + offset, rawSize);
178 offset += rawSize;
179 }
180 }
181
182 /// low-level storage of exactly size bytes of raw data
183 void
184 Ipc::TypedMsgHdr::putRaw(const void *rawBuf, size_t rawSize)
185 {
186 if (rawSize > 0) {
187 Must(rawSize <= sizeof(data.raw) - data.size);
188 memcpy(data.raw + data.size, rawBuf, rawSize);
189 data.size += rawSize;
190 }
191 }
192
193 bool
194 Ipc::TypedMsgHdr::hasFd() const
195 {
196 struct cmsghdr *cmsg = CMSG_FIRSTHDR(this);
197 return cmsg &&
198 cmsg->cmsg_level == SOL_SOCKET &&
199 cmsg->cmsg_type == SCM_RIGHTS;
200 }
201
202 void
203 Ipc::TypedMsgHdr::putFd(int fd)
204 {
205 Must(fd >= 0);
206 Must(!hasFd());
207 allocControl();
208
209 const int fdCount = 1;
210
211 struct cmsghdr *cmsg = CMSG_FIRSTHDR(this);
212 cmsg->cmsg_level = SOL_SOCKET;
213 cmsg->cmsg_type = SCM_RIGHTS;
214 cmsg->cmsg_len = CMSG_LEN(sizeof(int) * fdCount);
215
216 int *fdStore = reinterpret_cast<int*>(SQUID_CMSG_DATA(cmsg));
217 memcpy(fdStore, &fd, fdCount * sizeof(int));
218 msg_controllen = cmsg->cmsg_len;
219
220 Must(hasFd());
221 }
222
223 int
224 Ipc::TypedMsgHdr::getFd() const
225 {
226 Must(msg_control && msg_controllen);
227 Must(hasFd());
228
229 struct cmsghdr *cmsg = CMSG_FIRSTHDR(this);
230 Must(cmsg->cmsg_level == SOL_SOCKET);
231 Must(cmsg->cmsg_type == SCM_RIGHTS);
232
233 const int fdCount = 1;
234 const int *fdStore = reinterpret_cast<const int*>(SQUID_CMSG_DATA(cmsg));
235 int fd = -1;
236 memcpy(&fd, fdStore, fdCount * sizeof(int));
237 return fd;
238 }
239
240 void
241 Ipc::TypedMsgHdr::prepForReading()
242 {
243 clear();
244 // no sync() like other clear() calls because the
245 // alloc*() below "sync()" the parts they allocate.
246 allocName();
247 allocData();
248 allocControl();
249 }
250
251 /// initialize io vector with one io record
252 void
253 Ipc::TypedMsgHdr::allocData()
254 {
255 Must(!msg_iovlen && !msg_iov);
256 msg_iovlen = 1;
257 msg_iov = ios;
258 ios[0].iov_base = &data;
259 ios[0].iov_len = sizeof(data);
260 data.type_ = 0;
261 data.size = 0;
262 }
263
264 void
265 Ipc::TypedMsgHdr::allocName()
266 {
267 Must(!msg_name && !msg_namelen);
268 msg_name = &name;
269 msg_namelen = sizeof(name); // is that the right size?
270 }
271
272 void
273 Ipc::TypedMsgHdr::allocControl()
274 {
275 Must(!msg_control && !msg_controllen);
276 msg_control = &ctrl;
277 msg_controllen = sizeof(ctrl);
278 }
279