PageRenderTime 60ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 2ms

/mcs/class/referencesource/System/net/System/Net/Sockets/Socket.cs

http://github.com/mono/mono
C# | 10332 lines | 6761 code | 1552 blank | 2019 comment | 1643 complexity | f3cf07bc4700d0d7e8094627109d65a8 MD5 | raw file
Possible License(s): GPL-2.0, CC-BY-SA-3.0, LGPL-2.0, MPL-2.0-no-copyleft-exception, LGPL-2.1, Unlicense, Apache-2.0

Large files files are truncated, but you can click here to view the full file

  1. //------------------------------------------------------------------------------
  2. // <copyright file="Socket.cs" company="Microsoft">
  3. // Copyright (c) Microsoft Corporation. All rights reserved.
  4. // </copyright>
  5. //------------------------------------------------------------------------------
  6. #if MONO
  7. #undef FEATURE_PAL
  8. #endif
  9. namespace System.Net.Sockets {
  10. using System.Collections;
  11. using System.Collections.Generic;
  12. using System.Diagnostics;
  13. using System.Globalization;
  14. using System.IO;
  15. using System.Net;
  16. using System.Net.Configuration;
  17. using System.Runtime.InteropServices;
  18. using System.Security.Permissions;
  19. using System.Threading;
  20. using System.Runtime.Versioning;
  21. using System.Diagnostics.Contracts;
  22. using System.ComponentModel;
  23. /// <devdoc>
  24. /// <para>The <see cref='Sockets.Socket'/> class implements the Berkeley sockets
  25. /// interface.</para>
  26. /// </devdoc>
  27. public partial class Socket : IDisposable
  28. {
  29. #if !MONO
  30. internal const int DefaultCloseTimeout = -1; // don't change for default, otherwise breaking change
  31. // AcceptQueue - queued list of accept requests for BeginAccept or async Result for Begin Connect
  32. private object m_AcceptQueueOrConnectResult;
  33. // the following 8 members represent the state of the socket
  34. private SafeCloseSocket m_Handle;
  35. // m_RightEndPoint is null if the socket has not been bound. Otherwise, it is any EndPoint of the
  36. // correct type (IPEndPoint, etc).
  37. internal EndPoint m_RightEndPoint;
  38. internal EndPoint m_RemoteEndPoint;
  39. // this flags monitor if the socket was ever connected at any time and if it still is.
  40. private bool m_IsConnected; // = false;
  41. private bool m_IsDisconnected; // = false;
  42. // when the socket is created it will be in blocking mode
  43. // we'll only be able to Accept or Connect, so we only need
  44. // to handle one of these cases at a time
  45. private bool willBlock = true; // desired state of the socket for the user
  46. private bool willBlockInternal = true; // actual win32 state of the socket
  47. private bool isListening = false;
  48. // Our internal state doesn't automatically get updated after a non-blocking connect
  49. // completes. Keep track of whether we're doing a non-blocking connect, and make sure
  50. // to poll for the real state until we're done connecting.
  51. private bool m_NonBlockingConnectInProgress;
  52. // Keep track of the kind of endpoint used to do a non-blocking connect, so we can set
  53. // it to m_RightEndPoint when we discover we're connected.
  54. private EndPoint m_NonBlockingConnectRightEndPoint;
  55. // These are constants initialized by constructor
  56. private AddressFamily addressFamily;
  57. private SocketType socketType;
  58. private ProtocolType protocolType;
  59. // These caches are one degree off of Socket since they're not used in the sync case/when disabled in config.
  60. private CacheSet m_Caches;
  61. private class CacheSet
  62. {
  63. internal CallbackClosure ConnectClosureCache;
  64. internal CallbackClosure AcceptClosureCache;
  65. internal CallbackClosure SendClosureCache;
  66. internal CallbackClosure ReceiveClosureCache;
  67. internal OverlappedCache SendOverlappedCache;
  68. internal OverlappedCache ReceiveOverlappedCache;
  69. }
  70. //
  71. // Overlapped constants.
  72. //
  73. #if !(FEATURE_PAL && !MONO) || CORIOLIS
  74. internal static volatile bool UseOverlappedIO;
  75. #else
  76. // Disable the I/O completion port for Rotor
  77. internal static volatile bool UseOverlappedIO = true;
  78. #endif // !(FEATURE_PAL && !MONO) || CORIOLIS
  79. private bool useOverlappedIO;
  80. // Bool marked true if the native socket m_Handle was bound to the ThreadPool
  81. private bool m_BoundToThreadPool; // = false;
  82. // Bool marked true if the native socket option IP_PKTINFO or IPV6_PKTINFO has been set
  83. private bool m_ReceivingPacketInformation;
  84. // Event used for async Connect/Accept calls
  85. private ManualResetEvent m_AsyncEvent;
  86. private RegisteredWaitHandle m_RegisteredWait;
  87. private AsyncEventBits m_BlockEventBits = AsyncEventBits.FdNone;
  88. //These members are to cache permission checks
  89. private SocketAddress m_PermittedRemoteAddress;
  90. private DynamicWinsockMethods m_DynamicWinsockMethods;
  91. #endif // !MONO
  92. private static object s_InternalSyncObject;
  93. #if !MONO
  94. private int m_CloseTimeout = Socket.DefaultCloseTimeout;
  95. private int m_IntCleanedUp; // 0 if not completed >0 otherwise.
  96. private const int microcnv = 1000000;
  97. private readonly static int protocolInformationSize = Marshal.SizeOf(typeof(UnsafeNclNativeMethods.OSSOCK.WSAPROTOCOL_INFO));
  98. #endif // !MONO
  99. internal static volatile bool s_SupportsIPv4;
  100. internal static volatile bool s_SupportsIPv6;
  101. internal static volatile bool s_OSSupportsIPv6;
  102. internal static volatile bool s_Initialized;
  103. #if !MONO
  104. private static volatile WaitOrTimerCallback s_RegisteredWaitCallback;
  105. #endif
  106. private static volatile bool s_LoggingEnabled;
  107. #if !FEATURE_PAL // perfcounter
  108. internal static volatile bool s_PerfCountersEnabled;
  109. #endif
  110. //************* constructors *************************
  111. //------------------------------------
  112. // Creates a Dual Mode socket for working with both IPv4 and IPv6
  113. public Socket(SocketType socketType, ProtocolType protocolType)
  114. : this(AddressFamily.InterNetworkV6, socketType, protocolType) {
  115. DualMode = true;
  116. }
  117. /// <devdoc>
  118. /// <para>
  119. /// Initializes a new instance of the <see cref='Sockets.Socket'/> class.
  120. /// </para>
  121. /// </devdoc>
  122. public Socket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType) {
  123. #if WASM
  124. throw new PlatformNotSupportedException ();
  125. #else
  126. s_LoggingEnabled = Logging.On;
  127. if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Socket", addressFamily);
  128. InitializeSockets();
  129. #if MONO
  130. int error;
  131. m_Handle = new SafeSocketHandle (Socket_icall (addressFamily, socketType, protocolType, out error), true);
  132. #else
  133. m_Handle = SafeCloseSocket.CreateWSASocket(
  134. addressFamily,
  135. socketType,
  136. protocolType);
  137. #endif
  138. if (m_Handle.IsInvalid) {
  139. //
  140. // failed to create the win32 socket, throw
  141. //
  142. throw new SocketException();
  143. }
  144. this.addressFamily = addressFamily;
  145. this.socketType = socketType;
  146. this.protocolType = protocolType;
  147. IPProtectionLevel defaultProtectionLevel = SettingsSectionInternal.Section.IPProtectionLevel;
  148. if (defaultProtectionLevel != IPProtectionLevel.Unspecified) {
  149. SetIPProtectionLevel(defaultProtectionLevel);
  150. }
  151. #if MONO
  152. SocketDefaults ();
  153. #endif
  154. if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "Socket", null);
  155. #endif
  156. }
  157. #if !MONO
  158. public Socket(SocketInformation socketInformation) {
  159. s_LoggingEnabled = Logging.On;
  160. if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Socket", addressFamily);
  161. ExceptionHelper.UnrestrictedSocketPermission.Demand();
  162. InitializeSockets();
  163. if(socketInformation.ProtocolInformation == null || socketInformation.ProtocolInformation.Length < protocolInformationSize){
  164. throw new ArgumentException(SR.GetString(SR.net_sockets_invalid_socketinformation), "socketInformation.ProtocolInformation");
  165. }
  166. unsafe{
  167. fixed(byte * pinnedBuffer = socketInformation.ProtocolInformation){
  168. m_Handle = SafeCloseSocket.CreateWSASocket(pinnedBuffer);
  169. UnsafeNclNativeMethods.OSSOCK.WSAPROTOCOL_INFO protocolInfo = (UnsafeNclNativeMethods.OSSOCK.WSAPROTOCOL_INFO)Marshal.PtrToStructure((IntPtr)pinnedBuffer, typeof(UnsafeNclNativeMethods.OSSOCK.WSAPROTOCOL_INFO));
  170. addressFamily = protocolInfo.iAddressFamily;
  171. socketType = (SocketType)protocolInfo.iSocketType;
  172. protocolType = (ProtocolType)protocolInfo.iProtocol;
  173. }
  174. }
  175. if (m_Handle.IsInvalid) {
  176. SocketException e = new SocketException();
  177. if(e.ErrorCode == (int)SocketError.InvalidArgument){
  178. throw new ArgumentException(SR.GetString(SR.net_sockets_invalid_socketinformation), "socketInformation");
  179. }
  180. else {
  181. throw e;
  182. }
  183. }
  184. if (addressFamily != AddressFamily.InterNetwork && addressFamily != AddressFamily.InterNetworkV6) {
  185. throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
  186. }
  187. m_IsConnected = socketInformation.IsConnected;
  188. willBlock = !socketInformation.IsNonBlocking;
  189. InternalSetBlocking(willBlock);
  190. isListening = socketInformation.IsListening;
  191. UseOnlyOverlappedIO = socketInformation.UseOnlyOverlappedIO;
  192. //are we bound? if so, what's the local endpoint?
  193. if (socketInformation.RemoteEndPoint != null) {
  194. m_RightEndPoint = socketInformation.RemoteEndPoint;
  195. m_RemoteEndPoint = socketInformation.RemoteEndPoint;
  196. }
  197. else {
  198. EndPoint ep = null;
  199. if (addressFamily == AddressFamily.InterNetwork ) {
  200. ep = IPEndPoint.Any;
  201. }
  202. else if(addressFamily == AddressFamily.InterNetworkV6) {
  203. ep = IPEndPoint.IPv6Any;
  204. }
  205. SocketAddress socketAddress = ep.Serialize();
  206. SocketError errorCode;
  207. try
  208. {
  209. errorCode = UnsafeNclNativeMethods.OSSOCK.getsockname(
  210. m_Handle,
  211. socketAddress.m_Buffer,
  212. ref socketAddress.m_Size);
  213. }
  214. catch (ObjectDisposedException)
  215. {
  216. errorCode = SocketError.NotSocket;
  217. }
  218. if (errorCode == SocketError.Success) {
  219. try {
  220. //we're bound
  221. m_RightEndPoint = ep.Create(socketAddress);
  222. }
  223. catch {
  224. }
  225. }
  226. }
  227. if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "Socket", null);
  228. }
  229. /// <devdoc>
  230. /// <para>
  231. /// Called by the class to create a socket to accept an
  232. /// incoming request.
  233. /// </para>
  234. /// </devdoc>
  235. private Socket(SafeCloseSocket fd) {
  236. s_LoggingEnabled = Logging.On;
  237. if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Socket", null);
  238. InitializeSockets();
  239. // ExceptionHelper.UnmanagedPermission.Demand();
  240. //<
  241. //
  242. // this should never happen, let's check anyway
  243. //
  244. if (fd == null || fd.IsInvalid) {
  245. throw new ArgumentException(SR.GetString(SR.net_InvalidSocketHandle));
  246. }
  247. m_Handle = fd;
  248. addressFamily = Sockets.AddressFamily.Unknown;
  249. socketType = Sockets.SocketType.Unknown;
  250. protocolType = Sockets.ProtocolType.Unknown;
  251. if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "Socket", null);
  252. }
  253. #endif
  254. //************* properties *************************
  255. /// <devdoc>
  256. /// <para>Indicates whether IPv4 support is available and enabled on this machine.</para>
  257. /// </devdoc>
  258. [Obsolete("SupportsIPv4 is obsoleted for this type, please use OSSupportsIPv4 instead. http://go.microsoft.com/fwlink/?linkid=14202")]
  259. public static bool SupportsIPv4 {
  260. get {
  261. InitializeSockets();
  262. return s_SupportsIPv4;
  263. }
  264. }
  265. // Renamed to be consistent with OSSupportsIPv6
  266. public static bool OSSupportsIPv4 {
  267. get {
  268. InitializeSockets();
  269. return s_SupportsIPv4;
  270. }
  271. }
  272. /// <devdoc>
  273. /// <para>Indicates whether IPv6 support is available and enabled on this machine.</para>
  274. /// </devdoc>
  275. [Obsolete("SupportsIPv6 is obsoleted for this type, please use OSSupportsIPv6 instead. http://go.microsoft.com/fwlink/?linkid=14202")]
  276. public static bool SupportsIPv6 {
  277. get {
  278. InitializeSockets();
  279. return s_SupportsIPv6;
  280. }
  281. }
  282. internal static bool LegacySupportsIPv6 {
  283. get {
  284. InitializeSockets();
  285. return s_SupportsIPv6;
  286. }
  287. }
  288. public static bool OSSupportsIPv6 {
  289. get {
  290. InitializeSockets();
  291. return s_OSSupportsIPv6;
  292. }
  293. }
  294. #if !MONO
  295. /// <devdoc>
  296. /// <para>
  297. /// Gets the amount of data pending in the network's input buffer that can be
  298. /// read from the socket.
  299. /// </para>
  300. /// </devdoc>
  301. public int Available {
  302. get {
  303. if (CleanedUp) {
  304. throw new ObjectDisposedException(this.GetType().FullName);
  305. }
  306. int argp = 0;
  307. // This may throw ObjectDisposedException.
  308. SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.ioctlsocket(
  309. m_Handle,
  310. IoctlSocketConstants.FIONREAD,
  311. ref argp);
  312. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Available_get() UnsafeNclNativeMethods.OSSOCK.ioctlsocket returns errorCode:" + errorCode);
  313. //
  314. // if the native call fails we'll throw a SocketException
  315. //
  316. if (errorCode==SocketError.SocketError) {
  317. //
  318. // update our internal state after this socket error and throw
  319. //
  320. SocketException socketException = new SocketException();
  321. UpdateStatusAfterSocketError(socketException);
  322. if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "Available", socketException);
  323. throw socketException;
  324. }
  325. return argp;
  326. }
  327. }
  328. /// <devdoc>
  329. /// <para>
  330. /// Gets the local end point.
  331. /// </para>
  332. /// </devdoc>
  333. public EndPoint LocalEndPoint {
  334. get {
  335. if (CleanedUp) {
  336. throw new ObjectDisposedException(this.GetType().FullName);
  337. }
  338. if (m_NonBlockingConnectInProgress && Poll(0, SelectMode.SelectWrite))
  339. {
  340. // update the state if we've become connected after a non-blocking connect
  341. m_IsConnected = true;
  342. m_RightEndPoint = m_NonBlockingConnectRightEndPoint;
  343. m_NonBlockingConnectInProgress = false;
  344. }
  345. if (m_RightEndPoint == null) {
  346. return null;
  347. }
  348. SocketAddress socketAddress = m_RightEndPoint.Serialize();
  349. // This may throw ObjectDisposedException.
  350. SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.getsockname(
  351. m_Handle,
  352. socketAddress.m_Buffer,
  353. ref socketAddress.m_Size);
  354. if (errorCode!=SocketError.Success) {
  355. //
  356. // update our internal state after this socket error and throw
  357. //
  358. SocketException socketException = new SocketException();
  359. UpdateStatusAfterSocketError(socketException);
  360. if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "LocalEndPoint", socketException);
  361. throw socketException;
  362. }
  363. return m_RightEndPoint.Create(socketAddress);
  364. }
  365. }
  366. /// <devdoc>
  367. /// <para>
  368. /// Gets the remote end point
  369. /// </para>
  370. /// </devdoc>
  371. public EndPoint RemoteEndPoint {
  372. get {
  373. if (CleanedUp) {
  374. throw new ObjectDisposedException(this.GetType().FullName);
  375. }
  376. if (m_RemoteEndPoint==null) {
  377. if (m_NonBlockingConnectInProgress && Poll(0, SelectMode.SelectWrite))
  378. {
  379. // update the state if we've become connected after a non-blocking connect
  380. m_IsConnected = true;
  381. m_RightEndPoint = m_NonBlockingConnectRightEndPoint;
  382. m_NonBlockingConnectInProgress = false;
  383. }
  384. if (m_RightEndPoint==null) {
  385. return null;
  386. }
  387. SocketAddress socketAddress = m_RightEndPoint.Serialize();
  388. // This may throw ObjectDisposedException.
  389. SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.getpeername(
  390. m_Handle,
  391. socketAddress.m_Buffer,
  392. ref socketAddress.m_Size);
  393. if (errorCode!=SocketError.Success) {
  394. //
  395. // update our internal state after this socket error and throw
  396. //
  397. SocketException socketException = new SocketException();
  398. UpdateStatusAfterSocketError(socketException);
  399. if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "RemoteEndPoint", socketException);
  400. throw socketException;
  401. }
  402. try {
  403. m_RemoteEndPoint = m_RightEndPoint.Create(socketAddress);
  404. }
  405. catch {
  406. }
  407. }
  408. return m_RemoteEndPoint;
  409. }
  410. }
  411. #endif // !MONO
  412. /// <devdoc>
  413. /// <para>
  414. /// Gets the operating system m_Handle for the socket.
  415. ///YUKON: should we cut this method off, who are the users?
  416. /// </para>
  417. /// </devdoc>
  418. public IntPtr Handle {
  419. get {
  420. #if !MONO
  421. ExceptionHelper.UnmanagedPermission.Demand();
  422. #endif
  423. return m_Handle.DangerousGetHandle();
  424. }
  425. }
  426. #if !MONO
  427. internal SafeCloseSocket SafeHandle {
  428. get {
  429. return m_Handle;
  430. }
  431. }
  432. // Non-blocking I/O control
  433. /// <devdoc>
  434. /// <para>
  435. /// Gets and sets the blocking mode of a socket.
  436. /// </para>
  437. /// </devdoc>
  438. public bool Blocking {
  439. get {
  440. //
  441. // return the user's desired blocking behaviour (not the actual win32 state)
  442. //
  443. return willBlock;
  444. }
  445. set {
  446. if (CleanedUp) {
  447. throw new ObjectDisposedException(this.GetType().FullName);
  448. }
  449. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::set_Blocking() value:" + value.ToString() + " willBlock:" + willBlock.ToString() + " willBlockInternal:" + willBlockInternal.ToString());
  450. bool current;
  451. SocketError errorCode = InternalSetBlocking(value, out current);
  452. if (errorCode!=SocketError.Success) {
  453. //
  454. // update our internal state after this socket error and throw
  455. SocketException socketException = new SocketException(errorCode);
  456. UpdateStatusAfterSocketError(socketException);
  457. if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "Blocking", socketException);
  458. throw socketException;
  459. }
  460. //
  461. // win32 call succeeded, update desired state
  462. //
  463. willBlock = current;
  464. }
  465. }
  466. #endif // !MONO
  467. public bool UseOnlyOverlappedIO{
  468. get {
  469. //
  470. // return the user's desired blocking behaviour (not the actual win32 state)
  471. //
  472. return useOverlappedIO;
  473. }
  474. set {
  475. #if !MONO
  476. if (m_BoundToThreadPool) {
  477. throw new InvalidOperationException(SR.GetString(SR.net_io_completionportwasbound));
  478. }
  479. #endif
  480. useOverlappedIO = value;
  481. }
  482. }
  483. #if !MONO
  484. /// <devdoc>
  485. /// <para>
  486. /// Gets the connection state of the Socket. This property will return the latest
  487. /// known state of the Socket. When it returns false, the Socket was either never connected
  488. /// or it is not connected anymore. When it returns true, though, there's no guarantee that the Socket
  489. /// is still connected, but only that it was connected at the time of the last IO operation.
  490. /// </para>
  491. /// </devdoc>
  492. public bool Connected {
  493. get {
  494. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Connected() m_IsConnected:"+m_IsConnected);
  495. if (m_NonBlockingConnectInProgress && Poll(0, SelectMode.SelectWrite))
  496. {
  497. // update the state if we've become connected after a non-blocking connect
  498. m_IsConnected = true;
  499. m_RightEndPoint = m_NonBlockingConnectRightEndPoint;
  500. m_NonBlockingConnectInProgress = false;
  501. }
  502. return m_IsConnected;
  503. }
  504. }
  505. #endif // !MONO
  506. /// <devdoc>
  507. /// <para>
  508. /// Gets the socket's address family.
  509. /// </para>
  510. /// </devdoc>
  511. public AddressFamily AddressFamily {
  512. get {
  513. return addressFamily;
  514. }
  515. }
  516. /// <devdoc>
  517. /// <para>
  518. /// Gets the socket's socketType.
  519. /// </para>
  520. /// </devdoc>
  521. public SocketType SocketType {
  522. get {
  523. return socketType;
  524. }
  525. }
  526. /// <devdoc>
  527. /// <para>
  528. /// Gets the socket's protocol socketType.
  529. /// </para>
  530. /// </devdoc>
  531. public ProtocolType ProtocolType {
  532. get {
  533. return protocolType;
  534. }
  535. }
  536. #if !MONO
  537. public bool IsBound{
  538. get{
  539. return (m_RightEndPoint != null);
  540. }
  541. }
  542. #endif // !MONO
  543. public bool ExclusiveAddressUse{
  544. get {
  545. return (int)GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse) != 0 ? true : false;
  546. }
  547. set {
  548. if (IsBound) {
  549. throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustnotbebound));
  550. }
  551. SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse, value ? 1 : 0);
  552. }
  553. }
  554. public int ReceiveBufferSize {
  555. get {
  556. return (int)GetSocketOption(SocketOptionLevel.Socket,
  557. SocketOptionName.ReceiveBuffer);
  558. }
  559. set {
  560. if (value<0) {
  561. throw new ArgumentOutOfRangeException("value");
  562. }
  563. SetSocketOption(SocketOptionLevel.Socket,
  564. SocketOptionName.ReceiveBuffer, value);
  565. }
  566. }
  567. public int SendBufferSize {
  568. get {
  569. return (int)GetSocketOption(SocketOptionLevel.Socket,
  570. SocketOptionName.SendBuffer);
  571. }
  572. set {
  573. if (value<0) {
  574. throw new ArgumentOutOfRangeException("value");
  575. }
  576. SetSocketOption(SocketOptionLevel.Socket,
  577. SocketOptionName.SendBuffer, value);
  578. }
  579. }
  580. public int ReceiveTimeout {
  581. get {
  582. return (int)GetSocketOption(SocketOptionLevel.Socket,
  583. SocketOptionName.ReceiveTimeout);
  584. }
  585. set {
  586. if (value< -1) {
  587. throw new ArgumentOutOfRangeException("value");
  588. }
  589. if (value == -1) {
  590. value = 0;
  591. }
  592. SetSocketOption(SocketOptionLevel.Socket,
  593. SocketOptionName.ReceiveTimeout, value);
  594. }
  595. }
  596. public int SendTimeout {
  597. get {
  598. return (int)GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout);
  599. }
  600. set {
  601. if (value< -1) {
  602. throw new ArgumentOutOfRangeException("value");
  603. }
  604. if (value == -1) {
  605. value = 0;
  606. }
  607. SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, value);
  608. }
  609. }
  610. public LingerOption LingerState {
  611. get {
  612. return (LingerOption)GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger);
  613. }
  614. set {
  615. SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, value);
  616. }
  617. }
  618. #if !MONO
  619. public bool NoDelay {
  620. get {
  621. return (int)GetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay) != 0 ? true : false;
  622. }
  623. set {
  624. SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, value ? 1 : 0);
  625. }
  626. }
  627. #endif // !MONO
  628. public short Ttl{
  629. get {
  630. if (addressFamily == AddressFamily.InterNetwork) {
  631. return (short)(int)GetSocketOption(SocketOptionLevel.IP, SocketOptionName.IpTimeToLive);
  632. }
  633. else if (addressFamily == AddressFamily.InterNetworkV6) {
  634. return (short)(int)GetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IpTimeToLive);
  635. }
  636. else{
  637. throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
  638. }
  639. }
  640. set {
  641. // valid values are from 0 to 255 since Ttl is really just a byte value on the wire
  642. if (value < 0 || value > 255) {
  643. throw new ArgumentOutOfRangeException("value");
  644. }
  645. if (addressFamily == AddressFamily.InterNetwork) {
  646. SetSocketOption(SocketOptionLevel.IP, SocketOptionName.IpTimeToLive, value);
  647. }
  648. else if (addressFamily == AddressFamily.InterNetworkV6) {
  649. SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IpTimeToLive, value);
  650. }
  651. else{
  652. throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
  653. }
  654. }
  655. }
  656. public bool DontFragment{
  657. get {
  658. if (addressFamily == AddressFamily.InterNetwork) {
  659. return (int)GetSocketOption(SocketOptionLevel.IP, SocketOptionName.DontFragment) != 0 ? true : false;
  660. }
  661. else{
  662. throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
  663. }
  664. }
  665. set {
  666. if (addressFamily == AddressFamily.InterNetwork) {
  667. SetSocketOption(SocketOptionLevel.IP, SocketOptionName.DontFragment, value ? 1 : 0);
  668. }
  669. else{
  670. throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
  671. }
  672. }
  673. }
  674. #if !MONO
  675. public bool MulticastLoopback{
  676. get {
  677. if (addressFamily == AddressFamily.InterNetwork) {
  678. return (int)GetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastLoopback) != 0 ? true : false;
  679. }
  680. else if (addressFamily == AddressFamily.InterNetworkV6) {
  681. return (int)GetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.MulticastLoopback) != 0 ? true : false;
  682. }
  683. else{
  684. throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
  685. }
  686. }
  687. set {
  688. if (addressFamily == AddressFamily.InterNetwork) {
  689. SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastLoopback, value ? 1 : 0);
  690. }
  691. else if (addressFamily == AddressFamily.InterNetworkV6) {
  692. SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.MulticastLoopback, value ? 1 : 0);
  693. }
  694. else{
  695. throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
  696. }
  697. }
  698. }
  699. public bool EnableBroadcast{
  700. get {
  701. return (int)GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast) != 0 ? true : false;
  702. }
  703. set {
  704. SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, value ? 1 : 0);
  705. }
  706. }
  707. #endif // !MONO
  708. public bool DualMode {
  709. get {
  710. if (AddressFamily != AddressFamily.InterNetworkV6) {
  711. throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
  712. }
  713. return ((int)GetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only) == 0);
  714. }
  715. set {
  716. if (AddressFamily != AddressFamily.InterNetworkV6) {
  717. throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
  718. }
  719. SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, value ? 0 : 1);
  720. }
  721. }
  722. private bool IsDualMode {
  723. get {
  724. return AddressFamily == AddressFamily.InterNetworkV6 && DualMode;
  725. }
  726. }
  727. internal bool CanTryAddressFamily(AddressFamily family) {
  728. return (family == addressFamily) || (family == AddressFamily.InterNetwork && IsDualMode);
  729. }
  730. //************* public methods *************************
  731. #if !MONO
  732. /// <devdoc>
  733. /// <para>Associates a socket with an end point.</para>
  734. /// </devdoc>
  735. public void Bind(EndPoint localEP) {
  736. if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Bind", localEP);
  737. if (CleanedUp) {
  738. throw new ObjectDisposedException(this.GetType().FullName);
  739. }
  740. //
  741. // parameter validation
  742. //
  743. if (localEP==null) {
  744. throw new ArgumentNullException("localEP");
  745. }
  746. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Bind() localEP:" + localEP.ToString());
  747. EndPoint endPointSnapshot = localEP;
  748. IPEndPoint ipSnapshot = localEP as IPEndPoint;
  749. //
  750. // for now security is implemented only on IPEndPoint
  751. // If EndPoint is of other type - unmanaged code permisison is demanded
  752. //
  753. if (ipSnapshot != null)
  754. {
  755. // Take a snapshot that will make it immutable and not derived.
  756. ipSnapshot = ipSnapshot.Snapshot();
  757. // DualMode: Do the security check on the users IPv4 address, but map to IPv6 before binding.
  758. endPointSnapshot = RemapIPEndPoint(ipSnapshot);
  759. //
  760. // create the permissions the user would need for the call
  761. //
  762. SocketPermission socketPermission
  763. = new SocketPermission(
  764. NetworkAccess.Accept,
  765. Transport,
  766. ipSnapshot.Address.ToString(),
  767. ipSnapshot.Port);
  768. //
  769. // demand for them
  770. //
  771. socketPermission.Demand();
  772. // Here the permission check has succeded.
  773. // NB: if local port is 0, then winsock will assign some>1024,
  774. // so assuming that this is safe. We will not check the
  775. // NetworkAccess.Accept permissions in Receive.
  776. }
  777. else {
  778. //<
  779. ExceptionHelper.UnmanagedPermission.Demand();
  780. }
  781. //
  782. // ask the EndPoint to generate a SocketAddress that we
  783. // can pass down to winsock
  784. //
  785. SocketAddress socketAddress = CallSerializeCheckDnsEndPoint(endPointSnapshot);
  786. DoBind(endPointSnapshot, socketAddress);
  787. if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "Bind", "");
  788. }
  789. internal void InternalBind(EndPoint localEP)
  790. {
  791. if (s_LoggingEnabled) Logging.Enter(Logging.Sockets, this, "InternalBind", localEP);
  792. if (CleanedUp)
  793. {
  794. throw new ObjectDisposedException(GetType().FullName);
  795. }
  796. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::InternalBind() localEP:" + localEP.ToString());
  797. GlobalLog.Assert(!(localEP is DnsEndPoint), "Calling InternalBind with a DnsEndPoint, about to get NotImplementedException");
  798. //
  799. // ask the EndPoint to generate a SocketAddress that we
  800. // can pass down to winsock
  801. //
  802. EndPoint endPointSnapshot = localEP;
  803. SocketAddress socketAddress = SnapshotAndSerialize(ref endPointSnapshot);
  804. DoBind(endPointSnapshot, socketAddress);
  805. if (s_LoggingEnabled) Logging.Exit(Logging.Sockets, this, "InternalBind", "");
  806. }
  807. private void DoBind(EndPoint endPointSnapshot, SocketAddress socketAddress)
  808. {
  809. // Mitigation for Blue Screen of Death (Win7, maybe others)
  810. IPEndPoint ipEndPoint = endPointSnapshot as IPEndPoint;
  811. if (!OSSupportsIPv4 && ipEndPoint != null && ipEndPoint.Address.IsIPv4MappedToIPv6)
  812. {
  813. SocketException socketException = new SocketException(SocketError.InvalidArgument);
  814. UpdateStatusAfterSocketError(socketException);
  815. if (s_LoggingEnabled) Logging.Exception(Logging.Sockets, this, "DoBind", socketException);
  816. throw socketException;
  817. }
  818. // This may throw ObjectDisposedException.
  819. SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.bind(
  820. m_Handle,
  821. socketAddress.m_Buffer,
  822. socketAddress.m_Size);
  823. #if TRAVE
  824. try
  825. {
  826. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Bind() SRC:" + ValidationHelper.ToString(LocalEndPoint) + " UnsafeNclNativeMethods.OSSOCK.bind returns errorCode:" + errorCode);
  827. }
  828. catch (ObjectDisposedException) { }
  829. #endif
  830. //
  831. // if the native call fails we'll throw a SocketException
  832. //
  833. if (errorCode != SocketError.Success)
  834. {
  835. //
  836. // update our internal state after this socket error and throw
  837. //
  838. SocketException socketException = new SocketException();
  839. UpdateStatusAfterSocketError(socketException);
  840. if (s_LoggingEnabled) Logging.Exception(Logging.Sockets, this, "DoBind", socketException);
  841. throw socketException;
  842. }
  843. if (m_RightEndPoint == null)
  844. {
  845. //
  846. // save a copy of the EndPoint so we can use it for Create()
  847. //
  848. m_RightEndPoint = endPointSnapshot;
  849. }
  850. }
  851. /// <devdoc>
  852. /// <para>Establishes a connection to a remote system.</para>
  853. /// </devdoc>
  854. public void Connect(EndPoint remoteEP) {
  855. if (CleanedUp) {
  856. throw new ObjectDisposedException(this.GetType().FullName);
  857. }
  858. //
  859. // parameter validation
  860. //
  861. if (remoteEP==null) {
  862. throw new ArgumentNullException("remoteEP");
  863. }
  864. if(m_IsDisconnected){
  865. throw new InvalidOperationException(SR.GetString(SR.net_sockets_disconnectedConnect));
  866. }
  867. if (isListening)
  868. {
  869. throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustnotlisten));
  870. }
  871. ValidateBlockingMode();
  872. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Connect() DST:" + ValidationHelper.ToString(remoteEP));
  873. DnsEndPoint dnsEP = remoteEP as DnsEndPoint;
  874. if (dnsEP != null)
  875. {
  876. if (dnsEP.AddressFamily != AddressFamily.Unspecified && !CanTryAddressFamily(dnsEP.AddressFamily))
  877. {
  878. throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
  879. }
  880. Connect(dnsEP.Host, dnsEP.Port);
  881. return;
  882. }
  883. //This will check the permissions for connect
  884. EndPoint endPointSnapshot = remoteEP;
  885. SocketAddress socketAddress = CheckCacheRemote(ref endPointSnapshot, true);
  886. if (!Blocking)
  887. {
  888. m_NonBlockingConnectRightEndPoint = endPointSnapshot;
  889. m_NonBlockingConnectInProgress = true;
  890. }
  891. DoConnect(endPointSnapshot, socketAddress);
  892. }
  893. public void Connect(IPAddress address, int port){
  894. if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Connect", address);
  895. if (CleanedUp){
  896. throw new ObjectDisposedException(this.GetType().FullName);
  897. }
  898. //if address family isn't the socket address family throw
  899. if (address==null) {
  900. throw new ArgumentNullException("address");
  901. }
  902. if (!ValidationHelper.ValidateTcpPort(port)) {
  903. throw new ArgumentOutOfRangeException("port");
  904. }
  905. if (!CanTryAddressFamily(address.AddressFamily)) {
  906. throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
  907. }
  908. IPEndPoint remoteEP = new IPEndPoint(address, port);
  909. Connect(remoteEP);
  910. if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "Connect", null);
  911. }
  912. public void Connect(string host, int port){
  913. if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Connect", host);
  914. if (CleanedUp){
  915. throw new ObjectDisposedException(this.GetType().FullName);
  916. }
  917. if (host==null) {
  918. throw new ArgumentNullException("host");
  919. }
  920. if (!ValidationHelper.ValidateTcpPort(port)){
  921. throw new ArgumentOutOfRangeException("port");
  922. }
  923. if (addressFamily != AddressFamily.InterNetwork && addressFamily != AddressFamily.InterNetworkV6) {
  924. throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
  925. }
  926. IPAddress[] addresses = Dns.GetHostAddresses(host);
  927. Connect(addresses,port);
  928. if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "Connect", null);
  929. }
  930. #endif // !MONO
  931. public void Connect(IPAddress[] addresses, int port){
  932. if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Connect", addresses);
  933. if (CleanedUp){
  934. throw new ObjectDisposedException(this.GetType().FullName);
  935. }
  936. if (addresses==null) {
  937. throw new ArgumentNullException("addresses");
  938. }
  939. if (addresses.Length == 0) {
  940. throw new ArgumentException(SR.GetString(SR.net_sockets_invalid_ipaddress_length), "addresses");
  941. }
  942. if (!ValidationHelper.ValidateTcpPort(port)) {
  943. throw new ArgumentOutOfRangeException("port");
  944. }
  945. if (addressFamily != AddressFamily.InterNetwork && addressFamily != AddressFamily.InterNetworkV6) {
  946. throw new NotSupportedException(SR.GetString(SR.net_invalidversion));
  947. }
  948. Exception lastex = null;
  949. foreach ( IPAddress address in addresses ) {
  950. if (CanTryAddressFamily(address.AddressFamily)) {
  951. try
  952. {
  953. Connect(new IPEndPoint(address,port) );
  954. lastex = null;
  955. break;
  956. }
  957. catch ( Exception ex )
  958. {
  959. if (NclUtilities.IsFatal(ex)) throw;
  960. lastex = ex;
  961. }
  962. }
  963. }
  964. if ( lastex != null )
  965. throw lastex;
  966. //if we're not connected, then we didn't get a valid ipaddress in the list
  967. if (!Connected) {
  968. throw new ArgumentException(SR.GetString(SR.net_invalidAddressList), "addresses");
  969. }
  970. if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "Connect", null);
  971. }
  972. #if !MONO
  973. /// <devdoc>
  974. /// <para>
  975. /// Forces a socket connection to close.
  976. /// </para>
  977. /// </devdoc>
  978. public void Close()
  979. {
  980. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Close() timeout = " + m_CloseTimeout);
  981. if (s_LoggingEnabled) Logging.Enter(Logging.Sockets, this, "Close", null);
  982. ((IDisposable)this).Dispose();
  983. if (s_LoggingEnabled) Logging.Exit(Logging.Sockets, this, "Close", null);
  984. }
  985. public void Close(int timeout)
  986. {
  987. if (timeout < -1)
  988. {
  989. throw new ArgumentOutOfRangeException("timeout");
  990. }
  991. m_CloseTimeout = timeout;
  992. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Close() timeout = " + m_CloseTimeout);
  993. ((IDisposable)this).Dispose();
  994. }
  995. /// <devdoc>
  996. /// <para>
  997. /// Places a socket in a listening state.
  998. /// </para>
  999. /// </devdoc>
  1000. public void Listen(int backlog) {
  1001. if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Listen", backlog);
  1002. if (CleanedUp) {
  1003. throw new ObjectDisposedException(this.GetType().FullName);
  1004. }
  1005. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Listen() backlog:" + backlog.ToString());
  1006. // No access permissions are necessary here because
  1007. // the verification is done for Bind
  1008. // This may throw ObjectDisposedException.
  1009. SocketError errorCode = UnsafeNclNativeMethods.OSSOCK.listen(
  1010. m_Handle,
  1011. backlog);
  1012. #if TRAVE
  1013. try
  1014. {
  1015. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Listen() SRC:" + ValidationHelper.ToString(LocalEndPoint) + " UnsafeNclNativeMethods.OSSOCK.listen returns errorCode:" + errorCode);
  1016. }
  1017. catch (ObjectDisposedException) { }
  1018. #endif
  1019. //
  1020. // if the native call fails we'll throw a SocketException
  1021. //
  1022. if (errorCode!=SocketError.Success) {
  1023. //
  1024. // update our internal state after this socket error and throw
  1025. //
  1026. SocketException socketException = new SocketException();
  1027. UpdateStatusAfterSocketError(socketException);
  1028. if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "Listen", socketException);
  1029. throw socketException;
  1030. }
  1031. isListening = true;
  1032. if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "Listen", "");
  1033. }
  1034. /// <devdoc>
  1035. /// <para>
  1036. /// Creates a new <see cref='Sockets.Socket'/> instance to handle an incoming
  1037. /// connection.
  1038. /// </para>
  1039. /// </devdoc>
  1040. public Socket Accept() {
  1041. if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Accept", "");
  1042. //
  1043. // parameter validation
  1044. //
  1045. if (CleanedUp) {
  1046. throw new ObjectDisposedException(this.GetType().FullName);
  1047. }
  1048. if (m_RightEndPoint==null) {
  1049. throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustbind));
  1050. }
  1051. if(!isListening){
  1052. throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustlisten));
  1053. }
  1054. if(m_IsDisconnected){
  1055. throw new InvalidOperationException(SR.GetString(SR.net_sockets_disconnectedAccept));
  1056. }
  1057. ValidateBlockingMode();
  1058. GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::Accept() SRC:" + ValidationHelper.ToString(LocalEndPoint));
  1059. SocketAddress socketAddress = m_RightEndPoint.Serialize();
  1060. // This may throw ObjectDisposedException.
  1061. SafeCloseSocket acceptedSocketHandle = SafeCloseSocket.Accept(
  1062. m_Handle,
  1063. socketAddress.m_Buffer,
  1064. ref socketAddress.m_Size);
  1065. //
  1066. // if the native call fails we'll throw a SocketException
  1067. //
  1068. if (acceptedSocketHandle.IsInvalid) {
  1069. //
  1070. // update our internal state after this socket error and throw
  1071. //
  1072. SocketException socketException = new SocketException();
  1073. UpdateStatusAfterSocketError(socketException);
  1074. if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "Accept", socketException);
  1075. throw socketException;
  1076. }
  1077. Socket socket = CreateAcceptSocket(acceptedSocketHandle, m_RightEndPoint.Create(socketAddress), false);
  1078. if (s_LoggingEnabled) {
  1079. Logging.PrintInfo(Logging.Sockets, socket, SR.GetString(SR.net_log_socket_accepted, socket.RemoteEndPoint, socket.LocalEndPoint));
  1080. Logging.Exit(Logging.Sockets, this, "Accept", socket);
  1081. }
  1082. return socket;
  1083. }
  1084. #endif // !MONO
  1085. /// <devdoc>
  1086. /// <para>Sends a data buffer to a connected socket.</para>
  1087. /// </devdoc>
  1088. public int Send(byte[] buffer, int size, SocketFlags socketFlags) {
  1089. return Send(buffer, 0, size, socketFlags);
  1090. }
  1091. /// <devdoc>
  1092. /// <para>[To be supplied.]</para>
  1093. /// </devdoc>
  1094. public int Send(byte[] buffer, SocketFlags socketFlags) {
  1095. return Send(buffer, 0, buffer!=null ? buffer.Length : 0, socketFlags);
  1096. }
  1097. /// <devdoc>
  1098. /// <para>[To be supplied.]</para>
  1099. /// </devdoc>
  1100. public int Send(byte[] buffer) {
  1101. return Send(buffer, 0, buffer!=null ? buffer.Length : 0, SocketFlags.None);
  1102. }
  1103. #if !FEATURE_PAL
  1104. /// <devdoc>
  1105. /// <para>[To be supplied.]</para>
  1106. /// </devdoc>
  1107. public int Send(IList<ArraySegment<byte>> buffers) {
  1108. return Send(buffers,SocketFlags.None);
  1109. }
  1110. /// <devdoc>
  1111. /// <para>[To be supplied.]</para>
  1112. /// </devdoc>
  1113. public int Send(IList<ArraySegment<byte>> buffers, SocketFlags socketFlags) {
  1114. SocketError errorCode;
  1115. int bytesTransferred = Send(buffers, socketFlags, out errorCode);
  1116. if(errorCode != SocketError.Success){
  1117. throw new SocketException(errorCode);
  1118. }
  1119. return bytesTransferred;
  1120. }
  1121. #if !MONO
  1122. public int Send(IList<ArraySegment<byte>> buffers, SocketFlags socketFlags, out SocketError errorCode) {
  1123. if(s_LoggingEnabled)Logging.Enter(Logging.Sockets, this, "Send", "");
  1124. if (CleanedUp) {
  1125. throw new ObjectDisposedException(this.GetType().FullName);
  1126. }
  1127. if (buffers==null) {
  1128. throw

Large files files are truncated, but you can click here to view the full file