nsSocketTransportService2.cpp 46 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523
  1. /* This Source Code Form is subject to the terms of the Mozilla Public
  2. * License, v. 2.0. If a copy of the MPL was not distributed with this
  3. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  4. #include "nsSocketTransportService2.h"
  5. #include "nsSocketTransport2.h"
  6. #include "NetworkActivityMonitor.h"
  7. #include "mozilla/Preferences.h"
  8. #include "nsIOService.h"
  9. #include "nsASocketHandler.h"
  10. #include "nsError.h"
  11. #include "prnetdb.h"
  12. #include "prerror.h"
  13. #include "nsIPrefService.h"
  14. #include "nsIPrefBranch.h"
  15. #include "nsServiceManagerUtils.h"
  16. #include "nsIObserverService.h"
  17. #include "mozilla/Atomics.h"
  18. #include "mozilla/Services.h"
  19. #include "mozilla/Likely.h"
  20. #include "mozilla/PublicSSL.h"
  21. #include "mozilla/ChaosMode.h"
  22. #include "mozilla/PodOperations.h"
  23. #include "nsThreadUtils.h"
  24. #include "nsIFile.h"
  25. #include "nsIWidget.h"
  26. namespace mozilla {
  27. namespace net {
  28. LazyLogModule gSocketTransportLog("nsSocketTransport");
  29. LazyLogModule gUDPSocketLog("UDPSocket");
  30. LazyLogModule gTCPSocketLog("TCPSocket");
  31. nsSocketTransportService *gSocketTransportService = nullptr;
  32. Atomic<PRThread*, Relaxed> gSocketThread;
  33. #define SEND_BUFFER_PREF "network.tcp.sendbuffer"
  34. #define KEEPALIVE_ENABLED_PREF "network.tcp.keepalive.enabled"
  35. #define KEEPALIVE_IDLE_TIME_PREF "network.tcp.keepalive.idle_time"
  36. #define KEEPALIVE_RETRY_INTERVAL_PREF "network.tcp.keepalive.retry_interval"
  37. #define KEEPALIVE_PROBE_COUNT_PREF "network.tcp.keepalive.probe_count"
  38. #define SOCKET_LIMIT_TARGET 1000U
  39. #define SOCKET_LIMIT_MIN 50U
  40. #define BLIP_INTERVAL_PREF "network.activity.blipIntervalMilliseconds"
  41. #define MAX_TIME_BETWEEN_TWO_POLLS "network.sts.max_time_for_events_between_two_polls"
  42. #define MAX_TIME_FOR_PR_CLOSE_DURING_SHUTDOWN "network.sts.max_time_for_pr_close_during_shutdown"
  43. #define REPAIR_POLLABLE_EVENT_TIME 10
  44. uint32_t nsSocketTransportService::gMaxCount;
  45. PRCallOnceType nsSocketTransportService::gMaxCountInitOnce;
  46. //-----------------------------------------------------------------------------
  47. bool
  48. nsSocketTransportService::SocketContext::IsTimedOut(PRIntervalTime now) const
  49. {
  50. return TimeoutIn(now) == 0;
  51. }
  52. void
  53. nsSocketTransportService::SocketContext::StartTimeout(PRIntervalTime now)
  54. {
  55. if (!mPollStartEpoch) {
  56. mPollStartEpoch = now;
  57. }
  58. }
  59. void
  60. nsSocketTransportService::SocketContext::StopTimeout()
  61. {
  62. mPollStartEpoch = 0;
  63. }
  64. void
  65. nsSocketTransportService::SocketContext::ResetTimeout()
  66. {
  67. if (mPollStartEpoch && mHandler->mPollTimeout == UINT16_MAX) {
  68. mPollStartEpoch = 0;
  69. }
  70. }
  71. PRIntervalTime
  72. nsSocketTransportService::SocketContext::TimeoutIn(PRIntervalTime now) const
  73. {
  74. if (mHandler->mPollTimeout == UINT16_MAX || !mPollStartEpoch) {
  75. return NS_SOCKET_POLL_TIMEOUT;
  76. }
  77. PRIntervalTime elapsed = (now - mPollStartEpoch);
  78. PRIntervalTime timeout = PR_SecondsToInterval(mHandler->mPollTimeout);
  79. if (elapsed >= timeout) {
  80. return 0;
  81. }
  82. return timeout - elapsed;
  83. }
  84. //-----------------------------------------------------------------------------
  85. // ctor/dtor (called on the main/UI thread by the service manager)
  86. nsSocketTransportService::nsSocketTransportService()
  87. : mThread(nullptr)
  88. , mLock("nsSocketTransportService::mLock")
  89. , mInitialized(false)
  90. , mShuttingDown(false)
  91. , mOffline(false)
  92. , mGoingOffline(false)
  93. , mRawThread(nullptr)
  94. , mActiveListSize(SOCKET_LIMIT_MIN)
  95. , mIdleListSize(SOCKET_LIMIT_MIN)
  96. , mActiveCount(0)
  97. , mIdleCount(0)
  98. , mSentBytesCount(0)
  99. , mReceivedBytesCount(0)
  100. , mSendBufferSize(0)
  101. , mKeepaliveIdleTimeS(600)
  102. , mKeepaliveRetryIntervalS(1)
  103. , mKeepaliveProbeCount(kDefaultTCPKeepCount)
  104. , mKeepaliveEnabledPref(false)
  105. , mServingPendingQueue(false)
  106. , mMaxTimePerPollIter(100)
  107. , mMaxTimeForPrClosePref(PR_SecondsToInterval(5))
  108. , mSleepPhase(false)
  109. , mProbedMaxCount(false)
  110. #if defined(XP_WIN)
  111. , mPolling(false)
  112. #endif
  113. {
  114. NS_ASSERTION(NS_IsMainThread(), "wrong thread");
  115. PR_CallOnce(&gMaxCountInitOnce, DiscoverMaxCount);
  116. mActiveList = (SocketContext *)
  117. moz_xmalloc(sizeof(SocketContext) * mActiveListSize);
  118. mIdleList = (SocketContext *)
  119. moz_xmalloc(sizeof(SocketContext) * mIdleListSize);
  120. mPollList = (PRPollDesc *)
  121. moz_xmalloc(sizeof(PRPollDesc) * (mActiveListSize + 1));
  122. NS_ASSERTION(!gSocketTransportService, "must not instantiate twice");
  123. gSocketTransportService = this;
  124. }
  125. nsSocketTransportService::~nsSocketTransportService()
  126. {
  127. NS_ASSERTION(NS_IsMainThread(), "wrong thread");
  128. NS_ASSERTION(!mInitialized, "not shutdown properly");
  129. free(mActiveList);
  130. free(mIdleList);
  131. free(mPollList);
  132. gSocketTransportService = nullptr;
  133. }
  134. //-----------------------------------------------------------------------------
  135. // event queue (any thread)
  136. already_AddRefed<nsIThread>
  137. nsSocketTransportService::GetThreadSafely()
  138. {
  139. MutexAutoLock lock(mLock);
  140. nsCOMPtr<nsIThread> result = mThread;
  141. return result.forget();
  142. }
  143. NS_IMETHODIMP
  144. nsSocketTransportService::DispatchFromScript(nsIRunnable *event, uint32_t flags)
  145. {
  146. nsCOMPtr<nsIRunnable> event_ref(event);
  147. return Dispatch(event_ref.forget(), flags);
  148. }
  149. NS_IMETHODIMP
  150. nsSocketTransportService::Dispatch(already_AddRefed<nsIRunnable> event, uint32_t flags)
  151. {
  152. nsCOMPtr<nsIRunnable> event_ref(event);
  153. SOCKET_LOG(("STS dispatch [%p]\n", event_ref.get()));
  154. nsCOMPtr<nsIThread> thread = GetThreadSafely();
  155. nsresult rv;
  156. rv = thread ? thread->Dispatch(event_ref.forget(), flags) : NS_ERROR_NOT_INITIALIZED;
  157. if (rv == NS_ERROR_UNEXPECTED) {
  158. // Thread is no longer accepting events. We must have just shut it
  159. // down on the main thread. Pretend we never saw it.
  160. rv = NS_ERROR_NOT_INITIALIZED;
  161. }
  162. return rv;
  163. }
  164. NS_IMETHODIMP
  165. nsSocketTransportService::DelayedDispatch(already_AddRefed<nsIRunnable>, uint32_t)
  166. {
  167. return NS_ERROR_NOT_IMPLEMENTED;
  168. }
  169. NS_IMETHODIMP
  170. nsSocketTransportService::IsOnCurrentThread(bool *result)
  171. {
  172. nsCOMPtr<nsIThread> thread = GetThreadSafely();
  173. NS_ENSURE_TRUE(thread, NS_ERROR_NOT_INITIALIZED);
  174. return thread->IsOnCurrentThread(result);
  175. }
  176. //-----------------------------------------------------------------------------
  177. // socket api (socket thread only)
  178. NS_IMETHODIMP
  179. nsSocketTransportService::NotifyWhenCanAttachSocket(nsIRunnable *event)
  180. {
  181. SOCKET_LOG(("nsSocketTransportService::NotifyWhenCanAttachSocket\n"));
  182. NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread");
  183. if (CanAttachSocket()) {
  184. return Dispatch(event, NS_DISPATCH_NORMAL);
  185. }
  186. auto *runnable = new LinkedRunnableEvent(event);
  187. mPendingSocketQueue.insertBack(runnable);
  188. return NS_OK;
  189. }
  190. NS_IMETHODIMP
  191. nsSocketTransportService::AttachSocket(PRFileDesc *fd, nsASocketHandler *handler)
  192. {
  193. SOCKET_LOG(("nsSocketTransportService::AttachSocket [handler=%p]\n", handler));
  194. NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread");
  195. if (!CanAttachSocket()) {
  196. return NS_ERROR_NOT_AVAILABLE;
  197. }
  198. SocketContext sock;
  199. sock.mFD = fd;
  200. sock.mHandler = handler;
  201. sock.mPollStartEpoch = 0;
  202. nsresult rv = AddToIdleList(&sock);
  203. if (NS_SUCCEEDED(rv))
  204. NS_ADDREF(handler);
  205. return rv;
  206. }
  207. // the number of sockets that can be attached at any given time is
  208. // limited. this is done because some operating systems (e.g., Win9x)
  209. // limit the number of sockets that can be created by an application.
  210. // AttachSocket will fail if the limit is exceeded. consumers should
  211. // call CanAttachSocket and check the result before creating a socket.
  212. bool
  213. nsSocketTransportService::CanAttachSocket()
  214. {
  215. uint32_t total = mActiveCount + mIdleCount;
  216. bool rv = total < gMaxCount;
  217. return rv;
  218. }
  219. nsresult
  220. nsSocketTransportService::DetachSocket(SocketContext *listHead, SocketContext *sock)
  221. {
  222. SOCKET_LOG(("nsSocketTransportService::DetachSocket [handler=%p]\n", sock->mHandler));
  223. MOZ_ASSERT((listHead == mActiveList) || (listHead == mIdleList),
  224. "DetachSocket invalid head");
  225. // inform the handler that this socket is going away
  226. sock->mHandler->OnSocketDetached(sock->mFD);
  227. mSentBytesCount += sock->mHandler->ByteCountSent();
  228. mReceivedBytesCount += sock->mHandler->ByteCountReceived();
  229. // cleanup
  230. sock->mFD = nullptr;
  231. NS_RELEASE(sock->mHandler);
  232. if (listHead == mActiveList)
  233. RemoveFromPollList(sock);
  234. else
  235. RemoveFromIdleList(sock);
  236. // NOTE: sock is now an invalid pointer
  237. //
  238. // notify the first element on the pending socket queue...
  239. //
  240. nsCOMPtr<nsIRunnable> event;
  241. LinkedRunnableEvent *runnable = mPendingSocketQueue.getFirst();
  242. if (runnable) {
  243. event = runnable->TakeEvent();
  244. runnable->remove();
  245. delete runnable;
  246. }
  247. if (event) {
  248. // move event from pending queue to dispatch queue
  249. return Dispatch(event, NS_DISPATCH_NORMAL);
  250. }
  251. return NS_OK;
  252. }
  253. nsresult
  254. nsSocketTransportService::AddToPollList(SocketContext *sock)
  255. {
  256. MOZ_ASSERT(!(static_cast<uint32_t>(sock - mActiveList) < mActiveListSize),
  257. "AddToPollList Socket Already Active");
  258. SOCKET_LOG(("nsSocketTransportService::AddToPollList [handler=%p]\n", sock->mHandler));
  259. if (mActiveCount == mActiveListSize) {
  260. SOCKET_LOG((" Active List size of %d met\n", mActiveCount));
  261. if (!GrowActiveList()) {
  262. NS_ERROR("too many active sockets");
  263. return NS_ERROR_OUT_OF_MEMORY;
  264. }
  265. }
  266. uint32_t newSocketIndex = mActiveCount;
  267. if (ChaosMode::isActive(ChaosFeature::NetworkScheduling)) {
  268. newSocketIndex = ChaosMode::randomUint32LessThan(mActiveCount + 1);
  269. PodMove(mActiveList + newSocketIndex + 1, mActiveList + newSocketIndex,
  270. mActiveCount - newSocketIndex);
  271. PodMove(mPollList + newSocketIndex + 2, mPollList + newSocketIndex + 1,
  272. mActiveCount - newSocketIndex);
  273. }
  274. sock->StartTimeout(PR_IntervalNow());
  275. mActiveList[newSocketIndex] = *sock;
  276. mActiveCount++;
  277. mPollList[newSocketIndex + 1].fd = sock->mFD;
  278. mPollList[newSocketIndex + 1].in_flags = sock->mHandler->mPollFlags;
  279. mPollList[newSocketIndex + 1].out_flags = 0;
  280. SOCKET_LOG((" active=%u idle=%u\n", mActiveCount, mIdleCount));
  281. return NS_OK;
  282. }
  283. void
  284. nsSocketTransportService::RemoveFromPollList(SocketContext *sock)
  285. {
  286. SOCKET_LOG(("nsSocketTransportService::RemoveFromPollList [handler=%p]\n", sock->mHandler));
  287. uint32_t index = sock - mActiveList;
  288. MOZ_ASSERT(index < mActiveListSize, "invalid index");
  289. SOCKET_LOG((" index=%u mActiveCount=%u\n", index, mActiveCount));
  290. if (index != mActiveCount-1) {
  291. mActiveList[index] = mActiveList[mActiveCount-1];
  292. mPollList[index+1] = mPollList[mActiveCount];
  293. }
  294. mActiveCount--;
  295. SOCKET_LOG((" active=%u idle=%u\n", mActiveCount, mIdleCount));
  296. }
  297. nsresult
  298. nsSocketTransportService::AddToIdleList(SocketContext *sock)
  299. {
  300. MOZ_ASSERT(!(static_cast<uint32_t>(sock - mIdleList) < mIdleListSize),
  301. "AddToIdlelList Socket Already Idle");
  302. SOCKET_LOG(("nsSocketTransportService::AddToIdleList [handler=%p]\n", sock->mHandler));
  303. if (mIdleCount == mIdleListSize) {
  304. SOCKET_LOG((" Idle List size of %d met\n", mIdleCount));
  305. if (!GrowIdleList()) {
  306. NS_ERROR("too many idle sockets");
  307. return NS_ERROR_OUT_OF_MEMORY;
  308. }
  309. }
  310. mIdleList[mIdleCount] = *sock;
  311. mIdleCount++;
  312. SOCKET_LOG((" active=%u idle=%u\n", mActiveCount, mIdleCount));
  313. return NS_OK;
  314. }
  315. void
  316. nsSocketTransportService::RemoveFromIdleList(SocketContext *sock)
  317. {
  318. SOCKET_LOG(("nsSocketTransportService::RemoveFromIdleList [handler=%p]\n", sock->mHandler));
  319. uint32_t index = sock - mIdleList;
  320. NS_ASSERTION(index < mIdleListSize, "invalid index in idle list");
  321. if (index != mIdleCount-1)
  322. mIdleList[index] = mIdleList[mIdleCount-1];
  323. mIdleCount--;
  324. SOCKET_LOG((" active=%u idle=%u\n", mActiveCount, mIdleCount));
  325. }
  326. void
  327. nsSocketTransportService::MoveToIdleList(SocketContext *sock)
  328. {
  329. nsresult rv = AddToIdleList(sock);
  330. if (NS_FAILED(rv))
  331. DetachSocket(mActiveList, sock);
  332. else
  333. RemoveFromPollList(sock);
  334. }
  335. void
  336. nsSocketTransportService::MoveToPollList(SocketContext *sock)
  337. {
  338. nsresult rv = AddToPollList(sock);
  339. if (NS_FAILED(rv))
  340. DetachSocket(mIdleList, sock);
  341. else
  342. RemoveFromIdleList(sock);
  343. }
  344. bool
  345. nsSocketTransportService::GrowActiveList()
  346. {
  347. int32_t toAdd = gMaxCount - mActiveListSize;
  348. if (toAdd > 100) {
  349. toAdd = 100;
  350. } else if (toAdd < 1) {
  351. MOZ_ASSERT(false, "CanAttachSocket() should prevent this");
  352. return false;
  353. }
  354. mActiveListSize += toAdd;
  355. mActiveList = (SocketContext *)
  356. moz_xrealloc(mActiveList, sizeof(SocketContext) * mActiveListSize);
  357. mPollList = (PRPollDesc *)
  358. moz_xrealloc(mPollList, sizeof(PRPollDesc) * (mActiveListSize + 1));
  359. return true;
  360. }
  361. bool
  362. nsSocketTransportService::GrowIdleList()
  363. {
  364. int32_t toAdd = gMaxCount - mIdleListSize;
  365. if (toAdd > 100) {
  366. toAdd = 100;
  367. } else if (toAdd < 1) {
  368. MOZ_ASSERT(false, "CanAttachSocket() should prevent this");
  369. return false;
  370. }
  371. mIdleListSize += toAdd;
  372. mIdleList = (SocketContext *)
  373. moz_xrealloc(mIdleList, sizeof(SocketContext) * mIdleListSize);
  374. return true;
  375. }
  376. PRIntervalTime
  377. nsSocketTransportService::PollTimeout(PRIntervalTime now)
  378. {
  379. if (mActiveCount == 0) {
  380. return NS_SOCKET_POLL_TIMEOUT;
  381. }
  382. // compute minimum time before any socket timeout expires.
  383. PRIntervalTime minR = NS_SOCKET_POLL_TIMEOUT;
  384. for (uint32_t i=0; i<mActiveCount; ++i) {
  385. const SocketContext &s = mActiveList[i];
  386. PRIntervalTime r = s.TimeoutIn(now);
  387. if (r < minR) {
  388. minR = r;
  389. }
  390. }
  391. if (minR == NS_SOCKET_POLL_TIMEOUT) {
  392. SOCKET_LOG(("poll timeout: none\n"));
  393. return NS_SOCKET_POLL_TIMEOUT;
  394. }
  395. SOCKET_LOG(("poll timeout: %lu seconds\n", PR_IntervalToSeconds(minR)));
  396. return minR;
  397. }
  398. int32_t
  399. nsSocketTransportService::Poll(PRIntervalTime ts)
  400. {
  401. PRPollDesc *pollList;
  402. uint32_t pollCount;
  403. PRIntervalTime pollTimeout;
  404. // If there are pending events for this thread then
  405. // DoPollIteration() should service the network without blocking.
  406. bool pendingEvents = false;
  407. mRawThread->HasPendingEvents(&pendingEvents);
  408. if (mPollList[0].fd) {
  409. mPollList[0].out_flags = 0;
  410. pollList = mPollList;
  411. pollCount = mActiveCount + 1;
  412. pollTimeout = pendingEvents ? PR_INTERVAL_NO_WAIT : PollTimeout(ts);
  413. }
  414. else {
  415. // no pollable event, so busy wait...
  416. pollCount = mActiveCount;
  417. if (pollCount)
  418. pollList = &mPollList[1];
  419. else
  420. pollList = nullptr;
  421. pollTimeout =
  422. pendingEvents ? PR_INTERVAL_NO_WAIT : PR_MillisecondsToInterval(25);
  423. }
  424. SOCKET_LOG((" timeout = %i milliseconds\n",
  425. PR_IntervalToMilliseconds(pollTimeout)));
  426. int32_t rv = PR_Poll(pollList, pollCount, pollTimeout);
  427. SOCKET_LOG((" ...returned after %i milliseconds\n",
  428. PR_IntervalToMilliseconds(PR_IntervalNow() - ts)));
  429. return rv;
  430. }
  431. //-----------------------------------------------------------------------------
  432. // xpcom api
  433. NS_IMPL_ISUPPORTS(nsSocketTransportService,
  434. nsISocketTransportService,
  435. nsIRoutedSocketTransportService,
  436. nsIEventTarget,
  437. nsIThreadObserver,
  438. nsIRunnable,
  439. nsPISocketTransportService,
  440. nsIObserver)
  441. // called from main thread only
  442. NS_IMETHODIMP
  443. nsSocketTransportService::Init()
  444. {
  445. if (!NS_IsMainThread()) {
  446. NS_ERROR("wrong thread");
  447. return NS_ERROR_UNEXPECTED;
  448. }
  449. if (mInitialized)
  450. return NS_OK;
  451. if (mShuttingDown)
  452. return NS_ERROR_UNEXPECTED;
  453. nsCOMPtr<nsIThread> thread;
  454. nsresult rv = NS_NewNamedThread("Socket Thread", getter_AddRefs(thread), this);
  455. if (NS_FAILED(rv)) return rv;
  456. {
  457. MutexAutoLock lock(mLock);
  458. // Install our mThread, protecting against concurrent readers
  459. thread.swap(mThread);
  460. }
  461. nsCOMPtr<nsIPrefBranch> tmpPrefService = do_GetService(NS_PREFSERVICE_CONTRACTID);
  462. if (tmpPrefService) {
  463. tmpPrefService->AddObserver(SEND_BUFFER_PREF, this, false);
  464. tmpPrefService->AddObserver(KEEPALIVE_ENABLED_PREF, this, false);
  465. tmpPrefService->AddObserver(KEEPALIVE_IDLE_TIME_PREF, this, false);
  466. tmpPrefService->AddObserver(KEEPALIVE_RETRY_INTERVAL_PREF, this, false);
  467. tmpPrefService->AddObserver(KEEPALIVE_PROBE_COUNT_PREF, this, false);
  468. tmpPrefService->AddObserver(MAX_TIME_BETWEEN_TWO_POLLS, this, false);
  469. tmpPrefService->AddObserver(MAX_TIME_FOR_PR_CLOSE_DURING_SHUTDOWN, this, false);
  470. }
  471. UpdatePrefs();
  472. nsCOMPtr<nsIObserverService> obsSvc = services::GetObserverService();
  473. if (obsSvc) {
  474. obsSvc->AddObserver(this, "profile-initial-state", false);
  475. obsSvc->AddObserver(this, "last-pb-context-exited", false);
  476. obsSvc->AddObserver(this, NS_WIDGET_SLEEP_OBSERVER_TOPIC, true);
  477. obsSvc->AddObserver(this, NS_WIDGET_WAKE_OBSERVER_TOPIC, true);
  478. obsSvc->AddObserver(this, "xpcom-shutdown-threads", false);
  479. }
  480. mInitialized = true;
  481. return NS_OK;
  482. }
  483. // called from main thread only
  484. NS_IMETHODIMP
  485. nsSocketTransportService::Shutdown(bool aXpcomShutdown)
  486. {
  487. SOCKET_LOG(("nsSocketTransportService::Shutdown\n"));
  488. NS_ENSURE_STATE(NS_IsMainThread());
  489. if (!mInitialized)
  490. return NS_OK;
  491. if (mShuttingDown)
  492. return NS_ERROR_UNEXPECTED;
  493. {
  494. MutexAutoLock lock(mLock);
  495. // signal the socket thread to shutdown
  496. mShuttingDown = true;
  497. if (mPollableEvent) {
  498. mPollableEvent->Signal();
  499. }
  500. }
  501. if (!aXpcomShutdown) {
  502. return ShutdownThread();
  503. }
  504. return NS_OK;
  505. }
  506. nsresult
  507. nsSocketTransportService::ShutdownThread()
  508. {
  509. SOCKET_LOG(("nsSocketTransportService::ShutdownThread\n"));
  510. NS_ENSURE_STATE(NS_IsMainThread());
  511. if (!mInitialized || !mShuttingDown)
  512. return NS_OK;
  513. // join with thread
  514. mThread->Shutdown();
  515. {
  516. MutexAutoLock lock(mLock);
  517. // Drop our reference to mThread and make sure that any concurrent
  518. // readers are excluded
  519. mThread = nullptr;
  520. }
  521. nsCOMPtr<nsIPrefBranch> tmpPrefService = do_GetService(NS_PREFSERVICE_CONTRACTID);
  522. if (tmpPrefService)
  523. tmpPrefService->RemoveObserver(SEND_BUFFER_PREF, this);
  524. nsCOMPtr<nsIObserverService> obsSvc = services::GetObserverService();
  525. if (obsSvc) {
  526. obsSvc->RemoveObserver(this, "profile-initial-state");
  527. obsSvc->RemoveObserver(this, "last-pb-context-exited");
  528. obsSvc->RemoveObserver(this, NS_WIDGET_SLEEP_OBSERVER_TOPIC);
  529. obsSvc->RemoveObserver(this, NS_WIDGET_WAKE_OBSERVER_TOPIC);
  530. obsSvc->RemoveObserver(this, "xpcom-shutdown-threads");
  531. }
  532. if (mAfterWakeUpTimer) {
  533. mAfterWakeUpTimer->Cancel();
  534. mAfterWakeUpTimer = nullptr;
  535. }
  536. NetworkActivityMonitor::Shutdown();
  537. mInitialized = false;
  538. mShuttingDown = false;
  539. return NS_OK;
  540. }
  541. NS_IMETHODIMP
  542. nsSocketTransportService::GetOffline(bool *offline)
  543. {
  544. *offline = mOffline;
  545. return NS_OK;
  546. }
  547. NS_IMETHODIMP
  548. nsSocketTransportService::SetOffline(bool offline)
  549. {
  550. MutexAutoLock lock(mLock);
  551. if (!mOffline && offline) {
  552. // signal the socket thread to go offline, so it will detach sockets
  553. mGoingOffline = true;
  554. mOffline = true;
  555. }
  556. else if (mOffline && !offline) {
  557. mOffline = false;
  558. }
  559. if (mPollableEvent) {
  560. mPollableEvent->Signal();
  561. }
  562. return NS_OK;
  563. }
  564. NS_IMETHODIMP
  565. nsSocketTransportService::GetKeepaliveIdleTime(int32_t *aKeepaliveIdleTimeS)
  566. {
  567. MOZ_ASSERT(aKeepaliveIdleTimeS);
  568. if (NS_WARN_IF(!aKeepaliveIdleTimeS)) {
  569. return NS_ERROR_NULL_POINTER;
  570. }
  571. *aKeepaliveIdleTimeS = mKeepaliveIdleTimeS;
  572. return NS_OK;
  573. }
  574. NS_IMETHODIMP
  575. nsSocketTransportService::GetKeepaliveRetryInterval(int32_t *aKeepaliveRetryIntervalS)
  576. {
  577. MOZ_ASSERT(aKeepaliveRetryIntervalS);
  578. if (NS_WARN_IF(!aKeepaliveRetryIntervalS)) {
  579. return NS_ERROR_NULL_POINTER;
  580. }
  581. *aKeepaliveRetryIntervalS = mKeepaliveRetryIntervalS;
  582. return NS_OK;
  583. }
  584. NS_IMETHODIMP
  585. nsSocketTransportService::GetKeepaliveProbeCount(int32_t *aKeepaliveProbeCount)
  586. {
  587. MOZ_ASSERT(aKeepaliveProbeCount);
  588. if (NS_WARN_IF(!aKeepaliveProbeCount)) {
  589. return NS_ERROR_NULL_POINTER;
  590. }
  591. *aKeepaliveProbeCount = mKeepaliveProbeCount;
  592. return NS_OK;
  593. }
  594. NS_IMETHODIMP
  595. nsSocketTransportService::CreateTransport(const char **types,
  596. uint32_t typeCount,
  597. const nsACString &host,
  598. int32_t port,
  599. nsIProxyInfo *proxyInfo,
  600. nsISocketTransport **result)
  601. {
  602. return CreateRoutedTransport(types, typeCount, host, port, NS_LITERAL_CSTRING(""), 0,
  603. proxyInfo, result);
  604. }
  605. NS_IMETHODIMP
  606. nsSocketTransportService::CreateRoutedTransport(const char **types,
  607. uint32_t typeCount,
  608. const nsACString &host,
  609. int32_t port,
  610. const nsACString &hostRoute,
  611. int32_t portRoute,
  612. nsIProxyInfo *proxyInfo,
  613. nsISocketTransport **result)
  614. {
  615. NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED);
  616. NS_ENSURE_TRUE(port >= 0 && port <= 0xFFFF, NS_ERROR_ILLEGAL_VALUE);
  617. RefPtr<nsSocketTransport> trans = new nsSocketTransport();
  618. nsresult rv = trans->Init(types, typeCount, host, port, hostRoute, portRoute, proxyInfo);
  619. if (NS_FAILED(rv)) {
  620. return rv;
  621. }
  622. trans.forget(result);
  623. return NS_OK;
  624. }
  625. NS_IMETHODIMP
  626. nsSocketTransportService::CreateUnixDomainTransport(nsIFile *aPath,
  627. nsISocketTransport **result)
  628. {
  629. nsresult rv;
  630. NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED);
  631. nsAutoCString path;
  632. rv = aPath->GetNativePath(path);
  633. if (NS_FAILED(rv))
  634. return rv;
  635. RefPtr<nsSocketTransport> trans = new nsSocketTransport();
  636. rv = trans->InitWithFilename(path.get());
  637. if (NS_FAILED(rv))
  638. return rv;
  639. trans.forget(result);
  640. return NS_OK;
  641. }
  642. NS_IMETHODIMP
  643. nsSocketTransportService::OnDispatchedEvent(nsIThreadInternal *thread)
  644. {
  645. #ifndef XP_WIN
  646. // On windows poll can hang and this became worse when we introduced the
  647. // patch for bug 698882 (see also bug 1292181), therefore we reverted the
  648. // behavior on windows to be as before bug 698882, e.g. write to the socket
  649. // also if an event dispatch is on the socket thread and writing to the
  650. // socket for each event.
  651. if (PR_GetCurrentThread() == gSocketThread) {
  652. // this check is redundant to one done inside ::Signal(), but
  653. // we can do it here and skip obtaining the lock - given that
  654. // this is a relatively common occurance its worth the
  655. // redundant code
  656. SOCKET_LOG(("OnDispatchedEvent Same Thread Skip Signal\n"));
  657. return NS_OK;
  658. }
  659. #else
  660. if (gIOService->IsNetTearingDown()) {
  661. // Poll can hang sometimes. If we are in shutdown, we are going to
  662. // start a watchdog. If we do not exit poll within
  663. // REPAIR_POLLABLE_EVENT_TIME signal a pollable event again.
  664. StartPollWatchdog();
  665. }
  666. #endif
  667. MutexAutoLock lock(mLock);
  668. if (mPollableEvent) {
  669. mPollableEvent->Signal();
  670. }
  671. return NS_OK;
  672. }
  673. NS_IMETHODIMP
  674. nsSocketTransportService::OnProcessNextEvent(nsIThreadInternal *thread,
  675. bool mayWait)
  676. {
  677. return NS_OK;
  678. }
  679. NS_IMETHODIMP
  680. nsSocketTransportService::AfterProcessNextEvent(nsIThreadInternal* thread,
  681. bool eventWasProcessed)
  682. {
  683. return NS_OK;
  684. }
  685. void
  686. nsSocketTransportService::MarkTheLastElementOfPendingQueue()
  687. {
  688. mServingPendingQueue = false;
  689. }
  690. NS_IMETHODIMP
  691. nsSocketTransportService::Run()
  692. {
  693. SOCKET_LOG(("STS thread init %d sockets\n", gMaxCount));
  694. psm::InitializeSSLServerCertVerificationThreads();
  695. gSocketThread = PR_GetCurrentThread();
  696. {
  697. MutexAutoLock lock(mLock);
  698. mPollableEvent.reset(new PollableEvent());
  699. //
  700. // NOTE: per bug 190000, this failure could be caused by Zone-Alarm
  701. // or similar software.
  702. //
  703. // NOTE: per bug 191739, this failure could also be caused by lack
  704. // of a loopback device on Windows and OS/2 platforms (it creates
  705. // a loopback socket pair on these platforms to implement a pollable
  706. // event object). if we can't create a pollable event, then we'll
  707. // have to "busy wait" to implement the socket event queue :-(
  708. //
  709. if (!mPollableEvent->Valid()) {
  710. mPollableEvent = nullptr;
  711. NS_WARNING("running socket transport thread without a pollable event");
  712. SOCKET_LOG(("running socket transport thread without a pollable event"));
  713. }
  714. mPollList[0].fd = mPollableEvent ? mPollableEvent->PollableFD() : nullptr;
  715. mPollList[0].in_flags = PR_POLL_READ | PR_POLL_EXCEPT;
  716. mPollList[0].out_flags = 0;
  717. }
  718. mRawThread = NS_GetCurrentThread();
  719. // hook ourselves up to observe event processing for this thread
  720. nsCOMPtr<nsIThreadInternal> threadInt = do_QueryInterface(mRawThread);
  721. threadInt->SetObserver(this);
  722. // make sure the pseudo random number generator is seeded on this thread
  723. srand(static_cast<unsigned>(PR_Now()));
  724. for (;;) {
  725. bool pendingEvents = false;
  726. do {
  727. DoPollIteration();
  728. mRawThread->HasPendingEvents(&pendingEvents);
  729. if (pendingEvents) {
  730. if (!mServingPendingQueue) {
  731. nsresult rv = Dispatch(NewRunnableMethod(this,
  732. &nsSocketTransportService::MarkTheLastElementOfPendingQueue),
  733. nsIEventTarget::DISPATCH_NORMAL);
  734. if (NS_FAILED(rv)) {
  735. NS_WARNING("Could not dispatch a new event on the "
  736. "socket thread.");
  737. } else {
  738. mServingPendingQueue = true;
  739. }
  740. }
  741. TimeStamp eventQueueStart = TimeStamp::NowLoRes();
  742. do {
  743. NS_ProcessNextEvent(mRawThread);
  744. pendingEvents = false;
  745. mRawThread->HasPendingEvents(&pendingEvents);
  746. } while (pendingEvents && mServingPendingQueue &&
  747. ((TimeStamp::NowLoRes() -
  748. eventQueueStart).ToMilliseconds() <
  749. mMaxTimePerPollIter));
  750. }
  751. } while (pendingEvents);
  752. bool goingOffline = false;
  753. // now that our event queue is empty, check to see if we should exit
  754. {
  755. MutexAutoLock lock(mLock);
  756. if (mShuttingDown) {
  757. break;
  758. }
  759. if (mGoingOffline) {
  760. mGoingOffline = false;
  761. goingOffline = true;
  762. }
  763. }
  764. // Avoid potential deadlock
  765. if (goingOffline)
  766. Reset(true);
  767. }
  768. SOCKET_LOG(("STS shutting down thread\n"));
  769. // detach all sockets, including locals
  770. Reset(false);
  771. // Final pass over the event queue. This makes sure that events posted by
  772. // socket detach handlers get processed.
  773. NS_ProcessPendingEvents(mRawThread);
  774. gSocketThread = nullptr;
  775. psm::StopSSLServerCertVerificationThreads();
  776. SOCKET_LOG(("STS thread exit\n"));
  777. return NS_OK;
  778. }
  779. void
  780. nsSocketTransportService::DetachSocketWithGuard(bool aGuardLocals,
  781. SocketContext *socketList,
  782. int32_t index)
  783. {
  784. bool isGuarded = false;
  785. if (aGuardLocals) {
  786. socketList[index].mHandler->IsLocal(&isGuarded);
  787. if (!isGuarded)
  788. socketList[index].mHandler->KeepWhenOffline(&isGuarded);
  789. }
  790. if (!isGuarded)
  791. DetachSocket(socketList, &socketList[index]);
  792. }
  793. void
  794. nsSocketTransportService::Reset(bool aGuardLocals)
  795. {
  796. // detach any sockets
  797. int32_t i;
  798. for (i = mActiveCount - 1; i >= 0; --i) {
  799. DetachSocketWithGuard(aGuardLocals, mActiveList, i);
  800. }
  801. for (i = mIdleCount - 1; i >= 0; --i) {
  802. DetachSocketWithGuard(aGuardLocals, mIdleList, i);
  803. }
  804. }
  805. nsresult
  806. nsSocketTransportService::DoPollIteration()
  807. {
  808. SOCKET_LOG(("STS poll iter\n"));
  809. // Freeze "now" for list updates and polling.
  810. PRIntervalTime now = PR_IntervalNow();
  811. int32_t i, count;
  812. //
  813. // poll loop
  814. //
  815. // walk active list backwards to see if any sockets should actually be
  816. // idle, then walk the idle list backwards to see if any idle sockets
  817. // should become active. take care to check only idle sockets that
  818. // were idle to begin with ;-)
  819. //
  820. count = mIdleCount;
  821. for (i=mActiveCount-1; i>=0; --i) {
  822. //---
  823. SOCKET_LOG((" active [%u] { handler=%p condition=%x pollflags=%hu }\n", i,
  824. mActiveList[i].mHandler,
  825. mActiveList[i].mHandler->mCondition,
  826. mActiveList[i].mHandler->mPollFlags));
  827. //---
  828. if (NS_FAILED(mActiveList[i].mHandler->mCondition)) {
  829. DetachSocket(mActiveList, &mActiveList[i]);
  830. } else {
  831. uint16_t in_flags = mActiveList[i].mHandler->mPollFlags;
  832. if (in_flags == 0) {
  833. MoveToIdleList(&mActiveList[i]);
  834. } else {
  835. // update poll flags
  836. mPollList[i+1].in_flags = in_flags;
  837. mPollList[i+1].out_flags = 0;
  838. // Active polling entry; start timeout.
  839. mActiveList[i].StartTimeout(now);
  840. }
  841. }
  842. }
  843. for (i=count-1; i>=0; --i) {
  844. //---
  845. SOCKET_LOG((" idle [%u] { handler=%p condition=%x pollflags=%hu }\n", i,
  846. mIdleList[i].mHandler,
  847. mIdleList[i].mHandler->mCondition,
  848. mIdleList[i].mHandler->mPollFlags));
  849. //---
  850. if (NS_FAILED(mIdleList[i].mHandler->mCondition)) {
  851. DetachSocket(mIdleList, &mIdleList[i]);
  852. } else if (mIdleList[i].mHandler->mPollFlags != 0) {
  853. MoveToPollList(&mIdleList[i]);
  854. }
  855. }
  856. SOCKET_LOG((" calling PR_Poll [active=%u idle=%u]\n", mActiveCount, mIdleCount));
  857. #if defined(XP_WIN)
  858. // 30 active connections is the historic limit before firefox 7's 256. A few
  859. // windows systems have troubles with the higher limit, so actively probe a
  860. // limit the first time we exceed 30.
  861. if ((mActiveCount > 30) && !mProbedMaxCount)
  862. ProbeMaxCount();
  863. #endif
  864. // Measures seconds spent while blocked on PR_Poll
  865. int32_t n = 0;
  866. if (!gIOService->IsNetTearingDown()) {
  867. // Let's not do polling during shutdown.
  868. #if defined(XP_WIN)
  869. StartPolling();
  870. #endif
  871. n = Poll(now);
  872. #if defined(XP_WIN)
  873. EndPolling();
  874. #endif
  875. }
  876. // Refresh when "now" is for following checks.
  877. now = PR_IntervalNow();
  878. if (n < 0) {
  879. SOCKET_LOG((" PR_Poll error [%d] os error [%d]\n", PR_GetError(),
  880. PR_GetOSError()));
  881. } else {
  882. //
  883. // service "active" sockets...
  884. //
  885. for (i=0; i<int32_t(mActiveCount); ++i) {
  886. PRPollDesc &desc = mPollList[i+1];
  887. SocketContext &s = mActiveList[i];
  888. if (n > 0 && desc.out_flags != 0) {
  889. s.StopTimeout();
  890. s.mHandler->OnSocketReady(desc.fd, desc.out_flags);
  891. } else if (s.IsTimedOut(now)) {
  892. // Socket timed out; disengage.
  893. s.StopTimeout();
  894. s.mHandler->OnSocketReady(desc.fd, -1);
  895. } else {
  896. // We may have recorded a timeout start on a socket and subsequently
  897. // set it to not time out. Check the socket and reset the timestamp
  898. // in this case to keep our states predictable.
  899. s.ResetTimeout();
  900. }
  901. }
  902. //
  903. // check for "dead" sockets and remove them (need to do this in
  904. // reverse order obviously).
  905. //
  906. for (i=mActiveCount-1; i>=0; --i) {
  907. if (NS_FAILED(mActiveList[i].mHandler->mCondition))
  908. DetachSocket(mActiveList, &mActiveList[i]);
  909. }
  910. if (n != 0 && (mPollList[0].out_flags & (PR_POLL_READ | PR_POLL_EXCEPT))) {
  911. MutexAutoLock lock(mLock);
  912. // acknowledge pollable event (should not block)
  913. if (mPollableEvent &&
  914. ((mPollList[0].out_flags & PR_POLL_EXCEPT) ||
  915. !mPollableEvent->Clear())) {
  916. // On Windows, the TCP loopback connection in the
  917. // pollable event may become broken when a laptop
  918. // switches between wired and wireless networks or
  919. // wakes up from hibernation. We try to create a
  920. // new pollable event. If that fails, we fall back
  921. // on "busy wait".
  922. NS_WARNING("Trying to repair mPollableEvent");
  923. mPollableEvent.reset(new PollableEvent());
  924. if (!mPollableEvent->Valid()) {
  925. mPollableEvent = nullptr;
  926. }
  927. SOCKET_LOG(("running socket transport thread without "
  928. "a pollable event now valid=%d", !!mPollableEvent));
  929. mPollList[0].fd = mPollableEvent ? mPollableEvent->PollableFD() : nullptr;
  930. mPollList[0].in_flags = PR_POLL_READ | PR_POLL_EXCEPT;
  931. mPollList[0].out_flags = 0;
  932. }
  933. }
  934. }
  935. return NS_OK;
  936. }
  937. void
  938. nsSocketTransportService::UpdateSendBufferPref(nsIPrefBranch *pref)
  939. {
  940. int32_t bufferSize;
  941. // If the pref is set, honor it. 0 means use OS defaults.
  942. nsresult rv = pref->GetIntPref(SEND_BUFFER_PREF, &bufferSize);
  943. if (NS_SUCCEEDED(rv)) {
  944. mSendBufferSize = bufferSize;
  945. return;
  946. }
  947. #if defined(XP_WIN)
  948. mSendBufferSize = 131072 * 4;
  949. #endif
  950. }
  951. nsresult
  952. nsSocketTransportService::UpdatePrefs()
  953. {
  954. mSendBufferSize = 0;
  955. nsCOMPtr<nsIPrefBranch> tmpPrefService = do_GetService(NS_PREFSERVICE_CONTRACTID);
  956. if (tmpPrefService) {
  957. UpdateSendBufferPref(tmpPrefService);
  958. // Default TCP Keepalive Values.
  959. int32_t keepaliveIdleTimeS;
  960. nsresult rv = tmpPrefService->GetIntPref(KEEPALIVE_IDLE_TIME_PREF,
  961. &keepaliveIdleTimeS);
  962. if (NS_SUCCEEDED(rv))
  963. mKeepaliveIdleTimeS = clamped(keepaliveIdleTimeS,
  964. 1, kMaxTCPKeepIdle);
  965. int32_t keepaliveRetryIntervalS;
  966. rv = tmpPrefService->GetIntPref(KEEPALIVE_RETRY_INTERVAL_PREF,
  967. &keepaliveRetryIntervalS);
  968. if (NS_SUCCEEDED(rv))
  969. mKeepaliveRetryIntervalS = clamped(keepaliveRetryIntervalS,
  970. 1, kMaxTCPKeepIntvl);
  971. int32_t keepaliveProbeCount;
  972. rv = tmpPrefService->GetIntPref(KEEPALIVE_PROBE_COUNT_PREF,
  973. &keepaliveProbeCount);
  974. if (NS_SUCCEEDED(rv))
  975. mKeepaliveProbeCount = clamped(keepaliveProbeCount,
  976. 1, kMaxTCPKeepCount);
  977. bool keepaliveEnabled = false;
  978. rv = tmpPrefService->GetBoolPref(KEEPALIVE_ENABLED_PREF,
  979. &keepaliveEnabled);
  980. if (NS_SUCCEEDED(rv) && keepaliveEnabled != mKeepaliveEnabledPref) {
  981. mKeepaliveEnabledPref = keepaliveEnabled;
  982. OnKeepaliveEnabledPrefChange();
  983. }
  984. int32_t maxTimePref;
  985. rv = tmpPrefService->GetIntPref(MAX_TIME_BETWEEN_TWO_POLLS,
  986. &maxTimePref);
  987. if (NS_SUCCEEDED(rv) && maxTimePref >= 0) {
  988. mMaxTimePerPollIter = maxTimePref;
  989. }
  990. int32_t maxTimeForPrClosePref;
  991. rv = tmpPrefService->GetIntPref(MAX_TIME_FOR_PR_CLOSE_DURING_SHUTDOWN,
  992. &maxTimeForPrClosePref);
  993. if (NS_SUCCEEDED(rv) && maxTimeForPrClosePref >=0) {
  994. mMaxTimeForPrClosePref = PR_MillisecondsToInterval(maxTimeForPrClosePref);
  995. }
  996. }
  997. return NS_OK;
  998. }
  999. void
  1000. nsSocketTransportService::OnKeepaliveEnabledPrefChange()
  1001. {
  1002. // Dispatch to socket thread if we're not executing there.
  1003. if (PR_GetCurrentThread() != gSocketThread) {
  1004. gSocketTransportService->Dispatch(
  1005. NewRunnableMethod(
  1006. this, &nsSocketTransportService::OnKeepaliveEnabledPrefChange),
  1007. NS_DISPATCH_NORMAL);
  1008. return;
  1009. }
  1010. SOCKET_LOG(("nsSocketTransportService::OnKeepaliveEnabledPrefChange %s",
  1011. mKeepaliveEnabledPref ? "enabled" : "disabled"));
  1012. // Notify each socket that keepalive has been en/disabled globally.
  1013. for (int32_t i = mActiveCount - 1; i >= 0; --i) {
  1014. NotifyKeepaliveEnabledPrefChange(&mActiveList[i]);
  1015. }
  1016. for (int32_t i = mIdleCount - 1; i >= 0; --i) {
  1017. NotifyKeepaliveEnabledPrefChange(&mIdleList[i]);
  1018. }
  1019. }
  1020. void
  1021. nsSocketTransportService::NotifyKeepaliveEnabledPrefChange(SocketContext *sock)
  1022. {
  1023. MOZ_ASSERT(sock, "SocketContext cannot be null!");
  1024. MOZ_ASSERT(sock->mHandler, "SocketContext does not have a handler!");
  1025. if (!sock || !sock->mHandler) {
  1026. return;
  1027. }
  1028. sock->mHandler->OnKeepaliveEnabledPrefChange(mKeepaliveEnabledPref);
  1029. }
  1030. NS_IMETHODIMP
  1031. nsSocketTransportService::Observe(nsISupports *subject,
  1032. const char *topic,
  1033. const char16_t *data)
  1034. {
  1035. if (!strcmp(topic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
  1036. UpdatePrefs();
  1037. return NS_OK;
  1038. }
  1039. if (!strcmp(topic, "profile-initial-state")) {
  1040. int32_t blipInterval = Preferences::GetInt(BLIP_INTERVAL_PREF, 0);
  1041. if (blipInterval <= 0) {
  1042. return NS_OK;
  1043. }
  1044. return net::NetworkActivityMonitor::Init(blipInterval);
  1045. }
  1046. if (!strcmp(topic, "last-pb-context-exited")) {
  1047. nsCOMPtr<nsIRunnable> ev =
  1048. NewRunnableMethod(this,
  1049. &nsSocketTransportService::ClosePrivateConnections);
  1050. nsresult rv = Dispatch(ev, nsIEventTarget::DISPATCH_NORMAL);
  1051. NS_ENSURE_SUCCESS(rv, rv);
  1052. }
  1053. if (!strcmp(topic, NS_TIMER_CALLBACK_TOPIC)) {
  1054. nsCOMPtr<nsITimer> timer = do_QueryInterface(subject);
  1055. if (timer == mAfterWakeUpTimer) {
  1056. mAfterWakeUpTimer = nullptr;
  1057. mSleepPhase = false;
  1058. }
  1059. #if defined(XP_WIN)
  1060. if (timer == mPollRepairTimer) {
  1061. DoPollRepair();
  1062. }
  1063. #endif
  1064. } else if (!strcmp(topic, NS_WIDGET_SLEEP_OBSERVER_TOPIC)) {
  1065. mSleepPhase = true;
  1066. if (mAfterWakeUpTimer) {
  1067. mAfterWakeUpTimer->Cancel();
  1068. mAfterWakeUpTimer = nullptr;
  1069. }
  1070. } else if (!strcmp(topic, NS_WIDGET_WAKE_OBSERVER_TOPIC)) {
  1071. if (mSleepPhase && !mAfterWakeUpTimer) {
  1072. mAfterWakeUpTimer = do_CreateInstance("@mozilla.org/timer;1");
  1073. if (mAfterWakeUpTimer) {
  1074. mAfterWakeUpTimer->Init(this, 2000, nsITimer::TYPE_ONE_SHOT);
  1075. }
  1076. }
  1077. } else if (!strcmp(topic, "xpcom-shutdown-threads")) {
  1078. ShutdownThread();
  1079. }
  1080. return NS_OK;
  1081. }
  1082. void
  1083. nsSocketTransportService::ClosePrivateConnections()
  1084. {
  1085. // Must be called on the socket thread.
  1086. #ifdef DEBUG
  1087. bool onSTSThread;
  1088. IsOnCurrentThread(&onSTSThread);
  1089. MOZ_ASSERT(onSTSThread);
  1090. #endif
  1091. for (int32_t i = mActiveCount - 1; i >= 0; --i) {
  1092. if (mActiveList[i].mHandler->mIsPrivate) {
  1093. DetachSocket(mActiveList, &mActiveList[i]);
  1094. }
  1095. }
  1096. for (int32_t i = mIdleCount - 1; i >= 0; --i) {
  1097. if (mIdleList[i].mHandler->mIsPrivate) {
  1098. DetachSocket(mIdleList, &mIdleList[i]);
  1099. }
  1100. }
  1101. ClearPrivateSSLState();
  1102. }
  1103. NS_IMETHODIMP
  1104. nsSocketTransportService::GetSendBufferSize(int32_t *value)
  1105. {
  1106. *value = mSendBufferSize;
  1107. return NS_OK;
  1108. }
  1109. /// ugly OS specific includes are placed at the bottom of the src for clarity
  1110. #if defined(XP_WIN)
  1111. #include <windows.h>
  1112. #elif defined(XP_UNIX) && !defined(AIX) && !defined(NEXTSTEP) && !defined(QNX)
  1113. #include <sys/resource.h>
  1114. #endif
  1115. // Right now the only need to do this is on windows.
  1116. #if defined(XP_WIN)
  1117. void
  1118. nsSocketTransportService::ProbeMaxCount()
  1119. {
  1120. NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread");
  1121. if (mProbedMaxCount)
  1122. return;
  1123. mProbedMaxCount = true;
  1124. // Allocate and test a PR_Poll up to the gMaxCount number of unconnected
  1125. // sockets. See bug 692260 - windows should be able to handle 1000 sockets
  1126. // in select() without a problem, but LSPs have been known to balk at lower
  1127. // numbers. (64 in the bug).
  1128. // Allocate
  1129. struct PRPollDesc pfd[SOCKET_LIMIT_TARGET];
  1130. uint32_t numAllocated = 0;
  1131. for (uint32_t index = 0 ; index < gMaxCount; ++index) {
  1132. pfd[index].in_flags = PR_POLL_READ | PR_POLL_WRITE | PR_POLL_EXCEPT;
  1133. pfd[index].out_flags = 0;
  1134. pfd[index].fd = PR_OpenTCPSocket(PR_AF_INET);
  1135. if (!pfd[index].fd) {
  1136. SOCKET_LOG(("Socket Limit Test index %d failed\n", index));
  1137. if (index < SOCKET_LIMIT_MIN)
  1138. gMaxCount = SOCKET_LIMIT_MIN;
  1139. else
  1140. gMaxCount = index;
  1141. break;
  1142. }
  1143. ++numAllocated;
  1144. }
  1145. // Test
  1146. static_assert(SOCKET_LIMIT_MIN >= 32U, "Minimum Socket Limit is >= 32");
  1147. while (gMaxCount <= numAllocated) {
  1148. int32_t rv = PR_Poll(pfd, gMaxCount, PR_MillisecondsToInterval(0));
  1149. SOCKET_LOG(("Socket Limit Test poll() size=%d rv=%d\n",
  1150. gMaxCount, rv));
  1151. if (rv >= 0)
  1152. break;
  1153. SOCKET_LOG(("Socket Limit Test poll confirmationSize=%d rv=%d error=%d\n",
  1154. gMaxCount, rv, PR_GetError()));
  1155. gMaxCount -= 32;
  1156. if (gMaxCount <= SOCKET_LIMIT_MIN) {
  1157. gMaxCount = SOCKET_LIMIT_MIN;
  1158. break;
  1159. }
  1160. }
  1161. // Free
  1162. for (uint32_t index = 0 ; index < numAllocated; ++index)
  1163. if (pfd[index].fd)
  1164. PR_Close(pfd[index].fd);
  1165. SOCKET_LOG(("Socket Limit Test max was confirmed at %d\n", gMaxCount));
  1166. }
  1167. #endif // windows
  1168. PRStatus
  1169. nsSocketTransportService::DiscoverMaxCount()
  1170. {
  1171. gMaxCount = SOCKET_LIMIT_MIN;
  1172. #if defined(XP_UNIX) && !defined(AIX) && !defined(NEXTSTEP) && !defined(QNX)
  1173. // On unix and os x network sockets and file
  1174. // descriptors are the same. OS X comes defaulted at 256,
  1175. // most linux at 1000. We can reliably use [sg]rlimit to
  1176. // query that and raise it if needed.
  1177. struct rlimit rlimitData;
  1178. if (getrlimit(RLIMIT_NOFILE, &rlimitData) == -1) // rlimit broken - use min
  1179. return PR_SUCCESS;
  1180. if (rlimitData.rlim_cur >= SOCKET_LIMIT_TARGET) { // larger than target!
  1181. gMaxCount = SOCKET_LIMIT_TARGET;
  1182. return PR_SUCCESS;
  1183. }
  1184. int32_t maxallowed = rlimitData.rlim_max;
  1185. if ((uint32_t)maxallowed <= SOCKET_LIMIT_MIN) {
  1186. return PR_SUCCESS; // so small treat as if rlimit is broken
  1187. }
  1188. if ((maxallowed == -1) || // no hard cap - ok to set target
  1189. ((uint32_t)maxallowed >= SOCKET_LIMIT_TARGET)) {
  1190. maxallowed = SOCKET_LIMIT_TARGET;
  1191. }
  1192. rlimitData.rlim_cur = maxallowed;
  1193. setrlimit(RLIMIT_NOFILE, &rlimitData);
  1194. if ((getrlimit(RLIMIT_NOFILE, &rlimitData) != -1) &&
  1195. (rlimitData.rlim_cur > SOCKET_LIMIT_MIN)) {
  1196. gMaxCount = rlimitData.rlim_cur;
  1197. }
  1198. #elif defined(XP_WIN) && !defined(WIN_CE)
  1199. // >= XP is confirmed to have at least 1000
  1200. static_assert(SOCKET_LIMIT_TARGET <= 1000, "SOCKET_LIMIT_TARGET max value is 1000");
  1201. gMaxCount = SOCKET_LIMIT_TARGET;
  1202. #else
  1203. // other platforms are harder to test - so leave at safe legacy value
  1204. #endif
  1205. return PR_SUCCESS;
  1206. }
  1207. // Used to return connection info to Dashboard.cpp
  1208. void
  1209. nsSocketTransportService::AnalyzeConnection(nsTArray<SocketInfo> *data,
  1210. struct SocketContext *context, bool aActive)
  1211. {
  1212. if (context->mHandler->mIsPrivate)
  1213. return;
  1214. PRFileDesc *aFD = context->mFD;
  1215. PRFileDesc *idLayer = PR_GetIdentitiesLayer(aFD, PR_NSPR_IO_LAYER);
  1216. NS_ENSURE_TRUE_VOID(idLayer);
  1217. bool tcp = PR_GetDescType(idLayer) == PR_DESC_SOCKET_TCP;
  1218. PRNetAddr peer_addr;
  1219. PodZero(&peer_addr);
  1220. PRStatus rv = PR_GetPeerName(aFD, &peer_addr);
  1221. if (rv != PR_SUCCESS)
  1222. return;
  1223. char host[64] = {0};
  1224. rv = PR_NetAddrToString(&peer_addr, host, sizeof(host));
  1225. if (rv != PR_SUCCESS)
  1226. return;
  1227. uint16_t port;
  1228. if (peer_addr.raw.family == PR_AF_INET)
  1229. port = peer_addr.inet.port;
  1230. else
  1231. port = peer_addr.ipv6.port;
  1232. port = PR_ntohs(port);
  1233. uint64_t sent = context->mHandler->ByteCountSent();
  1234. uint64_t received = context->mHandler->ByteCountReceived();
  1235. SocketInfo info = { nsCString(host), sent, received, port, aActive, tcp };
  1236. data->AppendElement(info);
  1237. }
  1238. void
  1239. nsSocketTransportService::GetSocketConnections(nsTArray<SocketInfo> *data)
  1240. {
  1241. NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread");
  1242. for (uint32_t i = 0; i < mActiveCount; i++)
  1243. AnalyzeConnection(data, &mActiveList[i], true);
  1244. for (uint32_t i = 0; i < mIdleCount; i++)
  1245. AnalyzeConnection(data, &mIdleList[i], false);
  1246. }
  1247. #if defined(XP_WIN)
  1248. void
  1249. nsSocketTransportService::StartPollWatchdog()
  1250. {
  1251. MutexAutoLock lock(mLock);
  1252. // Poll can hang sometimes. If we are in shutdown, we are going to start a
  1253. // watchdog. If we do not exit poll within REPAIR_POLLABLE_EVENT_TIME
  1254. // signal a pollable event again.
  1255. MOZ_ASSERT(gIOService->IsNetTearingDown());
  1256. if (mPolling && !mPollRepairTimer) {
  1257. mPollRepairTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
  1258. mPollRepairTimer->Init(this, REPAIR_POLLABLE_EVENT_TIME,
  1259. nsITimer::TYPE_REPEATING_SLACK);
  1260. }
  1261. }
  1262. void
  1263. nsSocketTransportService::DoPollRepair()
  1264. {
  1265. MutexAutoLock lock(mLock);
  1266. if (mPolling && mPollableEvent) {
  1267. mPollableEvent->Signal();
  1268. } else if (mPollRepairTimer) {
  1269. mPollRepairTimer->Cancel();
  1270. }
  1271. }
  1272. void
  1273. nsSocketTransportService::StartPolling()
  1274. {
  1275. MutexAutoLock lock(mLock);
  1276. mPolling = true;
  1277. }
  1278. void
  1279. nsSocketTransportService::EndPolling()
  1280. {
  1281. MutexAutoLock lock(mLock);
  1282. mPolling = false;
  1283. if (mPollRepairTimer) {
  1284. mPollRepairTimer->Cancel();
  1285. }
  1286. }
  1287. #endif
  1288. } // namespace net
  1289. } // namespace mozilla