1 /*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "socket.h"
18
19 #include <errno.h>
20 #include <string.h>
21
22 #include <linux/in6.h>
23 #include <net/ethernet.h>
24 #include <netinet/in.h>
25 #include <sys/types.h>
26 #include <sys/socket.h>
27 #include <unistd.h>
28
29 #include "address.h"
30 #include "message.h"
31
Socket()32 Socket::Socket() : mState(State::New), mSocket(-1) {
33 }
34
Socket(Socket && other)35 Socket::Socket(Socket&& other) noexcept : mState(other.mState), mSocket(other.mSocket) {
36 other.mSocket = -1;
37 other.mState = State::Moved;
38 }
39
~Socket()40 Socket::~Socket() {
41 if (mSocket != -1) {
42 close(mSocket);
43 mSocket = -1;
44 }
45 mState = State::Destructed;
46 }
47
operator =(Socket && other)48 Socket& Socket::operator=(Socket&& other) noexcept {
49 if (mSocket != -1) {
50 close(mSocket);
51 }
52 mSocket = other.mSocket;
53 mState = other.mState;
54 other.mSocket = -1;
55 other.mState = State::Moved;
56
57 return *this;
58 }
59
open(int domain,int type,int protocol)60 Result Socket::open(int domain, int type, int protocol) {
61 if (mState != State::New) {
62 return Result::error("open called on socket in invalid state");
63 }
64 mSocket = ::socket(domain, type | SOCK_CLOEXEC, protocol);
65 if (mSocket == -1) {
66 return Result::error(strerror(errno));
67 }
68 mState = State::Open;
69 return Result::success();
70 }
71
setInterface(const std::string & interface)72 Result Socket::setInterface(const std::string& interface) {
73 if (mState != State::Open) {
74 return Result::error("attempting to set option in invalid state");
75 }
76 int res = ::setsockopt(mSocket, SOL_SOCKET, SO_BINDTODEVICE,
77 interface.c_str(), interface.size());
78
79 return res == -1 ? Result::error(strerror(errno)) : Result::success();
80 }
81
setMulticastHopLimit(int hopLimit)82 Result Socket::setMulticastHopLimit(int hopLimit) {
83 if (mState != State::Open) {
84 return Result::error("attempting to set option in invalid state");
85 }
86 int res = ::setsockopt(mSocket, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
87 &hopLimit, sizeof(hopLimit));
88
89 return res == -1 ? Result::error(strerror(errno)) : Result::success();
90 }
91
setUnicastHopLimit(int hopLimit)92 Result Socket::setUnicastHopLimit(int hopLimit) {
93 if (mState != State::Open) {
94 return Result::error("attempting to set option in invalid state");
95 }
96 int res = ::setsockopt(mSocket, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
97 &hopLimit, sizeof(hopLimit));
98
99 return res == -1 ? Result::error(strerror(errno)) : Result::success();
100 }
101
setTransparent(bool transparent)102 Result Socket::setTransparent(bool transparent) {
103 if (mState != State::Open) {
104 return Result::error("attempting to set option in invalid state");
105 }
106 int v = transparent ? 1 : 0;
107 int res = ::setsockopt(mSocket, IPPROTO_IPV6, IPV6_TRANSPARENT,
108 &v, sizeof(v));
109
110 return res == -1 ? Result::error(strerror(errno)) : Result::success();
111 }
112
bind(const Address & address)113 Result Socket::bind(const Address& address) {
114 if (mState != State::Open) {
115 return Result::error("bind called on socket in invalid state");
116 }
117
118 int res = ::bind(mSocket, address.get<sockaddr>(), address.size());
119 if (res == -1) {
120 return Result::error(strerror(errno));
121 }
122
123 mState = State::Bound;
124 return Result::success();
125 }
126
receive(Message * receivingMessage)127 Result Socket::receive(Message* receivingMessage) {
128 if (receivingMessage == nullptr) {
129 return Result::error("No receivingMessage provided");
130 }
131 if (mState != State::Bound) {
132 return Result::error("Attempt to receive on a socket that isn't bound");
133 }
134
135 ssize_t rxBytes = ::recv(mSocket,
136 receivingMessage->data(),
137 receivingMessage->capacity(),
138 0);
139 if (rxBytes < 0) {
140 return Result::error(strerror(errno));
141 }
142
143 receivingMessage->setSize(static_cast<size_t>(rxBytes));
144 return Result::success();
145 }
146
receiveFrom(Message * receivingMessage,Address * from)147 Result Socket::receiveFrom(Message* receivingMessage, Address* from) {
148 if (receivingMessage == nullptr) {
149 return Result::error("No receivingMessage provided");
150 }
151 if (from == nullptr) {
152 return Result::error("No from address provided");
153 }
154 if (mState != State::Bound) {
155 return Result::error("Attempt to receive on a socket that isn't bound");
156 }
157
158 from->reset();
159 sockaddr* source = from->get<sockaddr>();
160 socklen_t sourceLen = from->size();
161 ssize_t rxBytes = ::recvfrom(mSocket,
162 receivingMessage->data(),
163 receivingMessage->capacity(),
164 0,
165 source,
166 &sourceLen);
167 if (rxBytes < 0) {
168 return Result::error(strerror(errno));
169 }
170
171 receivingMessage->setSize(static_cast<size_t>(rxBytes));
172 return Result::success();
173 }
174
send(const void * data,size_t size)175 Result Socket::send(const void* data, size_t size) {
176 if (mState != State::Bound && mState != State::Open) {
177 return Result::error("Attempt to send on a socket in invalid state");
178 }
179
180 int res = ::send(mSocket, data, size, 0);
181 if (res == -1) {
182 return Result::error(strerror(errno));
183 }
184 return Result::success();
185 }
186
sendTo(const sockaddr & destination,size_t destinationSize,const void * data,size_t size)187 Result Socket::sendTo(const sockaddr& destination,
188 size_t destinationSize,
189 const void* data,
190 size_t size) {
191 if (mState != State::Bound && mState != State::Open) {
192 return Result::error("Attempt to send on a socket in invalid state");
193 }
194
195 int res = ::sendto(mSocket, data, size, 0, &destination, destinationSize);
196 if (res == -1) {
197 return Result::error(strerror(errno));
198 }
199 return Result::success();
200 }
201
sendTo(const in6_addr & destination,const void * data,size_t size)202 Result Socket::sendTo(const in6_addr& destination,
203 const void* data,
204 size_t size) {
205 sockaddr_in6 addr;
206 memset(&addr, 0, sizeof(addr));
207 addr.sin6_family = AF_INET6;
208 addr.sin6_addr = destination;
209 return sendTo(*reinterpret_cast<sockaddr*>(&addr),
210 sizeof(addr),
211 data,
212 size);
213 }
214
sendFrom(const struct in6_addr & fromAddress,const sockaddr & destination,size_t destinationSize,const void * data,size_t size)215 Result Socket::sendFrom(const struct in6_addr& fromAddress,
216 const sockaddr& destination,
217 size_t destinationSize,
218 const void* data,
219 size_t size) {
220 struct msghdr messageHeader;
221 memset(&messageHeader, 0, sizeof(messageHeader));
222 // Even when sending this struct requires a non-const pointer, even when
223 // it's only going to be read. Do a const_cast instead of creating a
224 // method signature with illogical const-behavior.
225 messageHeader.msg_name = const_cast<struct sockaddr*>(&destination);
226 messageHeader.msg_namelen = destinationSize;
227
228 struct iovec iov;
229 messageHeader.msg_iov = &iov;
230 messageHeader.msg_iovlen = 1;
231
232 memset(&iov, 0, sizeof(iov));
233 iov.iov_base = const_cast<void*>(data);
234 iov.iov_len = size;
235
236 char control[CMSG_SPACE(sizeof(struct in6_pktinfo))] = { 0 };
237 messageHeader.msg_control = control;
238 messageHeader.msg_controllen = sizeof(control);
239
240 struct cmsghdr* controlHeader = CMSG_FIRSTHDR(&messageHeader);
241 controlHeader->cmsg_level = IPPROTO_IPV6;
242 controlHeader->cmsg_type = IPV6_PKTINFO;
243 controlHeader->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
244
245 auto packetInfoData = CMSG_DATA(controlHeader);
246 auto packetInfo = reinterpret_cast<struct in6_pktinfo*>(packetInfoData);
247 packetInfo->ipi6_addr = fromAddress;
248
249 int res = ::sendmsg(mSocket, &messageHeader, 0);
250 if (res == -1) {
251 int error = errno;
252 printf("sendmsg failed: %d\n", error);
253 return Result::error(strerror(error));
254 }
255 return Result::success();
256 }
257
sendFrom(const in6_addr & fromAddress,const in6_addr & destination,const void * data,size_t size)258 Result Socket::sendFrom(const in6_addr& fromAddress,
259 const in6_addr& destination,
260 const void* data,
261 size_t size) {
262 sockaddr_in6 addr;
263 memset(&addr, 0, sizeof(addr));
264 addr.sin6_family = AF_INET6;
265 addr.sin6_addr = destination;
266
267 return sendFrom(fromAddress,
268 *reinterpret_cast<sockaddr*>(&addr),
269 sizeof(addr),
270 data,
271 size);
272 }
273