1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/nsprpub/pr/src/io/prmapopt.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,458 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +/* 1.10 + * This file defines _PR_MapOptionName(). The purpose of putting 1.11 + * _PR_MapOptionName() in a separate file is to work around a Winsock 1.12 + * header file problem on Windows NT. 1.13 + * 1.14 + * On Windows NT, if we define _WIN32_WINNT to be 0x0400 (in order 1.15 + * to use Service Pack 3 extensions), windows.h includes winsock2.h 1.16 + * (instead of winsock.h), which doesn't define many socket options 1.17 + * defined in winsock.h. 1.18 + * 1.19 + * We need the socket options defined in winsock.h. So this file 1.20 + * includes winsock.h, with _WIN32_WINNT undefined. 1.21 + */ 1.22 + 1.23 +#if defined(WINNT) || defined(__MINGW32__) 1.24 +#include <winsock.h> 1.25 +#endif 1.26 + 1.27 +/* MinGW doesn't define these in its winsock.h. */ 1.28 +#ifdef __MINGW32__ 1.29 +#ifndef IP_TTL 1.30 +#define IP_TTL 7 1.31 +#endif 1.32 +#ifndef IP_TOS 1.33 +#define IP_TOS 8 1.34 +#endif 1.35 +#endif 1.36 + 1.37 +#include "primpl.h" 1.38 + 1.39 +#ifdef HAVE_NETINET_TCP_H 1.40 +#include <netinet/tcp.h> /* TCP_NODELAY, TCP_MAXSEG */ 1.41 +#endif 1.42 + 1.43 +#ifndef _PR_PTHREADS 1.44 + 1.45 +PRStatus PR_CALLBACK _PR_SocketGetSocketOption(PRFileDesc *fd, PRSocketOptionData *data) 1.46 +{ 1.47 + PRStatus rv; 1.48 + PRInt32 length; 1.49 + PRInt32 level, name; 1.50 + 1.51 + /* 1.52 + * PR_SockOpt_Nonblocking is a special case that does not 1.53 + * translate to a getsockopt() call 1.54 + */ 1.55 + if (PR_SockOpt_Nonblocking == data->option) 1.56 + { 1.57 + data->value.non_blocking = fd->secret->nonblocking; 1.58 + return PR_SUCCESS; 1.59 + } 1.60 + 1.61 + rv = _PR_MapOptionName(data->option, &level, &name); 1.62 + if (PR_SUCCESS == rv) 1.63 + { 1.64 + switch (data->option) 1.65 + { 1.66 + case PR_SockOpt_Linger: 1.67 + { 1.68 +#if !defined(XP_BEOS) || defined(BONE_VERSION) 1.69 + struct linger linger; 1.70 + length = sizeof(linger); 1.71 + rv = _PR_MD_GETSOCKOPT( 1.72 + fd, level, name, (char *) &linger, &length); 1.73 + if (PR_SUCCESS == rv) 1.74 + { 1.75 + PR_ASSERT(sizeof(linger) == length); 1.76 + data->value.linger.polarity = 1.77 + (linger.l_onoff) ? PR_TRUE : PR_FALSE; 1.78 + data->value.linger.linger = 1.79 + PR_SecondsToInterval(linger.l_linger); 1.80 + } 1.81 + break; 1.82 +#else 1.83 + PR_SetError( PR_NOT_IMPLEMENTED_ERROR, 0 ); 1.84 + return PR_FAILURE; 1.85 +#endif 1.86 + } 1.87 + case PR_SockOpt_Reuseaddr: 1.88 + case PR_SockOpt_Keepalive: 1.89 + case PR_SockOpt_NoDelay: 1.90 + case PR_SockOpt_Broadcast: 1.91 + case PR_SockOpt_Reuseport: 1.92 + { 1.93 +#ifdef WIN32 /* Winsock */ 1.94 + BOOL value; 1.95 +#else 1.96 + PRIntn value; 1.97 +#endif 1.98 + length = sizeof(value); 1.99 + rv = _PR_MD_GETSOCKOPT( 1.100 + fd, level, name, (char*)&value, &length); 1.101 + if (PR_SUCCESS == rv) 1.102 + data->value.reuse_addr = (0 == value) ? PR_FALSE : PR_TRUE; 1.103 + break; 1.104 + } 1.105 + case PR_SockOpt_McastLoopback: 1.106 + { 1.107 +#ifdef WIN32 /* Winsock */ 1.108 + BOOL bool; 1.109 +#else 1.110 + PRUint8 bool; 1.111 +#endif 1.112 + length = sizeof(bool); 1.113 + rv = _PR_MD_GETSOCKOPT( 1.114 + fd, level, name, (char*)&bool, &length); 1.115 + if (PR_SUCCESS == rv) 1.116 + data->value.mcast_loopback = (0 == bool) ? PR_FALSE : PR_TRUE; 1.117 + break; 1.118 + } 1.119 + case PR_SockOpt_RecvBufferSize: 1.120 + case PR_SockOpt_SendBufferSize: 1.121 + case PR_SockOpt_MaxSegment: 1.122 + { 1.123 + PRIntn value; 1.124 + length = sizeof(value); 1.125 + rv = _PR_MD_GETSOCKOPT( 1.126 + fd, level, name, (char*)&value, &length); 1.127 + if (PR_SUCCESS == rv) 1.128 + data->value.recv_buffer_size = value; 1.129 + break; 1.130 + } 1.131 + case PR_SockOpt_IpTimeToLive: 1.132 + case PR_SockOpt_IpTypeOfService: 1.133 + { 1.134 + /* These options should really be an int (or PRIntn). */ 1.135 + length = sizeof(PRUintn); 1.136 + rv = _PR_MD_GETSOCKOPT( 1.137 + fd, level, name, (char*)&data->value.ip_ttl, &length); 1.138 + break; 1.139 + } 1.140 + case PR_SockOpt_McastTimeToLive: 1.141 + { 1.142 +#ifdef WIN32 /* Winsock */ 1.143 + int ttl; 1.144 +#else 1.145 + PRUint8 ttl; 1.146 +#endif 1.147 + length = sizeof(ttl); 1.148 + rv = _PR_MD_GETSOCKOPT( 1.149 + fd, level, name, (char*)&ttl, &length); 1.150 + if (PR_SUCCESS == rv) 1.151 + data->value.mcast_ttl = ttl; 1.152 + break; 1.153 + } 1.154 +#ifdef IP_ADD_MEMBERSHIP 1.155 + case PR_SockOpt_AddMember: 1.156 + case PR_SockOpt_DropMember: 1.157 + { 1.158 + struct ip_mreq mreq; 1.159 + length = sizeof(mreq); 1.160 + rv = _PR_MD_GETSOCKOPT( 1.161 + fd, level, name, (char*)&mreq, &length); 1.162 + if (PR_SUCCESS == rv) 1.163 + { 1.164 + data->value.add_member.mcaddr.inet.ip = 1.165 + mreq.imr_multiaddr.s_addr; 1.166 + data->value.add_member.ifaddr.inet.ip = 1.167 + mreq.imr_interface.s_addr; 1.168 + } 1.169 + break; 1.170 + } 1.171 +#endif /* IP_ADD_MEMBERSHIP */ 1.172 + case PR_SockOpt_McastInterface: 1.173 + { 1.174 + /* This option is a struct in_addr. */ 1.175 + length = sizeof(data->value.mcast_if.inet.ip); 1.176 + rv = _PR_MD_GETSOCKOPT( 1.177 + fd, level, name, 1.178 + (char*)&data->value.mcast_if.inet.ip, &length); 1.179 + break; 1.180 + } 1.181 + default: 1.182 + PR_NOT_REACHED("Unknown socket option"); 1.183 + break; 1.184 + } 1.185 + } 1.186 + return rv; 1.187 +} /* _PR_SocketGetSocketOption */ 1.188 + 1.189 +PRStatus PR_CALLBACK _PR_SocketSetSocketOption(PRFileDesc *fd, const PRSocketOptionData *data) 1.190 +{ 1.191 + PRStatus rv; 1.192 + PRInt32 level, name; 1.193 + 1.194 + /* 1.195 + * PR_SockOpt_Nonblocking is a special case that does not 1.196 + * translate to a setsockopt call. 1.197 + */ 1.198 + if (PR_SockOpt_Nonblocking == data->option) 1.199 + { 1.200 +#ifdef WINNT 1.201 + PR_ASSERT((fd->secret->md.io_model_committed == PR_FALSE) 1.202 + || (fd->secret->nonblocking == data->value.non_blocking)); 1.203 + if (fd->secret->md.io_model_committed 1.204 + && (fd->secret->nonblocking != data->value.non_blocking)) 1.205 + { 1.206 + /* 1.207 + * On NT, once we have associated a socket with the io 1.208 + * completion port, we can't disassociate it. So we 1.209 + * can't change the nonblocking option of the socket 1.210 + * afterwards. 1.211 + */ 1.212 + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); 1.213 + return PR_FAILURE; 1.214 + } 1.215 +#endif 1.216 + fd->secret->nonblocking = data->value.non_blocking; 1.217 + return PR_SUCCESS; 1.218 + } 1.219 + 1.220 + rv = _PR_MapOptionName(data->option, &level, &name); 1.221 + if (PR_SUCCESS == rv) 1.222 + { 1.223 + switch (data->option) 1.224 + { 1.225 + case PR_SockOpt_Linger: 1.226 + { 1.227 +#if !defined(XP_BEOS) || defined(BONE_VERSION) 1.228 + struct linger linger; 1.229 + linger.l_onoff = data->value.linger.polarity; 1.230 + linger.l_linger = PR_IntervalToSeconds(data->value.linger.linger); 1.231 + rv = _PR_MD_SETSOCKOPT( 1.232 + fd, level, name, (char*)&linger, sizeof(linger)); 1.233 + break; 1.234 +#else 1.235 + PR_SetError( PR_NOT_IMPLEMENTED_ERROR, 0 ); 1.236 + return PR_FAILURE; 1.237 +#endif 1.238 + } 1.239 + case PR_SockOpt_Reuseaddr: 1.240 + case PR_SockOpt_Keepalive: 1.241 + case PR_SockOpt_NoDelay: 1.242 + case PR_SockOpt_Broadcast: 1.243 + case PR_SockOpt_Reuseport: 1.244 + { 1.245 +#ifdef WIN32 /* Winsock */ 1.246 + BOOL value; 1.247 +#else 1.248 + PRIntn value; 1.249 +#endif 1.250 + value = (data->value.reuse_addr) ? 1 : 0; 1.251 + rv = _PR_MD_SETSOCKOPT( 1.252 + fd, level, name, (char*)&value, sizeof(value)); 1.253 + break; 1.254 + } 1.255 + case PR_SockOpt_McastLoopback: 1.256 + { 1.257 +#ifdef WIN32 /* Winsock */ 1.258 + BOOL bool; 1.259 +#else 1.260 + PRUint8 bool; 1.261 +#endif 1.262 + bool = data->value.mcast_loopback ? 1 : 0; 1.263 + rv = _PR_MD_SETSOCKOPT( 1.264 + fd, level, name, (char*)&bool, sizeof(bool)); 1.265 + break; 1.266 + } 1.267 + case PR_SockOpt_RecvBufferSize: 1.268 + case PR_SockOpt_SendBufferSize: 1.269 + case PR_SockOpt_MaxSegment: 1.270 + { 1.271 + PRIntn value = data->value.recv_buffer_size; 1.272 + rv = _PR_MD_SETSOCKOPT( 1.273 + fd, level, name, (char*)&value, sizeof(value)); 1.274 + break; 1.275 + } 1.276 + case PR_SockOpt_IpTimeToLive: 1.277 + case PR_SockOpt_IpTypeOfService: 1.278 + { 1.279 + /* These options should really be an int (or PRIntn). */ 1.280 + rv = _PR_MD_SETSOCKOPT( 1.281 + fd, level, name, (char*)&data->value.ip_ttl, sizeof(PRUintn)); 1.282 + break; 1.283 + } 1.284 + case PR_SockOpt_McastTimeToLive: 1.285 + { 1.286 +#ifdef WIN32 /* Winsock */ 1.287 + int ttl; 1.288 +#else 1.289 + PRUint8 ttl; 1.290 +#endif 1.291 + ttl = data->value.mcast_ttl; 1.292 + rv = _PR_MD_SETSOCKOPT( 1.293 + fd, level, name, (char*)&ttl, sizeof(ttl)); 1.294 + break; 1.295 + } 1.296 +#ifdef IP_ADD_MEMBERSHIP 1.297 + case PR_SockOpt_AddMember: 1.298 + case PR_SockOpt_DropMember: 1.299 + { 1.300 + struct ip_mreq mreq; 1.301 + mreq.imr_multiaddr.s_addr = 1.302 + data->value.add_member.mcaddr.inet.ip; 1.303 + mreq.imr_interface.s_addr = 1.304 + data->value.add_member.ifaddr.inet.ip; 1.305 + rv = _PR_MD_SETSOCKOPT( 1.306 + fd, level, name, (char*)&mreq, sizeof(mreq)); 1.307 + break; 1.308 + } 1.309 +#endif /* IP_ADD_MEMBERSHIP */ 1.310 + case PR_SockOpt_McastInterface: 1.311 + { 1.312 + /* This option is a struct in_addr. */ 1.313 + rv = _PR_MD_SETSOCKOPT( 1.314 + fd, level, name, (char*)&data->value.mcast_if.inet.ip, 1.315 + sizeof(data->value.mcast_if.inet.ip)); 1.316 + break; 1.317 + } 1.318 + default: 1.319 + PR_NOT_REACHED("Unknown socket option"); 1.320 + break; 1.321 + } 1.322 + } 1.323 + return rv; 1.324 +} /* _PR_SocketSetSocketOption */ 1.325 + 1.326 +#endif /* ! _PR_PTHREADS */ 1.327 + 1.328 +/* 1.329 + ********************************************************************* 1.330 + ********************************************************************* 1.331 + ** 1.332 + ** Make sure that the following is at the end of this file, 1.333 + ** because we will be playing with macro redefines. 1.334 + ** 1.335 + ********************************************************************* 1.336 + ********************************************************************* 1.337 + */ 1.338 + 1.339 +/* 1.340 + * Not every platform has all the socket options we want to 1.341 + * support. Some older operating systems such as SunOS 4.1.3 1.342 + * don't have the IP multicast socket options. Win32 doesn't 1.343 + * have TCP_MAXSEG. 1.344 + * 1.345 + * To deal with this problem, we define the missing socket 1.346 + * options as _PR_NO_SUCH_SOCKOPT. _PR_MapOptionName() fails with 1.347 + * PR_OPERATION_NOT_SUPPORTED_ERROR if a socket option not 1.348 + * available on the platform is requested. 1.349 + */ 1.350 + 1.351 +/* 1.352 + * Sanity check. SO_LINGER and TCP_NODELAY should be available 1.353 + * on all platforms. Just to make sure we have included the 1.354 + * appropriate header files. Then any undefined socket options 1.355 + * are really missing. 1.356 + */ 1.357 + 1.358 +#if !defined(SO_LINGER) 1.359 +#error "SO_LINGER is not defined" 1.360 +#endif 1.361 + 1.362 +#if !defined(TCP_NODELAY) 1.363 +#error "TCP_NODELAY is not defined" 1.364 +#endif 1.365 + 1.366 +/* 1.367 + * Make sure the value of _PR_NO_SUCH_SOCKOPT is not 1.368 + * a valid socket option. 1.369 + */ 1.370 +#define _PR_NO_SUCH_SOCKOPT -1 1.371 + 1.372 +#ifndef SO_KEEPALIVE 1.373 +#define SO_KEEPALIVE _PR_NO_SUCH_SOCKOPT 1.374 +#endif 1.375 + 1.376 +#ifndef SO_SNDBUF 1.377 +#define SO_SNDBUF _PR_NO_SUCH_SOCKOPT 1.378 +#endif 1.379 + 1.380 +#ifndef SO_RCVBUF 1.381 +#define SO_RCVBUF _PR_NO_SUCH_SOCKOPT 1.382 +#endif 1.383 + 1.384 +#ifndef IP_MULTICAST_IF /* set/get IP multicast interface */ 1.385 +#define IP_MULTICAST_IF _PR_NO_SUCH_SOCKOPT 1.386 +#endif 1.387 + 1.388 +#ifndef IP_MULTICAST_TTL /* set/get IP multicast timetolive */ 1.389 +#define IP_MULTICAST_TTL _PR_NO_SUCH_SOCKOPT 1.390 +#endif 1.391 + 1.392 +#ifndef IP_MULTICAST_LOOP /* set/get IP multicast loopback */ 1.393 +#define IP_MULTICAST_LOOP _PR_NO_SUCH_SOCKOPT 1.394 +#endif 1.395 + 1.396 +#ifndef IP_ADD_MEMBERSHIP /* add an IP group membership */ 1.397 +#define IP_ADD_MEMBERSHIP _PR_NO_SUCH_SOCKOPT 1.398 +#endif 1.399 + 1.400 +#ifndef IP_DROP_MEMBERSHIP /* drop an IP group membership */ 1.401 +#define IP_DROP_MEMBERSHIP _PR_NO_SUCH_SOCKOPT 1.402 +#endif 1.403 + 1.404 +#ifndef IP_TTL /* set/get IP Time To Live */ 1.405 +#define IP_TTL _PR_NO_SUCH_SOCKOPT 1.406 +#endif 1.407 + 1.408 +#ifndef IP_TOS /* set/get IP Type Of Service */ 1.409 +#define IP_TOS _PR_NO_SUCH_SOCKOPT 1.410 +#endif 1.411 + 1.412 +#ifndef TCP_NODELAY /* don't delay to coalesce data */ 1.413 +#define TCP_NODELAY _PR_NO_SUCH_SOCKOPT 1.414 +#endif 1.415 + 1.416 +#ifndef TCP_MAXSEG /* maxumum segment size for tcp */ 1.417 +#define TCP_MAXSEG _PR_NO_SUCH_SOCKOPT 1.418 +#endif 1.419 + 1.420 +#ifndef SO_BROADCAST /* enable broadcast on UDP sockets */ 1.421 +#define SO_BROADCAST _PR_NO_SUCH_SOCKOPT 1.422 +#endif 1.423 + 1.424 +#ifndef SO_REUSEPORT /* allow local address & port reuse */ 1.425 +#define SO_REUSEPORT _PR_NO_SUCH_SOCKOPT 1.426 +#endif 1.427 + 1.428 +PRStatus _PR_MapOptionName( 1.429 + PRSockOption optname, PRInt32 *level, PRInt32 *name) 1.430 +{ 1.431 + static PRInt32 socketOptions[PR_SockOpt_Last] = 1.432 + { 1.433 + 0, SO_LINGER, SO_REUSEADDR, SO_KEEPALIVE, SO_RCVBUF, SO_SNDBUF, 1.434 + IP_TTL, IP_TOS, IP_ADD_MEMBERSHIP, IP_DROP_MEMBERSHIP, 1.435 + IP_MULTICAST_IF, IP_MULTICAST_TTL, IP_MULTICAST_LOOP, 1.436 + TCP_NODELAY, TCP_MAXSEG, SO_BROADCAST, SO_REUSEPORT 1.437 + }; 1.438 + static PRInt32 socketLevels[PR_SockOpt_Last] = 1.439 + { 1.440 + 0, SOL_SOCKET, SOL_SOCKET, SOL_SOCKET, SOL_SOCKET, SOL_SOCKET, 1.441 + IPPROTO_IP, IPPROTO_IP, IPPROTO_IP, IPPROTO_IP, 1.442 + IPPROTO_IP, IPPROTO_IP, IPPROTO_IP, 1.443 + IPPROTO_TCP, IPPROTO_TCP, SOL_SOCKET, SOL_SOCKET 1.444 + }; 1.445 + 1.446 + if ((optname < PR_SockOpt_Linger) 1.447 + || (optname >= PR_SockOpt_Last)) 1.448 + { 1.449 + PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); 1.450 + return PR_FAILURE; 1.451 + } 1.452 + 1.453 + if (socketOptions[optname] == _PR_NO_SUCH_SOCKOPT) 1.454 + { 1.455 + PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, 0); 1.456 + return PR_FAILURE; 1.457 + } 1.458 + *name = socketOptions[optname]; 1.459 + *level = socketLevels[optname]; 1.460 + return PR_SUCCESS; 1.461 +} /* _PR_MapOptionName */