• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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