nsUDPSocket.cpp 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534
  1. /* vim:set ts=2 sw=2 et cindent: */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #include "mozilla/Attributes.h"
  6. #include "mozilla/EndianUtils.h"
  7. #include "mozilla/dom/TypedArray.h"
  8. #include "mozilla/HoldDropJSObjects.h"
  9. #include "nsSocketTransport2.h"
  10. #include "nsUDPSocket.h"
  11. #include "nsProxyRelease.h"
  12. #include "nsAutoPtr.h"
  13. #include "nsError.h"
  14. #include "nsNetCID.h"
  15. #include "nsNetUtil.h"
  16. #include "nsIOService.h"
  17. #include "prnetdb.h"
  18. #include "prio.h"
  19. #include "nsNetAddr.h"
  20. #include "nsNetSegmentUtils.h"
  21. #include "NetworkActivityMonitor.h"
  22. #include "nsServiceManagerUtils.h"
  23. #include "nsStreamUtils.h"
  24. #include "nsIPipe.h"
  25. #include "prerror.h"
  26. #include "nsThreadUtils.h"
  27. #include "nsIDNSRecord.h"
  28. #include "nsIDNSService.h"
  29. #include "nsICancelable.h"
  30. namespace mozilla {
  31. namespace net {
  32. static const uint32_t UDP_PACKET_CHUNK_SIZE = 1400;
  33. static NS_DEFINE_CID(kSocketTransportServiceCID2, NS_SOCKETTRANSPORTSERVICE_CID);
  34. //-----------------------------------------------------------------------------
  35. typedef void (nsUDPSocket:: *nsUDPSocketFunc)(void);
  36. static nsresult
  37. PostEvent(nsUDPSocket *s, nsUDPSocketFunc func)
  38. {
  39. if (!gSocketTransportService)
  40. return NS_ERROR_FAILURE;
  41. return gSocketTransportService->Dispatch(NewRunnableMethod(s, func), NS_DISPATCH_NORMAL);
  42. }
  43. static nsresult
  44. ResolveHost(const nsACString &host, nsIDNSListener *listener)
  45. {
  46. nsresult rv;
  47. nsCOMPtr<nsIDNSService> dns =
  48. do_GetService("@mozilla.org/network/dns-service;1", &rv);
  49. if (NS_FAILED(rv)) {
  50. return rv;
  51. }
  52. nsCOMPtr<nsICancelable> tmpOutstanding;
  53. return dns->AsyncResolve(host, 0, listener, nullptr,
  54. getter_AddRefs(tmpOutstanding));
  55. }
  56. //-----------------------------------------------------------------------------
  57. class SetSocketOptionRunnable : public Runnable
  58. {
  59. public:
  60. SetSocketOptionRunnable(nsUDPSocket* aSocket, const PRSocketOptionData& aOpt)
  61. : mSocket(aSocket)
  62. , mOpt(aOpt)
  63. {}
  64. NS_IMETHOD Run() override
  65. {
  66. return mSocket->SetSocketOption(mOpt);
  67. }
  68. private:
  69. RefPtr<nsUDPSocket> mSocket;
  70. PRSocketOptionData mOpt;
  71. };
  72. //-----------------------------------------------------------------------------
  73. // nsUDPOutputStream impl
  74. //-----------------------------------------------------------------------------
  75. NS_IMPL_ISUPPORTS(nsUDPOutputStream, nsIOutputStream)
  76. nsUDPOutputStream::nsUDPOutputStream(nsUDPSocket* aSocket,
  77. PRFileDesc* aFD,
  78. PRNetAddr& aPrClientAddr)
  79. : mSocket(aSocket)
  80. , mFD(aFD)
  81. , mPrClientAddr(aPrClientAddr)
  82. , mIsClosed(false)
  83. {
  84. }
  85. nsUDPOutputStream::~nsUDPOutputStream()
  86. {
  87. }
  88. NS_IMETHODIMP nsUDPOutputStream::Close()
  89. {
  90. if (mIsClosed)
  91. return NS_BASE_STREAM_CLOSED;
  92. mIsClosed = true;
  93. return NS_OK;
  94. }
  95. NS_IMETHODIMP nsUDPOutputStream::Flush()
  96. {
  97. return NS_OK;
  98. }
  99. NS_IMETHODIMP nsUDPOutputStream::Write(const char * aBuf, uint32_t aCount, uint32_t *_retval)
  100. {
  101. if (mIsClosed)
  102. return NS_BASE_STREAM_CLOSED;
  103. *_retval = 0;
  104. int32_t count = PR_SendTo(mFD, aBuf, aCount, 0, &mPrClientAddr, PR_INTERVAL_NO_WAIT);
  105. if (count < 0) {
  106. PRErrorCode code = PR_GetError();
  107. return ErrorAccordingToNSPR(code);
  108. }
  109. *_retval = count;
  110. mSocket->AddOutputBytes(count);
  111. return NS_OK;
  112. }
  113. NS_IMETHODIMP nsUDPOutputStream::WriteFrom(nsIInputStream *aFromStream, uint32_t aCount, uint32_t *_retval)
  114. {
  115. return NS_ERROR_NOT_IMPLEMENTED;
  116. }
  117. NS_IMETHODIMP nsUDPOutputStream::WriteSegments(nsReadSegmentFun aReader, void *aClosure, uint32_t aCount, uint32_t *_retval)
  118. {
  119. return NS_ERROR_NOT_IMPLEMENTED;
  120. }
  121. NS_IMETHODIMP nsUDPOutputStream::IsNonBlocking(bool *_retval)
  122. {
  123. *_retval = true;
  124. return NS_OK;
  125. }
  126. //-----------------------------------------------------------------------------
  127. // nsUDPMessage impl
  128. //-----------------------------------------------------------------------------
  129. NS_IMPL_CYCLE_COLLECTING_ADDREF(nsUDPMessage)
  130. NS_IMPL_CYCLE_COLLECTING_RELEASE(nsUDPMessage)
  131. NS_IMPL_CYCLE_COLLECTION_CLASS(nsUDPMessage)
  132. NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsUDPMessage)
  133. NS_INTERFACE_MAP_ENTRY(nsISupports)
  134. NS_INTERFACE_MAP_ENTRY(nsIUDPMessage)
  135. NS_INTERFACE_MAP_END
  136. NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsUDPMessage)
  137. NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mJsobj)
  138. NS_IMPL_CYCLE_COLLECTION_TRACE_END
  139. NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsUDPMessage)
  140. NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
  141. NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsUDPMessage)
  142. tmp->mJsobj = nullptr;
  143. NS_IMPL_CYCLE_COLLECTION_UNLINK_END
  144. nsUDPMessage::nsUDPMessage(NetAddr* aAddr,
  145. nsIOutputStream* aOutputStream,
  146. FallibleTArray<uint8_t>& aData)
  147. : mOutputStream(aOutputStream)
  148. {
  149. memcpy(&mAddr, aAddr, sizeof(NetAddr));
  150. aData.SwapElements(mData);
  151. }
  152. nsUDPMessage::~nsUDPMessage()
  153. {
  154. DropJSObjects(this);
  155. }
  156. NS_IMETHODIMP
  157. nsUDPMessage::GetFromAddr(nsINetAddr * *aFromAddr)
  158. {
  159. NS_ENSURE_ARG_POINTER(aFromAddr);
  160. nsCOMPtr<nsINetAddr> result = new nsNetAddr(&mAddr);
  161. result.forget(aFromAddr);
  162. return NS_OK;
  163. }
  164. NS_IMETHODIMP
  165. nsUDPMessage::GetData(nsACString & aData)
  166. {
  167. aData.Assign(reinterpret_cast<const char*>(mData.Elements()), mData.Length());
  168. return NS_OK;
  169. }
  170. NS_IMETHODIMP
  171. nsUDPMessage::GetOutputStream(nsIOutputStream * *aOutputStream)
  172. {
  173. NS_ENSURE_ARG_POINTER(aOutputStream);
  174. NS_IF_ADDREF(*aOutputStream = mOutputStream);
  175. return NS_OK;
  176. }
  177. NS_IMETHODIMP
  178. nsUDPMessage::GetRawData(JSContext* cx,
  179. JS::MutableHandleValue aRawData)
  180. {
  181. if(!mJsobj){
  182. mJsobj = dom::Uint8Array::Create(cx, nullptr, mData.Length(), mData.Elements());
  183. HoldJSObjects(this);
  184. }
  185. aRawData.setObject(*mJsobj);
  186. return NS_OK;
  187. }
  188. FallibleTArray<uint8_t>&
  189. nsUDPMessage::GetDataAsTArray()
  190. {
  191. return mData;
  192. }
  193. //-----------------------------------------------------------------------------
  194. // nsUDPSocket
  195. //-----------------------------------------------------------------------------
  196. nsUDPSocket::nsUDPSocket()
  197. : mLock("nsUDPSocket.mLock")
  198. , mFD(nullptr)
  199. , mAppId(NECKO_UNKNOWN_APP_ID)
  200. , mIsInIsolatedMozBrowserElement(false)
  201. , mAttached(false)
  202. , mByteReadCount(0)
  203. , mByteWriteCount(0)
  204. {
  205. mAddr.raw.family = PR_AF_UNSPEC;
  206. // we want to be able to access the STS directly, and it may not have been
  207. // constructed yet. the STS constructor sets gSocketTransportService.
  208. if (!gSocketTransportService)
  209. {
  210. // This call can fail if we're offline, for example.
  211. nsCOMPtr<nsISocketTransportService> sts =
  212. do_GetService(kSocketTransportServiceCID2);
  213. }
  214. mSts = gSocketTransportService;
  215. MOZ_COUNT_CTOR(nsUDPSocket);
  216. }
  217. nsUDPSocket::~nsUDPSocket()
  218. {
  219. CloseSocket();
  220. MOZ_COUNT_DTOR(nsUDPSocket);
  221. }
  222. void
  223. nsUDPSocket::AddOutputBytes(uint64_t aBytes)
  224. {
  225. mByteWriteCount += aBytes;
  226. }
  227. void
  228. nsUDPSocket::OnMsgClose()
  229. {
  230. UDPSOCKET_LOG(("nsUDPSocket::OnMsgClose [this=%p]\n", this));
  231. if (NS_FAILED(mCondition))
  232. return;
  233. // tear down socket. this signals the STS to detach our socket handler.
  234. mCondition = NS_BINDING_ABORTED;
  235. // if we are attached, then socket transport service will call our
  236. // OnSocketDetached method automatically. Otherwise, we have to call it
  237. // (and thus close the socket) manually.
  238. if (!mAttached)
  239. OnSocketDetached(mFD);
  240. }
  241. void
  242. nsUDPSocket::OnMsgAttach()
  243. {
  244. UDPSOCKET_LOG(("nsUDPSocket::OnMsgAttach [this=%p]\n", this));
  245. if (NS_FAILED(mCondition))
  246. return;
  247. mCondition = TryAttach();
  248. // if we hit an error while trying to attach then bail...
  249. if (NS_FAILED(mCondition))
  250. {
  251. NS_ASSERTION(!mAttached, "should not be attached already");
  252. OnSocketDetached(mFD);
  253. }
  254. }
  255. nsresult
  256. nsUDPSocket::TryAttach()
  257. {
  258. nsresult rv;
  259. if (!gSocketTransportService)
  260. return NS_ERROR_FAILURE;
  261. if (gIOService->IsNetTearingDown()) {
  262. return NS_ERROR_FAILURE;
  263. }
  264. //
  265. // find out if it is going to be ok to attach another socket to the STS.
  266. // if not then we have to wait for the STS to tell us that it is ok.
  267. // the notification is asynchronous, which means that when we could be
  268. // in a race to call AttachSocket once notified. for this reason, when
  269. // we get notified, we just re-enter this function. as a result, we are
  270. // sure to ask again before calling AttachSocket. in this way we deal
  271. // with the race condition. though it isn't the most elegant solution,
  272. // it is far simpler than trying to build a system that would guarantee
  273. // FIFO ordering (which wouldn't even be that valuable IMO). see bug
  274. // 194402 for more info.
  275. //
  276. if (!gSocketTransportService->CanAttachSocket())
  277. {
  278. nsCOMPtr<nsIRunnable> event =
  279. NewRunnableMethod(this, &nsUDPSocket::OnMsgAttach);
  280. nsresult rv = gSocketTransportService->NotifyWhenCanAttachSocket(event);
  281. if (NS_FAILED(rv))
  282. return rv;
  283. }
  284. //
  285. // ok, we can now attach our socket to the STS for polling
  286. //
  287. rv = gSocketTransportService->AttachSocket(mFD, this);
  288. if (NS_FAILED(rv))
  289. return rv;
  290. mAttached = true;
  291. //
  292. // now, configure our poll flags for listening...
  293. //
  294. mPollFlags = (PR_POLL_READ | PR_POLL_EXCEPT);
  295. return NS_OK;
  296. }
  297. namespace {
  298. //-----------------------------------------------------------------------------
  299. // UDPMessageProxy
  300. //-----------------------------------------------------------------------------
  301. class UDPMessageProxy final : public nsIUDPMessage
  302. {
  303. public:
  304. UDPMessageProxy(NetAddr* aAddr,
  305. nsIOutputStream* aOutputStream,
  306. FallibleTArray<uint8_t>& aData)
  307. : mOutputStream(aOutputStream)
  308. {
  309. memcpy(&mAddr, aAddr, sizeof(mAddr));
  310. aData.SwapElements(mData);
  311. }
  312. NS_DECL_THREADSAFE_ISUPPORTS
  313. NS_DECL_NSIUDPMESSAGE
  314. private:
  315. ~UDPMessageProxy() {}
  316. NetAddr mAddr;
  317. nsCOMPtr<nsIOutputStream> mOutputStream;
  318. FallibleTArray<uint8_t> mData;
  319. };
  320. NS_IMPL_ISUPPORTS(UDPMessageProxy, nsIUDPMessage)
  321. NS_IMETHODIMP
  322. UDPMessageProxy::GetFromAddr(nsINetAddr * *aFromAddr)
  323. {
  324. NS_ENSURE_ARG_POINTER(aFromAddr);
  325. nsCOMPtr<nsINetAddr> result = new nsNetAddr(&mAddr);
  326. result.forget(aFromAddr);
  327. return NS_OK;
  328. }
  329. NS_IMETHODIMP
  330. UDPMessageProxy::GetData(nsACString & aData)
  331. {
  332. aData.Assign(reinterpret_cast<const char*>(mData.Elements()), mData.Length());
  333. return NS_OK;
  334. }
  335. FallibleTArray<uint8_t>&
  336. UDPMessageProxy::GetDataAsTArray()
  337. {
  338. return mData;
  339. }
  340. NS_IMETHODIMP
  341. UDPMessageProxy::GetRawData(JSContext* cx,
  342. JS::MutableHandleValue aRawData)
  343. {
  344. return NS_ERROR_NOT_IMPLEMENTED;
  345. }
  346. NS_IMETHODIMP
  347. UDPMessageProxy::GetOutputStream(nsIOutputStream * *aOutputStream)
  348. {
  349. NS_ENSURE_ARG_POINTER(aOutputStream);
  350. NS_IF_ADDREF(*aOutputStream = mOutputStream);
  351. return NS_OK;
  352. }
  353. } //anonymous namespace
  354. //-----------------------------------------------------------------------------
  355. // nsUDPSocket::nsASocketHandler
  356. //-----------------------------------------------------------------------------
  357. void
  358. nsUDPSocket::OnSocketReady(PRFileDesc *fd, int16_t outFlags)
  359. {
  360. NS_ASSERTION(NS_SUCCEEDED(mCondition), "oops");
  361. NS_ASSERTION(mFD == fd, "wrong file descriptor");
  362. NS_ASSERTION(outFlags != -1, "unexpected timeout condition reached");
  363. if (outFlags & (PR_POLL_ERR | PR_POLL_HUP | PR_POLL_NVAL))
  364. {
  365. NS_WARNING("error polling on listening socket");
  366. mCondition = NS_ERROR_UNEXPECTED;
  367. return;
  368. }
  369. PRNetAddr prClientAddr;
  370. uint32_t count;
  371. // Bug 1252755 - use 9216 bytes to allign with nICEr and transportlayer to
  372. // support the maximum size of jumbo frames
  373. char buff[9216];
  374. count = PR_RecvFrom(mFD, buff, sizeof(buff), 0, &prClientAddr, PR_INTERVAL_NO_WAIT);
  375. if (count < 1) {
  376. NS_WARNING("error of recvfrom on UDP socket");
  377. mCondition = NS_ERROR_UNEXPECTED;
  378. return;
  379. }
  380. mByteReadCount += count;
  381. FallibleTArray<uint8_t> data;
  382. if (!data.AppendElements(buff, count, fallible)) {
  383. mCondition = NS_ERROR_UNEXPECTED;
  384. return;
  385. }
  386. nsCOMPtr<nsIAsyncInputStream> pipeIn;
  387. nsCOMPtr<nsIAsyncOutputStream> pipeOut;
  388. uint32_t segsize = UDP_PACKET_CHUNK_SIZE;
  389. uint32_t segcount = 0;
  390. net_ResolveSegmentParams(segsize, segcount);
  391. nsresult rv = NS_NewPipe2(getter_AddRefs(pipeIn), getter_AddRefs(pipeOut),
  392. true, true, segsize, segcount);
  393. if (NS_FAILED(rv)) {
  394. return;
  395. }
  396. RefPtr<nsUDPOutputStream> os = new nsUDPOutputStream(this, mFD, prClientAddr);
  397. rv = NS_AsyncCopy(pipeIn, os, mSts,
  398. NS_ASYNCCOPY_VIA_READSEGMENTS, UDP_PACKET_CHUNK_SIZE);
  399. if (NS_FAILED(rv)) {
  400. return;
  401. }
  402. NetAddr netAddr;
  403. PRNetAddrToNetAddr(&prClientAddr, &netAddr);
  404. nsCOMPtr<nsIUDPMessage> message = new UDPMessageProxy(&netAddr, pipeOut, data);
  405. mListener->OnPacketReceived(this, message);
  406. }
  407. void
  408. nsUDPSocket::OnSocketDetached(PRFileDesc *fd)
  409. {
  410. // force a failure condition if none set; maybe the STS is shutting down :-/
  411. if (NS_SUCCEEDED(mCondition))
  412. mCondition = NS_ERROR_ABORT;
  413. if (mFD)
  414. {
  415. NS_ASSERTION(mFD == fd, "wrong file descriptor");
  416. CloseSocket();
  417. }
  418. if (mListener)
  419. {
  420. // need to atomically clear mListener. see our Close() method.
  421. RefPtr<nsIUDPSocketListener> listener = nullptr;
  422. {
  423. MutexAutoLock lock(mLock);
  424. listener = mListener.forget();
  425. }
  426. if (listener) {
  427. listener->OnStopListening(this, mCondition);
  428. NS_ProxyRelease(mListenerTarget, listener.forget());
  429. }
  430. }
  431. }
  432. void
  433. nsUDPSocket::IsLocal(bool *aIsLocal)
  434. {
  435. // If bound to loopback, this UDP socket only accepts local connections.
  436. *aIsLocal = mAddr.raw.family == nsINetAddr::FAMILY_LOCAL;
  437. }
  438. //-----------------------------------------------------------------------------
  439. // nsSocket::nsISupports
  440. //-----------------------------------------------------------------------------
  441. NS_IMPL_ISUPPORTS(nsUDPSocket, nsIUDPSocket)
  442. //-----------------------------------------------------------------------------
  443. // nsSocket::nsISocket
  444. //-----------------------------------------------------------------------------
  445. NS_IMETHODIMP
  446. nsUDPSocket::Init(int32_t aPort, bool aLoopbackOnly, nsIPrincipal *aPrincipal,
  447. bool aAddressReuse, uint8_t aOptionalArgc)
  448. {
  449. NetAddr addr;
  450. if (aPort < 0)
  451. aPort = 0;
  452. addr.raw.family = AF_INET;
  453. addr.inet.port = htons(aPort);
  454. if (aLoopbackOnly)
  455. addr.inet.ip = htonl(INADDR_LOOPBACK);
  456. else
  457. addr.inet.ip = htonl(INADDR_ANY);
  458. return InitWithAddress(&addr, aPrincipal, aAddressReuse, aOptionalArgc);
  459. }
  460. NS_IMETHODIMP
  461. nsUDPSocket::Init2(const nsACString& aAddr, int32_t aPort, nsIPrincipal *aPrincipal,
  462. bool aAddressReuse, uint8_t aOptionalArgc)
  463. {
  464. if (NS_WARN_IF(aAddr.IsEmpty())) {
  465. return NS_ERROR_INVALID_ARG;
  466. }
  467. PRNetAddr prAddr;
  468. if (PR_StringToNetAddr(aAddr.BeginReading(), &prAddr) != PR_SUCCESS) {
  469. return NS_ERROR_FAILURE;
  470. }
  471. NetAddr addr;
  472. if (aPort < 0)
  473. aPort = 0;
  474. addr.raw.family = AF_INET;
  475. addr.inet.port = htons(aPort);
  476. addr.inet.ip = prAddr.inet.ip;
  477. return InitWithAddress(&addr, aPrincipal, aAddressReuse, aOptionalArgc);
  478. }
  479. NS_IMETHODIMP
  480. nsUDPSocket::InitWithAddress(const NetAddr *aAddr, nsIPrincipal *aPrincipal,
  481. bool aAddressReuse, uint8_t aOptionalArgc)
  482. {
  483. NS_ENSURE_TRUE(mFD == nullptr, NS_ERROR_ALREADY_INITIALIZED);
  484. if (gIOService->IsNetTearingDown()) {
  485. return NS_ERROR_FAILURE;
  486. }
  487. bool addressReuse = (aOptionalArgc == 1) ? aAddressReuse : true;
  488. //
  489. // configure listening socket...
  490. //
  491. mFD = PR_OpenUDPSocket(aAddr->raw.family);
  492. if (!mFD)
  493. {
  494. NS_WARNING("unable to create UDP socket");
  495. return NS_ERROR_FAILURE;
  496. }
  497. if (aPrincipal) {
  498. mAppId = aPrincipal->GetAppId();
  499. mIsInIsolatedMozBrowserElement =
  500. aPrincipal->GetIsInIsolatedMozBrowserElement();
  501. }
  502. uint16_t port;
  503. if (NS_FAILED(net::GetPort(aAddr, &port))) {
  504. NS_WARNING("invalid bind address");
  505. goto fail;
  506. }
  507. PRSocketOptionData opt;
  508. // Linux kernel will sometimes hand out a used port if we bind
  509. // to port 0 with SO_REUSEADDR
  510. if (port) {
  511. opt.option = PR_SockOpt_Reuseaddr;
  512. opt.value.reuse_addr = addressReuse;
  513. PR_SetSocketOption(mFD, &opt);
  514. }
  515. opt.option = PR_SockOpt_Nonblocking;
  516. opt.value.non_blocking = true;
  517. PR_SetSocketOption(mFD, &opt);
  518. PRNetAddr addr;
  519. PR_InitializeNetAddr(PR_IpAddrAny, 0, &addr);
  520. NetAddrToPRNetAddr(aAddr, &addr);
  521. if (PR_Bind(mFD, &addr) != PR_SUCCESS)
  522. {
  523. NS_WARNING("failed to bind socket");
  524. goto fail;
  525. }
  526. // get the resulting socket address, which may be different than what
  527. // we passed to bind.
  528. if (PR_GetSockName(mFD, &addr) != PR_SUCCESS)
  529. {
  530. NS_WARNING("cannot get socket name");
  531. goto fail;
  532. }
  533. PRNetAddrToNetAddr(&addr, &mAddr);
  534. // create proxy via NetworkActivityMonitor
  535. NetworkActivityMonitor::AttachIOLayer(mFD);
  536. // wait until AsyncListen is called before polling the socket for
  537. // client connections.
  538. return NS_OK;
  539. fail:
  540. Close();
  541. return NS_ERROR_FAILURE;
  542. }
  543. NS_IMETHODIMP
  544. nsUDPSocket::Connect(const NetAddr *aAddr)
  545. {
  546. UDPSOCKET_LOG(("nsUDPSocket::Connect [this=%p]\n", this));
  547. NS_ENSURE_ARG(aAddr);
  548. if (NS_WARN_IF(!mFD)) {
  549. return NS_ERROR_NOT_INITIALIZED;
  550. }
  551. bool onSTSThread = false;
  552. mSts->IsOnCurrentThread(&onSTSThread);
  553. NS_ASSERTION(onSTSThread, "NOT ON STS THREAD");
  554. if (!onSTSThread) {
  555. return NS_ERROR_FAILURE;
  556. }
  557. PRNetAddr prAddr;
  558. NetAddrToPRNetAddr(aAddr, &prAddr);
  559. if (PR_Connect(mFD, &prAddr, PR_INTERVAL_NO_WAIT) != PR_SUCCESS) {
  560. NS_WARNING("Cannot PR_Connect");
  561. return NS_ERROR_FAILURE;
  562. }
  563. // get the resulting socket address, which may have been updated.
  564. PRNetAddr addr;
  565. if (PR_GetSockName(mFD, &addr) != PR_SUCCESS)
  566. {
  567. NS_WARNING("cannot get socket name");
  568. return NS_ERROR_FAILURE;
  569. }
  570. PRNetAddrToNetAddr(&addr, &mAddr);
  571. return NS_OK;
  572. }
  573. NS_IMETHODIMP
  574. nsUDPSocket::Close()
  575. {
  576. {
  577. MutexAutoLock lock(mLock);
  578. // we want to proxy the close operation to the socket thread if a listener
  579. // has been set. otherwise, we should just close the socket here...
  580. if (!mListener)
  581. {
  582. // Here we want to go directly with closing the socket since some tests
  583. // expects this happen synchronously.
  584. CloseSocket();
  585. return NS_OK;
  586. }
  587. }
  588. return PostEvent(this, &nsUDPSocket::OnMsgClose);
  589. }
  590. NS_IMETHODIMP
  591. nsUDPSocket::GetPort(int32_t *aResult)
  592. {
  593. // no need to enter the lock here
  594. uint16_t result;
  595. nsresult rv = net::GetPort(&mAddr, &result);
  596. *aResult = static_cast<int32_t>(result);
  597. return rv;
  598. }
  599. NS_IMETHODIMP
  600. nsUDPSocket::GetLocalAddr(nsINetAddr * *aResult)
  601. {
  602. NS_ENSURE_ARG_POINTER(aResult);
  603. nsCOMPtr<nsINetAddr> result = new nsNetAddr(&mAddr);
  604. result.forget(aResult);
  605. return NS_OK;
  606. }
  607. void
  608. nsUDPSocket::CloseSocket()
  609. {
  610. if (mFD) {
  611. if (gIOService->IsNetTearingDown() &&
  612. ((PR_IntervalNow() - gIOService->NetTearingDownStarted()) >
  613. gSocketTransportService->MaxTimeForPrClosePref())) {
  614. // If shutdown last to long, let the socket leak and do not close it.
  615. UDPSOCKET_LOG(("Intentional leak"));
  616. } else {
  617. PR_Close(mFD);
  618. }
  619. mFD = nullptr;
  620. }
  621. }
  622. NS_IMETHODIMP
  623. nsUDPSocket::GetAddress(NetAddr *aResult)
  624. {
  625. // no need to enter the lock here
  626. memcpy(aResult, &mAddr, sizeof(mAddr));
  627. return NS_OK;
  628. }
  629. namespace {
  630. //-----------------------------------------------------------------------------
  631. // SocketListenerProxy
  632. //-----------------------------------------------------------------------------
  633. class SocketListenerProxy final : public nsIUDPSocketListener
  634. {
  635. ~SocketListenerProxy() {}
  636. public:
  637. explicit SocketListenerProxy(nsIUDPSocketListener* aListener)
  638. : mListener(new nsMainThreadPtrHolder<nsIUDPSocketListener>(aListener))
  639. , mTargetThread(do_GetCurrentThread())
  640. { }
  641. NS_DECL_THREADSAFE_ISUPPORTS
  642. NS_DECL_NSIUDPSOCKETLISTENER
  643. class OnPacketReceivedRunnable : public Runnable
  644. {
  645. public:
  646. OnPacketReceivedRunnable(const nsMainThreadPtrHandle<nsIUDPSocketListener>& aListener,
  647. nsIUDPSocket* aSocket,
  648. nsIUDPMessage* aMessage)
  649. : mListener(aListener)
  650. , mSocket(aSocket)
  651. , mMessage(aMessage)
  652. { }
  653. NS_DECL_NSIRUNNABLE
  654. private:
  655. nsMainThreadPtrHandle<nsIUDPSocketListener> mListener;
  656. nsCOMPtr<nsIUDPSocket> mSocket;
  657. nsCOMPtr<nsIUDPMessage> mMessage;
  658. };
  659. class OnStopListeningRunnable : public Runnable
  660. {
  661. public:
  662. OnStopListeningRunnable(const nsMainThreadPtrHandle<nsIUDPSocketListener>& aListener,
  663. nsIUDPSocket* aSocket,
  664. nsresult aStatus)
  665. : mListener(aListener)
  666. , mSocket(aSocket)
  667. , mStatus(aStatus)
  668. { }
  669. NS_DECL_NSIRUNNABLE
  670. private:
  671. nsMainThreadPtrHandle<nsIUDPSocketListener> mListener;
  672. nsCOMPtr<nsIUDPSocket> mSocket;
  673. nsresult mStatus;
  674. };
  675. private:
  676. nsMainThreadPtrHandle<nsIUDPSocketListener> mListener;
  677. nsCOMPtr<nsIEventTarget> mTargetThread;
  678. };
  679. NS_IMPL_ISUPPORTS(SocketListenerProxy,
  680. nsIUDPSocketListener)
  681. NS_IMETHODIMP
  682. SocketListenerProxy::OnPacketReceived(nsIUDPSocket* aSocket,
  683. nsIUDPMessage* aMessage)
  684. {
  685. RefPtr<OnPacketReceivedRunnable> r =
  686. new OnPacketReceivedRunnable(mListener, aSocket, aMessage);
  687. return mTargetThread->Dispatch(r, NS_DISPATCH_NORMAL);
  688. }
  689. NS_IMETHODIMP
  690. SocketListenerProxy::OnStopListening(nsIUDPSocket* aSocket,
  691. nsresult aStatus)
  692. {
  693. RefPtr<OnStopListeningRunnable> r =
  694. new OnStopListeningRunnable(mListener, aSocket, aStatus);
  695. return mTargetThread->Dispatch(r, NS_DISPATCH_NORMAL);
  696. }
  697. NS_IMETHODIMP
  698. SocketListenerProxy::OnPacketReceivedRunnable::Run()
  699. {
  700. NetAddr netAddr;
  701. nsCOMPtr<nsINetAddr> nsAddr;
  702. mMessage->GetFromAddr(getter_AddRefs(nsAddr));
  703. nsAddr->GetNetAddr(&netAddr);
  704. nsCOMPtr<nsIOutputStream> outputStream;
  705. mMessage->GetOutputStream(getter_AddRefs(outputStream));
  706. FallibleTArray<uint8_t>& data = mMessage->GetDataAsTArray();
  707. nsCOMPtr<nsIUDPMessage> message = new nsUDPMessage(&netAddr,
  708. outputStream,
  709. data);
  710. mListener->OnPacketReceived(mSocket, message);
  711. return NS_OK;
  712. }
  713. NS_IMETHODIMP
  714. SocketListenerProxy::OnStopListeningRunnable::Run()
  715. {
  716. mListener->OnStopListening(mSocket, mStatus);
  717. return NS_OK;
  718. }
  719. class SocketListenerProxyBackground final : public nsIUDPSocketListener
  720. {
  721. ~SocketListenerProxyBackground() {}
  722. public:
  723. explicit SocketListenerProxyBackground(nsIUDPSocketListener* aListener)
  724. : mListener(aListener)
  725. , mTargetThread(do_GetCurrentThread())
  726. { }
  727. NS_DECL_THREADSAFE_ISUPPORTS
  728. NS_DECL_NSIUDPSOCKETLISTENER
  729. class OnPacketReceivedRunnable : public Runnable
  730. {
  731. public:
  732. OnPacketReceivedRunnable(const nsCOMPtr<nsIUDPSocketListener>& aListener,
  733. nsIUDPSocket* aSocket,
  734. nsIUDPMessage* aMessage)
  735. : mListener(aListener)
  736. , mSocket(aSocket)
  737. , mMessage(aMessage)
  738. { }
  739. NS_DECL_NSIRUNNABLE
  740. private:
  741. nsCOMPtr<nsIUDPSocketListener> mListener;
  742. nsCOMPtr<nsIUDPSocket> mSocket;
  743. nsCOMPtr<nsIUDPMessage> mMessage;
  744. };
  745. class OnStopListeningRunnable : public Runnable
  746. {
  747. public:
  748. OnStopListeningRunnable(const nsCOMPtr<nsIUDPSocketListener>& aListener,
  749. nsIUDPSocket* aSocket,
  750. nsresult aStatus)
  751. : mListener(aListener)
  752. , mSocket(aSocket)
  753. , mStatus(aStatus)
  754. { }
  755. NS_DECL_NSIRUNNABLE
  756. private:
  757. nsCOMPtr<nsIUDPSocketListener> mListener;
  758. nsCOMPtr<nsIUDPSocket> mSocket;
  759. nsresult mStatus;
  760. };
  761. private:
  762. nsCOMPtr<nsIUDPSocketListener> mListener;
  763. nsCOMPtr<nsIEventTarget> mTargetThread;
  764. };
  765. NS_IMPL_ISUPPORTS(SocketListenerProxyBackground,
  766. nsIUDPSocketListener)
  767. NS_IMETHODIMP
  768. SocketListenerProxyBackground::OnPacketReceived(nsIUDPSocket* aSocket,
  769. nsIUDPMessage* aMessage)
  770. {
  771. RefPtr<OnPacketReceivedRunnable> r =
  772. new OnPacketReceivedRunnable(mListener, aSocket, aMessage);
  773. return mTargetThread->Dispatch(r, NS_DISPATCH_NORMAL);
  774. }
  775. NS_IMETHODIMP
  776. SocketListenerProxyBackground::OnStopListening(nsIUDPSocket* aSocket,
  777. nsresult aStatus)
  778. {
  779. RefPtr<OnStopListeningRunnable> r =
  780. new OnStopListeningRunnable(mListener, aSocket, aStatus);
  781. return mTargetThread->Dispatch(r, NS_DISPATCH_NORMAL);
  782. }
  783. NS_IMETHODIMP
  784. SocketListenerProxyBackground::OnPacketReceivedRunnable::Run()
  785. {
  786. NetAddr netAddr;
  787. nsCOMPtr<nsINetAddr> nsAddr;
  788. mMessage->GetFromAddr(getter_AddRefs(nsAddr));
  789. nsAddr->GetNetAddr(&netAddr);
  790. nsCOMPtr<nsIOutputStream> outputStream;
  791. mMessage->GetOutputStream(getter_AddRefs(outputStream));
  792. FallibleTArray<uint8_t>& data = mMessage->GetDataAsTArray();
  793. UDPSOCKET_LOG(("%s [this=%p], len %u", __FUNCTION__, this, data.Length()));
  794. nsCOMPtr<nsIUDPMessage> message = new UDPMessageProxy(&netAddr,
  795. outputStream,
  796. data);
  797. mListener->OnPacketReceived(mSocket, message);
  798. return NS_OK;
  799. }
  800. NS_IMETHODIMP
  801. SocketListenerProxyBackground::OnStopListeningRunnable::Run()
  802. {
  803. mListener->OnStopListening(mSocket, mStatus);
  804. return NS_OK;
  805. }
  806. class PendingSend : public nsIDNSListener
  807. {
  808. public:
  809. NS_DECL_THREADSAFE_ISUPPORTS
  810. NS_DECL_NSIDNSLISTENER
  811. PendingSend(nsUDPSocket *aSocket, uint16_t aPort,
  812. FallibleTArray<uint8_t> &aData)
  813. : mSocket(aSocket)
  814. , mPort(aPort)
  815. {
  816. mData.SwapElements(aData);
  817. }
  818. private:
  819. virtual ~PendingSend() {}
  820. RefPtr<nsUDPSocket> mSocket;
  821. uint16_t mPort;
  822. FallibleTArray<uint8_t> mData;
  823. };
  824. NS_IMPL_ISUPPORTS(PendingSend, nsIDNSListener)
  825. NS_IMETHODIMP
  826. PendingSend::OnLookupComplete(nsICancelable *request,
  827. nsIDNSRecord *rec,
  828. nsresult status)
  829. {
  830. if (NS_FAILED(status)) {
  831. NS_WARNING("Failed to send UDP packet due to DNS lookup failure");
  832. return NS_OK;
  833. }
  834. NetAddr addr;
  835. if (NS_SUCCEEDED(rec->GetNextAddr(mPort, &addr))) {
  836. uint32_t count;
  837. nsresult rv = mSocket->SendWithAddress(&addr, mData.Elements(),
  838. mData.Length(), &count);
  839. NS_ENSURE_SUCCESS(rv, rv);
  840. }
  841. return NS_OK;
  842. }
  843. class PendingSendStream : public nsIDNSListener
  844. {
  845. public:
  846. NS_DECL_THREADSAFE_ISUPPORTS
  847. NS_DECL_NSIDNSLISTENER
  848. PendingSendStream(nsUDPSocket *aSocket, uint16_t aPort,
  849. nsIInputStream *aStream)
  850. : mSocket(aSocket)
  851. , mPort(aPort)
  852. , mStream(aStream) {}
  853. private:
  854. virtual ~PendingSendStream() {}
  855. RefPtr<nsUDPSocket> mSocket;
  856. uint16_t mPort;
  857. nsCOMPtr<nsIInputStream> mStream;
  858. };
  859. NS_IMPL_ISUPPORTS(PendingSendStream, nsIDNSListener)
  860. NS_IMETHODIMP
  861. PendingSendStream::OnLookupComplete(nsICancelable *request,
  862. nsIDNSRecord *rec,
  863. nsresult status)
  864. {
  865. if (NS_FAILED(status)) {
  866. NS_WARNING("Failed to send UDP packet due to DNS lookup failure");
  867. return NS_OK;
  868. }
  869. NetAddr addr;
  870. if (NS_SUCCEEDED(rec->GetNextAddr(mPort, &addr))) {
  871. nsresult rv = mSocket->SendBinaryStreamWithAddress(&addr, mStream);
  872. NS_ENSURE_SUCCESS(rv, rv);
  873. }
  874. return NS_OK;
  875. }
  876. class SendRequestRunnable: public Runnable {
  877. public:
  878. SendRequestRunnable(nsUDPSocket *aSocket,
  879. const NetAddr &aAddr,
  880. FallibleTArray<uint8_t>&& aData)
  881. : mSocket(aSocket)
  882. , mAddr(aAddr)
  883. , mData(Move(aData))
  884. { }
  885. NS_DECL_NSIRUNNABLE
  886. private:
  887. RefPtr<nsUDPSocket> mSocket;
  888. const NetAddr mAddr;
  889. FallibleTArray<uint8_t> mData;
  890. };
  891. NS_IMETHODIMP
  892. SendRequestRunnable::Run()
  893. {
  894. uint32_t count;
  895. mSocket->SendWithAddress(&mAddr, mData.Elements(),
  896. mData.Length(), &count);
  897. return NS_OK;
  898. }
  899. } // namespace
  900. NS_IMETHODIMP
  901. nsUDPSocket::AsyncListen(nsIUDPSocketListener *aListener)
  902. {
  903. // ensuring mFD implies ensuring mLock
  904. NS_ENSURE_TRUE(mFD, NS_ERROR_NOT_INITIALIZED);
  905. NS_ENSURE_TRUE(mListener == nullptr, NS_ERROR_IN_PROGRESS);
  906. {
  907. MutexAutoLock lock(mLock);
  908. mListenerTarget = NS_GetCurrentThread();
  909. if (NS_IsMainThread()) {
  910. // PNecko usage
  911. mListener = new SocketListenerProxy(aListener);
  912. } else {
  913. // PBackground usage from media/mtransport
  914. mListener = new SocketListenerProxyBackground(aListener);
  915. }
  916. }
  917. return PostEvent(this, &nsUDPSocket::OnMsgAttach);
  918. }
  919. NS_IMETHODIMP
  920. nsUDPSocket::Send(const nsACString &aHost, uint16_t aPort,
  921. const uint8_t *aData, uint32_t aDataLength,
  922. uint32_t *_retval)
  923. {
  924. NS_ENSURE_ARG(aData);
  925. NS_ENSURE_ARG_POINTER(_retval);
  926. *_retval = 0;
  927. FallibleTArray<uint8_t> fallibleArray;
  928. if (!fallibleArray.InsertElementsAt(0, aData, aDataLength, fallible)) {
  929. return NS_ERROR_OUT_OF_MEMORY;
  930. }
  931. nsCOMPtr<nsIDNSListener> listener = new PendingSend(this, aPort, fallibleArray);
  932. nsresult rv = ResolveHost(aHost, listener);
  933. NS_ENSURE_SUCCESS(rv, rv);
  934. *_retval = aDataLength;
  935. return NS_OK;
  936. }
  937. NS_IMETHODIMP
  938. nsUDPSocket::SendWithAddr(nsINetAddr *aAddr, const uint8_t *aData,
  939. uint32_t aDataLength, uint32_t *_retval)
  940. {
  941. NS_ENSURE_ARG(aAddr);
  942. NS_ENSURE_ARG(aData);
  943. NS_ENSURE_ARG_POINTER(_retval);
  944. NetAddr netAddr;
  945. aAddr->GetNetAddr(&netAddr);
  946. return SendWithAddress(&netAddr, aData, aDataLength, _retval);
  947. }
  948. NS_IMETHODIMP
  949. nsUDPSocket::SendWithAddress(const NetAddr *aAddr, const uint8_t *aData,
  950. uint32_t aDataLength, uint32_t *_retval)
  951. {
  952. NS_ENSURE_ARG(aAddr);
  953. NS_ENSURE_ARG(aData);
  954. NS_ENSURE_ARG_POINTER(_retval);
  955. *_retval = 0;
  956. PRNetAddr prAddr;
  957. NetAddrToPRNetAddr(aAddr, &prAddr);
  958. bool onSTSThread = false;
  959. mSts->IsOnCurrentThread(&onSTSThread);
  960. if (onSTSThread) {
  961. MutexAutoLock lock(mLock);
  962. if (!mFD) {
  963. // socket is not initialized or has been closed
  964. return NS_ERROR_FAILURE;
  965. }
  966. int32_t count = PR_SendTo(mFD, aData, sizeof(uint8_t) *aDataLength,
  967. 0, &prAddr, PR_INTERVAL_NO_WAIT);
  968. if (count < 0) {
  969. PRErrorCode code = PR_GetError();
  970. return ErrorAccordingToNSPR(code);
  971. }
  972. this->AddOutputBytes(count);
  973. *_retval = count;
  974. } else {
  975. FallibleTArray<uint8_t> fallibleArray;
  976. if (!fallibleArray.InsertElementsAt(0, aData, aDataLength, fallible)) {
  977. return NS_ERROR_OUT_OF_MEMORY;
  978. }
  979. nsresult rv = mSts->Dispatch(
  980. new SendRequestRunnable(this, *aAddr, Move(fallibleArray)),
  981. NS_DISPATCH_NORMAL);
  982. NS_ENSURE_SUCCESS(rv, rv);
  983. *_retval = aDataLength;
  984. }
  985. return NS_OK;
  986. }
  987. NS_IMETHODIMP
  988. nsUDPSocket::SendBinaryStream(const nsACString &aHost, uint16_t aPort,
  989. nsIInputStream *aStream)
  990. {
  991. NS_ENSURE_ARG(aStream);
  992. nsCOMPtr<nsIDNSListener> listener = new PendingSendStream(this, aPort, aStream);
  993. return ResolveHost(aHost, listener);
  994. }
  995. NS_IMETHODIMP
  996. nsUDPSocket::SendBinaryStreamWithAddress(const NetAddr *aAddr, nsIInputStream *aStream)
  997. {
  998. NS_ENSURE_ARG(aAddr);
  999. NS_ENSURE_ARG(aStream);
  1000. PRNetAddr prAddr;
  1001. PR_InitializeNetAddr(PR_IpAddrAny, 0, &prAddr);
  1002. NetAddrToPRNetAddr(aAddr, &prAddr);
  1003. RefPtr<nsUDPOutputStream> os = new nsUDPOutputStream(this, mFD, prAddr);
  1004. return NS_AsyncCopy(aStream, os, mSts, NS_ASYNCCOPY_VIA_READSEGMENTS,
  1005. UDP_PACKET_CHUNK_SIZE);
  1006. }
  1007. nsresult
  1008. nsUDPSocket::SetSocketOption(const PRSocketOptionData& aOpt)
  1009. {
  1010. bool onSTSThread = false;
  1011. mSts->IsOnCurrentThread(&onSTSThread);
  1012. if (!onSTSThread) {
  1013. // Dispatch to STS thread and re-enter this method there
  1014. nsCOMPtr<nsIRunnable> runnable = new SetSocketOptionRunnable(this, aOpt);
  1015. nsresult rv = mSts->Dispatch(runnable, NS_DISPATCH_NORMAL);
  1016. if (NS_WARN_IF(NS_FAILED(rv))) {
  1017. return rv;
  1018. }
  1019. return NS_OK;
  1020. }
  1021. if (NS_WARN_IF(!mFD)) {
  1022. return NS_ERROR_NOT_INITIALIZED;
  1023. }
  1024. if (PR_SetSocketOption(mFD, &aOpt) != PR_SUCCESS) {
  1025. UDPSOCKET_LOG(("nsUDPSocket::SetSocketOption [this=%p] failed for type %d, "
  1026. "error %d\n", this, aOpt.option, PR_GetError()));
  1027. return NS_ERROR_FAILURE;
  1028. }
  1029. return NS_OK;
  1030. }
  1031. NS_IMETHODIMP
  1032. nsUDPSocket::JoinMulticast(const nsACString& aAddr, const nsACString& aIface)
  1033. {
  1034. if (NS_WARN_IF(aAddr.IsEmpty())) {
  1035. return NS_ERROR_INVALID_ARG;
  1036. }
  1037. if (NS_WARN_IF(!mFD)) {
  1038. return NS_ERROR_NOT_INITIALIZED;
  1039. }
  1040. PRNetAddr prAddr;
  1041. if (PR_StringToNetAddr(aAddr.BeginReading(), &prAddr) != PR_SUCCESS) {
  1042. return NS_ERROR_FAILURE;
  1043. }
  1044. PRNetAddr prIface;
  1045. if (aIface.IsEmpty()) {
  1046. PR_InitializeNetAddr(PR_IpAddrAny, 0, &prIface);
  1047. } else {
  1048. if (PR_StringToNetAddr(aIface.BeginReading(), &prIface) != PR_SUCCESS) {
  1049. return NS_ERROR_FAILURE;
  1050. }
  1051. }
  1052. return JoinMulticastInternal(prAddr, prIface);
  1053. }
  1054. NS_IMETHODIMP
  1055. nsUDPSocket::JoinMulticastAddr(const NetAddr aAddr, const NetAddr* aIface)
  1056. {
  1057. if (NS_WARN_IF(!mFD)) {
  1058. return NS_ERROR_NOT_INITIALIZED;
  1059. }
  1060. PRNetAddr prAddr;
  1061. NetAddrToPRNetAddr(&aAddr, &prAddr);
  1062. PRNetAddr prIface;
  1063. if (!aIface) {
  1064. PR_InitializeNetAddr(PR_IpAddrAny, 0, &prIface);
  1065. } else {
  1066. NetAddrToPRNetAddr(aIface, &prIface);
  1067. }
  1068. return JoinMulticastInternal(prAddr, prIface);
  1069. }
  1070. nsresult
  1071. nsUDPSocket::JoinMulticastInternal(const PRNetAddr& aAddr,
  1072. const PRNetAddr& aIface)
  1073. {
  1074. PRSocketOptionData opt;
  1075. opt.option = PR_SockOpt_AddMember;
  1076. opt.value.add_member.mcaddr = aAddr;
  1077. opt.value.add_member.ifaddr = aIface;
  1078. nsresult rv = SetSocketOption(opt);
  1079. if (NS_WARN_IF(NS_FAILED(rv))) {
  1080. return NS_ERROR_FAILURE;
  1081. }
  1082. return NS_OK;
  1083. }
  1084. NS_IMETHODIMP
  1085. nsUDPSocket::LeaveMulticast(const nsACString& aAddr, const nsACString& aIface)
  1086. {
  1087. if (NS_WARN_IF(aAddr.IsEmpty())) {
  1088. return NS_ERROR_INVALID_ARG;
  1089. }
  1090. if (NS_WARN_IF(!mFD)) {
  1091. return NS_ERROR_NOT_INITIALIZED;
  1092. }
  1093. PRNetAddr prAddr;
  1094. if (PR_StringToNetAddr(aAddr.BeginReading(), &prAddr) != PR_SUCCESS) {
  1095. return NS_ERROR_FAILURE;
  1096. }
  1097. PRNetAddr prIface;
  1098. if (aIface.IsEmpty()) {
  1099. PR_InitializeNetAddr(PR_IpAddrAny, 0, &prIface);
  1100. } else {
  1101. if (PR_StringToNetAddr(aIface.BeginReading(), &prIface) != PR_SUCCESS) {
  1102. return NS_ERROR_FAILURE;
  1103. }
  1104. }
  1105. return LeaveMulticastInternal(prAddr, prIface);
  1106. }
  1107. NS_IMETHODIMP
  1108. nsUDPSocket::LeaveMulticastAddr(const NetAddr aAddr, const NetAddr* aIface)
  1109. {
  1110. if (NS_WARN_IF(!mFD)) {
  1111. return NS_ERROR_NOT_INITIALIZED;
  1112. }
  1113. PRNetAddr prAddr;
  1114. NetAddrToPRNetAddr(&aAddr, &prAddr);
  1115. PRNetAddr prIface;
  1116. if (!aIface) {
  1117. PR_InitializeNetAddr(PR_IpAddrAny, 0, &prIface);
  1118. } else {
  1119. NetAddrToPRNetAddr(aIface, &prIface);
  1120. }
  1121. return LeaveMulticastInternal(prAddr, prIface);
  1122. }
  1123. nsresult
  1124. nsUDPSocket::LeaveMulticastInternal(const PRNetAddr& aAddr,
  1125. const PRNetAddr& aIface)
  1126. {
  1127. PRSocketOptionData opt;
  1128. opt.option = PR_SockOpt_DropMember;
  1129. opt.value.drop_member.mcaddr = aAddr;
  1130. opt.value.drop_member.ifaddr = aIface;
  1131. nsresult rv = SetSocketOption(opt);
  1132. if (NS_WARN_IF(NS_FAILED(rv))) {
  1133. return NS_ERROR_FAILURE;
  1134. }
  1135. return NS_OK;
  1136. }
  1137. NS_IMETHODIMP
  1138. nsUDPSocket::GetMulticastLoopback(bool* aLoopback)
  1139. {
  1140. return NS_ERROR_NOT_IMPLEMENTED;
  1141. }
  1142. NS_IMETHODIMP
  1143. nsUDPSocket::SetMulticastLoopback(bool aLoopback)
  1144. {
  1145. if (NS_WARN_IF(!mFD)) {
  1146. return NS_ERROR_NOT_INITIALIZED;
  1147. }
  1148. PRSocketOptionData opt;
  1149. opt.option = PR_SockOpt_McastLoopback;
  1150. opt.value.mcast_loopback = aLoopback;
  1151. nsresult rv = SetSocketOption(opt);
  1152. if (NS_WARN_IF(NS_FAILED(rv))) {
  1153. return NS_ERROR_FAILURE;
  1154. }
  1155. return NS_OK;
  1156. }
  1157. NS_IMETHODIMP
  1158. nsUDPSocket::GetRecvBufferSize(int* size)
  1159. {
  1160. // Bug 1252759 - missing support for GetSocketOption
  1161. return NS_ERROR_NOT_IMPLEMENTED;
  1162. }
  1163. NS_IMETHODIMP
  1164. nsUDPSocket::SetRecvBufferSize(int size)
  1165. {
  1166. if (NS_WARN_IF(!mFD)) {
  1167. return NS_ERROR_NOT_INITIALIZED;
  1168. }
  1169. PRSocketOptionData opt;
  1170. opt.option = PR_SockOpt_RecvBufferSize;
  1171. opt.value.recv_buffer_size = size;
  1172. nsresult rv = SetSocketOption(opt);
  1173. if (NS_WARN_IF(NS_FAILED(rv))) {
  1174. return NS_ERROR_FAILURE;
  1175. }
  1176. return NS_OK;
  1177. }
  1178. NS_IMETHODIMP
  1179. nsUDPSocket::GetSendBufferSize(int* size)
  1180. {
  1181. // Bug 1252759 - missing support for GetSocketOption
  1182. return NS_ERROR_NOT_IMPLEMENTED;
  1183. }
  1184. NS_IMETHODIMP
  1185. nsUDPSocket::SetSendBufferSize(int size)
  1186. {
  1187. if (NS_WARN_IF(!mFD)) {
  1188. return NS_ERROR_NOT_INITIALIZED;
  1189. }
  1190. PRSocketOptionData opt;
  1191. opt.option = PR_SockOpt_SendBufferSize;
  1192. opt.value.send_buffer_size = size;
  1193. nsresult rv = SetSocketOption(opt);
  1194. if (NS_WARN_IF(NS_FAILED(rv))) {
  1195. return NS_ERROR_FAILURE;
  1196. }
  1197. return NS_OK;
  1198. }
  1199. NS_IMETHODIMP
  1200. nsUDPSocket::GetMulticastInterface(nsACString& aIface)
  1201. {
  1202. return NS_ERROR_NOT_IMPLEMENTED;
  1203. }
  1204. NS_IMETHODIMP
  1205. nsUDPSocket::GetMulticastInterfaceAddr(NetAddr* aIface)
  1206. {
  1207. return NS_ERROR_NOT_IMPLEMENTED;
  1208. }
  1209. NS_IMETHODIMP
  1210. nsUDPSocket::SetMulticastInterface(const nsACString& aIface)
  1211. {
  1212. if (NS_WARN_IF(!mFD)) {
  1213. return NS_ERROR_NOT_INITIALIZED;
  1214. }
  1215. PRNetAddr prIface;
  1216. if (aIface.IsEmpty()) {
  1217. PR_InitializeNetAddr(PR_IpAddrAny, 0, &prIface);
  1218. } else {
  1219. if (PR_StringToNetAddr(aIface.BeginReading(), &prIface) != PR_SUCCESS) {
  1220. return NS_ERROR_FAILURE;
  1221. }
  1222. }
  1223. return SetMulticastInterfaceInternal(prIface);
  1224. }
  1225. NS_IMETHODIMP
  1226. nsUDPSocket::SetMulticastInterfaceAddr(NetAddr aIface)
  1227. {
  1228. if (NS_WARN_IF(!mFD)) {
  1229. return NS_ERROR_NOT_INITIALIZED;
  1230. }
  1231. PRNetAddr prIface;
  1232. NetAddrToPRNetAddr(&aIface, &prIface);
  1233. return SetMulticastInterfaceInternal(prIface);
  1234. }
  1235. nsresult
  1236. nsUDPSocket::SetMulticastInterfaceInternal(const PRNetAddr& aIface)
  1237. {
  1238. PRSocketOptionData opt;
  1239. opt.option = PR_SockOpt_McastInterface;
  1240. opt.value.mcast_if = aIface;
  1241. nsresult rv = SetSocketOption(opt);
  1242. if (NS_WARN_IF(NS_FAILED(rv))) {
  1243. return NS_ERROR_FAILURE;
  1244. }
  1245. return NS_OK;
  1246. }
  1247. } // namespace net
  1248. } // namespace mozilla