1 /* 2 * Copyright (c) 2009-2011, The Regents of the University of California, 3 * through Lawrence Berkeley National Laboratory (subject to receipt of any 4 * required approvals from the U.S. Dept. of Energy). All rights reserved. 5 * 6 * This code is distributed under a BSD style license, see the LICENSE file 7 * for complete information. 8 */ 9 10 #include <stdio.h> 11 #include <unistd.h> 12 #include <errno.h> 13 #include <sys/socket.h> 14 #include <sys/types.h> 15 #include <sys/errno.h> 16 #include <netinet/in.h> 17 #include <netinet/tcp.h> 18 #include <assert.h> 19 #include <netdb.h> 20 #include <string.h> 21 #include <sys/fcntl.h> 22 23 #include "net.h" 24 #include "timer.h" 25 26 /* netdial and netannouce code comes from libtask: http://swtch.com/libtask/ 27 * Copyright: http://swtch.com/libtask/COPYRIGHT 28 */ 29 30 /* make connection to server */ 31 int 32 netdial(int domain, int proto, char *local, char *server, int port) 33 { 34 int s; 35 struct addrinfo hints, *res; 36 37 s = socket(domain, proto, 0); 38 if (s < 0) { 39 return (-1); 40 } 41 42 if (local) { 43 memset(&hints, 0, sizeof(hints)); 44 hints.ai_family = domain; 45 hints.ai_socktype = proto; 46 47 // XXX: Check getaddrinfo for errors! 48 if (getaddrinfo(local, NULL, &hints, &res) != 0) 49 return (-1); 50 51 if (bind(s, (struct sockaddr *) res->ai_addr, res->ai_addrlen) < 0) 52 return (-1); 53 54 freeaddrinfo(res); 55 } 56 57 memset(&hints, 0, sizeof(hints)); 58 hints.ai_family = domain; 59 hints.ai_socktype = proto; 60 61 // XXX: Check getaddrinfo for errors! 62 if (getaddrinfo(server, NULL, &hints, &res) != 0) 63 return (-1); 64 65 ((struct sockaddr_in *) res->ai_addr)->sin_port = htons(port); 66 67 if (connect(s, (struct sockaddr *) res->ai_addr, res->ai_addrlen) < 0 && errno != EINPROGRESS) { 68 return (-1); 69 } 70 71 freeaddrinfo(res); 72 73 return (s); 74 } 75 76 /***************************************************************/ 77 78 int 79 netannounce(int domain, int proto, char *local, int port) 80 { 81 int s, opt; 82 struct addrinfo hints, *res; 83 char portstr[6]; 84 85 s = socket(domain, proto, 0); 86 if (s < 0) { 87 return (-1); 88 } 89 opt = 1; 90 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &opt, sizeof(opt)); 91 92 snprintf(portstr, 6, "%d", port); 93 memset(&hints, 0, sizeof(hints)); 94 hints.ai_family = domain; 95 hints.ai_socktype = proto; 96 hints.ai_flags = AI_PASSIVE; 97 // XXX: Check getaddrinfo for errors! 98 if (getaddrinfo(local, portstr, &hints, &res) != 0) 99 return (-1); 100 101 if (bind(s, (struct sockaddr *) res->ai_addr, res->ai_addrlen) < 0) { 102 close(s); 103 return (-1); 104 } 105 106 freeaddrinfo(res); 107 108 if (proto == SOCK_STREAM) { 109 if (listen(s, 5) < 0) { 110 return (-1); 111 } 112 } 113 114 return (s); 115 } 116 117 118 /*******************************************************************/ 119 /* reads 'count' byptes from a socket */ 120 /********************************************************************/ 121 122 int 123 Nread(int fd, void *buf, int count, int prot) 124 { 125 register int n; 126 register int nleft = count; 127 128 while (nleft > 0) { 129 if ((n = read(fd, buf, nleft)) < 0) { 130 if (errno == EINTR) 131 n = 0; 132 else 133 return (-1); 134 } else if (n == 0) 135 break; 136 137 nleft -= n; 138 buf += n; 139 } 140 return (count - nleft); 141 } 142 143 144 /* 145 * N W R I T E 146 * 147 * XXX: After updating this function to use read/write, the only difference between 148 * TCP and UDP is that udp handles ENOBUFS. Should we merge the two? 149 */ 150 151 int 152 Nwrite(int fd, void *buf, int count, int prot) 153 { 154 register int n; 155 register int nleft = count; 156 157 if (prot == SOCK_DGRAM) { /* UDP mode */ 158 while (nleft > 0) { 159 if ((n = write(fd, buf, nleft)) < 0) { 160 if (errno == EINTR) { 161 n = 0; 162 } else if (errno == ENOBUFS) { 163 /* wait if run out of buffers */ 164 /* XXX: but how long to wait? Start shorter and increase delay each time?? */ 165 delay(18000); // XXX: Fixme! 166 n = 0; 167 } else { 168 return (-1); 169 } 170 } 171 nleft -= n; 172 buf += n; 173 } 174 } else { 175 while (nleft > 0) { 176 if ((n = write(fd, buf, nleft)) < 0) { 177 if (errno == EINTR) 178 n = 0; 179 else 180 return (-1); 181 } 182 nleft -= n; 183 buf += n; 184 } 185 } 186 return (count); 187 } 188 189 /*************************************************************************/ 190 191 /** 192 * getsock_tcp_mss - Returns the MSS size for TCP 193 * 194 */ 195 196 int 197 getsock_tcp_mss(int inSock) 198 { 199 int mss = 0; 200 201 int rc; 202 socklen_t len; 203 204 assert(inSock >= 0); /* print error and exit if this is not true */ 205 206 /* query for mss */ 207 len = sizeof(mss); 208 rc = getsockopt(inSock, IPPROTO_TCP, TCP_MAXSEG, (char *)&mss, &len); 209 210 return mss; 211 } 212 213 214 215 /*************************************************************/ 216 217 /* sets TCP_NODELAY and TCP_MAXSEG if requested */ 218 // XXX: This function is not being used. 219 220 int 221 set_tcp_options(int sock, int no_delay, int mss) 222 { 223 224 socklen_t len; 225 226 if (no_delay == 1) { 227 int no_delay = 1; 228 229 len = sizeof(no_delay); 230 int rc = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, 231 (char *)&no_delay, len); 232 233 if (rc == -1) { 234 perror("TCP_NODELAY"); 235 return -1; 236 } 237 } 238 #ifdef TCP_MAXSEG 239 if (mss > 0) { 240 int rc; 241 int new_mss; 242 243 len = sizeof(new_mss); 244 245 assert(sock != -1); 246 247 /* set */ 248 new_mss = mss; 249 len = sizeof(new_mss); 250 rc = setsockopt(sock, IPPROTO_TCP, TCP_MAXSEG, (char *)&new_mss, len); 251 if (rc == -1) { 252 perror("setsockopt"); 253 return -1; 254 } 255 /* verify results */ 256 rc = getsockopt(sock, IPPROTO_TCP, TCP_MAXSEG, (char *)&new_mss, &len); 257 if (new_mss != mss) { 258 perror("setsockopt value mismatch"); 259 return -1; 260 } 261 } 262 #endif 263 return 0; 264 } 265 266 /****************************************************************************/ 267 268 // XXX: This function is not being used. 269 int 270 setnonblocking(int sock) 271 { 272 int opts = 0; 273 274 opts = (opts | O_NONBLOCK); 275 if (fcntl(sock, F_SETFL, opts) < 0) 276 { 277 perror("fcntl(F_SETFL)"); 278 return -1; 279 } 280 return 0; 281 } 282 283