PageRenderTime 57ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/Languages/IronPython/IronPython.Modules/socket.cs

http://github.com/IronLanguages/main
C# | 3078 lines | 2579 code | 348 blank | 151 comment | 580 complexity | 5c961e9e4e7e991a8290db1150c646e3 MD5 | raw file
Possible License(s): CPL-1.0, BSD-3-Clause, ISC, GPL-2.0, MPL-2.0-no-copyleft-exception
  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Apache License, Version 2.0. A
  6. * copy of the license can be found in the License.html file at the root of this distribution. If
  7. * you cannot locate the Apache License, Version 2.0, please send an email to
  8. * ironpy@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
  9. * by the terms of the Apache License, Version 2.0.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. *
  14. * ***************************************************************************/
  15. #if FEATURE_FULL_NET
  16. using System;
  17. using System.Collections;
  18. using System.Collections.Generic;
  19. using System.Diagnostics;
  20. using System.IO;
  21. using System.Net;
  22. using System.Net.Sockets;
  23. using System.Net.Security;
  24. using System.Runtime.InteropServices;
  25. using System.Security.Cryptography.X509Certificates;
  26. using System.Security.Authentication;
  27. using System.Runtime.CompilerServices;
  28. using System.Text;
  29. using Microsoft.Scripting;
  30. using Microsoft.Scripting.Runtime;
  31. using IronPython.Runtime;
  32. using IronPython.Runtime.Exceptions;
  33. using IronPython.Runtime.Operations;
  34. using IronPython.Runtime.Types;
  35. #if FEATURE_NUMERICS
  36. using System.Numerics;
  37. #else
  38. using Microsoft.Scripting.Math;
  39. #endif
  40. using PythonArray = IronPython.Modules.ArrayModule.array;
  41. using SpecialNameAttribute = System.Runtime.CompilerServices.SpecialNameAttribute;
  42. using Microsoft.Scripting.Utils;
  43. #if NETCOREAPP1_0
  44. using Environment = System.FakeEnvironment;
  45. #endif
  46. [assembly: PythonModule("socket", typeof(IronPython.Modules.PythonSocket))]
  47. namespace IronPython.Modules {
  48. public static class PythonSocket {
  49. private static readonly object _defaultTimeoutKey = new object();
  50. private static readonly object _defaultBufsizeKey = new object();
  51. private const int DefaultBufferSize = 8192;
  52. public static PythonTuple _delegate_methods = PythonTuple.MakeTuple("recv", "recvfrom", "recv_into", "recvfrom_into", "send", "sendto");
  53. [SpecialName]
  54. public static void PerformModuleReload(PythonContext/*!*/ context, PythonDictionary/*!*/ dict) {
  55. if (!context.HasModuleState(_defaultTimeoutKey)) {
  56. context.SetModuleState(_defaultTimeoutKey, null);
  57. }
  58. context.SetModuleState(_defaultBufsizeKey, DefaultBufferSize);
  59. PythonType socketErr = GetSocketError(context, dict);
  60. context.EnsureModuleException("socketherror", socketErr, dict, "herror", "socket");
  61. context.EnsureModuleException("socketgaierror", socketErr, dict, "gaierror", "socket");
  62. context.EnsureModuleException("sockettimeout", socketErr, dict, "timeout", "socket");
  63. }
  64. internal static PythonType GetSocketError(PythonContext context, PythonDictionary dict) {
  65. return context.EnsureModuleException("socketerror", PythonExceptions.IOError, dict, "error", "socket");
  66. }
  67. #if NETSTANDARD
  68. private static ConditionalWeakTable<Socket, object> fakeHandles = new ConditionalWeakTable<Socket, object>();
  69. private static long maxHandle = 0;
  70. #endif
  71. private static IntPtr GetHandle(this Socket socket)
  72. {
  73. #if NETSTANDARD
  74. object handle;
  75. lock (fakeHandles) {
  76. if (!fakeHandles.TryGetValue(socket, out handle)) {
  77. handle = (IntPtr)maxHandle++;
  78. fakeHandles.Add(socket, handle);
  79. }
  80. }
  81. return (IntPtr)handle;
  82. #else
  83. return socket.Handle;
  84. #endif
  85. }
  86. public const string __doc__ = "Implementation module for socket operations.\n\n"
  87. + "This module is a loose wrapper around the .NET System.Net.Sockets API, so you\n"
  88. + "may find the corresponding MSDN documentation helpful in decoding error\n"
  89. + "messages and understanding corner cases.\n"
  90. + "\n"
  91. + "This implementation of socket differs slightly from the standard CPython\n"
  92. + "socket module. Many of these differences are due to the implementation of the\n"
  93. + ".NET socket libraries. These differences are summarized below. For full\n"
  94. + "details, check the docstrings of the functions mentioned.\n"
  95. + " - s.accept(), s.connect(), and s.connect_ex() do not support timeouts.\n"
  96. + " - Timeouts in s.sendall() don't work correctly.\n"
  97. + " - s.dup() is not implemented.\n"
  98. + " - SSL support is not implemented."
  99. + "\n"
  100. + "An Extra IronPython-specific function is exposed only if the clr module is\n"
  101. + "imported:\n"
  102. + " - s.HandleToSocket() returns the System.Net.Sockets.Socket object associated\n"
  103. + " with a particular \"file descriptor number\" (as returned by s.fileno()).\n"
  104. ;
  105. #region Socket object
  106. public static PythonType SocketType = DynamicHelpers.GetPythonTypeFromType(typeof(socket));
  107. [PythonType]
  108. [Documentation("socket([family[, type[, proto]]]) -> socket object\n\n"
  109. + "Create a socket (a network connection endpoint) of the given family, type,\n"
  110. + "and protocol. socket() accepts keyword arguments.\n"
  111. + " - family (address family) defaults to AF_INET\n"
  112. + " - type (socket type) defaults to SOCK_STREAM\n"
  113. + " - proto (protocol type) defaults to 0, which specifies the default protocol\n"
  114. + "\n"
  115. + "This module supports only IP sockets. It does not support raw or Unix sockets.\n"
  116. + "Both IPv4 and IPv6 are supported.")]
  117. public class socket : IWeakReferenceable {
  118. #region Fields
  119. /// <summary>
  120. /// handleToSocket allows us to translate from Python's idea of a socket resource (file
  121. /// descriptor numbers) to .NET's idea of a socket resource (System.Net.Socket objects).
  122. /// In particular, this allows the select module to convert file numbers (as returned by
  123. /// fileno()) and convert them to Socket objects so that it can do something useful with them.
  124. /// </summary>
  125. private static readonly Dictionary<IntPtr, WeakReference> _handleToSocket = new Dictionary<IntPtr, WeakReference>();
  126. private const int DefaultAddressFamily = (int)AddressFamily.InterNetwork;
  127. private const int DefaultSocketType = (int)System.Net.Sockets.SocketType.Stream;
  128. private const int DefaultProtocolType = (int)ProtocolType.Unspecified;
  129. internal Socket _socket;
  130. internal string _hostName;
  131. private WeakRefTracker _weakRefTracker = null;
  132. private int _referenceCount = 1;
  133. public const string __module__ = "socket";
  134. internal CodeContext/*!*/ _context;
  135. private int _timeout;
  136. #endregion
  137. #region Public API
  138. public socket() {
  139. }
  140. public void __init__(CodeContext/*!*/ context, [DefaultParameterValue(DefaultAddressFamily)] int addressFamily,
  141. [DefaultParameterValue(DefaultSocketType)] int socketType,
  142. [DefaultParameterValue(DefaultProtocolType)] int protocolType,
  143. [DefaultParameterValue(null)]socket _sock) {
  144. System.Net.Sockets.SocketType type = (System.Net.Sockets.SocketType)Enum.ToObject(typeof(System.Net.Sockets.SocketType), socketType);
  145. if (!Enum.IsDefined(typeof(System.Net.Sockets.SocketType), type)) {
  146. throw MakeException(context, new SocketException((int)SocketError.SocketNotSupported));
  147. }
  148. AddressFamily family = (AddressFamily)Enum.ToObject(typeof(AddressFamily), addressFamily);
  149. if (!Enum.IsDefined(typeof(AddressFamily), family)) {
  150. throw MakeException(context, new SocketException((int)SocketError.AddressFamilyNotSupported));
  151. }
  152. ProtocolType proto = (ProtocolType)Enum.ToObject(typeof(ProtocolType), protocolType);
  153. if (!Enum.IsDefined(typeof(ProtocolType), proto)) {
  154. throw MakeException(context, new SocketException((int)SocketError.ProtocolNotSupported));
  155. }
  156. if (_sock == null) {
  157. Socket newSocket;
  158. try {
  159. newSocket = new Socket(family, type, proto);
  160. } catch (SocketException e) {
  161. throw MakeException(context, e);
  162. }
  163. Initialize(context, newSocket);
  164. } else {
  165. _socket = _sock._socket;
  166. _hostName = _sock._hostName;
  167. // we now own the lifetime of the socket
  168. GC.SuppressFinalize(_sock);
  169. Initialize(context, _socket);
  170. }
  171. }
  172. public void __del__() {
  173. _close();
  174. }
  175. ~socket() {
  176. _close();
  177. }
  178. public socket _sock {
  179. get {
  180. return this;
  181. }
  182. }
  183. #if !NETSTANDARD
  184. private IAsyncResult _acceptResult;
  185. #endif
  186. [Documentation("accept() -> (conn, address)\n\n"
  187. + "Accept a connection. The socket must be bound and listening before calling\n"
  188. + "accept(). conn is a new socket object connected to the remote host, and\n"
  189. + "address is the remote host's address (e.g. a (host, port) tuple for IPv4).\n"
  190. + "\n"
  191. )]
  192. public PythonTuple accept() {
  193. socket wrappedRemoteSocket;
  194. Socket realRemoteSocket;
  195. try {
  196. #if NETSTANDARD
  197. // TODO: support timeout != 0
  198. realRemoteSocket = _socket.Accept();
  199. #else
  200. if (_acceptResult != null && _acceptResult.IsCompleted) {
  201. // previous async result has completed
  202. realRemoteSocket = _socket.EndAccept(_acceptResult);
  203. } else {
  204. int timeoutTime = _timeout;
  205. if (timeoutTime != 0) {
  206. // use the existing or create a new async request
  207. var asyncResult = _acceptResult ?? _socket.BeginAccept((x) => { }, null);
  208. if (asyncResult.AsyncWaitHandle.WaitOne(timeoutTime)) {
  209. // it's completed, end and throw it away
  210. realRemoteSocket = _socket.EndAccept(asyncResult);
  211. _acceptResult = null;
  212. } else {
  213. // save the async result for later incase it completes
  214. _acceptResult = asyncResult;
  215. throw PythonExceptions.CreateThrowable(timeout(_context), 0, "timeout");
  216. }
  217. } else {
  218. realRemoteSocket = _socket.Accept();
  219. }
  220. }
  221. #endif
  222. } catch (Exception e) {
  223. throw MakeException(_context, e);
  224. }
  225. wrappedRemoteSocket = new socket(_context, realRemoteSocket);
  226. return PythonTuple.MakeTuple(wrappedRemoteSocket, wrappedRemoteSocket.getpeername());
  227. }
  228. [Documentation("bind(address) -> None\n\n"
  229. + "Bind to an address. If the socket is already bound, socket.error is raised.\n"
  230. + "For IP sockets, address is a (host, port) tuple. Raw sockets are not\n"
  231. + "supported.\n"
  232. + "\n"
  233. + "If you do not care which local address is assigned, set host to INADDR_ANY and\n"
  234. + "the system will assign the most appropriate network address. Similarly, if you\n"
  235. + "set port to 0, the system will assign an available port number between 1024\n"
  236. + "and 5000."
  237. )]
  238. public void bind(PythonTuple address) {
  239. IPEndPoint localEP = TupleToEndPoint(_context, address, _socket.AddressFamily, out _hostName);
  240. try {
  241. _socket.Bind(localEP);
  242. } catch (Exception e) {
  243. throw MakeException(_context, e);
  244. }
  245. }
  246. [Documentation("close() -> None\n\nClose the socket. It cannot be used after being closed.")]
  247. public void close() {
  248. var refs = System.Threading.Interlocked.Decrement(ref _referenceCount);
  249. // Don't actually close the socket if other file objects are
  250. // still referring to this socket.
  251. if (refs < 1) {
  252. _close();
  253. }
  254. }
  255. internal void _close() {
  256. if (_socket != null) {
  257. lock (_handleToSocket) {
  258. WeakReference weakref;
  259. if (_handleToSocket.TryGetValue(_socket.GetHandle(), out weakref)) {
  260. Socket target = (weakref.Target as Socket);
  261. if (target == _socket || target == null) {
  262. _handleToSocket.Remove(_socket.GetHandle());
  263. }
  264. }
  265. }
  266. ((IDisposable)_socket).Dispose();
  267. _referenceCount = 0;
  268. }
  269. }
  270. [Documentation("connect(address) -> None\n\n"
  271. + "Connect to a remote socket at the given address. IP addresses are expressed\n"
  272. + "as (host, port).\n"
  273. + "\n"
  274. + "Raises socket.error if the socket has been closed, the socket is listening, or\n"
  275. + "another connection error occurred."
  276. + "\n"
  277. + "Difference from CPython: connect() does not support timeouts in blocking mode.\n"
  278. + "If a timeout is set and the socket is in blocking mode, connect() will block\n"
  279. + "indefinitely until a connection is made or an error occurs."
  280. )]
  281. public void connect(PythonTuple address) {
  282. IPEndPoint remoteEP = TupleToEndPoint(_context, address, _socket.AddressFamily, out _hostName);
  283. try {
  284. _socket.Connect(remoteEP);
  285. } catch (Exception e) {
  286. throw MakeException(_context, e);
  287. }
  288. }
  289. [Documentation("connect_ex(address) -> error_code\n\n"
  290. + "Like connect(), but return an error code insted of raising an exception for\n"
  291. + "socket exceptions raised by the underlying system Connect() call. Note that\n"
  292. + "exceptions other than SocketException generated by the system Connect() call\n"
  293. + "will still be raised.\n"
  294. + "\n"
  295. + "A return value of 0 indicates that the connect call was successful."
  296. + "\n"
  297. + "Difference from CPython: connect_ex() does not support timeouts in blocking\n"
  298. + "mode. If a timeout is set and the socket is in blocking mode, connect_ex() will\n"
  299. + "block indefinitely until a connection is made or an error occurs."
  300. )]
  301. public int connect_ex(PythonTuple address) {
  302. IPEndPoint remoteEP = TupleToEndPoint(_context, address, _socket.AddressFamily, out _hostName);
  303. try {
  304. _socket.Connect(remoteEP);
  305. } catch (SocketException e) {
  306. return (int)e.SocketErrorCode;
  307. }
  308. return (int)SocketError.Success;
  309. }
  310. [Documentation("fileno() -> file_handle\n\n"
  311. + "Return the underlying system handle for this socket (a 64-bit integer)."
  312. )]
  313. public Int64 fileno() {
  314. try {
  315. return _socket.GetHandle().ToInt64();
  316. } catch (Exception e) {
  317. throw MakeException(_context, e);
  318. }
  319. }
  320. [Documentation("getpeername() -> address\n\n"
  321. + "Return the address of the remote end of this socket. The address format is\n"
  322. + "family-dependent (e.g. a (host, port) tuple for IPv4)."
  323. )]
  324. public PythonTuple getpeername() {
  325. try {
  326. IPEndPoint remoteEP = _socket.RemoteEndPoint as IPEndPoint;
  327. if (remoteEP == null) {
  328. throw MakeException(_context, new SocketException((int)SocketError.AddressFamilyNotSupported));
  329. }
  330. return EndPointToTuple(remoteEP);
  331. } catch (Exception e) {
  332. throw MakeException(_context, e);
  333. }
  334. }
  335. [Documentation("getsockname() -> address\n\n"
  336. + "Return the address of the local end of this socket. The address format is\n"
  337. + "family-dependent (e.g. a (host, port) tuple for IPv4)."
  338. )]
  339. public PythonTuple getsockname() {
  340. try {
  341. IPEndPoint localEP = _socket.LocalEndPoint as IPEndPoint;
  342. if (localEP == null) {
  343. throw MakeException(_context, new SocketException((int)SocketError.InvalidArgument));
  344. }
  345. return EndPointToTuple(localEP);
  346. } catch (Exception e) {
  347. throw MakeException(_context, e);
  348. }
  349. }
  350. [Documentation("getsockopt(level, optname[, buflen]) -> value\n\n"
  351. + "Return the value of a socket option. level is one of the SOL_* constants\n"
  352. + "defined in this module, and optname is one of the SO_* constants. If buflen is\n"
  353. + "omitted or zero, an integer value is returned. If it is present, a byte string\n"
  354. + "whose maximum length is buflen bytes) is returned. The caller must the decode\n"
  355. + "the resulting byte string."
  356. )]
  357. public object getsockopt(int optionLevel, int optionName, [DefaultParameterValue(0)] int optionLength) {
  358. SocketOptionLevel level = (SocketOptionLevel)Enum.ToObject(typeof(SocketOptionLevel), optionLevel);
  359. if (!Enum.IsDefined(typeof(SocketOptionLevel), level)) {
  360. throw MakeException(_context, new SocketException((int)SocketError.InvalidArgument));
  361. }
  362. SocketOptionName name = (SocketOptionName)Enum.ToObject(typeof(SocketOptionName), optionName);
  363. if (!Enum.IsDefined(typeof(SocketOptionName), name)) {
  364. throw MakeException(_context, new SocketException((int)SocketError.ProtocolOption));
  365. }
  366. try {
  367. if (optionLength == 0) {
  368. // Integer return value
  369. return (int)_socket.GetSocketOption(level, name);
  370. } else {
  371. // Byte string return value
  372. return _socket.GetSocketOption(level, name, optionLength).MakeString();
  373. }
  374. } catch (Exception e) {
  375. throw MakeException(_context, e);
  376. }
  377. }
  378. [Documentation("listen(backlog) -> None\n\n"
  379. + "Listen for connections on the socket. Backlog is the maximum length of the\n"
  380. + "pending connections queue. The maximum value is system-dependent."
  381. )]
  382. public void listen(int backlog) {
  383. try {
  384. _socket.Listen(backlog);
  385. } catch (Exception e) {
  386. throw MakeException(_context, e);
  387. }
  388. }
  389. [Documentation("makefile([mode[, bufsize]]) -> file object\n\n"
  390. + "Return a regular file object corresponding to the socket. The mode\n"
  391. + "and bufsize arguments are as for the built-in open() function.")]
  392. public PythonFile makefile([DefaultParameterValue("r")]string mode, [DefaultParameterValue(8192)]int bufSize) {
  393. System.Threading.Interlocked.Increment(ref _referenceCount); // dup our handle
  394. return new _fileobject(_context, this, mode, bufSize, false);
  395. }
  396. [Documentation("recv(bufsize[, flags]) -> string\n\n"
  397. + "Receive data from the socket, up to bufsize bytes. For connection-oriented\n"
  398. + "protocols (e.g. SOCK_STREAM), you must first call either connect() or\n"
  399. + "accept(). Connectionless protocols (e.g. SOCK_DGRAM) may also use recvfrom().\n"
  400. + "\n"
  401. + "recv() blocks until data is available, unless a timeout was set using\n"
  402. + "settimeout(). If the timeout was exceeded, socket.timeout is raised."
  403. + "recv() returns immediately with zero bytes when the connection is closed."
  404. )]
  405. public string recv(int maxBytes, [DefaultParameterValue(0)] int flags) {
  406. int bytesRead;
  407. if (maxBytes < 0)
  408. throw PythonOps.ValueError("negative buffersize in recv");
  409. byte[] buffer = new byte[maxBytes];
  410. try {
  411. bytesRead = _socket.Receive(buffer, (SocketFlags)flags);
  412. } catch (Exception e) {
  413. throw MakeRecvException(e, SocketError.NotConnected);
  414. }
  415. return PythonOps.MakeString(buffer, bytesRead);
  416. }
  417. [Documentation("recv_into(buffer, [nbytes[, flags]]) -> nbytes_read\n\n"
  418. + "A version of recv() that stores its data into a buffer rather than creating\n"
  419. + "a new string. Receive up to buffersize bytes from the socket. If buffersize\n"
  420. + "is not specified (or 0), receive up to the size available in the given buffer.\n\n"
  421. + "See recv() for documentation about the flags.\n"
  422. )]
  423. public int recv_into(PythonBuffer buffer, [DefaultParameterValue(0)]int nbytes, [DefaultParameterValue(0)]int flags) {
  424. if (nbytes < 0) {
  425. throw PythonOps.ValueError("negative buffersize in recv_into");
  426. }
  427. throw PythonOps.TypeError("buffer is read-only");
  428. }
  429. [Documentation("recv_into(buffer, [nbytes[, flags]]) -> nbytes_read\n\n"
  430. + "A version of recv() that stores its data into a buffer rather than creating\n"
  431. + "a new string. Receive up to buffersize bytes from the socket. If buffersize\n"
  432. + "is not specified (or 0), receive up to the size available in the given buffer.\n\n"
  433. + "See recv() for documentation about the flags.\n"
  434. )]
  435. public int recv_into(string buffer, [DefaultParameterValue(0)]int nbytes, [DefaultParameterValue(0)]int flags) {
  436. throw PythonOps.TypeError("Cannot use string as modifiable buffer");
  437. }
  438. [Documentation("recv_into(buffer, [nbytes[, flags]]) -> nbytes_read\n\n"
  439. + "A version of recv() that stores its data into a buffer rather than creating\n"
  440. + "a new string. Receive up to buffersize bytes from the socket. If buffersize\n"
  441. + "is not specified (or 0), receive up to the size available in the given buffer.\n\n"
  442. + "See recv() for documentation about the flags.\n"
  443. )]
  444. public int recv_into(PythonArray buffer, [DefaultParameterValue(0)]int nbytes, [DefaultParameterValue(0)]int flags) {
  445. int bytesRead;
  446. byte[] byteBuffer = new byte[byteBufferSize("recv_into", nbytes, buffer.__len__(), buffer.itemsize)];
  447. try {
  448. bytesRead = _socket.Receive(byteBuffer, (SocketFlags)flags);
  449. } catch (Exception e) {
  450. throw MakeRecvException(e, SocketError.NotConnected);
  451. }
  452. buffer.FromStream(new MemoryStream(byteBuffer), 0);
  453. return bytesRead;
  454. }
  455. [Documentation("recv_into(bytearray, [nbytes[, flags]]) -> nbytes_read\n\n"
  456. + "A version of recv() that stores its data into a bytearray rather than creating\n"
  457. + "a new string. Receive up to buffersize bytes from the socket. If buffersize\n"
  458. + "is not specified (or 0), receive up to the size available in the given buffer.\n\n"
  459. + "See recv() for documentation about the flags.\n"
  460. )]
  461. public int recv_into(ByteArray buffer, [DefaultParameterValue(0)]int nbytes, [DefaultParameterValue(0)]int flags) {
  462. int bytesRead;
  463. byte[] byteBuffer = new byte[byteBufferSize("recv_into", nbytes, buffer.Count, 1)];
  464. try {
  465. bytesRead = _socket.Receive(byteBuffer, (SocketFlags)flags);
  466. } catch (Exception e) {
  467. throw MakeRecvException(e, SocketError.NotConnected);
  468. }
  469. for (int i = 0; i < bytesRead; i++) {
  470. buffer[i] = byteBuffer[i];
  471. }
  472. return bytesRead;
  473. }
  474. [Documentation("recv_into(memoryview, [nbytes[, flags]]) -> nbytes_read\n\n"
  475. + "A version of recv() that stores its data into a bytearray rather than creating\n"
  476. + "a new string. Receive up to buffersize bytes from the socket. If buffersize\n"
  477. + "is not specified (or 0), receive up to the size available in the given buffer.\n\n"
  478. + "See recv() for documentation about the flags.\n"
  479. )]
  480. public int recv_into(MemoryView buffer, [DefaultParameterValue(0)]int nbytes, [DefaultParameterValue(0)]int flags) {
  481. int bytesRead;
  482. byte[] byteBuffer = buffer.tobytes().ToByteArray();
  483. try {
  484. bytesRead = _socket.Receive(byteBuffer, (SocketFlags)flags);
  485. }
  486. catch (Exception e) {
  487. if (_socket.SendTimeout == 0) {
  488. var s = new SocketException((int)SocketError.NotConnected);
  489. throw PythonExceptions.CreateThrowable(error(_context), (int)SocketError.NotConnected, s.Message);
  490. }
  491. else
  492. throw MakeException(_context, e);
  493. }
  494. buffer[new Slice(0, bytesRead)] = byteBuffer.Slice(new Slice(0, bytesRead));
  495. return bytesRead;
  496. }
  497. public int recv_into(object buffer, [DefaultParameterValue(0)]int nbytes, [DefaultParameterValue(0)]int flags){
  498. throw PythonOps.TypeError(string.Format("recv_into() argument 1 must be read-write buffer, not {0}",PythonOps.GetPythonTypeName(buffer)));
  499. }
  500. [Documentation("recvfrom(bufsize[, flags]) -> (string, address)\n\n"
  501. + "Receive data from the socket, up to bufsize bytes. string is the data\n"
  502. + "received, and address (whose format is protocol-dependent) is the address of\n"
  503. + "the socket from which the data was received."
  504. )]
  505. public PythonTuple recvfrom(int maxBytes, [DefaultParameterValue(0)] int flags) {
  506. if (maxBytes < 0) {
  507. throw PythonOps.ValueError("negative buffersize in recvfrom");
  508. }
  509. int bytesRead;
  510. byte[] buffer = new byte[maxBytes];
  511. IPEndPoint remoteIPEP = new IPEndPoint(IPAddress.Any, 0);
  512. EndPoint remoteEP = remoteIPEP;
  513. try {
  514. bytesRead = _socket.ReceiveFrom(buffer, (SocketFlags)flags, ref remoteEP);
  515. } catch (Exception e) {
  516. throw MakeRecvException(e, SocketError.InvalidArgument);
  517. }
  518. string data = PythonOps.MakeString(buffer, bytesRead);
  519. PythonTuple remoteAddress = EndPointToTuple((IPEndPoint)remoteEP);
  520. return PythonTuple.MakeTuple(data, remoteAddress);
  521. }
  522. [Documentation("recvfrom_into(buffer[, nbytes[, flags]]) -> (nbytes, address info)\n\n"
  523. + "Like recv_into(buffer[, nbytes[, flags]]) but also return the sender's address info.\n"
  524. )]
  525. public PythonTuple recvfrom_into(PythonBuffer buffer, [DefaultParameterValue(0)]int nbytes, [DefaultParameterValue(0)]int flags) {
  526. if (nbytes < 0) {
  527. throw PythonOps.ValueError("negative buffersize in recvfrom_into");
  528. }
  529. throw PythonOps.TypeError("buffer is read-only");
  530. }
  531. [Documentation("recvfrom_into(buffer[, nbytes[, flags]]) -> (nbytes, address info)\n\n"
  532. + "Like recv_into(buffer[, nbytes[, flags]]) but also return the sender's address info.\n"
  533. )]
  534. public PythonTuple recvfrom_into(string buffer, [DefaultParameterValue(0)]int nbytes, [DefaultParameterValue(0)]int flags) {
  535. throw PythonOps.TypeError("Cannot use string as modifiable buffer");
  536. }
  537. [Documentation("recvfrom_into(buffer[, nbytes[, flags]]) -> (nbytes, address info)\n\n"
  538. + "Like recv_into(buffer[, nbytes[, flags]]) but also return the sender's address info.\n"
  539. )]
  540. public PythonTuple recvfrom_into(PythonArray buffer, [DefaultParameterValue(0)]int nbytes, [DefaultParameterValue(0)]int flags) {
  541. int bytesRead;
  542. byte[] byteBuffer = new byte[byteBufferSize("recvfrom_into", nbytes, buffer.__len__(), buffer.itemsize)];
  543. IPEndPoint remoteIPEP = new IPEndPoint(IPAddress.Any, 0);
  544. EndPoint remoteEP = remoteIPEP;
  545. try {
  546. bytesRead = _socket.ReceiveFrom(byteBuffer, (SocketFlags)flags, ref remoteEP);
  547. } catch (Exception e) {
  548. throw MakeRecvException(e, SocketError.InvalidArgument);
  549. }
  550. buffer.FromStream(new MemoryStream(byteBuffer), 0);
  551. PythonTuple remoteAddress = EndPointToTuple((IPEndPoint)remoteEP);
  552. return PythonTuple.MakeTuple(bytesRead, remoteAddress);
  553. }
  554. [Documentation("recvfrom_into(buffer[, nbytes[, flags]]) -> (nbytes, address info)\n\n"
  555. + "Like recv_into(buffer[, nbytes[, flags]]) but also return the sender's address info.\n"
  556. )]
  557. public PythonTuple recvfrom_into(MemoryView buffer, [DefaultParameterValue(0)]int nbytes, [DefaultParameterValue(0)]int flags){
  558. int bytesRead;
  559. byte[] byteBuffer = buffer.tobytes().ToByteArray();
  560. IPEndPoint remoteIPEP = new IPEndPoint(IPAddress.Any, 0);
  561. EndPoint remoteEP = remoteIPEP;
  562. try {
  563. bytesRead = _socket.ReceiveFrom(byteBuffer, (SocketFlags)flags, ref remoteEP);
  564. }
  565. catch (Exception e) {
  566. throw MakeRecvException(e, SocketError.InvalidArgument);
  567. }
  568. buffer[new Slice(0, bytesRead)] = byteBuffer.Slice(new Slice(0, bytesRead));
  569. PythonTuple remoteAddress = EndPointToTuple((IPEndPoint)remoteEP);
  570. return PythonTuple.MakeTuple(bytesRead, remoteAddress);
  571. }
  572. [Documentation("recvfrom_into(buffer[, nbytes[, flags]]) -> (nbytes, address info)\n\n"
  573. + "Like recv_into(buffer[, nbytes[, flags]]) but also return the sender's address info.\n"
  574. )]
  575. public PythonTuple recvfrom_into(IList<byte> buffer, [DefaultParameterValue(0)]int nbytes, [DefaultParameterValue(0)]int flags) {
  576. int bytesRead;
  577. byte[] byteBuffer = new byte[byteBufferSize("recvfrom_into", nbytes, buffer.Count, 1)];
  578. IPEndPoint remoteIPEP = new IPEndPoint(IPAddress.Any, 0);
  579. EndPoint remoteEP = remoteIPEP;
  580. try {
  581. bytesRead = _socket.ReceiveFrom(byteBuffer, (SocketFlags)flags, ref remoteEP);
  582. } catch (Exception e) {
  583. throw MakeRecvException(e, SocketError.InvalidArgument);
  584. }
  585. for (int i = 0; i < byteBuffer.Length; i++) {
  586. buffer[i] = byteBuffer[i];
  587. }
  588. PythonTuple remoteAddress = EndPointToTuple((IPEndPoint)remoteEP);
  589. return PythonTuple.MakeTuple(bytesRead, remoteAddress);
  590. }
  591. public PythonTuple recvfrom_into(object buffer, [DefaultParameterValue(0)]int nbytes, [DefaultParameterValue(0)]int flags) {
  592. throw PythonOps.TypeError(string.Format("recvfrom_into() argument 1 must be read-write buffer, not {0}", PythonOps.GetPythonTypeName(buffer)));
  593. }
  594. private static int byteBufferSize(string funcName, int nbytes, int bufLength, int itemSize) {
  595. if (nbytes < 0) {
  596. throw PythonOps.ValueError("negative buffersize in " + funcName);
  597. } else if (nbytes == 0) {
  598. return bufLength * itemSize;
  599. } else {
  600. int remainder = nbytes % itemSize;
  601. return Math.Min(remainder == 0 ? nbytes : nbytes + itemSize - remainder,
  602. bufLength * itemSize);
  603. }
  604. }
  605. private Exception MakeRecvException(Exception e, SocketError errorCode = SocketError.InvalidArgument) {
  606. // on the socket recv throw a special socket error code when SendTimeout is zero
  607. if (_socket.SendTimeout == 0) {
  608. var s = new SocketException((int)errorCode);
  609. return PythonExceptions.CreateThrowable(error(_context), (int)SocketError.InvalidArgument, s.Message);
  610. }
  611. else
  612. return MakeException(_context, e);
  613. }
  614. [Documentation("send(string[, flags]) -> bytes_sent\n\n"
  615. + "Send data to the remote socket. The socket must be connected to a remote\n"
  616. + "socket (by calling either connect() or accept(). Returns the number of bytes\n"
  617. + "sent to the remote socket.\n"
  618. + "\n"
  619. + "Note that the successful completion of a send() call does not mean that all of\n"
  620. + "the data was sent. The caller must keep track of the number of bytes sent and\n"
  621. + "retry the operation until all of the data has been sent.\n"
  622. + "\n"
  623. + "Also note that there is no guarantee that the data you send will appear on the\n"
  624. + "network immediately. To increase network efficiency, the underlying system may\n"
  625. + "delay transmission until a significant amount of outgoing data is collected. A\n"
  626. + "successful completion of the Send method means that the underlying system has\n"
  627. + "had room to buffer your data for a network send"
  628. )]
  629. public int send(string data, [DefaultParameterValue(0)] int flags) {
  630. byte[] buffer = data.MakeByteArray();
  631. try {
  632. return _socket.Send(buffer, (SocketFlags)flags);
  633. } catch (Exception e) {
  634. throw MakeException(_context, e);
  635. }
  636. }
  637. [Documentation("send(string[, flags]) -> bytes_sent\n\n"
  638. + "Send data to the remote socket. The socket must be connected to a remote\n"
  639. + "socket (by calling either connect() or accept(). Returns the number of bytes\n"
  640. + "sent to the remote socket.\n"
  641. + "\n"
  642. + "Note that the successful completion of a send() call does not mean that all of\n"
  643. + "the data was sent. The caller must keep track of the number of bytes sent and\n"
  644. + "retry the operation until all of the data has been sent.\n"
  645. + "\n"
  646. + "Also note that there is no guarantee that the data you send will appear on the\n"
  647. + "network immediately. To increase network efficiency, the underlying system may\n"
  648. + "delay transmission until a significant amount of outgoing data is collected. A\n"
  649. + "successful completion of the Send method means that the underlying system has\n"
  650. + "had room to buffer your data for a network send"
  651. )]
  652. public int send(Bytes data, [DefaultParameterValue(0)] int flags) {
  653. byte[] buffer = data.GetUnsafeByteArray();
  654. try {
  655. return _socket.Send(buffer, (SocketFlags)flags);
  656. } catch (Exception e) {
  657. throw MakeException(_context, e);
  658. }
  659. }
  660. [Documentation("send(string[, flags]) -> bytes_sent\n\n"
  661. + "Send data to the remote socket. The socket must be connected to a remote\n"
  662. + "socket (by calling either connect() or accept(). Returns the number of bytes\n"
  663. + "sent to the remote socket.\n"
  664. + "\n"
  665. + "Note that the successful completion of a send() call does not mean that all of\n"
  666. + "the data was sent. The caller must keep track of the number of bytes sent and\n"
  667. + "retry the operation until all of the data has been sent.\n"
  668. + "\n"
  669. + "Also note that there is no guarantee that the data you send will appear on the\n"
  670. + "network immediately. To increase network efficiency, the underlying system may\n"
  671. + "delay transmission until a significant amount of outgoing data is collected. A\n"
  672. + "successful completion of the Send method means that the underlying system has\n"
  673. + "had room to buffer your data for a network send"
  674. )]
  675. public int send(PythonBuffer data, [DefaultParameterValue(0)] int flags) {
  676. byte[] buffer = data.byteCache;
  677. try {
  678. return _socket.Send(buffer, (SocketFlags)flags);
  679. } catch (Exception e) {
  680. throw MakeException(_context, e);
  681. }
  682. }
  683. [Documentation("sendall(string[, flags]) -> None\n\n"
  684. + "Send data to the remote socket. The socket must be connected to a remote\n"
  685. + "socket (by calling either connect() or accept().\n"
  686. + "\n"
  687. + "Unlike send(), sendall() blocks until all of the data has been sent or until a\n"
  688. + "timeout or an error occurs. None is returned on success. If an error occurs,\n"
  689. + "there is no way to tell how much data, if any, was sent.\n"
  690. + "\n"
  691. + "Difference from CPython: timeouts do not function as you would expect. The\n"
  692. + "function is implemented using multiple calls to send(), so the timeout timer\n"
  693. + "is reset after each of those calls. That means that the upper bound on the\n"
  694. + "time that it will take for sendall() to return is the number of bytes in\n"
  695. + "string times the timeout interval.\n"
  696. + "\n"
  697. + "Also note that there is no guarantee that the data you send will appear on the\n"
  698. + "network immediately. To increase network efficiency, the underlying system may\n"
  699. + "delay transmission until a significant amount of outgoing data is collected. A\n"
  700. + "successful completion of the Send method means that the underlying system has\n"
  701. + "had room to buffer your data for a network send"
  702. )]
  703. public void sendall(string data, [DefaultParameterValue(0)] int flags) {
  704. sendallWorker(data.MakeByteArray(), flags);
  705. }
  706. [Documentation("sendall(string[, flags]) -> None\n\n"
  707. + "Send data to the remote socket. The socket must be connected to a remote\n"
  708. + "socket (by calling either connect() or accept().\n"
  709. + "\n"
  710. + "Unlike send(), sendall() blocks until all of the data has been sent or until a\n"
  711. + "timeout or an error occurs. None is returned on success. If an error occurs,\n"
  712. + "there is no way to tell how much data, if any, was sent.\n"
  713. + "\n"
  714. + "Difference from CPython: timeouts do not function as you would expect. The\n"
  715. + "function is implemented using multiple calls to send(), so the timeout timer\n"
  716. + "is reset after each of those calls. That means that the upper bound on the\n"
  717. + "time that it will take for sendall() to return is the number of bytes in\n"
  718. + "string times the timeout interval.\n"
  719. + "\n"
  720. + "Also note that there is no guarantee that the data you send will appear on the\n"
  721. + "network immediately. To increase network efficiency, the underlying system may\n"
  722. + "delay transmission until a significant amount of outgoing data is collected. A\n"
  723. + "successful completion of the Send method means that the underlying system has\n"
  724. + "had room to buffer your data for a network send"
  725. )]
  726. public void sendall(Bytes data, [DefaultParameterValue(0)] int flags) {
  727. sendallWorker(data.GetUnsafeByteArray(), flags);
  728. }
  729. [Documentation("sendall(string[, flags]) -> None\n\n"
  730. + "Send data to the remote socket. The socket must be connected to a remote\n"
  731. + "socket (by calling either connect() or accept().\n"
  732. + "\n"
  733. + "Unlike send(), sendall() blocks until all of the data has been sent or until a\n"
  734. + "timeout or an error occurs. None is returned on success. If an error occurs,\n"
  735. + "there is no way to tell how much data, if any, was sent.\n"
  736. + "\n"
  737. + "Difference from CPython: timeouts do not function as you would expect. The\n"
  738. + "function is implemented using multiple calls to send(), so the timeout timer\n"
  739. + "is reset after each of those calls. That means that the upper bound on the\n"
  740. + "time that it will take for sendall() to return is the number of bytes in\n"
  741. + "string times the timeout interval.\n"
  742. + "\n"
  743. + "Also note that there is no guarantee that the data you send will appear on the\n"
  744. + "network immediately. To increase network efficiency, the underlying system may\n"
  745. + "delay transmission until a significant amount of outgoing data is collected. A\n"
  746. + "successful completion of the Send method means that the underlying system has\n"
  747. + "had room to buffer your data for a network send"
  748. )]
  749. public void sendall(PythonBuffer data, [DefaultParameterValue(0)] int flags) {
  750. sendallWorker(data.byteCache, flags);
  751. }
  752. private void sendallWorker(byte[] buffer, int flags) {
  753. try {
  754. int bytesTotal = buffer.Length;
  755. int bytesRemaining = bytesTotal;
  756. while (bytesRemaining > 0) {
  757. bytesRemaining -= _socket.Send(buffer, bytesTotal - bytesRemaining, bytesRemaining, (SocketFlags)flags);
  758. }
  759. } catch (Exception e) {
  760. throw MakeException(_context, e);
  761. }
  762. }
  763. [Documentation("sendto(string[, flags], address) -> bytes_sent\n\n"
  764. + "Send data to the remote socket. The socket does not need to be connected to a\n"
  765. + "remote socket since the address is specified in the call to sendto(). Returns\n"
  766. + "the number of bytes sent to the remote socket.\n"
  767. + "\n"
  768. + "Blocking sockets will block until the all of the bytes in the buffer are sent.\n"
  769. + "Since a nonblocking Socket completes immediately, it might not send all of the\n"
  770. + "bytes in the buffer. It is your application's responsibility to keep track of\n"
  771. + "the number of bytes sent and to retry the operation until the application sends\n"
  772. + "all of the bytes in the buffer.\n"
  773. + "\n"
  774. + "Note that there is no guarantee that the data you send will appear on the\n"
  775. + "network immediately. To increase network efficiency, the underlying system may\n"
  776. + "delay transmission until a significant amount of outgoing data is collected. A\n"
  777. + "successful completion of the Send method means that the underlying system has\n"
  778. + "had room to buffer your data for a network send"
  779. )]
  780. public int sendto(string data, int flags, PythonTuple address) {
  781. byte[] buffer = data.MakeByteArray();
  782. EndPoint remoteEP = TupleToEndPoint(_context, address, _socket.AddressFamily, out _hostName);
  783. try {
  784. return _socket.SendTo(buffer, (SocketFlags)flags, remoteEP);
  785. } catch (Exception e) {
  786. throw MakeException(_context, e);
  787. }
  788. }
  789. [Documentation("sendto(string[, flags], address) -> bytes_sent\n\n"
  790. + "Send data to the remote socket. The socket does not need to be connected to a\n"
  791. + "remote socket since the address is specified in the call to sendto(). Returns\n"
  792. + "the number of bytes sent to the remote socket.\n"
  793. + "\n"
  794. + "Blocking sockets will block until the all of the bytes in the buffer are sent.\n"
  795. + "Since a nonblocking Socket completes immediately, it might not send all of the\n"
  796. + "bytes in the buffer. It is your application's responsibility to keep track of\n"
  797. + "the number of bytes sent and to retry the operation until the application sends\n"
  798. + "all of the bytes in the buffer.\n"
  799. + "\n"
  800. + "Note that there is no guarantee that the data you send will appear on the\n"
  801. + "network immediately. To increase network efficiency, the underlying system may\n"
  802. + "delay transmission until a significant amount of outgoing data is collected. A\n"
  803. + "successful completion of the Send method means that the underlying system has\n"
  804. + "had room to buffer your data for a network send"
  805. )]
  806. public int sendto(Bytes data, int flags, PythonTuple address) {
  807. byte[] buffer = data.GetUnsafeByteArray();
  808. EndPoint remoteEP = TupleToEndPoint(_context, address, _socket.AddressFamily, out _hostName);
  809. try {
  810. return _socket.SendTo(buffer, (SocketFlags)flags, remoteEP);
  811. } catch (Exception e) {
  812. throw MakeException(_context, e);
  813. }
  814. }
  815. [Documentation("")]
  816. public int sendto(string data, PythonTuple address) {
  817. return sendto(data, 0, address);
  818. }
  819. [Documentation("")]
  820. public int sendto(Bytes data, PythonTuple address) {
  821. return sendto(data, 0, address);
  822. }
  823. [Documentation("setblocking(flag) -> None\n\n"
  824. + "Set the blocking mode of the socket. If flag is 0, the socket will be set to\n"
  825. + "non-blocking mode; otherwise, it will be set to blocking mode. If the socket is\n"
  826. + "in blocking mode, and a method is called (such as send() or recv() which does\n"
  827. + "not complete immediately, the caller will block execution until the requested\n"
  828. + "operation completes. In non-blocking mode, a socket.timeout exception would\n"
  829. + "would be raised in this case.\n"
  830. + "\n"
  831. + "Note that changing blocking mode also affects the timeout setting:\n"
  832. + "setblocking(0) is equivalent to settimeout(0), and setblocking(1) is equivalent\n"
  833. + "to settimeout(None)."
  834. )]
  835. public void setblocking(int shouldBlock) {
  836. if (shouldBlock == 0) {
  837. settimeout(0);
  838. } else {
  839. settimeout(null);
  840. }
  841. }
  842. [Documentation("settimeout(value) -> None\n\n"
  843. + "Set a timeout on blocking socket methods. value may be either None or a\n"
  844. + "non-negative float, with one of the following meanings:\n"
  845. + " - None: disable timeouts and block indefinitely"
  846. + " - 0.0: don't block at all (return immediately if the operation can be\n"
  847. + " completed; raise socket.error otherwise)\n"
  848. + " - float > 0.0: block for up to the specified number of seconds; raise\n"
  849. + " socket.timeout if the operation cannot be completed in time\n"
  850. + "\n"
  851. + "settimeout(None) is equivalent to setblocking(1), and settimeout(0.0) is\n"
  852. + "equivalent to setblocking(0)."
  853. + "\n"
  854. + "If the timeout is non-zero and is less than 0.5, it will be set to 0.5. This\n"
  855. + "limitation is specific to IronPython.\n"
  856. )]
  857. // NOTE: The above IronPython specific timeout behavior is due to the underlying
  858. // .Net Socket.SendTimeout behavior and is outside of our control.
  859. public void settimeout(object timeout) {
  860. try {
  861. if (timeout == null) {
  862. _socket.Blocking = true;
  863. _socket.SendTimeout = 0;
  864. } else {
  865. double seconds;
  866. seconds = Converter.ConvertToDouble(timeout);
  867. if (seconds < 0) {
  868. throw PythonOps.ValueError("Timeout value out of range");
  869. }
  870. _socket.Blocking = seconds > 0; // 0 timeout means non-blocking mode
  871. _socket.SendTimeout = (int)(seconds * MillisecondsPerSecond);
  872. _timeout = (int)(seconds * MillisecondsPerSecond);
  873. }
  874. } finally {
  875. _socket.ReceiveTimeout = _socket.SendTimeout;
  876. }
  877. }
  878. [Documentation("gettimeout() -> value\n\n"
  879. + "Return the timeout duration in seconds for this socket as a float. If no\n"
  880. + "timeout is set, return None. For more details on timeouts and blocking, see the\n"
  881. + "Python socket module documentation."
  882. )]
  883. public object gettimeout() {
  884. try {
  885. if (_socket.Blocking && _socket.SendTimeout == 0) {
  886. return null;
  887. } else {
  888. return (double)_socket.SendTimeout / MillisecondsPerSecond;
  889. }
  890. } catch (Exception e) {
  891. throw MakeException(_context, e);
  892. }
  893. }
  894. [Documentation("setsockopt(level, optname[, value]) -> None\n\n"
  895. + "Set the value of a socket option. level is one of the SOL_* constants defined\n"
  896. + "in this module, and optname is one of the SO_* constants. value may be either\n"
  897. + "an integer or a string containing a binary structure. The caller is responsible\n"
  898. + "for properly encoding the byte string."
  899. )]
  900. public void setsockopt(int optionLevel, int optionName, object value) {
  901. SocketOptionLevel level = (SocketOptionLevel)Enum.ToObject(typeof(SocketOptionLevel), optionLevel);
  902. if (!Enum.IsDefined(typeof(SocketOptionLevel), level)) {
  903. throw MakeException(_context, new SocketException((int)SocketError.InvalidArgument));
  904. }
  905. SocketOptionName name = (SocketOptionName)Enum.ToObject(typeof(SocketOptionName), optionName);
  906. if (!Enum.IsDefined(typeof(SocketOptionName), name)) {
  907. throw MakeException(_context, new SocketException((int)SocketError.ProtocolOption));
  908. }
  909. try {
  910. int intValue;
  911. if (Converter.TryConvertToInt32(value, out intValue)) {
  912. _socket.SetSocketOption(level, name, intValue);
  913. return;
  914. }
  915. string strValue;
  916. if (Converter.TryConvertToString(value, out strValue)) {
  917. _socket.SetSocketOption(level, name, strValue.MakeByteArray());
  918. return;
  919. }
  920. } catch (Exception e) {
  921. throw MakeException(_context, e);
  922. }
  923. throw PythonOps.TypeError("setsockopt() argument 3 must be int or string");
  924. }
  925. [Documentation("shutdown() -> None\n\n"
  926. + "Return the timeout duration in seconds for this socket as a float. If no\n"
  927. + "timeout is set, return None. For more details on timeouts and blocking, see the\n"
  928. + "Python socket module documentation."
  929. )]
  930. public void shutdown(int how) {
  931. SocketShutdown howValue = (SocketShutdown)Enum.ToObject(typeof(SocketShutdown), how);
  932. if (!Enum.IsDefined(typeof(SocketShutdown), howValue)) {
  933. throw MakeException(_context, new SocketException((int)SocketError.InvalidArgument));
  934. }
  935. try {
  936. _socket.Shutdown(howValue);
  937. } catch (Exception e) {
  938. throw MakeException(_context, e);
  939. }
  940. }
  941. public int family {
  942. get { return (int)_socket.AddressFamily; }
  943. }
  944. public int type {
  945. get { return (int)_socket.SocketType; }
  946. }
  947. public int proto {
  948. get { return (int)_socket.ProtocolType; }
  949. }
  950. public int ioctl(BigInteger cmd, object option)
  951. {
  952. if(cmd == SIO_KEEPALIVE_VALS){
  953. if (!(option is PythonTuple))
  954. throw PythonOps.TypeError("option must be 3-item sequence, not int");
  955. var tOption = (PythonTuple)option;
  956. if (tOption.Count != 3)
  957. throw PythonOps.TypeError(string.Format("option must be sequence of length 3, not {0}", tOption.Count));
  958. //(onoff, timeout, interval)
  959. if ((!(tOption[0] is int)) && (!(tOption[1] is int)) && (!(tOption[2] is int)))
  960. throw PythonOps.TypeError("option integer required");
  961. int onoff = (int)tOption[0];
  962. int timeout = (int)tOption[1];
  963. int interval = (int)tOption[2];
  964. int size = sizeof(UInt32);
  965. byte[] inArray = new byte[size * 3];
  966. Array.Copy(BitConverter.GetBytes(onoff), 0, inArray, 0, size);
  967. Array.Copy(BitConverter.GetBytes(timeout), 0, inArray, size, size);
  968. Array.Copy(BitConverter.GetBytes(size), 0, inArray, size*2, size);
  969. return _socket.IOControl((IOControlCode)(long)cmd, inArray, null);
  970. }
  971. else if(cmd == SIO_RCVALL){
  972. if (!(option is int))
  973. throw PythonOps.TypeError("option integer required");
  974. return _socket.IOControl((IOControlCode)(long)cmd, BitConverter.GetBytes((int)option), null);
  975. }
  976. else
  977. throw PythonOps.ValueError(string.Format("invalid ioctl command {0}", cmd));
  978. }
  979. public override string ToString() {
  980. try {
  981. return String.Format("<socket object, fd={0}, family={1}, type={2}, protocol={3}>",
  982. fileno(), family, type, proto);
  983. } catch {
  984. return "<socket object, fd=?, family=?, type=, protocol=>";
  985. }
  986. }
  987. /// <summary>
  988. /// Return the internal System.Net.Sockets.Socket socket object associated with the given
  989. /// handle (as returned by GetHandle()), or null if no corresponding socket exists. This is
  990. /// primarily intended to be used by other modules (such as select) that implement
  991. /// networking primitives. User code should not normally need to call this function.
  992. /// </summary>
  993. internal static Socket HandleToSocket(Int64 handle) {
  994. WeakReference weakref;
  995. lock (_handleToSocket) {
  996. if (_handleToSocket.TryGetValue((IntPtr)handle, out weakref)) {
  997. return (weakref.Target as Socket);
  998. }
  999. }
  1000. return null;
  1001. }
  1002. #endregion
  1003. #region IWeakReferenceable Implementation
  1004. WeakRefTracker IWeakReferenceable.GetWeakRef() {
  1005. return _weakRefTracker;
  1006. }
  1007. bool IWeakReferenceable.SetWeakRef(WeakRefTracker value) {
  1008. _weakRefTracker = value;
  1009. return true;
  1010. }
  1011. void IWeakReferenceable.SetFinalizer(WeakRefTracker value) {
  1012. _weakRefTracker = value;
  1013. }
  1014. #endregion
  1015. #region Private Implementation
  1016. /// <summary>
  1017. /// Create a Python socket object from an existing .NET socket object
  1018. /// (like one returned from Socket.Accept())
  1019. /// </summary>
  1020. private socket(CodeContext/*!*/ context, Socket socket) {
  1021. Initialize(context, socket);
  1022. }
  1023. /// <summary>
  1024. /// Perform initialization common to all constructors
  1025. /// </summary>
  1026. private void Initialize(CodeContext context, Socket socket) {
  1027. _socket = socket;
  1028. _context = context;
  1029. int? defaultTimeout = GetDefaultTimeout(context);
  1030. if (defaultTimeout == null) {
  1031. settimeout(null);
  1032. } else {
  1033. settimeout((double)defaultTimeout / MillisecondsPerSecond);
  1034. }
  1035. lock (_handleToSocket) {
  1036. _handleToSocket[socket.GetHandle()] = new WeakReference(socket);
  1037. }
  1038. }
  1039. #endregion
  1040. }
  1041. #endregion
  1042. #region Fields
  1043. private const string AnyAddrToken = "";
  1044. private const string BroadcastAddrToken = "<broadcast>";
  1045. private const string LocalhostAddrToken = "";
  1046. private const int IPv4AddrBytes = 4;
  1047. private const int IPv6AddrBytes = 16;
  1048. private const double MillisecondsPerSecond = 1000.0;
  1049. #endregion
  1050. #region Public API
  1051. public static object _GLOBAL_DEFAULT_TIMEOUT = new object();
  1052. [Documentation("Connect to *address* and return the socket object.\n\n"
  1053. + "Convenience function. Connect to *address* (a 2-tuple ``(host,\n"
  1054. + "port)``) and return the socket object. Passing the optional\n"
  1055. + "*timeout* parameter will set the timeout on the socket instance\n"
  1056. + "before attempting to connect. If no *timeout* is supplied, the\n"
  1057. + "global default timeout setting returned by :func:`getdefaulttimeout`\n"
  1058. + "is used.\n"
  1059. )]
  1060. public static socket create_connection(CodeContext/*!*/ context, PythonTuple address) {
  1061. return create_connection(context, address, _GLOBAL_DEFAULT_TIMEOUT);
  1062. }
  1063. [Documentation("Connect to *address* and return the socket object.\n\n"
  1064. + "Convenience function. Connect to *address* (a 2-tuple ``(host,\n"
  1065. + "port)``) and return the socket object. Passing the optional\n"
  1066. + "*timeout* parameter will set the timeout on the socket instance\n"
  1067. + "before attempting to connect. If no *timeout* is supplied, the\n"
  1068. + "global default timeout setting returned by :func:`getdefaulttimeout`\n"
  1069. + "is used.\n"
  1070. )]
  1071. public static socket create_connection(CodeContext/*!*/ context, PythonTuple address, object timeout) {
  1072. return create_connection(context, address, timeout, null);
  1073. }
  1074. public static socket create_connection(CodeContext/*!*/ context, PythonTuple address, object timeout, PythonTuple source_address) {
  1075. string host = Converter.ConvertToString(address[0]);
  1076. object port = address[1];
  1077. Exception lastException = null;
  1078. var addrInfos = getaddrinfo(context, host, port, 0, SOCK_STREAM, (int)ProtocolType.IP, (int)SocketFlags.None);
  1079. if (addrInfos.Count == 0) {
  1080. throw PythonExceptions.CreateThrowableForRaise(context, error(context), "getaddrinfo returns an empty list");
  1081. }
  1082. foreach (PythonTuple current in addrInfos) {
  1083. int family = Converter.ConvertToInt32(current[0]);
  1084. int socktype = Converter.ConvertToInt32(current[1]);
  1085. int proto = Converter.ConvertToInt32(current[2]);
  1086. // TODO: name is unused?
  1087. // string name = Converter.ConvertToString(current[3]);
  1088. PythonTuple sockaddress = (PythonTuple)current[4];
  1089. socket socket = null;
  1090. try {
  1091. socket = new socket();
  1092. socket.__init__(context, family, socktype, proto, null);
  1093. if (timeout != _GLOBAL_DEFAULT_TIMEOUT) {
  1094. socket.settimeout(timeout);
  1095. }
  1096. if (source_address != null) {
  1097. socket.bind(source_address);
  1098. }
  1099. socket.connect(sockaddress);
  1100. return socket;
  1101. } catch (Exception ex) {
  1102. lastException = ex;
  1103. if (socket != null) {
  1104. socket.close();
  1105. }
  1106. }
  1107. }
  1108. throw lastException;
  1109. }
  1110. [Documentation("")]
  1111. public static List getaddrinfo(
  1112. CodeContext/*!*/ context,
  1113. string host,
  1114. object port,
  1115. [DefaultParameterValue((int)AddressFamily.Unspecified)] int family,
  1116. [DefaultParameterValue(0)] int socktype,
  1117. [DefaultParameterValue((int)ProtocolType.IP)] int proto,
  1118. [DefaultParameterValue((int)SocketFlags.None)] int flags
  1119. ) {
  1120. int numericPort;
  1121. if (port == null) {
  1122. numericPort = 0;
  1123. } else if (port is int) {
  1124. numericPort = (int)port;
  1125. } else if (port is Extensible<int>) {
  1126. numericPort = ((Extensible<int>)port).Value;
  1127. } else if (port is string) {
  1128. if (!Int32.TryParse((string)port, out numericPort)) {
  1129. try{
  1130. port = getservbyname(context,(string)port,null);
  1131. }
  1132. catch{
  1133. throw PythonExceptions.CreateThrowable(gaierror(context), "getaddrinfo failed");
  1134. }
  1135. }
  1136. } else if (port is ExtensibleString) {
  1137. if (!Int32.TryParse(((ExtensibleString)port).Value, out numericPort)) {
  1138. try{
  1139. port = getservbyname(context, (string)port, null);
  1140. }
  1141. catch{
  1142. throw PythonExceptions.CreateThrowable(gaierror(context), "getaddrinfo failed");
  1143. }
  1144. }
  1145. } else {
  1146. throw PythonExceptions.CreateThrowable(gaierror(context), "getaddrinfo failed");
  1147. }
  1148. if (socktype != 0) {
  1149. // we just use this to validate; socketType isn't actually used
  1150. System.Net.Sockets.SocketType socketType = (System.Net.Sockets.SocketType)Enum.ToObject(typeof(System.Net.Sockets.SocketType), socktype);
  1151. if (socketType == System.Net.Sockets.SocketType.Unknown || !Enum.IsDefined(typeof(System.Net.Sockets.SocketType), socketType)) {
  1152. throw PythonExceptions.CreateThrowable(gaierror(context), PythonTuple.MakeTuple((int)SocketError.SocketNotSupported, "getaddrinfo failed"));
  1153. }
  1154. }
  1155. AddressFamily addressFamily = (AddressFamily)Enum.ToObject(typeof(AddressFamily), family);
  1156. if (!Enum.IsDefined(typeof(AddressFamily), addressFamily)) {
  1157. throw PythonExceptions.CreateThrowable(gaierror(context), PythonTuple.MakeTuple((int)SocketError.AddressFamilyNotSupported, "getaddrinfo failed"));
  1158. }
  1159. // Again, we just validate, but don't actually use protocolType
  1160. Enum.ToObject(typeof(ProtocolType), proto);
  1161. if (host == null)
  1162. host = "localhost";
  1163. IPAddress[] ips = HostToAddresses(context, host, addressFamily);
  1164. List results = new List();
  1165. foreach (IPAddress ip in ips) {
  1166. results.append(PythonTuple.MakeTuple(
  1167. (int)ip.AddressFamily,
  1168. socktype,
  1169. proto,
  1170. "",
  1171. EndPointToTuple(new IPEndPoint(ip, numericPort))
  1172. ));
  1173. }
  1174. return results;
  1175. }
  1176. private static PythonType gaierror(CodeContext/*!*/ context) {
  1177. return (PythonType)PythonContext.GetContext(context).GetModuleState("socketgaierror");
  1178. }
  1179. private static IPHostEntry GetHostEntry(string host) {
  1180. #if NETSTANDARD
  1181. try {
  1182. return Dns.GetHostEntryAsync(host).Result;
  1183. }
  1184. catch (AggregateException ae) {
  1185. System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(ae.InnerException).Throw();
  1186. throw;
  1187. }
  1188. #else
  1189. return Dns.GetHostEntry(host);
  1190. #endif
  1191. }
  1192. private static IPAddress[] GetHostAddresses(string host)
  1193. {
  1194. #if NETSTANDARD
  1195. try {
  1196. return Dns.GetHostAddressesAsync(host).Result;
  1197. }
  1198. catch (AggregateException ae)
  1199. {
  1200. System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(ae.InnerException).Throw();
  1201. throw;
  1202. }
  1203. #else
  1204. return Dns.GetHostAddresses(host);
  1205. #endif
  1206. }
  1207. [Documentation("getfqdn([hostname_or_ip]) -> hostname\n\n"
  1208. + "Return the fully-qualified domain name for the specified hostname or IP\n"
  1209. + "address. An unspecified or empty name is interpreted as the local host. If the\n"
  1210. + "name lookup fails, the passed-in name is returned as-is."
  1211. )]
  1212. public static string getfqdn(string host) {
  1213. if (host == null) {
  1214. throw PythonOps.TypeError("expected string, got None");
  1215. }
  1216. host = host.Trim();
  1217. if (host == string.Empty || host == "0.0.0.0") {
  1218. host = gethostname();
  1219. }
  1220. if (host == BroadcastAddrToken) {
  1221. return host;
  1222. }
  1223. try {
  1224. IPHostEntry hostEntry = GetHostEntry(host);
  1225. if (hostEntry.HostName.Contains(".")) {
  1226. return hostEntry.HostName;
  1227. } else {
  1228. foreach (string addr in hostEntry.Aliases) {
  1229. if (addr.Contains(".")) {
  1230. return addr;
  1231. }
  1232. }
  1233. }
  1234. } catch (SocketException) {
  1235. // ignore and return host below
  1236. }
  1237. // seems to match CPython behavior, although docs say gethostname() should be returned
  1238. return host;
  1239. }
  1240. [Documentation("")]
  1241. public static string getfqdn() {
  1242. return getfqdn(LocalhostAddrToken);
  1243. }
  1244. [Documentation("gethostbyname(hostname) -> ip address\n\n"
  1245. + "Return the string IPv4 address associated with the given hostname (e.g.\n"
  1246. + "'10.10.0.1'). The hostname is returned as-is if it an IPv4 address. The empty\n"
  1247. + "string is treated as the local host.\n"
  1248. + "\n"
  1249. + "gethostbyname() doesn't support IPv6; for IPv4/IPv6 support, use getaddrinfo()."
  1250. )]
  1251. public static string gethostbyname(CodeContext/*!*/ context, string host) {
  1252. return HostToAddress(context, host, AddressFamily.InterNetwork).ToString();
  1253. }
  1254. [Documentation("gethostbyname_ex(hostname) -> (hostname, aliases, ip_addresses)\n\n"
  1255. + "Return the real host name, a list of aliases, and a list of IP addresses\n"
  1256. + "associated with the given hostname. If the hostname is an IPv4 address, the\n"
  1257. + "tuple ([hostname, [], [hostname]) is returned without doing a DNS lookup.\n"
  1258. + "\n"
  1259. + "gethostbyname_ex() doesn't support IPv6; for IPv4/IPv6 support, use\n"
  1260. + "getaddrinfo()."
  1261. )]
  1262. public static PythonTuple gethostbyname_ex(CodeContext/*!*/ context, string host) {
  1263. string hostname;
  1264. List aliases;
  1265. List ips = PythonOps.MakeList();
  1266. IPAddress addr;
  1267. if (IPAddress.TryParse(host, out addr)) {
  1268. if (AddressFamily.InterNetwork == addr.AddressFamily) {
  1269. hostname = host;
  1270. aliases = PythonOps.MakeEmptyList(0);
  1271. ips.append(host);
  1272. } else {
  1273. throw PythonExceptions.CreateThrowable(gaierror(context), (int)SocketError.HostNotFound, "no IPv4 addresses associated with host");
  1274. }
  1275. } else {
  1276. IPHostEntry hostEntry;
  1277. try {
  1278. hostEntry = GetHostEntry(host);
  1279. } catch (SocketException e) {
  1280. throw PythonExceptions.CreateThrowable(gaierror(context), (int)e.SocketErrorCode, "no IPv4 addresses associated with host");
  1281. }
  1282. hostname = hostEntry.HostName;
  1283. aliases = PythonOps.MakeList(hostEntry.Aliases);
  1284. foreach (IPAddress ip in hostEntry.AddressList) {
  1285. if (AddressFamily.InterNetwork == ip.AddressFamily) {
  1286. ips.append(ip.ToString());
  1287. }
  1288. }
  1289. }
  1290. return PythonTuple.MakeTuple(hostname, aliases, ips);
  1291. }
  1292. [Documentation("gethostname() -> hostname\nReturn this machine's hostname")]
  1293. public static string gethostname() {
  1294. return Dns.GetHostName();
  1295. }
  1296. [Documentation("gethostbyaddr(host) -> (hostname, aliases, ipaddrs)\n\n"
  1297. + "Return a tuple of (primary hostname, alias hostnames, ip addresses). host may\n"
  1298. + "be either a hostname or an IP address."
  1299. )]
  1300. public static object gethostbyaddr(CodeContext/*!*/ context, string host) {
  1301. if (host == "") {
  1302. host = gethostname();
  1303. }
  1304. // This conversion seems to match CPython behavior
  1305. host = gethostbyname(context, host);
  1306. IPAddress[] ips = null;
  1307. IPHostEntry hostEntry = null;
  1308. try {
  1309. ips = GetHostAddresses(host);
  1310. hostEntry = GetHostEntry(host);
  1311. }
  1312. catch (Exception e) {
  1313. throw MakeException(context, e);
  1314. }
  1315. List ipStrings = PythonOps.MakeList();
  1316. foreach (IPAddress ip in ips) {
  1317. ipStrings.append(ip.ToString());
  1318. }
  1319. return PythonTuple.MakeTuple(hostEntry.HostName, PythonOps.MakeList(hostEntry.Aliases), ipStrings);
  1320. }
  1321. [Documentation("getnameinfo(socketaddr, flags) -> (host, port)\n"
  1322. + "Given a socket address, the return a tuple of the corresponding hostname and\n"
  1323. + "port. Available flags:\n"
  1324. + " - NI_NOFQDN: Return only the hostname part of the domain name for hosts on the\n"
  1325. + " same domain as the executing machine.\n"
  1326. + " - NI_NUMERICHOST: return the numeric form of the host (e.g. '127.0.0.1' or\n"
  1327. + " '::1' rather than 'localhost').\n"
  1328. + " - NI_NAMEREQD: Raise an error if the hostname cannot be looked up.\n"
  1329. + " - NI_NUMERICSERV: Return string containing the numeric form of the port (e.g.\n"
  1330. + " '80' rather than 'http'). This flag is required (see below).\n"
  1331. + " - NI_DGRAM: Silently ignored (see below).\n"
  1332. + "\n"
  1333. )]
  1334. public static object getnameinfo(CodeContext/*!*/ context, PythonTuple socketAddr, int flags) {
  1335. if (socketAddr.__len__() < 2 || socketAddr.__len__() > 4) {
  1336. throw PythonOps.TypeError("socket address must be a 2-tuple (IPv4 or IPv6) or 4-tuple (IPv6)");
  1337. }
  1338. string host = Converter.ConvertToString(socketAddr[0]);
  1339. if (host == null) throw PythonOps.TypeError("argument 1 must be string");
  1340. int port = 0;
  1341. try {
  1342. port = (int)socketAddr[1];
  1343. } catch (InvalidCastException) {
  1344. throw PythonOps.TypeError("an integer is required");
  1345. }
  1346. string resultHost = null;
  1347. string resultPort = null;
  1348. // Host
  1349. IList<IPAddress> addrs = null;
  1350. try {
  1351. addrs = HostToAddresses(context, host, AddressFamily.InterNetwork);
  1352. if (addrs.Count < 1) {
  1353. throw PythonExceptions.CreateThrowable(error(context), "sockaddr resolved to zero addresses");
  1354. }
  1355. } catch (SocketException e) {
  1356. throw PythonExceptions.CreateThrowable(gaierror(context), (int)e.SocketErrorCode, e.Message);
  1357. } catch (IndexOutOfRangeException) {
  1358. throw PythonExceptions.CreateThrowable(gaierror(context), "sockaddr resolved to zero addresses");
  1359. }
  1360. if (addrs.Count > 1) {
  1361. // ignore non-IPV4 addresses
  1362. List<IPAddress> newAddrs = new List<IPAddress>(addrs.Count);
  1363. foreach (IPAddress addr in addrs) {
  1364. if (addr.AddressFamily == AddressFamily.InterNetwork) {
  1365. newAddrs.Add(addr);
  1366. }
  1367. }
  1368. if (newAddrs.Count > 1) {
  1369. throw PythonExceptions.CreateThrowable(error(context), "sockaddr resolved to multiple addresses");
  1370. }
  1371. addrs = newAddrs;
  1372. }
  1373. if (addrs.Count < 1) {
  1374. throw PythonExceptions.CreateThrowable(error(context), "sockaddr resolved to zero addresses");
  1375. }
  1376. IPHostEntry hostEntry = null;
  1377. try {
  1378. #if NETSTANDARD
  1379. hostEntry = Dns.GetHostEntryAsync(addrs[0]).Result;
  1380. #else
  1381. hostEntry = Dns.GetHostEntry(addrs[0]);
  1382. #endif
  1383. } catch (SocketException e) {
  1384. throw PythonExceptions.CreateThrowable(gaierror(context), (int)e.SocketErrorCode, e.Message);
  1385. }
  1386. if ((flags & (int)NI_NUMERICHOST) != 0) {
  1387. resultHost = addrs[0].ToString();
  1388. } else if ((flags & (int)NI_NOFQDN) != 0) {
  1389. resultHost = RemoveLocalDomain(hostEntry.HostName);
  1390. } else {
  1391. resultHost = hostEntry.HostName;
  1392. }
  1393. // Port
  1394. if ((flags & (int)NI_NUMERICSERV) == 0) {
  1395. //call the servbyport to translate port if not just use the port.ToString as the result
  1396. try{
  1397. resultPort = getservbyport(context, port,null);
  1398. }
  1399. catch{
  1400. resultPort = port.ToString();
  1401. }
  1402. flags = flags | (int)NI_NUMERICSERV;
  1403. }
  1404. else
  1405. resultPort = port.ToString();
  1406. return PythonTuple.MakeTuple(resultHost, resultPort);
  1407. }
  1408. [Documentation("getprotobyname(protoname) -> integer proto\n\n"
  1409. + "Given a string protocol name (e.g. \"udp\"), return the associated integer\n"
  1410. + "protocol number, suitable for passing to socket(). The name is case\n"
  1411. + "insensitive.\n"
  1412. + "\n"
  1413. + "Raises socket.error if no protocol number can be found."
  1414. )]
  1415. public static object getprotobyname(CodeContext/*!*/ context, string protocolName) {
  1416. switch (protocolName.ToLower()) {
  1417. case "ah": return IPPROTO_AH;
  1418. case "esp": return IPPROTO_ESP;
  1419. case "dstopts": return IPPROTO_DSTOPTS;
  1420. case "fragment": return IPPROTO_FRAGMENT;
  1421. case "ggp": return IPPROTO_GGP;
  1422. case "icmp": return IPPROTO_ICMP;
  1423. case "icmpv6": return IPPROTO_ICMPV6;
  1424. case "ip": return IPPROTO_IP;
  1425. case "ipv4": return IPPROTO_IPV4;
  1426. case "ipv6": return IPPROTO_IPV6;
  1427. case "nd": return IPPROTO_ND;
  1428. case "none": return IPPROTO_NONE;
  1429. case "pup": return IPPROTO_PUP;
  1430. case "raw": return IPPROTO_RAW;
  1431. case "routing": return IPPROTO_ROUTING;
  1432. case "tcp": return IPPROTO_TCP;
  1433. case "udp": return IPPROTO_UDP;
  1434. default:
  1435. throw PythonExceptions.CreateThrowable(error(context), "protocol not found");
  1436. }
  1437. }
  1438. [Documentation("getservbyname(service_name[, protocol_name]) -> port\n\n"
  1439. + "Return a port number from a service name and protocol name.\n"
  1440. + "The optional protocol name, if given, should be 'tcp' or 'udp',\n"
  1441. + "otherwise any protocol will match."
  1442. )]
  1443. public static int getservbyname(CodeContext/*!*/ context, string serviceName, [DefaultParameterValue(null)] string protocolName)
  1444. {
  1445. if(protocolName != null){
  1446. protocolName = protocolName.ToLower();
  1447. if(protocolName != "udp" && protocolName != "tcp")
  1448. throw PythonExceptions.CreateThrowable(error(context), "service/proto not found");
  1449. }
  1450. // try the pinvoke call if it fails fall back to hard coded swtich statement
  1451. try {
  1452. return SocketUtil.GetServiceByName(serviceName, protocolName);
  1453. }
  1454. catch{}
  1455. switch (serviceName.ToLower()){
  1456. case "echo": return 7;
  1457. case "daytime": return 13;
  1458. case "ftp-data": return 20;
  1459. case "ftp": if (protocolName == null || protocolName == "tcp") return 21; else goto default;
  1460. case "ssh": return 22;
  1461. case "telnet": return 23;
  1462. case "smtp": if (protocolName == null || protocolName == "tcp") return 25; else goto default;
  1463. case "time": return 37;
  1464. case "rlp": return 39;
  1465. case "nameserver": return 42;
  1466. case "nicname": if (protocolName == null || protocolName == "tcp") return 43; else goto default;
  1467. case "domain": return 53;
  1468. case "bootps": if (protocolName == null || protocolName == "udp") return 67; else goto default;
  1469. case "bootpc": if (protocolName == null || protocolName == "udp") return 68; else goto default;
  1470. case "tftp": if (protocolName == null || protocolName == "udp") return 69; else goto default;
  1471. case "http": if (protocolName == null || protocolName == "tcp") return 80; else goto default;
  1472. case "kerberos": return 88;
  1473. case "rtelnet": if (protocolName == null || protocolName == "tcp") return 107; else goto default;
  1474. case "pop2": if (protocolName == null || protocolName == "tcp") return 109; else goto default;
  1475. case "pop3": if (protocolName == null || protocolName == "tcp") return 110; else goto default;
  1476. case "nntp": if (protocolName == null || protocolName == "tcp") return 119; else goto default;
  1477. case "ntp": if (protocolName == null || protocolName == "udp") return 123; else goto default;
  1478. case "imap": if (protocolName == null || protocolName == "tcp") return 143; else goto default;
  1479. case "snmp": if (protocolName == null || protocolName == "udp") return 161; else goto default;
  1480. case "snmptrap": if (protocolName == null || protocolName == "udp") return 162; else goto default;
  1481. case "ldap": if (protocolName == null || protocolName == "tcp") return 389; else goto default;
  1482. case "https": if (protocolName == null || protocolName == "tcp") return 430; else goto default;
  1483. case "dhcpv6-client": return 546;
  1484. case "dhcpv6-server": return 547;
  1485. case "rtsp": return 554;
  1486. default:
  1487. throw PythonExceptions.CreateThrowable(error(context), "service/proto not found");
  1488. }
  1489. }
  1490. [Documentation("getservbyport(port[, protocol_name]) -> service_name\n\n"
  1491. + "Return a service name from a port number and protocol name.\n"
  1492. + "The optional protocol name, if given, should be 'tcp' or 'udp',\n"
  1493. + "otherwise any protocol will match."
  1494. )]
  1495. public static string getservbyport(CodeContext/*!*/ context, int port, [DefaultParameterValue(null)] string protocolName) {
  1496. if (port < 0 || port > 65535)
  1497. throw PythonOps.OverflowError("getservbyport: port must be 0-65535.");
  1498. if (protocolName != null){
  1499. protocolName = protocolName.ToLower();
  1500. if (protocolName != "udp" && protocolName != "tcp")
  1501. throw PythonExceptions.CreateThrowable(error(context), "port/proto not found");
  1502. }
  1503. // try the pinvoke call if it fails fall back to hard coded swtich statement
  1504. try{
  1505. return SocketUtil.GetServiceByPort((ushort)port, protocolName);
  1506. }
  1507. catch{ }
  1508. switch (port)
  1509. {
  1510. case 7: return "echo";
  1511. case 13: return "daytime";
  1512. case 20: return "ftp-data";
  1513. case 21: if (protocolName == null || protocolName == "tcp") return "ftp"; else goto default;
  1514. case 22: return "ssh";
  1515. case 23: return "telnet";
  1516. case 25: if (protocolName == null || protocolName == "tcp") return "smtp"; else goto default;
  1517. case 37: return "time";
  1518. case 39: return "rlp";
  1519. case 42: return "nameserver";
  1520. case 43: if (protocolName == null || protocolName == "tcp") return "nicname"; else goto default;
  1521. case 53: return "domain";
  1522. case 67: if (protocolName == null || protocolName == "udp") return "bootps"; else goto default;
  1523. case 68: if (protocolName == null || protocolName == "udp") return "bootpc"; else goto default;
  1524. case 69: if (protocolName == null || protocolName == "udp") return "tftp"; else goto default;
  1525. case 80: if (protocolName == null || protocolName == "tcp") return "http"; else goto default;
  1526. case 88: return "kerberos";
  1527. case 107: if (protocolName == null || protocolName == "tcp") return "rtelnet"; else goto default;
  1528. case 109: if (protocolName == null || protocolName == "tcp") return "pop2"; else goto default;
  1529. case 110: if (protocolName == null || protocolName == "tcp") return "pop3"; else goto default;
  1530. case 119: if (protocolName == null || protocolName == "tcp") return "nntp"; else goto default;
  1531. case 123: if (protocolName == null || protocolName == "udp") return "ntp"; else goto default;
  1532. case 143: if (protocolName == null || protocolName == "tcp") return "imap"; else goto default;
  1533. case 161: if (protocolName == null || protocolName == "udp") return "snmp"; else goto default;
  1534. case 162: if (protocolName == null || protocolName == "udp") return "snmptrap"; else goto default;
  1535. case 389: if (protocolName == null || protocolName == "tcp") return "ldap"; else goto default;
  1536. case 430: if (protocolName == null || protocolName == "tcp") return "https"; else goto default;
  1537. case 546: return "dhcpv6-client";
  1538. case 547: return "dhcpv6-server";
  1539. case 554: return "rtsp";
  1540. default:
  1541. throw PythonExceptions.CreateThrowable(error(context), "port/proto not found");
  1542. }
  1543. }
  1544. [Documentation("ntohl(x) -> integer\n\nConvert a 32-bit integer from network byte order to host byte order.")]
  1545. public static object ntohl(object x) {
  1546. int res = IPAddress.NetworkToHostOrder(SignInsensitiveToInt32(x));
  1547. if (res < 0) {
  1548. return (BigInteger)(uint)res;
  1549. } else {
  1550. return res;
  1551. }
  1552. }
  1553. [Documentation("ntohs(x) -> integer\n\nConvert a 16-bit integer from network byte order to host byte order.")]
  1554. public static int ntohs(object x) {
  1555. return (int)(ushort)IPAddress.NetworkToHostOrder(SignInsensitiveToInt16(x));
  1556. }
  1557. [Documentation("htonl(x) -> integer\n\nConvert a 32bit integer from host byte order to network byte order.")]
  1558. public static object htonl(object x) {
  1559. int res = IPAddress.HostToNetworkOrder(SignInsensitiveToInt32(x));
  1560. if (res < 0) {
  1561. return (BigInteger)(uint)res;
  1562. } else {
  1563. return res;
  1564. }
  1565. }
  1566. [Documentation("htons(x) -> integer\n\nConvert a 16-bit integer from host byte order to network byte order.")]
  1567. public static int htons(object x) {
  1568. return (int)(ushort)IPAddress.HostToNetworkOrder(SignInsensitiveToInt16(x));
  1569. }
  1570. /// <summary>
  1571. /// Convert an object to a 32-bit integer. This adds two features to Converter.ToInt32:
  1572. /// 1. Sign is ignored. For example, 0xffff0000 converts to 4294901760, where Convert.ToInt32
  1573. /// would throw because 0xffff0000 is less than zero.
  1574. /// 2. Overflow exceptions are thrown. Converter.ToInt32 throws TypeError if x is
  1575. /// an integer, but is bigger than 32 bits. Instead, we throw OverflowException.
  1576. /// </summary>
  1577. private static int SignInsensitiveToInt32(object x) {
  1578. BigInteger bigValue = Converter.ConvertToBigInteger(x);
  1579. if (bigValue < 0) {
  1580. throw PythonOps.OverflowError("can't convert negative number to unsigned long");
  1581. } else if (bigValue <= int.MaxValue) {
  1582. return (int)bigValue;
  1583. } else {
  1584. return (int)(uint)bigValue;
  1585. }
  1586. }
  1587. /// <summary>
  1588. /// Convert an object to a 16-bit integer. This adds two features to Converter.ToInt16:
  1589. /// 1. Sign is ignored. For example, 0xff00 converts to 65280, where Convert.ToInt16
  1590. /// would throw because signed 0xff00 is -256.
  1591. /// 2. Overflow exceptions are thrown. Converter.ToInt16 throws TypeError if x is
  1592. /// an integer, but is bigger than 16 bits. Instead, we throw OverflowException.
  1593. /// </summary>
  1594. private static short SignInsensitiveToInt16(object x) {
  1595. BigInteger bigValue = Converter.ConvertToBigInteger(x);
  1596. if (bigValue < 0) {
  1597. throw PythonOps.OverflowError("can't convert negative number to unsigned long");
  1598. } else if (bigValue <= short.MaxValue) {
  1599. return (short)bigValue;
  1600. } else {
  1601. return (short)(ushort)bigValue;
  1602. }
  1603. }
  1604. [Documentation("inet_pton(addr_family, ip_string) -> packed_ip\n\n"
  1605. + "Convert an IP address (in string format, e.g. '127.0.0.1' or '::1') to a 32-bit\n"
  1606. + "packed binary format, as 4-byte (IPv4) or 16-byte (IPv6) string. The return\n"
  1607. + "format matches the format of the standard C library's in_addr or in6_addr\n"
  1608. + "struct.\n"
  1609. + "\n"
  1610. + "If the address format is invalid, socket.error will be raised. Validity is\n"
  1611. + "determined by the .NET System.Net.IPAddress.Parse() method.\n"
  1612. + "\n"
  1613. + "inet_pton() supports IPv4 and IPv6."
  1614. )]
  1615. public static string inet_pton(CodeContext/*!*/ context, int addressFamily, string ipString) {
  1616. if (addressFamily != (int)AddressFamily.InterNetwork && addressFamily != (int)AddressFamily.InterNetworkV6) {
  1617. throw MakeException(context, new SocketException((int)SocketError.AddressFamilyNotSupported));
  1618. }
  1619. IPAddress ip;
  1620. try {
  1621. ip = IPAddress.Parse(ipString);
  1622. if (addressFamily != (int)ip.AddressFamily) {
  1623. throw MakeException(context, new SocketException((int)SocketError.AddressFamilyNotSupported));
  1624. }
  1625. } catch (FormatException) {
  1626. throw PythonExceptions.CreateThrowable(error(context), "illegal IP address passed to inet_pton");
  1627. }
  1628. return ip.GetAddressBytes().MakeString();
  1629. }
  1630. [Documentation("inet_ntop(address_family, packed_ip) -> ip_string\n\n"
  1631. + "Convert a packed IP address (a 4-byte [IPv4] or 16-byte [IPv6] string) to a\n"
  1632. + "string IP address (e.g. '127.0.0.1' or '::1').\n"
  1633. + "\n"
  1634. + "The input format matches the format of the standard C library's in_addr or\n"
  1635. + "in6_addr struct. If the input string is not exactly 4 bytes or 16 bytes,\n"
  1636. + "socket.error will be raised.\n"
  1637. + "\n"
  1638. + "inet_ntop() supports IPv4 and IPv6."
  1639. )]
  1640. public static string inet_ntop(CodeContext/*!*/ context, int addressFamily, string packedIP) {
  1641. if (!(
  1642. (packedIP.Length == IPv4AddrBytes && addressFamily == (int)AddressFamily.InterNetwork)
  1643. || (packedIP.Length == IPv6AddrBytes && addressFamily == (int)AddressFamily.InterNetworkV6)
  1644. )) {
  1645. throw PythonExceptions.CreateThrowable(error(context), "invalid length of packed IP address string");
  1646. }
  1647. byte[] ipBytes = packedIP.MakeByteArray();
  1648. if (addressFamily == (int)AddressFamily.InterNetworkV6) {
  1649. return IPv6BytesToColonHex(ipBytes);
  1650. }
  1651. return (new IPAddress(ipBytes)).ToString();
  1652. }
  1653. [Documentation("inet_aton(ip_string) -> packed_ip\n"
  1654. + "Convert an IP address (in string dotted quad format, e.g. '127.0.0.1') to a\n"
  1655. + "32-bit packed binary format, as four-character string. The return format\n"
  1656. + "matches the format of the standard C library's in_addr struct.\n"
  1657. + "\n"
  1658. + "If the address format is invalid, socket.error will be raised. Validity is\n"
  1659. + "determined by the .NET System.Net.IPAddress.Parse() method.\n"
  1660. + "\n"
  1661. + "inet_aton() supports only IPv4."
  1662. )]
  1663. public static string inet_aton(CodeContext/*!*/ context, string ipString) {
  1664. return inet_pton(context, (int)AddressFamily.InterNetwork, ipString);
  1665. }
  1666. [Documentation("inet_ntoa(packed_ip) -> ip_string\n\n"
  1667. + "Convert a packed IP address (a 4-byte string) to a string IP address (in dotted\n"
  1668. + "quad format, e.g. '127.0.0.1'). The input format matches the format of the\n"
  1669. + "standard C library's in_addr struct.\n"
  1670. + "\n"
  1671. + "If the input string is not exactly 4 bytes, socket.error will be raised.\n"
  1672. + "\n"
  1673. + "inet_ntoa() supports only IPv4."
  1674. )]
  1675. public static string inet_ntoa(CodeContext/*!*/ context, string packedIP) {
  1676. return inet_ntop(context, (int)AddressFamily.InterNetwork, packedIP);
  1677. }
  1678. [Documentation("getdefaulttimeout() -> timeout\n\n"
  1679. + "Return the default timeout for new socket objects in seconds as a float. A\n"
  1680. + "value of None means that sockets have no timeout and begin in blocking mode.\n"
  1681. + "The default value when the module is imported is None."
  1682. )]
  1683. public static object getdefaulttimeout(CodeContext/*!*/ context) {
  1684. int? defaultTimeout = GetDefaultTimeout(context);
  1685. if (defaultTimeout == null) {
  1686. return null;
  1687. } else {
  1688. return (double)(defaultTimeout.Value) / MillisecondsPerSecond;
  1689. }
  1690. }
  1691. [Documentation("setdefaulttimeout(timeout) -> None\n\n"
  1692. + "Set the default timeout for new socket objects. timeout must be either None,\n"
  1693. + "meaning that sockets have no timeout and start in blocking mode, or a\n"
  1694. + "non-negative float that specifies the default timeout in seconds."
  1695. )]
  1696. public static void setdefaulttimeout(CodeContext/*!*/ context, object timeout) {
  1697. if (timeout == null) {
  1698. SetDefaultTimeout(context, null);
  1699. } else {
  1700. double seconds;
  1701. seconds = Converter.ConvertToDouble(timeout);
  1702. if (seconds < 0) {
  1703. throw PythonOps.ValueError("a non-negative float is required");
  1704. }
  1705. SetDefaultTimeout(context, (int)(seconds * MillisecondsPerSecond));
  1706. }
  1707. }
  1708. #endregion
  1709. #region Exported constants
  1710. public const int AF_APPLETALK = (int)AddressFamily.AppleTalk;
  1711. public const int AF_DECnet = (int)AddressFamily.DecNet;
  1712. public const int AF_INET = (int)AddressFamily.InterNetwork;
  1713. public const int AF_INET6 = (int)AddressFamily.InterNetworkV6;
  1714. public const int AF_IPX = (int)AddressFamily.Ipx;
  1715. public const int AF_IRDA = (int)AddressFamily.Irda;
  1716. public const int AF_SNA = (int)AddressFamily.Sna;
  1717. public const int AF_UNSPEC = (int)AddressFamily.Unspecified;
  1718. public const int AI_CANONNAME = (int)0x2;
  1719. public const int AI_NUMERICHOST = (int)0x4;
  1720. public const int AI_PASSIVE = (int)0x1;
  1721. public const int EAI_AGAIN = (int)SocketError.TryAgain;
  1722. public const int EAI_BADFLAGS = (int)SocketError.InvalidArgument;
  1723. public const int EAI_FAIL = (int)SocketError.NoRecovery;
  1724. public const int EAI_FAMILY = (int)SocketError.AddressFamilyNotSupported;
  1725. public const int EAI_MEMORY = (int)SocketError.NoBufferSpaceAvailable;
  1726. public const int EAI_NODATA = (int)SocketError.HostNotFound; // not SocketError.NoData, like you would think
  1727. public const int EAI_NONAME = (int)SocketError.HostNotFound;
  1728. public const int EAI_SERVICE = (int)SocketError.TypeNotFound;
  1729. public const int EAI_SOCKTYPE = (int)SocketError.SocketNotSupported;
  1730. public const int EAI_SYSTEM = (int)SocketError.SocketError;
  1731. public const int EBADF = (int)0x9;
  1732. public const int INADDR_ALLHOSTS_GROUP = unchecked((int)0xe0000001);
  1733. public const int INADDR_ANY = (int)0x00000000;
  1734. public const int INADDR_BROADCAST = unchecked((int)0xFFFFFFFF);
  1735. public const int INADDR_LOOPBACK = unchecked((int)0x7F000001);
  1736. public const int INADDR_MAX_LOCAL_GROUP = unchecked((int)0xe00000FF);
  1737. public const int INADDR_NONE = unchecked((int)0xFFFFFFFF);
  1738. public const int INADDR_UNSPEC_GROUP = unchecked((int)0xE0000000);
  1739. public const int IPPORT_RESERVED = 1024;
  1740. public const int IPPORT_USERRESERVED = 5000;
  1741. public const int IPPROTO_AH = (int)ProtocolType.IPSecAuthenticationHeader;
  1742. public const int IPPROTO_DSTOPTS = (int)ProtocolType.IPv6DestinationOptions;
  1743. public const int IPPROTO_ESP = (int)ProtocolType.IPSecEncapsulatingSecurityPayload;
  1744. public const int IPPROTO_FRAGMENT = (int)ProtocolType.IPv6FragmentHeader;
  1745. public const int IPPROTO_GGP = (int)ProtocolType.Ggp;
  1746. public const int IPPROTO_HOPOPTS = (int)ProtocolType.IPv6HopByHopOptions;
  1747. public const int IPPROTO_ICMP = (int)ProtocolType.Icmp;
  1748. public const int IPPROTO_ICMPV6 = (int)ProtocolType.IcmpV6;
  1749. public const int IPPROTO_IDP = (int)ProtocolType.Idp;
  1750. public const int IPPROTO_IGMP = (int)ProtocolType.Igmp;
  1751. public const int IPPROTO_IP = (int)ProtocolType.IP;
  1752. public const int IPPROTO_IPV4 = (int)ProtocolType.IPv4;
  1753. public const int IPPROTO_IPV6 = (int)ProtocolType.IPv6;
  1754. public const int IPPROTO_MAX = 256;
  1755. public const int IPPROTO_ND = (int)ProtocolType.ND;
  1756. public const int IPPROTO_NONE = (int)ProtocolType.IPv6NoNextHeader;
  1757. public const int IPPROTO_PUP = (int)ProtocolType.Pup;
  1758. public const int IPPROTO_RAW = (int)ProtocolType.Raw;
  1759. public const int IPPROTO_ROUTING = (int)ProtocolType.IPv6RoutingHeader;
  1760. public const int IPPROTO_TCP = (int)ProtocolType.Tcp;
  1761. public const int IPPROTO_UDP = (int)ProtocolType.Udp;
  1762. public const int IPV6_HOPLIMIT = (int)SocketOptionName.HopLimit;
  1763. public const int IPV6_JOIN_GROUP = (int)SocketOptionName.AddMembership;
  1764. public const int IPV6_LEAVE_GROUP = (int)SocketOptionName.DropMembership;
  1765. public const int IPV6_MULTICAST_HOPS = (int)SocketOptionName.MulticastTimeToLive;
  1766. public const int IPV6_MULTICAST_IF = (int)SocketOptionName.MulticastInterface;
  1767. public const int IPV6_MULTICAST_LOOP = (int)SocketOptionName.MulticastLoopback;
  1768. public const int IPV6_PKTINFO = (int)SocketOptionName.PacketInformation;
  1769. public const int IPV6_UNICAST_HOPS = (int)SocketOptionName.IpTimeToLive;
  1770. #if FEATURE_IPV6 && __MonoCS__
  1771. //TODO: Is this filed in a Mono bug report?
  1772. public const int IPV6_V6ONLY = 27;
  1773. #elif FEATURE_IPV6
  1774. public const int IPV6_V6ONLY = (int) SocketOptionName.IPv6Only;
  1775. #endif
  1776. public const int IP_ADD_MEMBERSHIP = (int)SocketOptionName.AddMembership;
  1777. public const int IP_DROP_MEMBERSHIP = (int)SocketOptionName.DropMembership;
  1778. public const int IP_HDRINCL = (int)SocketOptionName.HeaderIncluded;
  1779. public const int IP_MULTICAST_IF = (int)SocketOptionName.MulticastInterface;
  1780. public const int IP_MULTICAST_LOOP = (int)SocketOptionName.MulticastLoopback;
  1781. public const int IP_MULTICAST_TTL = (int)SocketOptionName.MulticastTimeToLive;
  1782. public const int IP_OPTIONS = (int)SocketOptionName.IPOptions;
  1783. public const int IP_TOS = (int)SocketOptionName.TypeOfService;
  1784. public const int IP_TTL = (int)SocketOptionName.IpTimeToLive;
  1785. public const int MSG_DONTROUTE = (int)SocketFlags.DontRoute;
  1786. public const int MSG_OOB = (int)SocketFlags.OutOfBand;
  1787. public const int MSG_PEEK = (int)SocketFlags.Peek;
  1788. public const int NI_DGRAM = 0x0010;
  1789. public const int NI_MAXHOST = 1025;
  1790. public const int NI_MAXSERV = 32;
  1791. public const int NI_NAMEREQD = 0x0004;
  1792. public const int NI_NOFQDN = 0x0001;
  1793. public const int NI_NUMERICHOST = 0x0002;
  1794. public const int NI_NUMERICSERV = 0x0008;
  1795. public const int SHUT_RD = (int)SocketShutdown.Receive;
  1796. public const int SHUT_RDWR = (int)SocketShutdown.Both;
  1797. public const int SHUT_WR = (int)SocketShutdown.Send;
  1798. public const int SOCK_DGRAM = (int)System.Net.Sockets.SocketType.Dgram;
  1799. public const int SOCK_RAW = (int)System.Net.Sockets.SocketType.Raw;
  1800. public const int SOCK_RDM = (int)System.Net.Sockets.SocketType.Rdm;
  1801. public const int SOCK_SEQPACKET = (int)System.Net.Sockets.SocketType.Seqpacket;
  1802. public const int SOCK_STREAM = (int)System.Net.Sockets.SocketType.Stream;
  1803. public const int SOL_IP = (int)SocketOptionLevel.IP;
  1804. public const int SOL_IPV6 = (int)SocketOptionLevel.IPv6;
  1805. public const int SOL_SOCKET = (int)SocketOptionLevel.Socket;
  1806. public const int SOL_TCP = (int)SocketOptionLevel.Tcp;
  1807. public const int SOL_UDP = (int)SocketOptionLevel.Udp;
  1808. public const int SOMAXCONN = (int)SocketOptionName.MaxConnections;
  1809. public const int SO_ACCEPTCONN = (int)SocketOptionName.AcceptConnection;
  1810. public const int SO_BROADCAST = (int)SocketOptionName.Broadcast;
  1811. public const int SO_DEBUG = (int)SocketOptionName.Debug;
  1812. public const int SO_DONTROUTE = (int)SocketOptionName.DontRoute;
  1813. public const int SO_ERROR = (int)SocketOptionName.Error;
  1814. public const int SO_EXCLUSIVEADDRUSE = (int)SocketOptionName.ExclusiveAddressUse;
  1815. public const int SO_KEEPALIVE = (int)SocketOptionName.KeepAlive;
  1816. public const int SO_LINGER = (int)SocketOptionName.Linger;
  1817. public const int SO_OOBINLINE = (int)SocketOptionName.OutOfBandInline;
  1818. public const int SO_RCVBUF = (int)SocketOptionName.ReceiveBuffer;
  1819. public const int SO_RCVLOWAT = (int)SocketOptionName.ReceiveLowWater;
  1820. public const int SO_RCVTIMEO = (int)SocketOptionName.ReceiveTimeout;
  1821. public const int SO_REUSEADDR = (int)SocketOptionName.ReuseAddress;
  1822. public const int SO_SNDBUF = (int)SocketOptionName.SendBuffer;
  1823. public const int SO_SNDLOWAT = (int)SocketOptionName.SendLowWater;
  1824. public const int SO_SNDTIMEO = (int)SocketOptionName.SendTimeout;
  1825. public const int SO_TYPE = (int)SocketOptionName.Type;
  1826. public const int SO_USELOOPBACK = (int)SocketOptionName.UseLoopback;
  1827. public const int TCP_NODELAY = (int)SocketOptionName.NoDelay;
  1828. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")]
  1829. public static readonly BigInteger SIO_RCVALL = (long)IOControlCode.ReceiveAll;
  1830. public static readonly BigInteger SIO_KEEPALIVE_VALS = (long)IOControlCode.KeepAliveValues;
  1831. public const int RCVALL_ON = 1;
  1832. public const int RCVALL_OFF = 0;
  1833. public const int RCVALL_SOCKETLEVELONLY = 2;
  1834. public const int RCVALL_MAX = 3;
  1835. public const int has_ipv6 = (int)1;
  1836. #endregion
  1837. #region Private implementation
  1838. /// <summary>
  1839. /// Return a standard socket exception (socket.error) whose message and error code come from a SocketException
  1840. /// This will eventually be enhanced to generate the correct error type (error, herror, gaierror) based on the error code.
  1841. /// </summary>
  1842. internal static Exception MakeException(CodeContext/*!*/ context, Exception exception) {
  1843. // !!! this shouldn't just blindly set the type to error (see summary)
  1844. if (exception is SocketException) {
  1845. SocketException se = (SocketException)exception;
  1846. switch (se.SocketErrorCode) {
  1847. case SocketError.NotConnected: // CPython times out when the socket isn't connected.
  1848. case SocketError.TimedOut:
  1849. return PythonExceptions.CreateThrowable(timeout(context), (int)se.SocketErrorCode, se.Message);
  1850. default:
  1851. return PythonExceptions.CreateThrowable(error(context), (int)se.SocketErrorCode, se.Message);
  1852. }
  1853. } else if (exception is ObjectDisposedException) {
  1854. return PythonExceptions.CreateThrowable(error(context), (int)EBADF, "the socket is closed");
  1855. } else if (exception is InvalidOperationException) {
  1856. return MakeException(context, new SocketException((int)SocketError.InvalidArgument));
  1857. } else {
  1858. return exception;
  1859. }
  1860. }
  1861. /// <summary>
  1862. /// Convert an IPv6 address byte array to a string in standard colon-hex notation.
  1863. /// The .NET IPAddress.ToString() method uses dotted-quad for the last 32 bits,
  1864. /// which differs from the normal Python implementation (but is allowed by the IETF);
  1865. /// this method returns the standard (no dotted-quad) colon-hex form.
  1866. /// </summary>
  1867. private static string IPv6BytesToColonHex(byte[] ipBytes) {
  1868. Debug.Assert(ipBytes.Length == IPv6AddrBytes);
  1869. const int bytesPerWord = 2; // in bytes
  1870. const int bitsPerByte = 8;
  1871. int[] words = new int[IPv6AddrBytes / bytesPerWord];
  1872. // Convert to array of 16-bit words
  1873. for (int i = 0; i < words.Length; i++) {
  1874. for (int j = 0; j < bytesPerWord; j++) {
  1875. words[i] <<= bitsPerByte;
  1876. words[i] += ipBytes[i * bytesPerWord + j];
  1877. }
  1878. }
  1879. // Find longest series of 0-valued words (to collapse to ::)
  1880. int longestStart = 0;
  1881. int longestLen = 0;
  1882. for (int i = 0; i < words.Length; i++) {
  1883. if (words[i] == 0) {
  1884. for (int j = i; j < words.Length; j++) {
  1885. if (words[j] != 0) {
  1886. i += longestLen;
  1887. break;
  1888. }
  1889. if (j - i + 1 > longestLen) {
  1890. longestStart = i;
  1891. longestLen = j - i + 1;
  1892. }
  1893. }
  1894. }
  1895. }
  1896. // Build colon-hex string
  1897. StringBuilder result = new StringBuilder(IPv6AddrBytes * 3);
  1898. for (int i = 0; i < words.Length; i++) {
  1899. if (i != 0) result.Append(':');
  1900. if (longestLen > 0 && i == longestStart) {
  1901. if (longestStart == 0) result.Append(':');
  1902. if (longestStart + longestLen == words.Length) result.Append(':');
  1903. i += longestLen - 1;
  1904. continue;
  1905. } else {
  1906. result.Append(words[i].ToString("x"));
  1907. }
  1908. }
  1909. return result.ToString();
  1910. }
  1911. /// <summary>
  1912. /// Handle conversion of "" to INADDR_ANY and "&lt;broadcast&gt;" to INADDR_BROADCAST.
  1913. /// Otherwise returns host unchanged.
  1914. /// </summary>
  1915. private static string ConvertSpecialAddresses(string host) {
  1916. switch (host) {
  1917. case AnyAddrToken:
  1918. return IPAddress.Any.ToString();
  1919. case BroadcastAddrToken:
  1920. return IPAddress.Broadcast.ToString();
  1921. default:
  1922. return host;
  1923. }
  1924. }
  1925. /// <summary>
  1926. /// Return the IP address associated with host, with optional address family checking.
  1927. /// host may be either a name or an IP address (in string form).
  1928. ///
  1929. /// If family is non-null, a gaierror will be thrown if the host's address family is
  1930. /// not the same as the specified family. gaierror is also raised if the hostname cannot be
  1931. /// converted to an IP address (e.g. through a name lookup failure).
  1932. /// </summary>
  1933. private static IPAddress HostToAddress(CodeContext/*!*/ context, string host, AddressFamily family) {
  1934. return HostToAddresses(context, host, family)[0];
  1935. }
  1936. /// <summary>
  1937. /// Return the IP address associated with host, with optional address family checking.
  1938. /// host may be either a name or an IP address (in string form).
  1939. ///
  1940. /// If family is non-null, a gaierror will be thrown if the host's address family is
  1941. /// not the same as the specified family. gaierror is also raised if the hostname cannot be
  1942. /// converted to an IP address (e.g. through a name lookup failure).
  1943. /// </summary>
  1944. private static IPAddress[] HostToAddresses(CodeContext/*!*/ context, string host, AddressFamily family) {
  1945. host = ConvertSpecialAddresses(host);
  1946. try {
  1947. IPAddress addr;
  1948. bool numeric = true;
  1949. int dotCount = 0;
  1950. foreach (char c in host) {
  1951. if (!Char.IsNumber(c) && c != '.') {
  1952. numeric = false;
  1953. } else if (c == '.') {
  1954. dotCount++;
  1955. }
  1956. }
  1957. if (numeric) {
  1958. if (dotCount == 3 && IPAddress.TryParse(host, out addr)) {
  1959. if (family == AddressFamily.Unspecified || family == addr.AddressFamily) {
  1960. return new IPAddress[] { addr };
  1961. }
  1962. }
  1963. // Incorrect family will raise exception below
  1964. } else {
  1965. IPHostEntry hostEntry = GetHostEntry(host);
  1966. List<IPAddress> addrs = new List<IPAddress>();
  1967. foreach (IPAddress ip in hostEntry.AddressList) {
  1968. if (family == AddressFamily.Unspecified || family == ip.AddressFamily) {
  1969. addrs.Add(ip);
  1970. }
  1971. }
  1972. if (addrs.Count > 0) return addrs.ToArray();
  1973. }
  1974. throw new SocketException((int)SocketError.HostNotFound);
  1975. } catch (SocketException e) {
  1976. throw PythonExceptions.CreateThrowable(gaierror(context), (int)e.SocketErrorCode, "no addresses of the specified family associated with host");
  1977. }
  1978. }
  1979. /// <summary>
  1980. /// Return fqdn, but with its domain removed if it's on the same domain as the local machine.
  1981. /// </summary>
  1982. private static string RemoveLocalDomain(string fqdn) {
  1983. char[] DNS_SEP = new char[] { '.' };
  1984. string[] myName = getfqdn().Split(DNS_SEP, 2);
  1985. string[] otherName = fqdn.Split(DNS_SEP, 2);
  1986. if (myName.Length < 2 || otherName.Length < 2) return fqdn;
  1987. if (myName[1] == otherName[1]) {
  1988. return otherName[0];
  1989. } else {
  1990. return fqdn;
  1991. }
  1992. }
  1993. /// <summary>
  1994. /// Convert a (host, port) tuple [IPv4] (host, port, flowinfo, scopeid) tuple [IPv6]
  1995. /// to its corresponding IPEndPoint.
  1996. ///
  1997. /// Throws gaierror if host is not a valid address.
  1998. /// Throws ArgumentTypeException if any of the following are true:
  1999. /// - address does not have exactly two elements
  2000. /// - address[0] is not a string
  2001. /// - address[1] is not an int
  2002. /// </summary>
  2003. private static IPEndPoint TupleToEndPoint(CodeContext/*!*/ context, PythonTuple address, AddressFamily family, out string host) {
  2004. if (address.__len__() != 2 && address.__len__() != 4) {
  2005. throw PythonOps.TypeError("address tuple must have exactly 2 (IPv4) or exactly 4 (IPv6) elements");
  2006. }
  2007. try {
  2008. host = Converter.ConvertToString(address[0]);
  2009. } catch (ArgumentTypeException) {
  2010. throw PythonOps.TypeError("host must be string");
  2011. }
  2012. int port;
  2013. try {
  2014. port = PythonContext.GetContext(context).ConvertToInt32(address[1]);
  2015. } catch (ArgumentTypeException) {
  2016. throw PythonOps.TypeError("port must be integer");
  2017. }
  2018. if (port < 0 || port > 65535) {
  2019. throw PythonOps.OverflowError("getsockaddrarg: port must be 0-65535");
  2020. }
  2021. IPAddress ip = HostToAddress(context, host, family);
  2022. if (address.__len__() == 2) {
  2023. return new IPEndPoint(ip, port);
  2024. } else {
  2025. try {
  2026. Converter.ConvertToInt64(address[2]);
  2027. } catch (ArgumentTypeException) {
  2028. throw PythonOps.TypeError("flowinfo must be integer");
  2029. }
  2030. // We don't actually do anything with flowinfo right now, but we validate it
  2031. // in case we want to do something in the future.
  2032. long scopeId;
  2033. try {
  2034. scopeId = Converter.ConvertToInt64(address[3]);
  2035. } catch (ArgumentTypeException) {
  2036. throw PythonOps.TypeError("scopeid must be integer");
  2037. }
  2038. IPEndPoint endPoint = new IPEndPoint(ip, port);
  2039. endPoint.Address.ScopeId = scopeId;
  2040. return endPoint;
  2041. }
  2042. }
  2043. /// <summary>
  2044. /// Convert an IPEndPoint to its corresponding (host, port) [IPv4] or (host, port, flowinfo, scopeid) [IPv6] tuple.
  2045. /// Throws SocketException if the address family is other than IPv4 or IPv6.
  2046. /// </summary>
  2047. private static PythonTuple EndPointToTuple(IPEndPoint endPoint) {
  2048. string ip = endPoint.Address.ToString();
  2049. int port = endPoint.Port;
  2050. switch (endPoint.Address.AddressFamily) {
  2051. case AddressFamily.InterNetwork:
  2052. return PythonTuple.MakeTuple(ip, port);
  2053. case AddressFamily.InterNetworkV6:
  2054. long flowInfo = 0; // RFC 3493 p. 7
  2055. long scopeId = endPoint.Address.ScopeId;
  2056. return PythonTuple.MakeTuple(ip, port, flowInfo, scopeId);
  2057. default:
  2058. throw new SocketException((int)SocketError.AddressFamilyNotSupported);
  2059. }
  2060. }
  2061. class PythonUserSocketStream : Stream {
  2062. private readonly object _userSocket;
  2063. private List<string> _data = new List<string>();
  2064. private int _dataSize;
  2065. private readonly int _bufSize;
  2066. private readonly bool _close;
  2067. public PythonUserSocketStream(object userSocket, int bufferSize, bool close) {
  2068. _userSocket = userSocket;
  2069. _bufSize = bufferSize;
  2070. _close = close;
  2071. }
  2072. public override bool CanRead {
  2073. get { return true; }
  2074. }
  2075. public override bool CanSeek {
  2076. get { return false; }
  2077. }
  2078. public override bool CanWrite {
  2079. get { return true; }
  2080. }
  2081. public override void Flush() {
  2082. if (_data.Count > 0) {
  2083. StringBuilder res = new StringBuilder();
  2084. foreach (string s in _data) {
  2085. res.Append(s);
  2086. }
  2087. DefaultContext.DefaultPythonContext.CallSplat(PythonOps.GetBoundAttr(DefaultContext.Default, _userSocket, "sendall"), res.ToString());
  2088. _data.Clear();
  2089. }
  2090. }
  2091. public override long Length {
  2092. get { throw new NotImplementedException(); }
  2093. }
  2094. public override long Position {
  2095. get {
  2096. throw new NotImplementedException();
  2097. }
  2098. set {
  2099. throw new NotImplementedException();
  2100. }
  2101. }
  2102. public override int Read(byte[] buffer, int offset, int count) {
  2103. object received = DefaultContext.DefaultPythonContext.CallSplat(PythonOps.GetBoundAttr(DefaultContext.Default, _userSocket, "recv"), count);
  2104. string data = Converter.ConvertToString(received);
  2105. return PythonAsciiEncoding.Instance.GetBytes(data, 0, data.Length, buffer, offset);
  2106. }
  2107. public override long Seek(long offset, SeekOrigin origin) {
  2108. throw new NotImplementedException();
  2109. }
  2110. public override void SetLength(long value) {
  2111. throw new NotImplementedException();
  2112. }
  2113. public override void Write(byte[] buffer, int offset, int count) {
  2114. string strData = new string(PythonAsciiEncoding.Instance.GetChars(buffer, offset, count));
  2115. _data.Add(strData);
  2116. _dataSize += strData.Length;
  2117. if (_dataSize > _bufSize) {
  2118. Flush();
  2119. }
  2120. }
  2121. protected override void Dispose(bool disposing) {
  2122. if (disposing) {
  2123. object closeObj;
  2124. if (PythonOps.TryGetBoundAttr(_userSocket, "close", out closeObj))
  2125. PythonCalls.Call(closeObj);
  2126. }
  2127. base.Dispose(disposing);
  2128. }
  2129. }
  2130. [PythonType]
  2131. public class _fileobject : PythonFile {
  2132. public new const string name = "<socket>";
  2133. private readonly socket _socket;
  2134. public const string __module__ = "socket";
  2135. private bool _close;
  2136. public object _sock; // Only present for compatibility with CPython tests
  2137. public object bufsize = DefaultBufferSize; // Only present for compatibility with CPython public API
  2138. public _fileobject(CodeContext/*!*/ context, object socket, [DefaultParameterValue("rb")]string mode, [DefaultParameterValue(-1)]int bufsize, [DefaultParameterValue(false)]bool close)
  2139. : base(PythonContext.GetContext(context)) {
  2140. Stream stream;
  2141. _close = close;
  2142. // subtypes of socket need to go through the user defined methods
  2143. if (socket != null && socket.GetType() == typeof(socket) && ((socket)socket)._socket.Connected) {
  2144. socket s = (socket as socket);
  2145. _socket = s;
  2146. stream = new NetworkStream(s._socket, false);
  2147. } else {
  2148. _socket = null;
  2149. stream = new PythonUserSocketStream(socket, GetBufferSize(context, bufsize), close);
  2150. }
  2151. _sock = socket;
  2152. base.__init__(stream, Encoding.GetEncoding(0), mode);
  2153. _isOpen = socket != null;
  2154. _close = (socket == null) ? false : close;
  2155. }
  2156. public void __init__(params object[] args) {
  2157. }
  2158. public void __init__([ParamDictionary]IDictionary<object, object> kwargs, params object[] args) {
  2159. }
  2160. public void __del__() {
  2161. if (_socket != null && _isOpen) {
  2162. if (_close) _socket.close();
  2163. _isOpen = false;
  2164. }
  2165. }
  2166. protected override void Dispose(bool disposing) {
  2167. if (_socket != null && _isOpen) {
  2168. if (_close) _socket.close();
  2169. _isOpen = false;
  2170. }
  2171. base.Dispose(disposing);
  2172. }
  2173. public override object close() {
  2174. if (!_isOpen) return null;
  2175. if (_socket != null && _close) {
  2176. _socket.close();
  2177. }
  2178. else if (this._stream != null && _close) {
  2179. _stream.Dispose();
  2180. }
  2181. _isOpen = false;
  2182. var obj = base.close();
  2183. return obj;
  2184. }
  2185. private static int GetBufferSize(CodeContext/*!*/ context, int size) {
  2186. if (size == -1) return Converter.ConvertToInt32(Getdefault_bufsize(context));
  2187. return size;
  2188. }
  2189. [SpecialName, PropertyMethod, StaticExtensionMethod]
  2190. public static object Getdefault_bufsize(CodeContext/*!*/ context) {
  2191. return PythonContext.GetContext(context).GetModuleState(_defaultBufsizeKey);
  2192. }
  2193. [SpecialName, PropertyMethod, StaticExtensionMethod]
  2194. public static void Setdefault_bufsize(CodeContext/*!*/ context, object value) {
  2195. PythonContext.GetContext(context).SetModuleState(_defaultBufsizeKey, value);
  2196. }
  2197. }
  2198. #endregion
  2199. private static int? GetDefaultTimeout(CodeContext/*!*/ context) {
  2200. return (int?)PythonContext.GetContext(context).GetModuleState(_defaultTimeoutKey);
  2201. }
  2202. private static void SetDefaultTimeout(CodeContext/*!*/ context, int? timeout) {
  2203. PythonContext.GetContext(context).SetModuleState(_defaultTimeoutKey, timeout);
  2204. }
  2205. private static PythonType error(CodeContext/*!*/ context) {
  2206. return (PythonType)PythonContext.GetContext(context).GetModuleState("socketerror");
  2207. }
  2208. private static PythonType herror(CodeContext/*!*/ context) {
  2209. return (PythonType)PythonContext.GetContext(context).GetModuleState("socketherror");
  2210. }
  2211. private static PythonType timeout(CodeContext/*!*/ context) {
  2212. return (PythonType)PythonContext.GetContext(context).GetModuleState("sockettimeout");
  2213. }
  2214. public class ssl {
  2215. private SslStream _sslStream;
  2216. private socket _socket;
  2217. private readonly X509Certificate2Collection _certCollection;
  2218. private readonly X509Certificate _cert;
  2219. private readonly int _protocol, _certsMode;
  2220. private readonly bool _validate, _serverSide;
  2221. private readonly CodeContext _context;
  2222. private readonly RemoteCertificateValidationCallback _callback;
  2223. private Exception _validationFailure;
  2224. private static readonly bool _supportsTls12;
  2225. private static readonly SslProtocols _SslProtocol_Tls12;
  2226. private static readonly SslProtocols _SslProtocol_Tls11;
  2227. static ssl()
  2228. {
  2229. // If .Net 4.5 or 4.6 are installed, try and detect
  2230. // the availability of Tls11/Tls12 dynamically:
  2231. SslProtocols result = SslProtocols.None;
  2232. bool succeeded = false;
  2233. try {
  2234. result = (SslProtocols)Enum.Parse(typeof(SslProtocols), "Tls12");
  2235. succeeded = true;
  2236. }
  2237. catch (ArgumentException) {
  2238. // This is thrown for invalid enumeration values:
  2239. // This is ok on .Net 2.0 or .Net 4.0 without .Net 4.5/4.6 installed.
  2240. }
  2241. _supportsTls12 = succeeded;
  2242. if (_supportsTls12)
  2243. {
  2244. _SslProtocol_Tls12 = result;
  2245. try {
  2246. _SslProtocol_Tls11 = (SslProtocols)Enum.Parse(typeof(SslProtocols), "Tls11");
  2247. }
  2248. catch (ArgumentException) {
  2249. // This is thrown for invalid enumeration values by Enum.Parse.
  2250. throw new InvalidOperationException("Tls12 exists in SslProtocols but not Tls11? Very unexpected!");
  2251. }
  2252. }
  2253. else
  2254. {
  2255. _SslProtocol_Tls11 = SslProtocols.None;
  2256. _SslProtocol_Tls12 = SslProtocols.None;
  2257. }
  2258. }
  2259. public ssl(CodeContext context, PythonSocket.socket sock, [DefaultParameterValue(null)] string keyfile, [DefaultParameterValue(null)] string certfile, [DefaultParameterValue(null)] X509Certificate2Collection certs) {
  2260. _context = context;
  2261. _sslStream = new SslStream(new NetworkStream(sock._socket, false), true, CertValidationCallback);
  2262. _socket = sock;
  2263. _protocol = PythonSsl.PROTOCOL_SSLv23 | PythonSsl.OP_NO_SSLv2 | PythonSsl.OP_NO_SSLv3;
  2264. _validate = false;
  2265. _certCollection = certs ?? new X509Certificate2Collection();
  2266. }
  2267. internal ssl(CodeContext context,
  2268. PythonSocket.socket sock,
  2269. bool server_side,
  2270. [DefaultParameterValue(null)] string keyfile,
  2271. [DefaultParameterValue(null)] string certfile,
  2272. [DefaultParameterValue(PythonSsl.CERT_NONE)]int certs_mode,
  2273. [DefaultParameterValue(PythonSsl.PROTOCOL_SSLv23 | PythonSsl.OP_NO_SSLv2 | PythonSsl.OP_NO_SSLv3)]int protocol,
  2274. string cacertsfile,
  2275. [DefaultParameterValue(null)] X509Certificate2Collection certs) {
  2276. if (sock == null) {
  2277. throw PythonOps.TypeError("expected socket object, got None");
  2278. }
  2279. _serverSide = server_side;
  2280. bool validate;
  2281. _certsMode = certs_mode;
  2282. RemoteCertificateValidationCallback callback;
  2283. switch (certs_mode) {
  2284. case PythonSsl.CERT_NONE:
  2285. validate = false;
  2286. callback = CertValidationCallback;
  2287. break;
  2288. case PythonSsl.CERT_OPTIONAL:
  2289. validate = true;
  2290. callback = CertValidationCallbackOptional;
  2291. break;
  2292. case PythonSsl.CERT_REQUIRED:
  2293. validate = true;
  2294. callback = CertValidationCallbackRequired;
  2295. break;
  2296. default:
  2297. throw new InvalidOperationException(String.Format("bad certs_mode: {0}", certs_mode));
  2298. }
  2299. _callback = callback;
  2300. if(certs != null) {
  2301. _certCollection = certs;
  2302. }
  2303. if (certfile != null) {
  2304. _cert = PythonSsl.ReadCertificate(context, certfile);
  2305. }
  2306. if(cacertsfile != null) {
  2307. _certCollection = new X509Certificate2Collection(new[] { PythonSsl.ReadCertificate(context, cacertsfile) });
  2308. }
  2309. _socket = sock;
  2310. EnsureSslStream(false);
  2311. _protocol = protocol;
  2312. _validate = validate;
  2313. _context = context;
  2314. }
  2315. private void EnsureSslStream(bool throwWhenNotConnected) {
  2316. if (_sslStream == null && _socket._socket.Connected) {
  2317. if (_serverSide) {
  2318. _sslStream = new SslStream(
  2319. new NetworkStream(_socket._socket, false),
  2320. true,
  2321. _callback
  2322. );
  2323. } else {
  2324. _sslStream = new SslStream(
  2325. new NetworkStream(_socket._socket, false),
  2326. true,
  2327. _callback,
  2328. CertSelectLocal
  2329. );
  2330. }
  2331. }
  2332. if (throwWhenNotConnected && _sslStream == null) {
  2333. var socket = _context.LanguageContext.GetBuiltinModule("socket");
  2334. var socketError = PythonSocket.GetSocketError(_context.LanguageContext, socket.__dict__);
  2335. throw PythonExceptions.CreateThrowable(socketError, 10057, "A request to send or receive data was disallowed because the socket is not connected.");
  2336. }
  2337. }
  2338. internal bool CertValidationCallback(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) {
  2339. return true;
  2340. }
  2341. internal bool CertValidationCallbackOptional(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) {
  2342. if (!_serverSide) {
  2343. if (certificate != null && sslPolicyErrors != SslPolicyErrors.None) {
  2344. ValidateCertificate(certificate, chain, sslPolicyErrors);
  2345. }
  2346. }
  2347. return true;
  2348. }
  2349. internal X509Certificate CertSelectLocal(object sender, string targetHost, X509CertificateCollection collection, X509Certificate remoteCertificate, string[] acceptableIssuers) {
  2350. if (acceptableIssuers != null && acceptableIssuers.Length > 0 && collection != null && collection.Count > 0) {
  2351. // Use the first certificate that is from an acceptable issuer.
  2352. foreach (X509Certificate certificate in collection) {
  2353. string issuer = certificate.Issuer;
  2354. if (Array.IndexOf(acceptableIssuers, issuer) != -1)
  2355. return certificate;
  2356. }
  2357. }
  2358. if (collection != null && collection.Count > 0) {
  2359. return collection[0];
  2360. }
  2361. return null;
  2362. }
  2363. internal bool CertValidationCallbackRequired(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) {
  2364. if (!_serverSide) {
  2365. // client check
  2366. if (certificate == null) {
  2367. ValidationError(SslPolicyErrors.None);
  2368. } else if (sslPolicyErrors != SslPolicyErrors.None) {
  2369. ValidateCertificate(certificate, chain, sslPolicyErrors);
  2370. }
  2371. }
  2372. return true;
  2373. }
  2374. private void ValidateCertificate(X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) {
  2375. chain = new X509Chain();
  2376. #if NETSTANDARD
  2377. // missing the X509Certificate2.ctor(X509Certificate) in .NET Core 1.0
  2378. chain.ChainPolicy.ExtraStore.AddRange(_certCollection);
  2379. chain.Build((X509Certificate2)certificate);
  2380. #else
  2381. X509Certificate2Collection certificates = new X509Certificate2Collection();
  2382. foreach (object cert in _certCollection) {
  2383. if (cert is X509Certificate2) {
  2384. certificates.Add((X509Certificate2)cert);
  2385. }
  2386. else if (cert is X509Certificate) {
  2387. certificates.Add(new X509Certificate2((X509Certificate)cert));
  2388. }
  2389. }
  2390. chain.ChainPolicy.ExtraStore.AddRange(certificates);
  2391. chain.Build(new X509Certificate2(certificate));
  2392. #endif
  2393. if (chain.ChainStatus.Length > 0) {
  2394. foreach (var elem in chain.ChainStatus) {
  2395. if (elem.Status == X509ChainStatusFlags.UntrustedRoot) {
  2396. bool isOk = false;
  2397. foreach (var cert in _certCollection) {
  2398. if (certificate.Issuer == cert.Subject) {
  2399. isOk = true;
  2400. }
  2401. }
  2402. if (isOk) {
  2403. continue;
  2404. }
  2405. }
  2406. ValidationError(sslPolicyErrors);
  2407. break;
  2408. }
  2409. }
  2410. }
  2411. private void ValidationError(object reason) {
  2412. _validationFailure = PythonExceptions.CreateThrowable(PythonSsl.SSLError(_context), "errors while validating certificate chain: ", reason.ToString());
  2413. }
  2414. public void do_handshake() {
  2415. try {
  2416. // make sure the remote side hasn't shutdown before authenticating so we don't
  2417. // hang if we're in blocking mode.
  2418. #pragma warning disable 219 // unused variable
  2419. int available = _socket._socket.Available;
  2420. #pragma warning restore 219
  2421. } catch (SocketException) {
  2422. throw PythonExceptions.CreateThrowable(PythonExceptions.IOError, "socket closed before handshake");
  2423. }
  2424. EnsureSslStream(true);
  2425. try {
  2426. if (_serverSide) {
  2427. #if NETSTANDARD
  2428. _sslStream.AuthenticateAsServerAsync(_cert, _certsMode == PythonSsl.CERT_REQUIRED, SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls, false).Wait();
  2429. #else
  2430. _sslStream.AuthenticateAsServer(_cert, _certsMode == PythonSsl.CERT_REQUIRED, SslProtocols.Default, false);
  2431. #endif
  2432. } else {
  2433. var collection = new X509CertificateCollection();
  2434. if (_cert != null) {
  2435. collection.Add(_cert);
  2436. }
  2437. #if NETSTANDARD
  2438. _sslStream.AuthenticateAsClientAsync(_socket._hostName, collection, SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls, false).Wait();
  2439. #else
  2440. _sslStream.AuthenticateAsClient(_socket._hostName, collection, SslProtocols.Default, false);
  2441. #endif
  2442. }
  2443. } catch (AuthenticationException e) {
  2444. ((IDisposable)_socket._socket).Dispose();
  2445. throw PythonExceptions.CreateThrowable(PythonSsl.SSLError(_context), "errors while performing handshake: ", e.ToString());
  2446. }
  2447. if (_validationFailure != null) {
  2448. throw _validationFailure;
  2449. }
  2450. }
  2451. public socket shutdown() {
  2452. _sslStream.Dispose();
  2453. return _socket;
  2454. }
  2455. /* supported communication based upon what the client & server specify
  2456. * as per the CPython docs:
  2457. * client / server SSLv2 SSLv3 SSLv23 TLSv1
  2458. SSLv2 yes no yes* no
  2459. SSLv3 yes yes yes no
  2460. SSLv23 yes no yes no
  2461. TLSv1 no no yes yes
  2462. */
  2463. private static SslProtocols GetProtocolType(int type) {
  2464. SslProtocols result = SslProtocols.None;
  2465. switch (type & ~PythonSsl.OP_NO_ALL) {
  2466. #pragma warning disable CS0618 // Type or member is obsolete
  2467. case PythonSsl.PROTOCOL_SSLv2:
  2468. result = SslProtocols.Ssl2;
  2469. break;
  2470. case PythonSsl.PROTOCOL_SSLv3:
  2471. result = SslProtocols.Ssl3;
  2472. break;
  2473. case PythonSsl.PROTOCOL_SSLv23:
  2474. result = SslProtocols.Ssl2 | SslProtocols.Ssl3 | SslProtocols.Tls | _SslProtocol_Tls11 | _SslProtocol_Tls12;
  2475. break;
  2476. #pragma warning restore CS0618 // Type or member is obsolete
  2477. case PythonSsl.PROTOCOL_TLSv1:
  2478. result = SslProtocols.Tls;
  2479. break;
  2480. case PythonSsl.PROTOCOL_TLSv1_1:
  2481. if (!_supportsTls12) {
  2482. throw new InvalidOperationException("bad ssl protocol type: " + type);
  2483. }
  2484. result = _SslProtocol_Tls11;
  2485. break;
  2486. case PythonSsl.PROTOCOL_TLSv1_2:
  2487. if (!_supportsTls12) {
  2488. throw new InvalidOperationException("bad ssl protocol type: " + type);
  2489. }
  2490. result = _SslProtocol_Tls12;
  2491. break;
  2492. default:
  2493. throw new InvalidOperationException("bad ssl protocol type: " + type);
  2494. }
  2495. // Filter out requested protocol exclusions:
  2496. #pragma warning disable CS0618 // Type or member is obsolete
  2497. result &= (type & PythonSsl.OP_NO_SSLv3) != 0 ? ~SslProtocols.Ssl3 : ~SslProtocols.None;
  2498. result &= (type & PythonSsl.OP_NO_SSLv2) != 0 ? ~SslProtocols.Ssl2 : ~SslProtocols.None;
  2499. #pragma warning restore CS0618 // Type or member is obsolete
  2500. result &= (type & PythonSsl.OP_NO_TLSv1) != 0 ? ~SslProtocols.Tls : ~SslProtocols.None;
  2501. if (_supportsTls12)
  2502. {
  2503. result &= (type & PythonSsl.OP_NO_TLSv1_1) != 0 ? ~_SslProtocol_Tls11 : ~SslProtocols.None;
  2504. result &= (type & PythonSsl.OP_NO_TLSv1_2) != 0 ? ~_SslProtocol_Tls12 : ~SslProtocols.None;
  2505. }
  2506. return result;
  2507. }
  2508. public PythonTuple cipher() {
  2509. if (_sslStream != null && _sslStream.IsAuthenticated) {
  2510. return PythonTuple.MakeTuple(
  2511. _sslStream.CipherAlgorithm.ToString(),
  2512. ProtocolToPython(),
  2513. _sslStream.CipherStrength
  2514. );
  2515. }
  2516. return null;
  2517. }
  2518. private string ProtocolToPython() {
  2519. switch (_sslStream.SslProtocol) {
  2520. #pragma warning disable CS0618 // Type or member is obsolete
  2521. case SslProtocols.Ssl2: return "SSLv2";
  2522. case SslProtocols.Ssl3: return "TLSv1/SSLv3";
  2523. #pragma warning restore CS0618 // Type or member is obsolete
  2524. case SslProtocols.Tls: return "TLSv1";
  2525. default: return _sslStream.SslProtocol.ToString();
  2526. }
  2527. }
  2528. public object peer_certificate(bool binary_form) {
  2529. if (_sslStream != null) {
  2530. var peerCert = _sslStream.RemoteCertificate;
  2531. if (peerCert != null) {
  2532. if (binary_form) {
  2533. return peerCert.GetRawCertData().MakeString();
  2534. } else if (_validate) {
  2535. return PythonSsl.CertificateToPython(_context, peerCert, true);
  2536. }
  2537. }
  2538. }
  2539. return null;
  2540. }
  2541. public int pending() {
  2542. return _socket._socket.Available;
  2543. }
  2544. [Documentation("issuer() -> issuer_certificate\n\n"
  2545. + "Returns a string that describes the issuer of the server's certificate. Only useful for debugging purposes."
  2546. )]
  2547. public string issuer() {
  2548. if (_sslStream != null && _sslStream.IsAuthenticated) {
  2549. X509Certificate remoteCertificate = _sslStream.RemoteCertificate;
  2550. if (remoteCertificate != null) {
  2551. return remoteCertificate.Issuer;
  2552. } else {
  2553. return String.Empty;
  2554. }
  2555. }
  2556. return String.Empty;
  2557. }
  2558. [Documentation("read([n]) -> buffer_read\n\n"
  2559. + "If n is present, reads up to n bytes from the SSL connection. Otherwise, reads to EOF."
  2560. )]
  2561. public string read(CodeContext/*!*/ context, [DefaultParameterValue(Int32.MaxValue)] int n) {
  2562. EnsureSslStream(true);
  2563. try {
  2564. byte[] buffer = new byte[2048];
  2565. MemoryStream result = new MemoryStream(n);
  2566. while (true) {
  2567. int readLength = (n < buffer.Length) ? n : buffer.Length;
  2568. int bytes = _sslStream.Read(buffer, 0, readLength);
  2569. if (bytes > 0) {
  2570. result.Write(buffer, 0, bytes);
  2571. n -= bytes;
  2572. }
  2573. if (bytes == 0 || n == 0 || bytes < readLength) {
  2574. return result.ToArray().MakeString();
  2575. }
  2576. }
  2577. } catch (Exception e) {
  2578. throw PythonSocket.MakeException(context, e);
  2579. }
  2580. }
  2581. [Documentation("server() -> server_certificate\n\n"
  2582. + "Returns a string that describes the server's certificate. Only useful for debugging purposes."
  2583. )]
  2584. public string server() {
  2585. if (_sslStream != null && _sslStream.IsAuthenticated) {
  2586. X509Certificate remoteCertificate = _sslStream.RemoteCertificate;
  2587. if (remoteCertificate != null) {
  2588. return remoteCertificate.Subject;
  2589. }
  2590. }
  2591. return String.Empty;
  2592. }
  2593. [Documentation("write(s) -> bytes_sent\n\n"
  2594. + "Writes the string s through the SSL connection."
  2595. )]
  2596. public int write(CodeContext/*!*/ context, string data) {
  2597. EnsureSslStream(true);
  2598. byte[] buffer = data.MakeByteArray();
  2599. try {
  2600. _sslStream.Write(buffer);
  2601. return buffer.Length;
  2602. } catch (Exception e) {
  2603. throw PythonSocket.MakeException(context, e);
  2604. }
  2605. }
  2606. }
  2607. }
  2608. internal class SocketUtilException : Exception {
  2609. public SocketUtilException() {
  2610. }
  2611. public SocketUtilException(string message)
  2612. : base(message) {
  2613. }
  2614. public SocketUtilException(string message, Exception inner)
  2615. : base(message, inner) {
  2616. }
  2617. }
  2618. // based on http://stackoverflow.com/questions/13246099/using-c-sharp-to-reference-a-port-number-to-service-name
  2619. // for the Linux Mono version and http://www.pinvoke.net/ for dllimports for winsock libraries
  2620. internal static class SocketUtil {
  2621. [StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
  2622. public struct servent {
  2623. public string s_name;
  2624. public IntPtr s_aliases;
  2625. public ushort s_port;
  2626. public string s_proto;
  2627. }
  2628. [StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
  2629. public struct servent64
  2630. {
  2631. public string s_name;
  2632. public IntPtr s_aliases;
  2633. public string s_proto;
  2634. public ushort s_port;
  2635. }
  2636. [StructLayout(LayoutKind.Sequential)]
  2637. internal struct WSAData {
  2638. public short wVersion;
  2639. public short wHighVersion;
  2640. [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 257)]
  2641. public string szDescription;
  2642. [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 129)]
  2643. public string szSystemStatus;
  2644. public short iMaxSockets;
  2645. public short iMaxUdpDg;
  2646. public int lpVendorInfo;
  2647. }
  2648. [DllImport("libc", SetLastError = true, CharSet = CharSet.Ansi, EntryPoint = "getservbyname")]
  2649. private static extern IntPtr getservbyname_linux(string name, string proto);
  2650. [DllImport("libc", SetLastError = true, CharSet = CharSet.Ansi, EntryPoint = "getservbyport")]
  2651. private static extern IntPtr getservbyport_linux(ushort port, string proto);
  2652. [DllImport("ws2_32.dll", SetLastError = true)]
  2653. static extern Int32 WSAStartup(Int16 wVersionRequested, out WSAData wsaData);
  2654. [DllImport("ws2_32.dll", SetLastError = true, CharSet = CharSet.Ansi)]
  2655. private static extern IntPtr getservbyname(string name, string proto);
  2656. [DllImport("ws2_32.dll", SetLastError = true, CharSet = CharSet.Ansi)]
  2657. private static extern IntPtr getservbyport(ushort port, string proto);
  2658. [DllImport("Ws2_32.dll", SetLastError = true)]
  2659. private static extern Int32 WSAGetLastError();
  2660. [DllImport("ws2_32.dll", SetLastError = true)]
  2661. static extern Int32 WSACleanup();
  2662. private static T PtrToStructure<T>(IntPtr result) {
  2663. #if NETSTANDARD
  2664. return Marshal.PtrToStructure<T>(result);
  2665. #else
  2666. return (T)Marshal.PtrToStructure(result, typeof(T));
  2667. #endif
  2668. }
  2669. public static string GetServiceByPortWindows(ushort port, string protocol) {
  2670. var test = Socket.OSSupportsIPv6; // make sure Winsock library is initiliazed
  2671. var netport = unchecked((ushort)IPAddress.HostToNetworkOrder(unchecked((short)port)));
  2672. var result = getservbyport(netport, protocol);
  2673. if (IntPtr.Zero == result)
  2674. throw new SocketUtilException(string.Format("Could not resolve service for port {0}", port));
  2675. #if CLR4
  2676. if (Environment.Is64BitProcess)
  2677. return PtrToStructure<servent64>(result).s_name;
  2678. else
  2679. #endif
  2680. return PtrToStructure<servent>(result).s_name;
  2681. }
  2682. public static string GetServiceByPortNonWindows(ushort port, string protocol) {
  2683. var netport = unchecked((ushort)IPAddress.HostToNetworkOrder(unchecked((short)port)));
  2684. var result = getservbyport_linux(netport, protocol);
  2685. if (IntPtr.Zero == result) {
  2686. throw new SocketUtilException(
  2687. string.Format("Could not resolve service for port {0}", port));
  2688. }
  2689. return PtrToStructure<servent>(result).s_name;
  2690. }
  2691. public static string GetServiceByPort(ushort port, string protocol) {
  2692. if (Environment.OSVersion.Platform == PlatformID.Unix || Environment.OSVersion.Platform == PlatformID.MacOSX)
  2693. return GetServiceByPortNonWindows(port, protocol);
  2694. else
  2695. return GetServiceByPortWindows(port, protocol);
  2696. }
  2697. public static ushort GetServiceByNameWindows(string service, string protocol) {
  2698. var test = Socket.OSSupportsIPv6; // make sure Winsock library is initiliazed
  2699. var result = getservbyname(service, protocol);
  2700. if (IntPtr.Zero == result)
  2701. throw new SocketUtilException(string.Format("Could not resolve port for service {0}", service));
  2702. ushort port;
  2703. #if CLR4
  2704. if (Environment.Is64BitProcess)
  2705. port = PtrToStructure<servent64>(result).s_port;
  2706. else
  2707. #endif
  2708. port = PtrToStructure<servent>(result).s_port;
  2709. var hostport = IPAddress.NetworkToHostOrder(unchecked((short)port));
  2710. return unchecked((ushort)hostport);
  2711. }
  2712. public static ushort GetServiceByNameNonWindows(string service, string protocol) {
  2713. var result = getservbyname_linux(service, protocol);
  2714. if (IntPtr.Zero == result) {
  2715. throw new SocketUtilException(
  2716. string.Format("Could not resolve port for service {0}", service));
  2717. }
  2718. ushort port = PtrToStructure<servent>(result).s_port;
  2719. var hostport = IPAddress.NetworkToHostOrder(unchecked((short)port));
  2720. return unchecked((ushort)hostport);
  2721. }
  2722. public static ushort GetServiceByName(string service, string protocol) {
  2723. if (Environment.OSVersion.Platform == PlatformID.Unix || Environment.OSVersion.Platform == PlatformID.MacOSX)
  2724. return GetServiceByNameNonWindows(service, protocol);
  2725. else
  2726. return GetServiceByNameWindows(service, protocol);
  2727. }
  2728. }
  2729. }
  2730. #endif