1/* Licensed to the Apache Software Foundation (ASF) under one or more 2 * contributor license agreements. See the NOTICE file distributed with 3 * this work for additional information regarding copyright ownership. 4 * The ASF licenses this file to You under the Apache License, Version 2.0 5 * (the "License"); you may not use this file except in compliance with 6 * the License. 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 "apr_arch_networkio.h" 18#include "apr_arch_misc.h" /* apr_os_level */ 19#include "apr_network_io.h" 20#include "apr_general.h" 21#include "apr_strings.h" 22#include <string.h> 23 24/* IPV6_V6ONLY is missing from pre-Windows 2008 SDK as well as MinGW 25 * (at least up through 1.0.16). 26 * Runtime support is a separate issue. 27 */ 28#ifndef IPV6_V6ONLY 29#define IPV6_V6ONLY 27 30#endif 31 32static apr_status_t soblock(SOCKET sd) 33{ 34 u_long zero = 0; 35 36 if (ioctlsocket(sd, FIONBIO, &zero) == SOCKET_ERROR) { 37 return apr_get_netos_error(); 38 } 39 return APR_SUCCESS; 40} 41 42static apr_status_t sononblock(SOCKET sd) 43{ 44 u_long one = 1; 45 46 if (ioctlsocket(sd, FIONBIO, &one) == SOCKET_ERROR) { 47 return apr_get_netos_error(); 48 } 49 return APR_SUCCESS; 50} 51 52 53APR_DECLARE(apr_status_t) apr_socket_timeout_set(apr_socket_t *sock, apr_interval_time_t t) 54{ 55 apr_status_t stat; 56 57 if (t == 0) { 58 /* Set the socket non-blocking if it was previously blocking */ 59 if (sock->timeout != 0) { 60 if ((stat = sononblock(sock->socketdes)) != APR_SUCCESS) 61 return stat; 62 } 63 } 64 else if (t > 0) { 65 /* Set the socket to blocking if it was previously non-blocking */ 66 if (sock->timeout == 0) { 67 if ((stat = soblock(sock->socketdes)) != APR_SUCCESS) 68 return stat; 69 } 70 /* Reset socket timeouts if the new timeout differs from the old timeout */ 71 if (sock->timeout != t) 72 { 73 /* Win32 timeouts are in msec, represented as int */ 74 sock->timeout_ms = (int)apr_time_as_msec(t); 75 setsockopt(sock->socketdes, SOL_SOCKET, SO_RCVTIMEO, 76 (char *) &sock->timeout_ms, 77 sizeof(sock->timeout_ms)); 78 setsockopt(sock->socketdes, SOL_SOCKET, SO_SNDTIMEO, 79 (char *) &sock->timeout_ms, 80 sizeof(sock->timeout_ms)); 81 } 82 } 83 else if (t < 0) { 84 int zero = 0; 85 /* Set the socket to blocking with infinite timeouts */ 86 if ((stat = soblock(sock->socketdes)) != APR_SUCCESS) 87 return stat; 88 setsockopt(sock->socketdes, SOL_SOCKET, SO_RCVTIMEO, 89 (char *) &zero, sizeof(zero)); 90 setsockopt(sock->socketdes, SOL_SOCKET, SO_SNDTIMEO, 91 (char *) &zero, sizeof(zero)); 92 } 93 sock->timeout = t; 94 return APR_SUCCESS; 95} 96 97 98APR_DECLARE(apr_status_t) apr_socket_opt_set(apr_socket_t *sock, 99 apr_int32_t opt, apr_int32_t on) 100{ 101 int one; 102 apr_status_t stat; 103 104 one = on ? 1 : 0; 105 106 switch (opt) { 107 case APR_SO_KEEPALIVE: 108 if (on != apr_is_option_set(sock, APR_SO_KEEPALIVE)) { 109 if (setsockopt(sock->socketdes, SOL_SOCKET, SO_KEEPALIVE, 110 (void *)&one, sizeof(int)) == -1) { 111 return apr_get_netos_error(); 112 } 113 apr_set_option(sock, APR_SO_KEEPALIVE, on); 114 } 115 break; 116 case APR_SO_DEBUG: 117 if (on != apr_is_option_set(sock, APR_SO_DEBUG)) { 118 if (setsockopt(sock->socketdes, SOL_SOCKET, SO_DEBUG, 119 (void *)&one, sizeof(int)) == -1) { 120 return apr_get_netos_error(); 121 } 122 apr_set_option(sock, APR_SO_DEBUG, on); 123 } 124 break; 125 case APR_SO_SNDBUF: 126 if (setsockopt(sock->socketdes, SOL_SOCKET, SO_SNDBUF, 127 (void *)&on, sizeof(int)) == -1) { 128 return apr_get_netos_error(); 129 } 130 break; 131 case APR_SO_RCVBUF: 132 if (setsockopt(sock->socketdes, SOL_SOCKET, SO_RCVBUF, 133 (void *)&on, sizeof(int)) == -1) { 134 return apr_get_netos_error(); 135 } 136 break; 137 case APR_SO_REUSEADDR: 138 if (on != apr_is_option_set(sock, APR_SO_REUSEADDR)) { 139 if (setsockopt(sock->socketdes, SOL_SOCKET, SO_REUSEADDR, 140 (void *)&one, sizeof(int)) == -1) { 141 return apr_get_netos_error(); 142 } 143 apr_set_option(sock, APR_SO_REUSEADDR, on); 144 } 145 break; 146 case APR_SO_NONBLOCK: 147 if (apr_is_option_set(sock, APR_SO_NONBLOCK) != on) { 148 if (on) { 149 if ((stat = sononblock(sock->socketdes)) != APR_SUCCESS) 150 return stat; 151 } 152 else { 153 if ((stat = soblock(sock->socketdes)) != APR_SUCCESS) 154 return stat; 155 } 156 apr_set_option(sock, APR_SO_NONBLOCK, on); 157 } 158 break; 159 case APR_SO_LINGER: 160 { 161 if (apr_is_option_set(sock, APR_SO_LINGER) != on) { 162 struct linger li; 163 li.l_onoff = on; 164 li.l_linger = APR_MAX_SECS_TO_LINGER; 165 if (setsockopt(sock->socketdes, SOL_SOCKET, SO_LINGER, 166 (char *) &li, sizeof(struct linger)) == -1) { 167 return apr_get_netos_error(); 168 } 169 apr_set_option(sock, APR_SO_LINGER, on); 170 } 171 break; 172 } 173 case APR_TCP_DEFER_ACCEPT: 174#if defined(TCP_DEFER_ACCEPT) 175 if (apr_is_option_set(sock, APR_TCP_DEFER_ACCEPT) != on) { 176 int optlevel = IPPROTO_TCP; 177 int optname = TCP_DEFER_ACCEPT; 178 179 if (setsockopt(sock->socketdes, optlevel, optname, 180 (void *)&on, sizeof(int)) == -1) { 181 return errno; 182 } 183 apr_set_option(sock, APR_TCP_DEFER_ACCEPT, on); 184 } 185#else 186 return APR_ENOTIMPL; 187#endif 188 case APR_TCP_NODELAY: 189 if (apr_is_option_set(sock, APR_TCP_NODELAY) != on) { 190 int optlevel = IPPROTO_TCP; 191 int optname = TCP_NODELAY; 192 193#if APR_HAVE_SCTP 194 if (sock->protocol == IPPROTO_SCTP) { 195 optlevel = IPPROTO_SCTP; 196 optname = SCTP_NODELAY; 197 } 198#endif 199 if (setsockopt(sock->socketdes, optlevel, optname, 200 (void *)&on, sizeof(int)) == -1) { 201 return apr_get_netos_error(); 202 } 203 apr_set_option(sock, APR_TCP_NODELAY, on); 204 } 205 break; 206 case APR_IPV6_V6ONLY: 207#if APR_HAVE_IPV6 208 if (apr_os_level < APR_WIN_VISTA && 209 sock->local_addr->family == AF_INET6) { 210 /* apr_set_option() called at socket creation */ 211 if (on) { 212 return APR_SUCCESS; 213 } 214 else { 215 return APR_ENOTIMPL; 216 } 217 } 218 /* we don't know the initial setting of this option, 219 * so don't check sock->options since that optimization 220 * won't work 221 */ 222 if (setsockopt(sock->socketdes, IPPROTO_IPV6, IPV6_V6ONLY, 223 (void *)&on, sizeof(int)) == -1) { 224 return apr_get_netos_error(); 225 } 226 apr_set_option(sock, APR_IPV6_V6ONLY, on); 227#else 228 return APR_ENOTIMPL; 229#endif 230 break; 231 default: 232 return APR_EINVAL; 233 break; 234 } 235 return APR_SUCCESS; 236} 237 238 239APR_DECLARE(apr_status_t) apr_socket_timeout_get(apr_socket_t *sock, apr_interval_time_t *t) 240{ 241 *t = sock->timeout; 242 return APR_SUCCESS; 243} 244 245 246APR_DECLARE(apr_status_t) apr_socket_opt_get(apr_socket_t *sock, 247 apr_int32_t opt, apr_int32_t *on) 248{ 249 switch (opt) { 250 case APR_SO_DISCONNECTED: 251 *on = sock->disconnected; 252 break; 253 case APR_SO_KEEPALIVE: 254 case APR_SO_DEBUG: 255 case APR_SO_REUSEADDR: 256 case APR_SO_NONBLOCK: 257 case APR_SO_LINGER: 258 default: 259 *on = apr_is_option_set(sock, opt); 260 break; 261 } 262 return APR_SUCCESS; 263} 264 265 266APR_DECLARE(apr_status_t) apr_socket_atmark(apr_socket_t *sock, int *atmark) 267{ 268 u_long oobmark; 269 270 if (ioctlsocket(sock->socketdes, SIOCATMARK, (void*) &oobmark) < 0) 271 return apr_get_netos_error(); 272 273 *atmark = (oobmark != 0); 274 275 return APR_SUCCESS; 276} 277 278 279APR_DECLARE(apr_status_t) apr_gethostname(char *buf, int len, 280 apr_pool_t *cont) 281{ 282 if (gethostname(buf, len) == -1) { 283 buf[0] = '\0'; 284 return apr_get_netos_error(); 285 } 286 else if (!memchr(buf, '\0', len)) { /* buffer too small */ 287 buf[0] = '\0'; 288 return APR_ENAMETOOLONG; 289 } 290 return APR_SUCCESS; 291} 292 293