]> git.ipfire.org Git - thirdparty/squid.git/blob - src/ipc/TypedMsgHdr.cc
SourceFormat Enforcement
[thirdparty/squid.git] / src / ipc / TypedMsgHdr.cc
1 /*
2 * Copyright (C) 1996-2017 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 memset(this, 0, sizeof(*this));
22 sync();
23 }
24
25 Ipc::TypedMsgHdr::TypedMsgHdr(const TypedMsgHdr &tmh)
26 {
27 memcpy(this, &tmh, sizeof(*this));
28 sync();
29 }
30
31 Ipc::TypedMsgHdr &Ipc::TypedMsgHdr::operator =(const TypedMsgHdr &tmh)
32 {
33 if (this != &tmh) { // skip assignment to self
34 memcpy(this, &tmh, sizeof(*this));
35 sync();
36 }
37 return *this;
38 }
39
40 // update msghdr and ios pointers based on msghdr counters
41 void Ipc::TypedMsgHdr::sync()
42 {
43 if (msg_name) { // we have a name
44 msg_name = &name;
45 } else {
46 Must(!msg_namelen && !msg_name);
47 }
48
49 if (msg_iov) { // we have a data component
50 Must(msg_iovlen == 1);
51 msg_iov = ios;
52 ios[0].iov_base = &data;
53 Must(ios[0].iov_len == sizeof(data));
54 } else {
55 Must(!msg_iovlen && !msg_iov);
56 }
57
58 if (msg_control) { // we have a control component
59 Must(msg_controllen > 0);
60 msg_control = &ctrl;
61 } else {
62 Must(!msg_controllen && !msg_control);
63 }
64 offset = 0;
65 }
66
67 int
68 Ipc::TypedMsgHdr::type() const
69 {
70 Must(msg_iovlen == 1);
71 return data.type_;
72 }
73
74 void
75 Ipc::TypedMsgHdr::address(const struct sockaddr_un& addr)
76 {
77 allocName();
78 name = addr;
79 msg_name = &name;
80 msg_namelen = SUN_LEN(&name);
81 }
82
83 void
84 Ipc::TypedMsgHdr::checkType(int destType) const
85 {
86 Must(type() == destType);
87 }
88
89 void
90 Ipc::TypedMsgHdr::setType(int aType)
91 {
92 if (data.type_) {
93 Must(data.type_ == aType);
94 } else {
95 allocData();
96 data.type_ = aType;
97 }
98 }
99
100 int
101 Ipc::TypedMsgHdr::getInt() const
102 {
103 int n = 0;
104 getPod(n);
105 return n;
106 }
107
108 void
109 Ipc::TypedMsgHdr::putInt(const int n)
110 {
111 putPod(n);
112 }
113
114 void
115 Ipc::TypedMsgHdr::getString(String &s) const
116 {
117 const int length = getInt();
118 Must(length >= 0);
119 // String uses memcpy uncoditionally; TODO: SBuf eliminates this check
120 if (!length) {
121 s.clean();
122 return;
123 }
124
125 Must(length <= maxSize);
126 // TODO: use SBuf.reserve() instead of a temporary buffer
127 char buf[maxSize];
128 getRaw(&buf, length);
129 s.limitInit(buf, length);
130 }
131
132 void
133 Ipc::TypedMsgHdr::putString(const String &s)
134 {
135 Must(s.psize() <= maxSize);
136 putInt(s.psize());
137 putRaw(s.rawBuf(), s.psize());
138 }
139
140 void
141 Ipc::TypedMsgHdr::getFixed(void *rawBuf, size_t rawSize) const
142 {
143 // no need to load size because it is constant
144 getRaw(rawBuf, rawSize);
145 }
146
147 void
148 Ipc::TypedMsgHdr::putFixed(const void *rawBuf, size_t rawSize)
149 {
150 // no need to store size because it is constant
151 putRaw(rawBuf, rawSize);
152 }
153
154 /// low-level loading of exactly size bytes of raw data
155 void
156 Ipc::TypedMsgHdr::getRaw(void *rawBuf, size_t rawSize) const
157 {
158 if (rawSize > 0) {
159 Must(rawSize <= data.size - offset);
160 memcpy(rawBuf, data.raw + offset, rawSize);
161 offset += rawSize;
162 }
163 }
164
165 /// low-level storage of exactly size bytes of raw data
166 void
167 Ipc::TypedMsgHdr::putRaw(const void *rawBuf, size_t rawSize)
168 {
169 if (rawSize > 0) {
170 Must(rawSize <= sizeof(data.raw) - data.size);
171 memcpy(data.raw + data.size, rawBuf, rawSize);
172 data.size += rawSize;
173 }
174 }
175
176 bool
177 Ipc::TypedMsgHdr::hasFd() const
178 {
179 struct cmsghdr *cmsg = CMSG_FIRSTHDR(this);
180 return cmsg &&
181 cmsg->cmsg_level == SOL_SOCKET &&
182 cmsg->cmsg_type == SCM_RIGHTS;
183 }
184
185 void
186 Ipc::TypedMsgHdr::putFd(int fd)
187 {
188 Must(fd >= 0);
189 Must(!hasFd());
190 allocControl();
191
192 const int fdCount = 1;
193
194 struct cmsghdr *cmsg = CMSG_FIRSTHDR(this);
195 cmsg->cmsg_level = SOL_SOCKET;
196 cmsg->cmsg_type = SCM_RIGHTS;
197 cmsg->cmsg_len = CMSG_LEN(sizeof(int) * fdCount);
198
199 int *fdStore = reinterpret_cast<int*>(SQUID_CMSG_DATA(cmsg));
200 memcpy(fdStore, &fd, fdCount * sizeof(int));
201 msg_controllen = cmsg->cmsg_len;
202
203 Must(hasFd());
204 }
205
206 int
207 Ipc::TypedMsgHdr::getFd() const
208 {
209 Must(msg_control && msg_controllen);
210 Must(hasFd());
211
212 struct cmsghdr *cmsg = CMSG_FIRSTHDR(this);
213 Must(cmsg->cmsg_level == SOL_SOCKET);
214 Must(cmsg->cmsg_type == SCM_RIGHTS);
215
216 const int fdCount = 1;
217 const int *fdStore = reinterpret_cast<const int*>(SQUID_CMSG_DATA(cmsg));
218 int fd = -1;
219 memcpy(&fd, fdStore, fdCount * sizeof(int));
220 return fd;
221 }
222
223 void
224 Ipc::TypedMsgHdr::prepForReading()
225 {
226 memset(this, 0, sizeof(*this));
227 allocName();
228 allocData();
229 allocControl();
230 }
231
232 /// initialize io vector with one io record
233 void
234 Ipc::TypedMsgHdr::allocData()
235 {
236 Must(!msg_iovlen && !msg_iov);
237 msg_iovlen = 1;
238 msg_iov = ios;
239 ios[0].iov_base = &data;
240 ios[0].iov_len = sizeof(data);
241 data.type_ = 0;
242 data.size = 0;
243 }
244
245 void
246 Ipc::TypedMsgHdr::allocName()
247 {
248 Must(!msg_name && !msg_namelen);
249 msg_name = &name;
250 msg_namelen = sizeof(name); // is that the right size?
251 }
252
253 void
254 Ipc::TypedMsgHdr::allocControl()
255 {
256 Must(!msg_control && !msg_controllen);
257 msg_control = &ctrl;
258 msg_controllen = sizeof(ctrl);
259 }
260