1/* 2 * This file is free software: you may copy, redistribute and/or modify it 3 * under the terms of the GNU General Public License as published by the 4 * Free Software Foundation, either version 2 of the License, or (at your 5 * option) any later version. 6 * 7 * This file is distributed in the hope that it will be useful, but 8 * WITHOUT ANY WARRANTY; without even the implied warranty of 9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 10 * General Public License for more details. 11 * 12 * You should have received a copy of the GNU General Public License 13 * along with this program. If not, see <http://www.gnu.org/licenses/>. 14 * 15 * This file incorporates work covered by the following copyright and 16 * permission notice: 17 * 18Copyright (c) 2007, 2008 by Juliusz Chroboczek 19 20Permission is hereby granted, free of charge, to any person obtaining a copy 21of this software and associated documentation files (the "Software"), to deal 22in the Software without restriction, including without limitation the rights 23to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 24copies of the Software, and to permit persons to whom the Software is 25furnished to do so, subject to the following conditions: 26 27The above copyright notice and this permission notice shall be included in 28all copies or substantial portions of the Software. 29 30THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 31IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 32FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 33AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 34LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 35OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 36THE SOFTWARE. 37*/ 38 39#include <unistd.h> 40#include <fcntl.h> 41#include <string.h> 42#include <sys/ioctl.h> 43#include <sys/types.h> 44#include <sys/uio.h> 45#include <sys/socket.h> 46#include <netinet/in.h> 47#include <arpa/inet.h> 48#include <errno.h> 49 50#include "babeld.h" 51#include "util.h" 52#include "net.h" 53 54int 55babel_socket(int port) 56{ 57 struct sockaddr_in6 sin6; 58 int s, rc; 59 int saved_errno; 60 int one = 1, zero = 0; 61 const int ds = 0xc0; /* CS6 - Network Control */ 62 63 s = socket(PF_INET6, SOCK_DGRAM, 0); 64 if(s < 0) 65 return -1; 66 67 rc = setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)); 68 if(rc < 0) 69 goto fail; 70 71 rc = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); 72 if(rc < 0) 73 goto fail; 74 75 rc = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, 76 &zero, sizeof(zero)); 77 if(rc < 0) 78 goto fail; 79 80 rc = setsockopt(s, IPPROTO_IPV6, IPV6_UNICAST_HOPS, 81 &one, sizeof(one)); 82 if(rc < 0) 83 goto fail; 84 85 rc = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, 86 &one, sizeof(one)); 87 if(rc < 0) 88 goto fail; 89 90#ifdef IPV6_TCLASS 91 rc = setsockopt(s, IPPROTO_IPV6, IPV6_TCLASS, &ds, sizeof(ds)); 92#else 93 rc = -1; 94 errno = ENOSYS; 95#endif 96 if(rc < 0) 97 perror("Couldn't set traffic class"); 98 99 rc = fcntl(s, F_GETFL, 0); 100 if(rc < 0) 101 goto fail; 102 103 rc = fcntl(s, F_SETFL, (rc | O_NONBLOCK)); 104 if(rc < 0) 105 goto fail; 106 107 rc = fcntl(s, F_GETFD, 0); 108 if(rc < 0) 109 goto fail; 110 111 rc = fcntl(s, F_SETFD, rc | FD_CLOEXEC); 112 if(rc < 0) 113 goto fail; 114 115 memset(&sin6, 0, sizeof(sin6)); 116 sin6.sin6_family = AF_INET6; 117 sin6.sin6_port = htons(port); 118 rc = bind(s, (struct sockaddr*)&sin6, sizeof(sin6)); 119 if(rc < 0) 120 goto fail; 121 122 return s; 123 124 fail: 125 saved_errno = errno; 126 close(s); 127 errno = saved_errno; 128 return -1; 129} 130 131int 132babel_recv(int s, void *buf, int buflen, struct sockaddr *sin, int slen) 133{ 134 struct iovec iovec; 135 struct msghdr msg; 136 int rc; 137 138 memset(&msg, 0, sizeof(msg)); 139 iovec.iov_base = buf; 140 iovec.iov_len = buflen; 141 msg.msg_name = sin; 142 msg.msg_namelen = slen; 143 msg.msg_iov = &iovec; 144 msg.msg_iovlen = 1; 145 146 rc = recvmsg(s, &msg, 0); 147 return rc; 148} 149 150int 151babel_send(int s, 152 void *buf1, int buflen1, void *buf2, int buflen2, 153 struct sockaddr *sin, int slen) 154{ 155 struct iovec iovec[2]; 156 struct msghdr msg; 157 int rc; 158 159 iovec[0].iov_base = buf1; 160 iovec[0].iov_len = buflen1; 161 iovec[1].iov_base = buf2; 162 iovec[1].iov_len = buflen2; 163 memset(&msg, 0, sizeof(msg)); 164 msg.msg_name = (struct sockaddr*)sin; 165 msg.msg_namelen = slen; 166 msg.msg_iov = iovec; 167 msg.msg_iovlen = 2; 168 169 again: 170 rc = sendmsg(s, &msg, 0); 171 if(rc < 0) { 172 if(errno == EINTR) 173 goto again; 174 else if(errno == EAGAIN) { 175 int rc2; 176 rc2 = wait_for_fd(1, s, 5); 177 if(rc2 > 0) 178 goto again; 179 errno = EAGAIN; 180 } 181 } 182 return rc; 183} 184 185int 186tcp_server_socket(int port, int local) 187{ 188 struct sockaddr_in6 sin6; 189 int s, rc, saved_errno; 190 int one = 1; 191 192 s = socket(PF_INET6, SOCK_STREAM, 0); 193 if(s < 0) 194 return -1; 195 196 rc = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); 197 if(rc < 0) 198 goto fail; 199 200 rc = fcntl(s, F_GETFL, 0); 201 if(rc < 0) 202 goto fail; 203 204 rc = fcntl(s, F_SETFL, (rc | O_NONBLOCK)); 205 if(rc < 0) 206 goto fail; 207 208 rc = fcntl(s, F_GETFD, 0); 209 if(rc < 0) 210 goto fail; 211 212 rc = fcntl(s, F_SETFD, rc | FD_CLOEXEC); 213 if(rc < 0) 214 goto fail; 215 216 memset(&sin6, 0, sizeof(sin6)); 217 sin6.sin6_family = AF_INET6; 218 sin6.sin6_port = htons(port); 219 if(local) { 220 rc = inet_pton(AF_INET6, "::1", &sin6.sin6_addr); 221 if(rc < 0) 222 goto fail; 223 } 224 rc = bind(s, (struct sockaddr*)&sin6, sizeof(sin6)); 225 if(rc < 0) 226 goto fail; 227 228 rc = listen(s, 2); 229 if(rc < 0) 230 goto fail; 231 232 return s; 233 234 fail: 235 saved_errno = errno; 236 close(s); 237 errno = saved_errno; 238 return -1; 239} 240