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 32 Socket::Socket() : mState(State::New), mSocket(-1) { 33 } 34 35 Socket::Socket(Socket&& other) noexcept : mState(other.mState), mSocket(other.mSocket) { 36 other.mSocket = -1; 37 other.mState = State::Moved; 38 } 39 40 Socket::~Socket() { 41 if (mSocket != -1) { 42 close(mSocket); 43 mSocket = -1; 44 } 45 mState = State::Destructed; 46 } 47 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 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 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 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 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 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 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 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 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 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 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 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 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 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