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