netwerk/base/src/nsServerSocket.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* vim:set ts=2 sw=2 et cindent: */
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 #include "nsSocketTransport2.h"
michael@0 7 #include "nsServerSocket.h"
michael@0 8 #include "nsProxyRelease.h"
michael@0 9 #include "nsAutoPtr.h"
michael@0 10 #include "nsError.h"
michael@0 11 #include "nsNetCID.h"
michael@0 12 #include "prnetdb.h"
michael@0 13 #include "prio.h"
michael@0 14 #include "nsThreadUtils.h"
michael@0 15 #include "mozilla/Attributes.h"
michael@0 16 #include "mozilla/Endian.h"
michael@0 17 #include "mozilla/net/DNS.h"
michael@0 18 #include "nsServiceManagerUtils.h"
michael@0 19 #include "nsIFile.h"
michael@0 20
michael@0 21 using namespace mozilla;
michael@0 22 using namespace mozilla::net;
michael@0 23
michael@0 24 static NS_DEFINE_CID(kSocketTransportServiceCID, NS_SOCKETTRANSPORTSERVICE_CID);
michael@0 25
michael@0 26 //-----------------------------------------------------------------------------
michael@0 27
michael@0 28 typedef void (nsServerSocket:: *nsServerSocketFunc)(void);
michael@0 29
michael@0 30 static nsresult
michael@0 31 PostEvent(nsServerSocket *s, nsServerSocketFunc func)
michael@0 32 {
michael@0 33 nsCOMPtr<nsIRunnable> ev = NS_NewRunnableMethod(s, func);
michael@0 34 if (!ev)
michael@0 35 return NS_ERROR_OUT_OF_MEMORY;
michael@0 36
michael@0 37 if (!gSocketTransportService)
michael@0 38 return NS_ERROR_FAILURE;
michael@0 39
michael@0 40 return gSocketTransportService->Dispatch(ev, NS_DISPATCH_NORMAL);
michael@0 41 }
michael@0 42
michael@0 43 //-----------------------------------------------------------------------------
michael@0 44 // nsServerSocket
michael@0 45 //-----------------------------------------------------------------------------
michael@0 46
michael@0 47 nsServerSocket::nsServerSocket()
michael@0 48 : mLock("nsServerSocket.mLock")
michael@0 49 , mFD(nullptr)
michael@0 50 , mAttached(false)
michael@0 51 , mKeepWhenOffline(false)
michael@0 52 {
michael@0 53 // we want to be able to access the STS directly, and it may not have been
michael@0 54 // constructed yet. the STS constructor sets gSocketTransportService.
michael@0 55 if (!gSocketTransportService)
michael@0 56 {
michael@0 57 // This call can fail if we're offline, for example.
michael@0 58 nsCOMPtr<nsISocketTransportService> sts =
michael@0 59 do_GetService(kSocketTransportServiceCID);
michael@0 60 }
michael@0 61 // make sure the STS sticks around as long as we do
michael@0 62 NS_IF_ADDREF(gSocketTransportService);
michael@0 63 }
michael@0 64
michael@0 65 nsServerSocket::~nsServerSocket()
michael@0 66 {
michael@0 67 Close(); // just in case :)
michael@0 68
michael@0 69 // release our reference to the STS
michael@0 70 nsSocketTransportService *serv = gSocketTransportService;
michael@0 71 NS_IF_RELEASE(serv);
michael@0 72 }
michael@0 73
michael@0 74 void
michael@0 75 nsServerSocket::OnMsgClose()
michael@0 76 {
michael@0 77 SOCKET_LOG(("nsServerSocket::OnMsgClose [this=%p]\n", this));
michael@0 78
michael@0 79 if (NS_FAILED(mCondition))
michael@0 80 return;
michael@0 81
michael@0 82 // tear down socket. this signals the STS to detach our socket handler.
michael@0 83 mCondition = NS_BINDING_ABORTED;
michael@0 84
michael@0 85 // if we are attached, then we'll close the socket in our OnSocketDetached.
michael@0 86 // otherwise, call OnSocketDetached from here.
michael@0 87 if (!mAttached)
michael@0 88 OnSocketDetached(mFD);
michael@0 89 }
michael@0 90
michael@0 91 void
michael@0 92 nsServerSocket::OnMsgAttach()
michael@0 93 {
michael@0 94 SOCKET_LOG(("nsServerSocket::OnMsgAttach [this=%p]\n", this));
michael@0 95
michael@0 96 if (NS_FAILED(mCondition))
michael@0 97 return;
michael@0 98
michael@0 99 mCondition = TryAttach();
michael@0 100
michael@0 101 // if we hit an error while trying to attach then bail...
michael@0 102 if (NS_FAILED(mCondition))
michael@0 103 {
michael@0 104 NS_ASSERTION(!mAttached, "should not be attached already");
michael@0 105 OnSocketDetached(mFD);
michael@0 106 }
michael@0 107 }
michael@0 108
michael@0 109 nsresult
michael@0 110 nsServerSocket::TryAttach()
michael@0 111 {
michael@0 112 nsresult rv;
michael@0 113
michael@0 114 if (!gSocketTransportService)
michael@0 115 return NS_ERROR_FAILURE;
michael@0 116
michael@0 117 //
michael@0 118 // find out if it is going to be ok to attach another socket to the STS.
michael@0 119 // if not then we have to wait for the STS to tell us that it is ok.
michael@0 120 // the notification is asynchronous, which means that when we could be
michael@0 121 // in a race to call AttachSocket once notified. for this reason, when
michael@0 122 // we get notified, we just re-enter this function. as a result, we are
michael@0 123 // sure to ask again before calling AttachSocket. in this way we deal
michael@0 124 // with the race condition. though it isn't the most elegant solution,
michael@0 125 // it is far simpler than trying to build a system that would guarantee
michael@0 126 // FIFO ordering (which wouldn't even be that valuable IMO). see bug
michael@0 127 // 194402 for more info.
michael@0 128 //
michael@0 129 if (!gSocketTransportService->CanAttachSocket())
michael@0 130 {
michael@0 131 nsCOMPtr<nsIRunnable> event =
michael@0 132 NS_NewRunnableMethod(this, &nsServerSocket::OnMsgAttach);
michael@0 133 if (!event)
michael@0 134 return NS_ERROR_OUT_OF_MEMORY;
michael@0 135
michael@0 136 nsresult rv = gSocketTransportService->NotifyWhenCanAttachSocket(event);
michael@0 137 if (NS_FAILED(rv))
michael@0 138 return rv;
michael@0 139 }
michael@0 140
michael@0 141 //
michael@0 142 // ok, we can now attach our socket to the STS for polling
michael@0 143 //
michael@0 144 rv = gSocketTransportService->AttachSocket(mFD, this);
michael@0 145 if (NS_FAILED(rv))
michael@0 146 return rv;
michael@0 147
michael@0 148 mAttached = true;
michael@0 149
michael@0 150 //
michael@0 151 // now, configure our poll flags for listening...
michael@0 152 //
michael@0 153 mPollFlags = (PR_POLL_READ | PR_POLL_EXCEPT);
michael@0 154 return NS_OK;
michael@0 155 }
michael@0 156
michael@0 157 //-----------------------------------------------------------------------------
michael@0 158 // nsServerSocket::nsASocketHandler
michael@0 159 //-----------------------------------------------------------------------------
michael@0 160
michael@0 161 void
michael@0 162 nsServerSocket::OnSocketReady(PRFileDesc *fd, int16_t outFlags)
michael@0 163 {
michael@0 164 NS_ASSERTION(NS_SUCCEEDED(mCondition), "oops");
michael@0 165 NS_ASSERTION(mFD == fd, "wrong file descriptor");
michael@0 166 NS_ASSERTION(outFlags != -1, "unexpected timeout condition reached");
michael@0 167
michael@0 168 if (outFlags & (PR_POLL_ERR | PR_POLL_HUP | PR_POLL_NVAL))
michael@0 169 {
michael@0 170 NS_WARNING("error polling on listening socket");
michael@0 171 mCondition = NS_ERROR_UNEXPECTED;
michael@0 172 return;
michael@0 173 }
michael@0 174
michael@0 175 PRFileDesc *clientFD;
michael@0 176 PRNetAddr prClientAddr;
michael@0 177 NetAddr clientAddr;
michael@0 178
michael@0 179 // NSPR doesn't tell us the peer address's length (as provided by the
michael@0 180 // 'accept' system call), so we can't distinguish between named,
michael@0 181 // unnamed, and abstract peer addresses. Clear prClientAddr first, so
michael@0 182 // that the path will at least be reliably empty for unnamed and
michael@0 183 // abstract addresses, and not garbage when the peer is unnamed.
michael@0 184 memset(&prClientAddr, 0, sizeof(prClientAddr));
michael@0 185
michael@0 186 clientFD = PR_Accept(mFD, &prClientAddr, PR_INTERVAL_NO_WAIT);
michael@0 187 PRNetAddrToNetAddr(&prClientAddr, &clientAddr);
michael@0 188 if (!clientFD)
michael@0 189 {
michael@0 190 NS_WARNING("PR_Accept failed");
michael@0 191 mCondition = NS_ERROR_UNEXPECTED;
michael@0 192 }
michael@0 193 else
michael@0 194 {
michael@0 195 nsRefPtr<nsSocketTransport> trans = new nsSocketTransport;
michael@0 196 if (!trans)
michael@0 197 mCondition = NS_ERROR_OUT_OF_MEMORY;
michael@0 198 else
michael@0 199 {
michael@0 200 nsresult rv = trans->InitWithConnectedSocket(clientFD, &clientAddr);
michael@0 201 if (NS_FAILED(rv))
michael@0 202 mCondition = rv;
michael@0 203 else
michael@0 204 mListener->OnSocketAccepted(this, trans);
michael@0 205 }
michael@0 206 }
michael@0 207 }
michael@0 208
michael@0 209 void
michael@0 210 nsServerSocket::OnSocketDetached(PRFileDesc *fd)
michael@0 211 {
michael@0 212 // force a failure condition if none set; maybe the STS is shutting down :-/
michael@0 213 if (NS_SUCCEEDED(mCondition))
michael@0 214 mCondition = NS_ERROR_ABORT;
michael@0 215
michael@0 216 if (mFD)
michael@0 217 {
michael@0 218 NS_ASSERTION(mFD == fd, "wrong file descriptor");
michael@0 219 PR_Close(mFD);
michael@0 220 mFD = nullptr;
michael@0 221 }
michael@0 222
michael@0 223 if (mListener)
michael@0 224 {
michael@0 225 mListener->OnStopListening(this, mCondition);
michael@0 226
michael@0 227 // need to atomically clear mListener. see our Close() method.
michael@0 228 nsIServerSocketListener *listener = nullptr;
michael@0 229 {
michael@0 230 MutexAutoLock lock(mLock);
michael@0 231 mListener.swap(listener);
michael@0 232 }
michael@0 233 // XXX we need to proxy the release to the listener's target thread to work
michael@0 234 // around bug 337492.
michael@0 235 if (listener)
michael@0 236 NS_ProxyRelease(mListenerTarget, listener);
michael@0 237 }
michael@0 238 }
michael@0 239
michael@0 240 void
michael@0 241 nsServerSocket::IsLocal(bool *aIsLocal)
michael@0 242 {
michael@0 243 #if defined(XP_UNIX)
michael@0 244 // Unix-domain sockets are always local.
michael@0 245 if (mAddr.raw.family == PR_AF_LOCAL)
michael@0 246 {
michael@0 247 *aIsLocal = true;
michael@0 248 return;
michael@0 249 }
michael@0 250 #endif
michael@0 251
michael@0 252 // If bound to loopback, this server socket only accepts local connections.
michael@0 253 *aIsLocal = PR_IsNetAddrType(&mAddr, PR_IpAddrLoopback);
michael@0 254 }
michael@0 255
michael@0 256 void
michael@0 257 nsServerSocket::KeepWhenOffline(bool *aKeepWhenOffline)
michael@0 258 {
michael@0 259 *aKeepWhenOffline = mKeepWhenOffline;
michael@0 260 }
michael@0 261
michael@0 262 //-----------------------------------------------------------------------------
michael@0 263 // nsServerSocket::nsISupports
michael@0 264 //-----------------------------------------------------------------------------
michael@0 265
michael@0 266 NS_IMPL_ISUPPORTS(nsServerSocket, nsIServerSocket)
michael@0 267
michael@0 268
michael@0 269 //-----------------------------------------------------------------------------
michael@0 270 // nsServerSocket::nsIServerSocket
michael@0 271 //-----------------------------------------------------------------------------
michael@0 272
michael@0 273 NS_IMETHODIMP
michael@0 274 nsServerSocket::Init(int32_t aPort, bool aLoopbackOnly, int32_t aBackLog)
michael@0 275 {
michael@0 276 return InitSpecialConnection(aPort, aLoopbackOnly ? LoopbackOnly : 0, aBackLog);
michael@0 277 }
michael@0 278
michael@0 279 NS_IMETHODIMP
michael@0 280 nsServerSocket::InitWithFilename(nsIFile *aPath, uint32_t aPermissions, int32_t aBacklog)
michael@0 281 {
michael@0 282 #if defined(XP_UNIX)
michael@0 283 nsresult rv;
michael@0 284
michael@0 285 nsAutoCString path;
michael@0 286 rv = aPath->GetNativePath(path);
michael@0 287 if (NS_FAILED(rv))
michael@0 288 return rv;
michael@0 289
michael@0 290 // Create a Unix domain PRNetAddr referring to the given path.
michael@0 291 PRNetAddr addr;
michael@0 292 if (path.Length() > sizeof(addr.local.path) - 1)
michael@0 293 return NS_ERROR_FILE_NAME_TOO_LONG;
michael@0 294 addr.local.family = PR_AF_LOCAL;
michael@0 295 memcpy(addr.local.path, path.get(), path.Length());
michael@0 296 addr.local.path[path.Length()] = '\0';
michael@0 297
michael@0 298 rv = InitWithAddress(&addr, aBacklog);
michael@0 299 if (NS_FAILED(rv))
michael@0 300 return rv;
michael@0 301
michael@0 302 return aPath->SetPermissions(aPermissions);
michael@0 303 #else
michael@0 304 return NS_ERROR_SOCKET_ADDRESS_NOT_SUPPORTED;
michael@0 305 #endif
michael@0 306 }
michael@0 307
michael@0 308 NS_IMETHODIMP
michael@0 309 nsServerSocket::InitSpecialConnection(int32_t aPort, nsServerSocketFlag aFlags,
michael@0 310 int32_t aBackLog)
michael@0 311 {
michael@0 312 PRNetAddrValue val;
michael@0 313 PRNetAddr addr;
michael@0 314
michael@0 315 if (aPort < 0)
michael@0 316 aPort = 0;
michael@0 317 if (aFlags & nsIServerSocket::LoopbackOnly)
michael@0 318 val = PR_IpAddrLoopback;
michael@0 319 else
michael@0 320 val = PR_IpAddrAny;
michael@0 321 PR_SetNetAddr(val, PR_AF_INET, aPort, &addr);
michael@0 322
michael@0 323 mKeepWhenOffline = ((aFlags & nsIServerSocket::KeepWhenOffline) != 0);
michael@0 324 return InitWithAddress(&addr, aBackLog);
michael@0 325 }
michael@0 326
michael@0 327 NS_IMETHODIMP
michael@0 328 nsServerSocket::InitWithAddress(const PRNetAddr *aAddr, int32_t aBackLog)
michael@0 329 {
michael@0 330 NS_ENSURE_TRUE(mFD == nullptr, NS_ERROR_ALREADY_INITIALIZED);
michael@0 331
michael@0 332 //
michael@0 333 // configure listening socket...
michael@0 334 //
michael@0 335
michael@0 336 mFD = PR_OpenTCPSocket(aAddr->raw.family);
michael@0 337 if (!mFD)
michael@0 338 {
michael@0 339 NS_WARNING("unable to create server socket");
michael@0 340 return ErrorAccordingToNSPR(PR_GetError());
michael@0 341 }
michael@0 342
michael@0 343 PRSocketOptionData opt;
michael@0 344
michael@0 345 opt.option = PR_SockOpt_Reuseaddr;
michael@0 346 opt.value.reuse_addr = true;
michael@0 347 PR_SetSocketOption(mFD, &opt);
michael@0 348
michael@0 349 opt.option = PR_SockOpt_Nonblocking;
michael@0 350 opt.value.non_blocking = true;
michael@0 351 PR_SetSocketOption(mFD, &opt);
michael@0 352
michael@0 353 if (PR_Bind(mFD, aAddr) != PR_SUCCESS)
michael@0 354 {
michael@0 355 NS_WARNING("failed to bind socket");
michael@0 356 goto fail;
michael@0 357 }
michael@0 358
michael@0 359 if (aBackLog < 0)
michael@0 360 aBackLog = 5; // seems like a reasonable default
michael@0 361
michael@0 362 if (PR_Listen(mFD, aBackLog) != PR_SUCCESS)
michael@0 363 {
michael@0 364 NS_WARNING("cannot listen on socket");
michael@0 365 goto fail;
michael@0 366 }
michael@0 367
michael@0 368 // get the resulting socket address, which may be different than what
michael@0 369 // we passed to bind.
michael@0 370 if (PR_GetSockName(mFD, &mAddr) != PR_SUCCESS)
michael@0 371 {
michael@0 372 NS_WARNING("cannot get socket name");
michael@0 373 goto fail;
michael@0 374 }
michael@0 375
michael@0 376 // wait until AsyncListen is called before polling the socket for
michael@0 377 // client connections.
michael@0 378 return NS_OK;
michael@0 379
michael@0 380 fail:
michael@0 381 nsresult rv = ErrorAccordingToNSPR(PR_GetError());
michael@0 382 Close();
michael@0 383 return rv;
michael@0 384 }
michael@0 385
michael@0 386 NS_IMETHODIMP
michael@0 387 nsServerSocket::Close()
michael@0 388 {
michael@0 389 {
michael@0 390 MutexAutoLock lock(mLock);
michael@0 391 // we want to proxy the close operation to the socket thread if a listener
michael@0 392 // has been set. otherwise, we should just close the socket here...
michael@0 393 if (!mListener)
michael@0 394 {
michael@0 395 if (mFD)
michael@0 396 {
michael@0 397 PR_Close(mFD);
michael@0 398 mFD = nullptr;
michael@0 399 }
michael@0 400 return NS_OK;
michael@0 401 }
michael@0 402 }
michael@0 403 return PostEvent(this, &nsServerSocket::OnMsgClose);
michael@0 404 }
michael@0 405
michael@0 406 namespace {
michael@0 407
michael@0 408 class ServerSocketListenerProxy MOZ_FINAL : public nsIServerSocketListener
michael@0 409 {
michael@0 410 public:
michael@0 411 ServerSocketListenerProxy(nsIServerSocketListener* aListener)
michael@0 412 : mListener(new nsMainThreadPtrHolder<nsIServerSocketListener>(aListener))
michael@0 413 , mTargetThread(do_GetCurrentThread())
michael@0 414 { }
michael@0 415
michael@0 416 NS_DECL_THREADSAFE_ISUPPORTS
michael@0 417 NS_DECL_NSISERVERSOCKETLISTENER
michael@0 418
michael@0 419 class OnSocketAcceptedRunnable : public nsRunnable
michael@0 420 {
michael@0 421 public:
michael@0 422 OnSocketAcceptedRunnable(const nsMainThreadPtrHandle<nsIServerSocketListener>& aListener,
michael@0 423 nsIServerSocket* aServ,
michael@0 424 nsISocketTransport* aTransport)
michael@0 425 : mListener(aListener)
michael@0 426 , mServ(aServ)
michael@0 427 , mTransport(aTransport)
michael@0 428 { }
michael@0 429
michael@0 430 NS_DECL_NSIRUNNABLE
michael@0 431
michael@0 432 private:
michael@0 433 nsMainThreadPtrHandle<nsIServerSocketListener> mListener;
michael@0 434 nsCOMPtr<nsIServerSocket> mServ;
michael@0 435 nsCOMPtr<nsISocketTransport> mTransport;
michael@0 436 };
michael@0 437
michael@0 438 class OnStopListeningRunnable : public nsRunnable
michael@0 439 {
michael@0 440 public:
michael@0 441 OnStopListeningRunnable(const nsMainThreadPtrHandle<nsIServerSocketListener>& aListener,
michael@0 442 nsIServerSocket* aServ,
michael@0 443 nsresult aStatus)
michael@0 444 : mListener(aListener)
michael@0 445 , mServ(aServ)
michael@0 446 , mStatus(aStatus)
michael@0 447 { }
michael@0 448
michael@0 449 NS_DECL_NSIRUNNABLE
michael@0 450
michael@0 451 private:
michael@0 452 nsMainThreadPtrHandle<nsIServerSocketListener> mListener;
michael@0 453 nsCOMPtr<nsIServerSocket> mServ;
michael@0 454 nsresult mStatus;
michael@0 455 };
michael@0 456
michael@0 457 private:
michael@0 458 nsMainThreadPtrHandle<nsIServerSocketListener> mListener;
michael@0 459 nsCOMPtr<nsIEventTarget> mTargetThread;
michael@0 460 };
michael@0 461
michael@0 462 NS_IMPL_ISUPPORTS(ServerSocketListenerProxy,
michael@0 463 nsIServerSocketListener)
michael@0 464
michael@0 465 NS_IMETHODIMP
michael@0 466 ServerSocketListenerProxy::OnSocketAccepted(nsIServerSocket* aServ,
michael@0 467 nsISocketTransport* aTransport)
michael@0 468 {
michael@0 469 nsRefPtr<OnSocketAcceptedRunnable> r =
michael@0 470 new OnSocketAcceptedRunnable(mListener, aServ, aTransport);
michael@0 471 return mTargetThread->Dispatch(r, NS_DISPATCH_NORMAL);
michael@0 472 }
michael@0 473
michael@0 474 NS_IMETHODIMP
michael@0 475 ServerSocketListenerProxy::OnStopListening(nsIServerSocket* aServ,
michael@0 476 nsresult aStatus)
michael@0 477 {
michael@0 478 nsRefPtr<OnStopListeningRunnable> r =
michael@0 479 new OnStopListeningRunnable(mListener, aServ, aStatus);
michael@0 480 return mTargetThread->Dispatch(r, NS_DISPATCH_NORMAL);
michael@0 481 }
michael@0 482
michael@0 483 NS_IMETHODIMP
michael@0 484 ServerSocketListenerProxy::OnSocketAcceptedRunnable::Run()
michael@0 485 {
michael@0 486 mListener->OnSocketAccepted(mServ, mTransport);
michael@0 487 return NS_OK;
michael@0 488 }
michael@0 489
michael@0 490 NS_IMETHODIMP
michael@0 491 ServerSocketListenerProxy::OnStopListeningRunnable::Run()
michael@0 492 {
michael@0 493 mListener->OnStopListening(mServ, mStatus);
michael@0 494 return NS_OK;
michael@0 495 }
michael@0 496
michael@0 497 } // anonymous namespace
michael@0 498
michael@0 499 NS_IMETHODIMP
michael@0 500 nsServerSocket::AsyncListen(nsIServerSocketListener *aListener)
michael@0 501 {
michael@0 502 // ensuring mFD implies ensuring mLock
michael@0 503 NS_ENSURE_TRUE(mFD, NS_ERROR_NOT_INITIALIZED);
michael@0 504 NS_ENSURE_TRUE(mListener == nullptr, NS_ERROR_IN_PROGRESS);
michael@0 505 {
michael@0 506 MutexAutoLock lock(mLock);
michael@0 507 mListener = new ServerSocketListenerProxy(aListener);
michael@0 508 mListenerTarget = NS_GetCurrentThread();
michael@0 509 }
michael@0 510 return PostEvent(this, &nsServerSocket::OnMsgAttach);
michael@0 511 }
michael@0 512
michael@0 513 NS_IMETHODIMP
michael@0 514 nsServerSocket::GetPort(int32_t *aResult)
michael@0 515 {
michael@0 516 // no need to enter the lock here
michael@0 517 uint16_t port;
michael@0 518 if (mAddr.raw.family == PR_AF_INET)
michael@0 519 port = mAddr.inet.port;
michael@0 520 else if (mAddr.raw.family == PR_AF_INET6)
michael@0 521 port = mAddr.ipv6.port;
michael@0 522 else
michael@0 523 return NS_ERROR_FAILURE;
michael@0 524
michael@0 525 *aResult = static_cast<int32_t>(NetworkEndian::readUint16(&port));
michael@0 526 return NS_OK;
michael@0 527 }
michael@0 528
michael@0 529 NS_IMETHODIMP
michael@0 530 nsServerSocket::GetAddress(PRNetAddr *aResult)
michael@0 531 {
michael@0 532 // no need to enter the lock here
michael@0 533 memcpy(aResult, &mAddr, sizeof(mAddr));
michael@0 534 return NS_OK;
michael@0 535 }

mercurial