nsprpub/pr/src/io/prmapopt.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 /*
michael@0 7 * This file defines _PR_MapOptionName(). The purpose of putting
michael@0 8 * _PR_MapOptionName() in a separate file is to work around a Winsock
michael@0 9 * header file problem on Windows NT.
michael@0 10 *
michael@0 11 * On Windows NT, if we define _WIN32_WINNT to be 0x0400 (in order
michael@0 12 * to use Service Pack 3 extensions), windows.h includes winsock2.h
michael@0 13 * (instead of winsock.h), which doesn't define many socket options
michael@0 14 * defined in winsock.h.
michael@0 15 *
michael@0 16 * We need the socket options defined in winsock.h. So this file
michael@0 17 * includes winsock.h, with _WIN32_WINNT undefined.
michael@0 18 */
michael@0 19
michael@0 20 #if defined(WINNT) || defined(__MINGW32__)
michael@0 21 #include <winsock.h>
michael@0 22 #endif
michael@0 23
michael@0 24 /* MinGW doesn't define these in its winsock.h. */
michael@0 25 #ifdef __MINGW32__
michael@0 26 #ifndef IP_TTL
michael@0 27 #define IP_TTL 7
michael@0 28 #endif
michael@0 29 #ifndef IP_TOS
michael@0 30 #define IP_TOS 8
michael@0 31 #endif
michael@0 32 #endif
michael@0 33
michael@0 34 #include "primpl.h"
michael@0 35
michael@0 36 #ifdef HAVE_NETINET_TCP_H
michael@0 37 #include <netinet/tcp.h> /* TCP_NODELAY, TCP_MAXSEG */
michael@0 38 #endif
michael@0 39
michael@0 40 #ifndef _PR_PTHREADS
michael@0 41
michael@0 42 PRStatus PR_CALLBACK _PR_SocketGetSocketOption(PRFileDesc *fd, PRSocketOptionData *data)
michael@0 43 {
michael@0 44 PRStatus rv;
michael@0 45 PRInt32 length;
michael@0 46 PRInt32 level, name;
michael@0 47
michael@0 48 /*
michael@0 49 * PR_SockOpt_Nonblocking is a special case that does not
michael@0 50 * translate to a getsockopt() call
michael@0 51 */
michael@0 52 if (PR_SockOpt_Nonblocking == data->option)
michael@0 53 {
michael@0 54 data->value.non_blocking = fd->secret->nonblocking;
michael@0 55 return PR_SUCCESS;
michael@0 56 }
michael@0 57
michael@0 58 rv = _PR_MapOptionName(data->option, &level, &name);
michael@0 59 if (PR_SUCCESS == rv)
michael@0 60 {
michael@0 61 switch (data->option)
michael@0 62 {
michael@0 63 case PR_SockOpt_Linger:
michael@0 64 {
michael@0 65 #if !defined(XP_BEOS) || defined(BONE_VERSION)
michael@0 66 struct linger linger;
michael@0 67 length = sizeof(linger);
michael@0 68 rv = _PR_MD_GETSOCKOPT(
michael@0 69 fd, level, name, (char *) &linger, &length);
michael@0 70 if (PR_SUCCESS == rv)
michael@0 71 {
michael@0 72 PR_ASSERT(sizeof(linger) == length);
michael@0 73 data->value.linger.polarity =
michael@0 74 (linger.l_onoff) ? PR_TRUE : PR_FALSE;
michael@0 75 data->value.linger.linger =
michael@0 76 PR_SecondsToInterval(linger.l_linger);
michael@0 77 }
michael@0 78 break;
michael@0 79 #else
michael@0 80 PR_SetError( PR_NOT_IMPLEMENTED_ERROR, 0 );
michael@0 81 return PR_FAILURE;
michael@0 82 #endif
michael@0 83 }
michael@0 84 case PR_SockOpt_Reuseaddr:
michael@0 85 case PR_SockOpt_Keepalive:
michael@0 86 case PR_SockOpt_NoDelay:
michael@0 87 case PR_SockOpt_Broadcast:
michael@0 88 case PR_SockOpt_Reuseport:
michael@0 89 {
michael@0 90 #ifdef WIN32 /* Winsock */
michael@0 91 BOOL value;
michael@0 92 #else
michael@0 93 PRIntn value;
michael@0 94 #endif
michael@0 95 length = sizeof(value);
michael@0 96 rv = _PR_MD_GETSOCKOPT(
michael@0 97 fd, level, name, (char*)&value, &length);
michael@0 98 if (PR_SUCCESS == rv)
michael@0 99 data->value.reuse_addr = (0 == value) ? PR_FALSE : PR_TRUE;
michael@0 100 break;
michael@0 101 }
michael@0 102 case PR_SockOpt_McastLoopback:
michael@0 103 {
michael@0 104 #ifdef WIN32 /* Winsock */
michael@0 105 BOOL bool;
michael@0 106 #else
michael@0 107 PRUint8 bool;
michael@0 108 #endif
michael@0 109 length = sizeof(bool);
michael@0 110 rv = _PR_MD_GETSOCKOPT(
michael@0 111 fd, level, name, (char*)&bool, &length);
michael@0 112 if (PR_SUCCESS == rv)
michael@0 113 data->value.mcast_loopback = (0 == bool) ? PR_FALSE : PR_TRUE;
michael@0 114 break;
michael@0 115 }
michael@0 116 case PR_SockOpt_RecvBufferSize:
michael@0 117 case PR_SockOpt_SendBufferSize:
michael@0 118 case PR_SockOpt_MaxSegment:
michael@0 119 {
michael@0 120 PRIntn value;
michael@0 121 length = sizeof(value);
michael@0 122 rv = _PR_MD_GETSOCKOPT(
michael@0 123 fd, level, name, (char*)&value, &length);
michael@0 124 if (PR_SUCCESS == rv)
michael@0 125 data->value.recv_buffer_size = value;
michael@0 126 break;
michael@0 127 }
michael@0 128 case PR_SockOpt_IpTimeToLive:
michael@0 129 case PR_SockOpt_IpTypeOfService:
michael@0 130 {
michael@0 131 /* These options should really be an int (or PRIntn). */
michael@0 132 length = sizeof(PRUintn);
michael@0 133 rv = _PR_MD_GETSOCKOPT(
michael@0 134 fd, level, name, (char*)&data->value.ip_ttl, &length);
michael@0 135 break;
michael@0 136 }
michael@0 137 case PR_SockOpt_McastTimeToLive:
michael@0 138 {
michael@0 139 #ifdef WIN32 /* Winsock */
michael@0 140 int ttl;
michael@0 141 #else
michael@0 142 PRUint8 ttl;
michael@0 143 #endif
michael@0 144 length = sizeof(ttl);
michael@0 145 rv = _PR_MD_GETSOCKOPT(
michael@0 146 fd, level, name, (char*)&ttl, &length);
michael@0 147 if (PR_SUCCESS == rv)
michael@0 148 data->value.mcast_ttl = ttl;
michael@0 149 break;
michael@0 150 }
michael@0 151 #ifdef IP_ADD_MEMBERSHIP
michael@0 152 case PR_SockOpt_AddMember:
michael@0 153 case PR_SockOpt_DropMember:
michael@0 154 {
michael@0 155 struct ip_mreq mreq;
michael@0 156 length = sizeof(mreq);
michael@0 157 rv = _PR_MD_GETSOCKOPT(
michael@0 158 fd, level, name, (char*)&mreq, &length);
michael@0 159 if (PR_SUCCESS == rv)
michael@0 160 {
michael@0 161 data->value.add_member.mcaddr.inet.ip =
michael@0 162 mreq.imr_multiaddr.s_addr;
michael@0 163 data->value.add_member.ifaddr.inet.ip =
michael@0 164 mreq.imr_interface.s_addr;
michael@0 165 }
michael@0 166 break;
michael@0 167 }
michael@0 168 #endif /* IP_ADD_MEMBERSHIP */
michael@0 169 case PR_SockOpt_McastInterface:
michael@0 170 {
michael@0 171 /* This option is a struct in_addr. */
michael@0 172 length = sizeof(data->value.mcast_if.inet.ip);
michael@0 173 rv = _PR_MD_GETSOCKOPT(
michael@0 174 fd, level, name,
michael@0 175 (char*)&data->value.mcast_if.inet.ip, &length);
michael@0 176 break;
michael@0 177 }
michael@0 178 default:
michael@0 179 PR_NOT_REACHED("Unknown socket option");
michael@0 180 break;
michael@0 181 }
michael@0 182 }
michael@0 183 return rv;
michael@0 184 } /* _PR_SocketGetSocketOption */
michael@0 185
michael@0 186 PRStatus PR_CALLBACK _PR_SocketSetSocketOption(PRFileDesc *fd, const PRSocketOptionData *data)
michael@0 187 {
michael@0 188 PRStatus rv;
michael@0 189 PRInt32 level, name;
michael@0 190
michael@0 191 /*
michael@0 192 * PR_SockOpt_Nonblocking is a special case that does not
michael@0 193 * translate to a setsockopt call.
michael@0 194 */
michael@0 195 if (PR_SockOpt_Nonblocking == data->option)
michael@0 196 {
michael@0 197 #ifdef WINNT
michael@0 198 PR_ASSERT((fd->secret->md.io_model_committed == PR_FALSE)
michael@0 199 || (fd->secret->nonblocking == data->value.non_blocking));
michael@0 200 if (fd->secret->md.io_model_committed
michael@0 201 && (fd->secret->nonblocking != data->value.non_blocking))
michael@0 202 {
michael@0 203 /*
michael@0 204 * On NT, once we have associated a socket with the io
michael@0 205 * completion port, we can't disassociate it. So we
michael@0 206 * can't change the nonblocking option of the socket
michael@0 207 * afterwards.
michael@0 208 */
michael@0 209 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
michael@0 210 return PR_FAILURE;
michael@0 211 }
michael@0 212 #endif
michael@0 213 fd->secret->nonblocking = data->value.non_blocking;
michael@0 214 return PR_SUCCESS;
michael@0 215 }
michael@0 216
michael@0 217 rv = _PR_MapOptionName(data->option, &level, &name);
michael@0 218 if (PR_SUCCESS == rv)
michael@0 219 {
michael@0 220 switch (data->option)
michael@0 221 {
michael@0 222 case PR_SockOpt_Linger:
michael@0 223 {
michael@0 224 #if !defined(XP_BEOS) || defined(BONE_VERSION)
michael@0 225 struct linger linger;
michael@0 226 linger.l_onoff = data->value.linger.polarity;
michael@0 227 linger.l_linger = PR_IntervalToSeconds(data->value.linger.linger);
michael@0 228 rv = _PR_MD_SETSOCKOPT(
michael@0 229 fd, level, name, (char*)&linger, sizeof(linger));
michael@0 230 break;
michael@0 231 #else
michael@0 232 PR_SetError( PR_NOT_IMPLEMENTED_ERROR, 0 );
michael@0 233 return PR_FAILURE;
michael@0 234 #endif
michael@0 235 }
michael@0 236 case PR_SockOpt_Reuseaddr:
michael@0 237 case PR_SockOpt_Keepalive:
michael@0 238 case PR_SockOpt_NoDelay:
michael@0 239 case PR_SockOpt_Broadcast:
michael@0 240 case PR_SockOpt_Reuseport:
michael@0 241 {
michael@0 242 #ifdef WIN32 /* Winsock */
michael@0 243 BOOL value;
michael@0 244 #else
michael@0 245 PRIntn value;
michael@0 246 #endif
michael@0 247 value = (data->value.reuse_addr) ? 1 : 0;
michael@0 248 rv = _PR_MD_SETSOCKOPT(
michael@0 249 fd, level, name, (char*)&value, sizeof(value));
michael@0 250 break;
michael@0 251 }
michael@0 252 case PR_SockOpt_McastLoopback:
michael@0 253 {
michael@0 254 #ifdef WIN32 /* Winsock */
michael@0 255 BOOL bool;
michael@0 256 #else
michael@0 257 PRUint8 bool;
michael@0 258 #endif
michael@0 259 bool = data->value.mcast_loopback ? 1 : 0;
michael@0 260 rv = _PR_MD_SETSOCKOPT(
michael@0 261 fd, level, name, (char*)&bool, sizeof(bool));
michael@0 262 break;
michael@0 263 }
michael@0 264 case PR_SockOpt_RecvBufferSize:
michael@0 265 case PR_SockOpt_SendBufferSize:
michael@0 266 case PR_SockOpt_MaxSegment:
michael@0 267 {
michael@0 268 PRIntn value = data->value.recv_buffer_size;
michael@0 269 rv = _PR_MD_SETSOCKOPT(
michael@0 270 fd, level, name, (char*)&value, sizeof(value));
michael@0 271 break;
michael@0 272 }
michael@0 273 case PR_SockOpt_IpTimeToLive:
michael@0 274 case PR_SockOpt_IpTypeOfService:
michael@0 275 {
michael@0 276 /* These options should really be an int (or PRIntn). */
michael@0 277 rv = _PR_MD_SETSOCKOPT(
michael@0 278 fd, level, name, (char*)&data->value.ip_ttl, sizeof(PRUintn));
michael@0 279 break;
michael@0 280 }
michael@0 281 case PR_SockOpt_McastTimeToLive:
michael@0 282 {
michael@0 283 #ifdef WIN32 /* Winsock */
michael@0 284 int ttl;
michael@0 285 #else
michael@0 286 PRUint8 ttl;
michael@0 287 #endif
michael@0 288 ttl = data->value.mcast_ttl;
michael@0 289 rv = _PR_MD_SETSOCKOPT(
michael@0 290 fd, level, name, (char*)&ttl, sizeof(ttl));
michael@0 291 break;
michael@0 292 }
michael@0 293 #ifdef IP_ADD_MEMBERSHIP
michael@0 294 case PR_SockOpt_AddMember:
michael@0 295 case PR_SockOpt_DropMember:
michael@0 296 {
michael@0 297 struct ip_mreq mreq;
michael@0 298 mreq.imr_multiaddr.s_addr =
michael@0 299 data->value.add_member.mcaddr.inet.ip;
michael@0 300 mreq.imr_interface.s_addr =
michael@0 301 data->value.add_member.ifaddr.inet.ip;
michael@0 302 rv = _PR_MD_SETSOCKOPT(
michael@0 303 fd, level, name, (char*)&mreq, sizeof(mreq));
michael@0 304 break;
michael@0 305 }
michael@0 306 #endif /* IP_ADD_MEMBERSHIP */
michael@0 307 case PR_SockOpt_McastInterface:
michael@0 308 {
michael@0 309 /* This option is a struct in_addr. */
michael@0 310 rv = _PR_MD_SETSOCKOPT(
michael@0 311 fd, level, name, (char*)&data->value.mcast_if.inet.ip,
michael@0 312 sizeof(data->value.mcast_if.inet.ip));
michael@0 313 break;
michael@0 314 }
michael@0 315 default:
michael@0 316 PR_NOT_REACHED("Unknown socket option");
michael@0 317 break;
michael@0 318 }
michael@0 319 }
michael@0 320 return rv;
michael@0 321 } /* _PR_SocketSetSocketOption */
michael@0 322
michael@0 323 #endif /* ! _PR_PTHREADS */
michael@0 324
michael@0 325 /*
michael@0 326 *********************************************************************
michael@0 327 *********************************************************************
michael@0 328 **
michael@0 329 ** Make sure that the following is at the end of this file,
michael@0 330 ** because we will be playing with macro redefines.
michael@0 331 **
michael@0 332 *********************************************************************
michael@0 333 *********************************************************************
michael@0 334 */
michael@0 335
michael@0 336 /*
michael@0 337 * Not every platform has all the socket options we want to
michael@0 338 * support. Some older operating systems such as SunOS 4.1.3
michael@0 339 * don't have the IP multicast socket options. Win32 doesn't
michael@0 340 * have TCP_MAXSEG.
michael@0 341 *
michael@0 342 * To deal with this problem, we define the missing socket
michael@0 343 * options as _PR_NO_SUCH_SOCKOPT. _PR_MapOptionName() fails with
michael@0 344 * PR_OPERATION_NOT_SUPPORTED_ERROR if a socket option not
michael@0 345 * available on the platform is requested.
michael@0 346 */
michael@0 347
michael@0 348 /*
michael@0 349 * Sanity check. SO_LINGER and TCP_NODELAY should be available
michael@0 350 * on all platforms. Just to make sure we have included the
michael@0 351 * appropriate header files. Then any undefined socket options
michael@0 352 * are really missing.
michael@0 353 */
michael@0 354
michael@0 355 #if !defined(SO_LINGER)
michael@0 356 #error "SO_LINGER is not defined"
michael@0 357 #endif
michael@0 358
michael@0 359 #if !defined(TCP_NODELAY)
michael@0 360 #error "TCP_NODELAY is not defined"
michael@0 361 #endif
michael@0 362
michael@0 363 /*
michael@0 364 * Make sure the value of _PR_NO_SUCH_SOCKOPT is not
michael@0 365 * a valid socket option.
michael@0 366 */
michael@0 367 #define _PR_NO_SUCH_SOCKOPT -1
michael@0 368
michael@0 369 #ifndef SO_KEEPALIVE
michael@0 370 #define SO_KEEPALIVE _PR_NO_SUCH_SOCKOPT
michael@0 371 #endif
michael@0 372
michael@0 373 #ifndef SO_SNDBUF
michael@0 374 #define SO_SNDBUF _PR_NO_SUCH_SOCKOPT
michael@0 375 #endif
michael@0 376
michael@0 377 #ifndef SO_RCVBUF
michael@0 378 #define SO_RCVBUF _PR_NO_SUCH_SOCKOPT
michael@0 379 #endif
michael@0 380
michael@0 381 #ifndef IP_MULTICAST_IF /* set/get IP multicast interface */
michael@0 382 #define IP_MULTICAST_IF _PR_NO_SUCH_SOCKOPT
michael@0 383 #endif
michael@0 384
michael@0 385 #ifndef IP_MULTICAST_TTL /* set/get IP multicast timetolive */
michael@0 386 #define IP_MULTICAST_TTL _PR_NO_SUCH_SOCKOPT
michael@0 387 #endif
michael@0 388
michael@0 389 #ifndef IP_MULTICAST_LOOP /* set/get IP multicast loopback */
michael@0 390 #define IP_MULTICAST_LOOP _PR_NO_SUCH_SOCKOPT
michael@0 391 #endif
michael@0 392
michael@0 393 #ifndef IP_ADD_MEMBERSHIP /* add an IP group membership */
michael@0 394 #define IP_ADD_MEMBERSHIP _PR_NO_SUCH_SOCKOPT
michael@0 395 #endif
michael@0 396
michael@0 397 #ifndef IP_DROP_MEMBERSHIP /* drop an IP group membership */
michael@0 398 #define IP_DROP_MEMBERSHIP _PR_NO_SUCH_SOCKOPT
michael@0 399 #endif
michael@0 400
michael@0 401 #ifndef IP_TTL /* set/get IP Time To Live */
michael@0 402 #define IP_TTL _PR_NO_SUCH_SOCKOPT
michael@0 403 #endif
michael@0 404
michael@0 405 #ifndef IP_TOS /* set/get IP Type Of Service */
michael@0 406 #define IP_TOS _PR_NO_SUCH_SOCKOPT
michael@0 407 #endif
michael@0 408
michael@0 409 #ifndef TCP_NODELAY /* don't delay to coalesce data */
michael@0 410 #define TCP_NODELAY _PR_NO_SUCH_SOCKOPT
michael@0 411 #endif
michael@0 412
michael@0 413 #ifndef TCP_MAXSEG /* maxumum segment size for tcp */
michael@0 414 #define TCP_MAXSEG _PR_NO_SUCH_SOCKOPT
michael@0 415 #endif
michael@0 416
michael@0 417 #ifndef SO_BROADCAST /* enable broadcast on UDP sockets */
michael@0 418 #define SO_BROADCAST _PR_NO_SUCH_SOCKOPT
michael@0 419 #endif
michael@0 420
michael@0 421 #ifndef SO_REUSEPORT /* allow local address & port reuse */
michael@0 422 #define SO_REUSEPORT _PR_NO_SUCH_SOCKOPT
michael@0 423 #endif
michael@0 424
michael@0 425 PRStatus _PR_MapOptionName(
michael@0 426 PRSockOption optname, PRInt32 *level, PRInt32 *name)
michael@0 427 {
michael@0 428 static PRInt32 socketOptions[PR_SockOpt_Last] =
michael@0 429 {
michael@0 430 0, SO_LINGER, SO_REUSEADDR, SO_KEEPALIVE, SO_RCVBUF, SO_SNDBUF,
michael@0 431 IP_TTL, IP_TOS, IP_ADD_MEMBERSHIP, IP_DROP_MEMBERSHIP,
michael@0 432 IP_MULTICAST_IF, IP_MULTICAST_TTL, IP_MULTICAST_LOOP,
michael@0 433 TCP_NODELAY, TCP_MAXSEG, SO_BROADCAST, SO_REUSEPORT
michael@0 434 };
michael@0 435 static PRInt32 socketLevels[PR_SockOpt_Last] =
michael@0 436 {
michael@0 437 0, SOL_SOCKET, SOL_SOCKET, SOL_SOCKET, SOL_SOCKET, SOL_SOCKET,
michael@0 438 IPPROTO_IP, IPPROTO_IP, IPPROTO_IP, IPPROTO_IP,
michael@0 439 IPPROTO_IP, IPPROTO_IP, IPPROTO_IP,
michael@0 440 IPPROTO_TCP, IPPROTO_TCP, SOL_SOCKET, SOL_SOCKET
michael@0 441 };
michael@0 442
michael@0 443 if ((optname < PR_SockOpt_Linger)
michael@0 444 || (optname >= PR_SockOpt_Last))
michael@0 445 {
michael@0 446 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
michael@0 447 return PR_FAILURE;
michael@0 448 }
michael@0 449
michael@0 450 if (socketOptions[optname] == _PR_NO_SUCH_SOCKOPT)
michael@0 451 {
michael@0 452 PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, 0);
michael@0 453 return PR_FAILURE;
michael@0 454 }
michael@0 455 *name = socketOptions[optname];
michael@0 456 *level = socketLevels[optname];
michael@0 457 return PR_SUCCESS;
michael@0 458 } /* _PR_MapOptionName */

mercurial