PageRenderTime 69ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/DICK.B1/IronPython.Modules/socket.cs

https://bitbucket.org/williamybs/uidipythontool
C# | 2377 lines | 1986 code | 253 blank | 138 comment | 302 complexity | 5058e6f68a7d999012f209c5b5282659 MD5 | raw file
  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Microsoft Public License. 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 Microsoft Public License, 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 Microsoft Public License.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. *
  14. * ***************************************************************************/
  15. #if !SILVERLIGHT // System.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.Text;
  28. using Microsoft.Scripting;
  29. using Microsoft.Scripting.Runtime;
  30. using IronPython.Runtime;
  31. using IronPython.Runtime.Exceptions;
  32. using IronPython.Runtime.Operations;
  33. using IronPython.Runtime.Types;
  34. #if CLR2
  35. using Microsoft.Scripting.Math;
  36. #else
  37. using System.Numerics;
  38. #endif
  39. using PythonArray = IronPython.Modules.ArrayModule.array;
  40. using SpecialNameAttribute = System.Runtime.CompilerServices.SpecialNameAttribute;
  41. [assembly: PythonModule("socket", typeof(IronPython.Modules.PythonSocket))]
  42. namespace IronPython.Modules {
  43. public static class PythonSocket {
  44. private static readonly object _defaultTimeoutKey = new object();
  45. private static readonly object _defaultBufsizeKey = new object();
  46. private const int DefaultBufferSize = 8192;
  47. [SpecialName]
  48. public static void PerformModuleReload(PythonContext/*!*/ context, PythonDictionary/*!*/ dict) {
  49. if (!context.HasModuleState(_defaultTimeoutKey)) {
  50. context.SetModuleState(_defaultTimeoutKey, null);
  51. }
  52. context.SetModuleState(_defaultBufsizeKey, DefaultBufferSize);
  53. PythonType socketErr = GetSocketError(context, dict);
  54. context.EnsureModuleException("socketherror", socketErr, dict, "herror", "socket");
  55. context.EnsureModuleException("socketgaierror", socketErr, dict, "gaierror", "socket");
  56. context.EnsureModuleException("sockettimeout", socketErr, dict, "timeout", "socket");
  57. }
  58. internal static PythonType GetSocketError(PythonContext context, PythonDictionary dict) {
  59. return context.EnsureModuleException("socketerror", PythonExceptions.IOError, dict, "error", "socket");
  60. }
  61. public const string __doc__ = "Implementation module for socket operations.\n\n"
  62. + "This module is a loose wrapper around the .NET System.Net.Sockets API, so you\n"
  63. + "may find the corresponding MSDN documentation helpful in decoding error\n"
  64. + "messages and understanding corner cases.\n"
  65. + "\n"
  66. + "This implementation of socket differs slightly from the standard CPython\n"
  67. + "socket module. Many of these differences are due to the implementation of the\n"
  68. + ".NET socket libraries. These differences are summarized below. For full\n"
  69. + "details, check the docstrings of the functions mentioned.\n"
  70. + " - s.accept(), s.connect(), and s.connect_ex() do not support timeouts.\n"
  71. + " - Timeouts in s.sendall() don't work correctly.\n"
  72. + " - s.dup() is not implemented.\n"
  73. + " - getservbyname() and getservbyport() are not implemented.\n"
  74. + " - SSL support is not implemented."
  75. + "\n"
  76. + "An Extra IronPython-specific function is exposed only if the clr module is\n"
  77. + "imported:\n"
  78. + " - s.HandleToSocket() returns the System.Net.Sockets.Socket object associated\n"
  79. + " with a particular \"file descriptor number\" (as returned by s.fileno()).\n"
  80. ;
  81. #region Socket object
  82. public static PythonType SocketType = DynamicHelpers.GetPythonTypeFromType(typeof(socket));
  83. [PythonType]
  84. [Documentation("socket([family[, type[, proto]]]) -> socket object\n\n"
  85. + "Create a socket (a network connection endpoint) of the given family, type,\n"
  86. + "and protocol. socket() accepts keyword arguments.\n"
  87. + " - family (address family) defaults to AF_INET\n"
  88. + " - type (socket type) defaults to SOCK_STREAM\n"
  89. + " - proto (protocol type) defaults to 0, which specifies the default protocol\n"
  90. + "\n"
  91. + "This module supports only IP sockets. It does not support raw or Unix sockets.\n"
  92. + "Both IPv4 and IPv6 are supported.")]
  93. public class socket : IWeakReferenceable {
  94. #region Fields
  95. /// <summary>
  96. /// handleToSocket allows us to translate from Python's idea of a socket resource (file
  97. /// descriptor numbers) to .NET's idea of a socket resource (System.Net.Socket objects).
  98. /// In particular, this allows the select module to convert file numbers (as returned by
  99. /// fileno()) and convert them to Socket objects so that it can do something useful with them.
  100. /// </summary>
  101. private static readonly Dictionary<IntPtr, WeakReference> _handleToSocket = new Dictionary<IntPtr, WeakReference>();
  102. private const int DefaultAddressFamily = (int)AddressFamily.InterNetwork;
  103. private const int DefaultSocketType = (int)System.Net.Sockets.SocketType.Stream;
  104. private const int DefaultProtocolType = (int)ProtocolType.Unspecified;
  105. internal Socket _socket;
  106. internal string _hostName;
  107. private WeakRefTracker _weakRefTracker = null;
  108. private int _referenceCount = 1;
  109. public const string __module__ = "socket";
  110. internal CodeContext/*!*/ _context;
  111. private int _timeout;
  112. #endregion
  113. #region Public API
  114. public socket() {
  115. }
  116. public void __init__(CodeContext/*!*/ context, [DefaultParameterValue(DefaultAddressFamily)] int addressFamily,
  117. [DefaultParameterValue(DefaultSocketType)] int socketType,
  118. [DefaultParameterValue(DefaultProtocolType)] int protocolType,
  119. [DefaultParameterValue(null)]socket _sock) {
  120. System.Net.Sockets.SocketType type = (System.Net.Sockets.SocketType)Enum.ToObject(typeof(System.Net.Sockets.SocketType), socketType);
  121. if (!Enum.IsDefined(typeof(System.Net.Sockets.SocketType), type)) {
  122. throw MakeException(context, new SocketException((int)SocketError.SocketNotSupported));
  123. }
  124. AddressFamily family = (AddressFamily)Enum.ToObject(typeof(AddressFamily), addressFamily);
  125. if (!Enum.IsDefined(typeof(AddressFamily), family)) {
  126. throw MakeException(context, new SocketException((int)SocketError.AddressFamilyNotSupported));
  127. }
  128. ProtocolType proto = (ProtocolType)Enum.ToObject(typeof(ProtocolType), protocolType);
  129. if (!Enum.IsDefined(typeof(ProtocolType), proto)) {
  130. throw MakeException(context, new SocketException((int)SocketError.ProtocolNotSupported));
  131. }
  132. if (_sock == null) {
  133. Socket newSocket;
  134. try {
  135. newSocket = new Socket(family, type, proto);
  136. } catch (SocketException e) {
  137. throw MakeException(context, e);
  138. }
  139. Initialize(context, newSocket);
  140. } else {
  141. _socket = _sock._socket;
  142. _hostName = _sock._hostName;
  143. // we now own the lifetime of the socket
  144. GC.SuppressFinalize(_sock);
  145. Initialize(context, _socket);
  146. }
  147. }
  148. ~socket() {
  149. close(true, true);
  150. }
  151. public socket _sock {
  152. get {
  153. return this;
  154. }
  155. }
  156. private IAsyncResult _acceptResult;
  157. [Documentation("accept() -> (conn, address)\n\n"
  158. + "Accept a connection. The socket must be bound and listening before calling\n"
  159. + "accept(). conn is a new socket object connected to the remote host, and\n"
  160. + "address is the remote host's address (e.g. a (host, port) tuple for IPv4).\n"
  161. + "\n"
  162. )]
  163. public PythonTuple accept() {
  164. socket wrappedRemoteSocket;
  165. Socket realRemoteSocket;
  166. try {
  167. if (_acceptResult != null && _acceptResult.IsCompleted) {
  168. // previous async result has completed
  169. realRemoteSocket = _socket.EndAccept(_acceptResult);
  170. } else {
  171. int timeoutTime = _timeout;
  172. if (timeoutTime != 0) {
  173. // use the existing or create a new async request
  174. var asyncResult = _acceptResult ?? _socket.BeginAccept((x) => { }, null);
  175. if (asyncResult.AsyncWaitHandle.WaitOne(timeoutTime)) {
  176. // it's completed, end and throw it away
  177. realRemoteSocket = _socket.EndAccept(asyncResult);
  178. _acceptResult = null;
  179. } else {
  180. // save the async result for later incase it completes
  181. _acceptResult = asyncResult;
  182. throw PythonExceptions.CreateThrowable(timeout(_context), 0, "timeout");
  183. }
  184. } else {
  185. realRemoteSocket = _socket.Accept();
  186. }
  187. }
  188. } catch (Exception e) {
  189. throw MakeException(_context, e);
  190. }
  191. wrappedRemoteSocket = new socket(_context, realRemoteSocket);
  192. return PythonTuple.MakeTuple(wrappedRemoteSocket, wrappedRemoteSocket.getpeername());
  193. }
  194. [Documentation("bind(address) -> None\n\n"
  195. + "Bind to an address. If the socket is already bound, socket.error is raised.\n"
  196. + "For IP sockets, address is a (host, port) tuple. Raw sockets are not\n"
  197. + "supported.\n"
  198. + "\n"
  199. + "If you do not care which local address is assigned, set host to INADDR_ANY and\n"
  200. + "the system will assign the most appropriate network address. Similarly, if you\n"
  201. + "set port to 0, the system will assign an available port number between 1024\n"
  202. + "and 5000."
  203. )]
  204. public void bind(PythonTuple address) {
  205. IPEndPoint localEP = TupleToEndPoint(_context, address, _socket.AddressFamily, out _hostName);
  206. try {
  207. _socket.Bind(localEP);
  208. } catch (Exception e) {
  209. throw MakeException(_context, e);
  210. }
  211. }
  212. [Documentation("close() -> None\n\nClose the socket. It cannot be used after being closed.")]
  213. public void close() {
  214. close(false, false);
  215. }
  216. internal void close(bool finalizing, bool removeAll) {
  217. if (finalizing || removeAll || System.Threading.Interlocked.Decrement(ref _referenceCount) == 0) {
  218. if (_socket != null) {
  219. lock (_handleToSocket) {
  220. WeakReference weakref;
  221. if (_handleToSocket.TryGetValue(_socket.Handle, out weakref)) {
  222. Socket target = (weakref.Target as Socket);
  223. if (target == _socket || target == null) {
  224. _handleToSocket.Remove(_socket.Handle);
  225. }
  226. }
  227. }
  228. }
  229. _referenceCount = 0;
  230. if (!finalizing) {
  231. GC.SuppressFinalize(this);
  232. }
  233. if (_socket != null) {
  234. try {
  235. _socket.Close();
  236. } catch (Exception e) {
  237. if (!finalizing) {
  238. throw MakeException(_context, e);
  239. }
  240. }
  241. }
  242. }
  243. }
  244. [Documentation("connect(address) -> None\n\n"
  245. + "Connect to a remote socket at the given address. IP addresses are expressed\n"
  246. + "as (host, port).\n"
  247. + "\n"
  248. + "Raises socket.error if the socket has been closed, the socket is listening, or\n"
  249. + "another connection error occurred."
  250. + "\n"
  251. + "Difference from CPython: connect() does not support timeouts in blocking mode.\n"
  252. + "If a timeout is set and the socket is in blocking mode, connect() will block\n"
  253. + "indefinitely until a connection is made or an error occurs."
  254. )]
  255. public void connect(PythonTuple address) {
  256. IPEndPoint remoteEP = TupleToEndPoint(_context, address, _socket.AddressFamily, out _hostName);
  257. try {
  258. _socket.Connect(remoteEP);
  259. } catch (Exception e) {
  260. throw MakeException(_context, e);
  261. }
  262. }
  263. [Documentation("connect_ex(address) -> error_code\n\n"
  264. + "Like connect(), but return an error code insted of raising an exception for\n"
  265. + "socket exceptions raised by the underlying system Connect() call. Note that\n"
  266. + "exceptions other than SocketException generated by the system Connect() call\n"
  267. + "will still be raised.\n"
  268. + "\n"
  269. + "A return value of 0 indicates that the connect call was successful."
  270. + "\n"
  271. + "Difference from CPython: connect_ex() does not support timeouts in blocking\n"
  272. + "mode. If a timeout is set and the socket is in blocking mode, connect_ex() will\n"
  273. + "block indefinitely until a connection is made or an error occurs."
  274. )]
  275. public int connect_ex(PythonTuple address) {
  276. IPEndPoint remoteEP = TupleToEndPoint(_context, address, _socket.AddressFamily, out _hostName);
  277. try {
  278. _socket.Connect(remoteEP);
  279. } catch (SocketException e) {
  280. return e.ErrorCode;
  281. }
  282. return (int)SocketError.Success;
  283. }
  284. [Documentation("fileno() -> file_handle\n\n"
  285. + "Return the underlying system handle for this socket (a 64-bit integer)."
  286. )]
  287. public Int64 fileno() {
  288. try {
  289. return _socket.Handle.ToInt64();
  290. } catch (Exception e) {
  291. throw MakeException(_context, e);
  292. }
  293. }
  294. [Documentation("getpeername() -> address\n\n"
  295. + "Return the address of the remote end of this socket. The address format is\n"
  296. + "family-dependent (e.g. a (host, port) tuple for IPv4)."
  297. )]
  298. public PythonTuple getpeername() {
  299. try {
  300. IPEndPoint remoteEP = _socket.RemoteEndPoint as IPEndPoint;
  301. if (remoteEP == null) {
  302. throw MakeException(_context, new SocketException((int)SocketError.AddressFamilyNotSupported));
  303. }
  304. return EndPointToTuple(remoteEP);
  305. } catch (Exception e) {
  306. throw MakeException(_context, e);
  307. }
  308. }
  309. [Documentation("getsockname() -> address\n\n"
  310. + "Return the address of the local end of this socket. The address format is\n"
  311. + "family-dependent (e.g. a (host, port) tuple for IPv4)."
  312. )]
  313. public PythonTuple getsockname() {
  314. try {
  315. IPEndPoint localEP = _socket.LocalEndPoint as IPEndPoint;
  316. if (localEP == null) {
  317. throw MakeException(_context, new SocketException((int)SocketError.InvalidArgument));
  318. }
  319. return EndPointToTuple(localEP);
  320. } catch (Exception e) {
  321. throw MakeException(_context, e);
  322. }
  323. }
  324. [Documentation("getsockopt(level, optname[, buflen]) -> value\n\n"
  325. + "Return the value of a socket option. level is one of the SOL_* constants\n"
  326. + "defined in this module, and optname is one of the SO_* constants. If buflen is\n"
  327. + "omitted or zero, an integer value is returned. If it is present, a byte string\n"
  328. + "whose maximum length is buflen bytes) is returned. The caller must the decode\n"
  329. + "the resulting byte string."
  330. )]
  331. public object getsockopt(int optionLevel, int optionName, [DefaultParameterValue(0)] int optionLength) {
  332. SocketOptionLevel level = (SocketOptionLevel)Enum.ToObject(typeof(SocketOptionLevel), optionLevel);
  333. if (!Enum.IsDefined(typeof(SocketOptionLevel), level)) {
  334. throw MakeException(_context, new SocketException((int)SocketError.InvalidArgument));
  335. }
  336. SocketOptionName name = (SocketOptionName)Enum.ToObject(typeof(SocketOptionName), optionName);
  337. if (!Enum.IsDefined(typeof(SocketOptionName), name)) {
  338. throw MakeException(_context, new SocketException((int)SocketError.ProtocolOption));
  339. }
  340. try {
  341. if (optionLength == 0) {
  342. // Integer return value
  343. return (int)_socket.GetSocketOption(level, name);
  344. } else {
  345. // Byte string return value
  346. return _socket.GetSocketOption(level, name, optionLength).MakeString();
  347. }
  348. } catch (Exception e) {
  349. throw MakeException(_context, e);
  350. }
  351. }
  352. [Documentation("listen(backlog) -> None\n\n"
  353. + "Listen for connections on the socket. Backlog is the maximum length of the\n"
  354. + "pending connections queue. The maximum value is system-dependent."
  355. )]
  356. public void listen(int backlog) {
  357. try {
  358. _socket.Listen(backlog);
  359. } catch (Exception e) {
  360. throw MakeException(_context, e);
  361. }
  362. }
  363. [Documentation("makefile([mode[, bufsize]]) -> file object\n\n"
  364. + "Return a regular file object corresponding to the socket. The mode\n"
  365. + "and bufsize arguments are as for the built-in open() function.")]
  366. public PythonFile makefile([DefaultParameterValue("r")]string mode, [DefaultParameterValue(8192)]int bufSize) {
  367. System.Threading.Interlocked.Increment(ref _referenceCount); // dup our handle
  368. return new _fileobject(_context, this, mode, bufSize, false);
  369. }
  370. [Documentation("recv(bufsize[, flags]) -> string\n\n"
  371. + "Receive data from the socket, up to bufsize bytes. For connection-oriented\n"
  372. + "protocols (e.g. SOCK_STREAM), you must first call either connect() or\n"
  373. + "accept(). Connectionless protocols (e.g. SOCK_DGRAM) may also use recvfrom().\n"
  374. + "\n"
  375. + "recv() blocks until data is available, unless a timeout was set using\n"
  376. + "settimeout(). If the timeout was exceeded, socket.timeout is raised."
  377. + "recv() returns immediately with zero bytes when the connection is closed."
  378. )]
  379. public string recv(int maxBytes, [DefaultParameterValue(0)] int flags) {
  380. int bytesRead;
  381. byte[] buffer = new byte[maxBytes];
  382. try {
  383. bytesRead = _socket.Receive(buffer, (SocketFlags)flags);
  384. } catch (Exception e) {
  385. throw MakeException(_context, e);
  386. }
  387. return PythonOps.MakeString(buffer, bytesRead);
  388. }
  389. [Documentation("recv_into(buffer, [nbytes[, flags]]) -> nbytes_read\n\n"
  390. + "A version of recv() that stores its data into a buffer rather than creating\n"
  391. + "a new string. Receive up to buffersize bytes from the socket. If buffersize\n"
  392. + "is not specified (or 0), receive up to the size available in the given buffer.\n\n"
  393. + "See recv() for documentation about the flags.\n"
  394. )]
  395. public int recv_into(PythonBuffer buffer, [DefaultParameterValue(0)]int nbytes, [DefaultParameterValue(0)]int flags) {
  396. if (nbytes < 0) {
  397. throw PythonOps.ValueError("negative buffersize in recv_into");
  398. }
  399. throw PythonOps.TypeError("buffer is read-only");
  400. }
  401. [Documentation("recv_into(buffer, [nbytes[, flags]]) -> nbytes_read\n\n"
  402. + "A version of recv() that stores its data into a buffer rather than creating\n"
  403. + "a new string. Receive up to buffersize bytes from the socket. If buffersize\n"
  404. + "is not specified (or 0), receive up to the size available in the given buffer.\n\n"
  405. + "See recv() for documentation about the flags.\n"
  406. )]
  407. public int recv_into(string buffer, [DefaultParameterValue(0)]int nbytes, [DefaultParameterValue(0)]int flags) {
  408. throw PythonOps.TypeError("Cannot use string as modifiable buffer");
  409. }
  410. [Documentation("recv_into(buffer, [nbytes[, flags]]) -> nbytes_read\n\n"
  411. + "A version of recv() that stores its data into a buffer rather than creating\n"
  412. + "a new string. Receive up to buffersize bytes from the socket. If buffersize\n"
  413. + "is not specified (or 0), receive up to the size available in the given buffer.\n\n"
  414. + "See recv() for documentation about the flags.\n"
  415. )]
  416. public int recv_into(PythonArray buffer, [DefaultParameterValue(0)]int nbytes, [DefaultParameterValue(0)]int flags) {
  417. int bytesRead;
  418. byte[] byteBuffer = new byte[byteBufferSize("recv_into", nbytes, buffer.__len__(), buffer.itemsize)];
  419. try {
  420. bytesRead = _socket.Receive(byteBuffer, (SocketFlags)flags);
  421. } catch (Exception e) {
  422. throw MakeException(_context, e);
  423. }
  424. buffer.FromStream(new MemoryStream(byteBuffer), 0);
  425. return bytesRead;
  426. }
  427. [Documentation("recv_into(bytearray, [nbytes[, flags]]) -> nbytes_read\n\n"
  428. + "A version of recv() that stores its data into a bytearray rather than creating\n"
  429. + "a new string. Receive up to buffersize bytes from the socket. If buffersize\n"
  430. + "is not specified (or 0), receive up to the size available in the given buffer.\n\n"
  431. + "See recv() for documentation about the flags.\n"
  432. )]
  433. public int recv_into(ByteArray buffer, [DefaultParameterValue(0)]int nbytes, [DefaultParameterValue(0)]int flags) {
  434. int bytesRead;
  435. byte[] byteBuffer = new byte[byteBufferSize("recv_into", nbytes, buffer.Count, 1)];
  436. try {
  437. bytesRead = _socket.Receive(byteBuffer, (SocketFlags)flags);
  438. } catch (Exception e) {
  439. throw MakeException(_context, e);
  440. }
  441. for (int i = 0; i < bytesRead; i++) {
  442. buffer[i] = byteBuffer[i];
  443. }
  444. return bytesRead;
  445. }
  446. [Documentation("recvfrom(bufsize[, flags]) -> (string, address)\n\n"
  447. + "Receive data from the socket, up to bufsize bytes. string is the data\n"
  448. + "received, and address (whose format is protocol-dependent) is the address of\n"
  449. + "the socket from which the data was received."
  450. )]
  451. public PythonTuple recvfrom(int maxBytes, [DefaultParameterValue(0)] int flags) {
  452. if (maxBytes < 0) {
  453. throw PythonOps.ValueError("negative buffersize in recvfrom");
  454. }
  455. int bytesRead;
  456. byte[] buffer = new byte[maxBytes];
  457. IPEndPoint remoteIPEP = new IPEndPoint(IPAddress.Any, 0);
  458. EndPoint remoteEP = remoteIPEP;
  459. try {
  460. bytesRead = _socket.ReceiveFrom(buffer, (SocketFlags)flags, ref remoteEP);
  461. } catch (Exception e) {
  462. throw MakeException(_context, e);
  463. }
  464. string data = PythonOps.MakeString(buffer, bytesRead);
  465. PythonTuple remoteAddress = EndPointToTuple((IPEndPoint)remoteEP);
  466. return PythonTuple.MakeTuple(data, remoteAddress);
  467. }
  468. [Documentation("recvfrom_into(buffer[, nbytes[, flags]]) -> (nbytes, address info)\n\n"
  469. + "Like recv_into(buffer[, nbytes[, flags]]) but also return the sender's address info.\n"
  470. )]
  471. public PythonTuple recvfrom_into(PythonBuffer buffer, [DefaultParameterValue(0)]int nbytes, [DefaultParameterValue(0)]int flags) {
  472. if (nbytes < 0) {
  473. throw PythonOps.ValueError("negative buffersize in recvfrom_into");
  474. }
  475. throw PythonOps.TypeError("buffer is read-only");
  476. }
  477. [Documentation("recvfrom_into(buffer[, nbytes[, flags]]) -> (nbytes, address info)\n\n"
  478. + "Like recv_into(buffer[, nbytes[, flags]]) but also return the sender's address info.\n"
  479. )]
  480. public PythonTuple recvfrom_into(string buffer, [DefaultParameterValue(0)]int nbytes, [DefaultParameterValue(0)]int flags) {
  481. throw PythonOps.TypeError("Cannot use string as modifiable buffer");
  482. }
  483. [Documentation("recvfrom_into(buffer[, nbytes[, flags]]) -> (nbytes, address info)\n\n"
  484. + "Like recv_into(buffer[, nbytes[, flags]]) but also return the sender's address info.\n"
  485. )]
  486. public PythonTuple recvfrom_into(PythonArray buffer, [DefaultParameterValue(0)]int nbytes, [DefaultParameterValue(0)]int flags) {
  487. int bytesRead;
  488. byte[] byteBuffer = new byte[byteBufferSize("recvfrom_into", nbytes, buffer.__len__(), buffer.itemsize)];
  489. IPEndPoint remoteIPEP = new IPEndPoint(IPAddress.Any, 0);
  490. EndPoint remoteEP = remoteIPEP;
  491. try {
  492. bytesRead = _socket.ReceiveFrom(byteBuffer, (SocketFlags)flags, ref remoteEP);
  493. } catch (Exception e) {
  494. throw MakeException(_context, e);
  495. }
  496. buffer.FromStream(new MemoryStream(byteBuffer), 0);
  497. PythonTuple remoteAddress = EndPointToTuple((IPEndPoint)remoteEP);
  498. return PythonTuple.MakeTuple(bytesRead, remoteAddress);
  499. }
  500. private static int byteBufferSize(string funcName, int nbytes, int bufLength, int itemSize) {
  501. if (nbytes < 0) {
  502. throw PythonOps.ValueError("negative buffersize in " + funcName);
  503. } else if (nbytes == 0) {
  504. return bufLength * itemSize;
  505. } else {
  506. int remainder = nbytes % itemSize;
  507. return Math.Min(remainder == 0 ? nbytes : nbytes + itemSize - remainder,
  508. bufLength * itemSize);
  509. }
  510. }
  511. [Documentation("send(string[, flags]) -> bytes_sent\n\n"
  512. + "Send data to the remote socket. The socket must be connected to a remote\n"
  513. + "socket (by calling either connect() or accept(). Returns the number of bytes\n"
  514. + "sent to the remote socket.\n"
  515. + "\n"
  516. + "Note that the successful completion of a send() call does not mean that all of\n"
  517. + "the data was sent. The caller must keep track of the number of bytes sent and\n"
  518. + "retry the operation until all of the data has been sent.\n"
  519. + "\n"
  520. + "Also note that there is no guarantee that the data you send will appear on the\n"
  521. + "network immediately. To increase network efficiency, the underlying system may\n"
  522. + "delay transmission until a significant amount of outgoing data is collected. A\n"
  523. + "successful completion of the Send method means that the underlying system has\n"
  524. + "had room to buffer your data for a network send"
  525. )]
  526. public int send(string data, [DefaultParameterValue(0)] int flags) {
  527. byte[] buffer = data.MakeByteArray();
  528. try {
  529. return _socket.Send(buffer, (SocketFlags)flags);
  530. } catch (Exception e) {
  531. throw MakeException(_context, e);
  532. }
  533. }
  534. [Documentation("send(string[, flags]) -> bytes_sent\n\n"
  535. + "Send data to the remote socket. The socket must be connected to a remote\n"
  536. + "socket (by calling either connect() or accept(). Returns the number of bytes\n"
  537. + "sent to the remote socket.\n"
  538. + "\n"
  539. + "Note that the successful completion of a send() call does not mean that all of\n"
  540. + "the data was sent. The caller must keep track of the number of bytes sent and\n"
  541. + "retry the operation until all of the data has been sent.\n"
  542. + "\n"
  543. + "Also note that there is no guarantee that the data you send will appear on the\n"
  544. + "network immediately. To increase network efficiency, the underlying system may\n"
  545. + "delay transmission until a significant amount of outgoing data is collected. A\n"
  546. + "successful completion of the Send method means that the underlying system has\n"
  547. + "had room to buffer your data for a network send"
  548. )]
  549. public int send(PythonBuffer data, [DefaultParameterValue(0)] int flags) {
  550. byte[] buffer = data.ToString().MakeByteArray();
  551. try {
  552. return _socket.Send(buffer, (SocketFlags)flags);
  553. } catch (Exception e) {
  554. throw MakeException(_context, e);
  555. }
  556. }
  557. [Documentation("sendall(string[, flags]) -> None\n\n"
  558. + "Send data to the remote socket. The socket must be connected to a remote\n"
  559. + "socket (by calling either connect() or accept().\n"
  560. + "\n"
  561. + "Unlike send(), sendall() blocks until all of the data has been sent or until a\n"
  562. + "timeout or an error occurs. None is returned on success. If an error occurs,\n"
  563. + "there is no way to tell how much data, if any, was sent.\n"
  564. + "\n"
  565. + "Difference from CPython: timeouts do not function as you would expect. The\n"
  566. + "function is implemented using multiple calls to send(), so the timeout timer\n"
  567. + "is reset after each of those calls. That means that the upper bound on the\n"
  568. + "time that it will take for sendall() to return is the number of bytes in\n"
  569. + "string times the timeout interval.\n"
  570. + "\n"
  571. + "Also note that there is no guarantee that the data you send will appear on the\n"
  572. + "network immediately. To increase network efficiency, the underlying system may\n"
  573. + "delay transmission until a significant amount of outgoing data is collected. A\n"
  574. + "successful completion of the Send method means that the underlying system has\n"
  575. + "had room to buffer your data for a network send"
  576. )]
  577. public void sendall(string data, [DefaultParameterValue(0)] int flags) {
  578. byte[] buffer = data.MakeByteArray();
  579. try {
  580. int bytesTotal = buffer.Length;
  581. int bytesRemaining = bytesTotal;
  582. while (bytesRemaining > 0) {
  583. bytesRemaining -= _socket.Send(buffer, bytesTotal - bytesRemaining, bytesRemaining, (SocketFlags)flags);
  584. }
  585. } catch (Exception e) {
  586. throw MakeException(_context, e);
  587. }
  588. }
  589. [Documentation("sendall(string[, flags]) -> None\n\n"
  590. + "Send data to the remote socket. The socket must be connected to a remote\n"
  591. + "socket (by calling either connect() or accept().\n"
  592. + "\n"
  593. + "Unlike send(), sendall() blocks until all of the data has been sent or until a\n"
  594. + "timeout or an error occurs. None is returned on success. If an error occurs,\n"
  595. + "there is no way to tell how much data, if any, was sent.\n"
  596. + "\n"
  597. + "Difference from CPython: timeouts do not function as you would expect. The\n"
  598. + "function is implemented using multiple calls to send(), so the timeout timer\n"
  599. + "is reset after each of those calls. That means that the upper bound on the\n"
  600. + "time that it will take for sendall() to return is the number of bytes in\n"
  601. + "string times the timeout interval.\n"
  602. + "\n"
  603. + "Also note that there is no guarantee that the data you send will appear on the\n"
  604. + "network immediately. To increase network efficiency, the underlying system may\n"
  605. + "delay transmission until a significant amount of outgoing data is collected. A\n"
  606. + "successful completion of the Send method means that the underlying system has\n"
  607. + "had room to buffer your data for a network send"
  608. )]
  609. public void sendall(PythonBuffer data, [DefaultParameterValue(0)] int flags) {
  610. byte[] buffer = data.ToString().MakeByteArray();
  611. try {
  612. int bytesTotal = buffer.Length;
  613. int bytesRemaining = bytesTotal;
  614. while (bytesRemaining > 0) {
  615. bytesRemaining -= _socket.Send(buffer, bytesTotal - bytesRemaining, bytesRemaining, (SocketFlags)flags);
  616. }
  617. } catch (Exception e) {
  618. throw MakeException(_context, e);
  619. }
  620. }
  621. [Documentation("sendto(string[, flags], address) -> bytes_sent\n\n"
  622. + "Send data to the remote socket. The socket does not need to be connected to a\n"
  623. + "remote socket since the address is specified in the call to sendto(). Returns\n"
  624. + "the number of bytes sent to the remote socket.\n"
  625. + "\n"
  626. + "Blocking sockets will block until the all of the bytes in the buffer are sent.\n"
  627. + "Since a nonblocking Socket completes immediately, it might not send all of the\n"
  628. + "bytes in the buffer. It is your application's responsibility to keep track of\n"
  629. + "the number of bytes sent and to retry the operation until the application sends\n"
  630. + "all of the bytes in the buffer.\n"
  631. + "\n"
  632. + "Note that there is no guarantee that the data you send will appear on the\n"
  633. + "network immediately. To increase network efficiency, the underlying system may\n"
  634. + "delay transmission until a significant amount of outgoing data is collected. A\n"
  635. + "successful completion of the Send method means that the underlying system has\n"
  636. + "had room to buffer your data for a network send"
  637. )]
  638. public int sendto(string data, int flags, PythonTuple address) {
  639. byte[] buffer = data.MakeByteArray();
  640. EndPoint remoteEP = TupleToEndPoint(_context, address, _socket.AddressFamily, out _hostName);
  641. try {
  642. return _socket.SendTo(buffer, (SocketFlags)flags, remoteEP);
  643. } catch (Exception e) {
  644. throw MakeException(_context, e);
  645. }
  646. }
  647. [Documentation("")]
  648. public int sendto(string data, PythonTuple address) {
  649. return sendto(data, 0, address);
  650. }
  651. [Documentation("setblocking(flag) -> None\n\n"
  652. + "Set the blocking mode of the socket. If flag is 0, the socket will be set to\n"
  653. + "non-blocking mode; otherwise, it will be set to blocking mode. If the socket is\n"
  654. + "in blocking mode, and a method is called (such as send() or recv() which does\n"
  655. + "not complete immediately, the caller will block execution until the requested\n"
  656. + "operation completes. In non-blocking mode, a socket.timeout exception would\n"
  657. + "would be raised in this case.\n"
  658. + "\n"
  659. + "Note that changing blocking mode also affects the timeout setting:\n"
  660. + "setblocking(0) is equivalent to settimeout(0), and setblocking(1) is equivalent\n"
  661. + "to settimeout(None)."
  662. )]
  663. public void setblocking(int shouldBlock) {
  664. if (shouldBlock == 0) {
  665. settimeout(0);
  666. } else {
  667. settimeout(null);
  668. }
  669. }
  670. [Documentation("settimeout(value) -> None\n\n"
  671. + "Set a timeout on blocking socket methods. value may be either None or a\n"
  672. + "non-negative float, with one of the following meanings:\n"
  673. + " - None: disable timeouts and block indefinitely"
  674. + " - 0.0: don't block at all (return immediately if the operation can be\n"
  675. + " completed; raise socket.error otherwise)\n"
  676. + " - float > 0.0: block for up to the specified number of seconds; raise\n"
  677. + " socket.timeout if the operation cannot be completed in time\n"
  678. + "\n"
  679. + "settimeout(None) is equivalent to setblocking(1), and settimeout(0.0) is\n"
  680. + "equivalent to setblocking(0)."
  681. + "\n"
  682. + "If the timeout is non-zero and is less than 0.5, it will be set to 0.5. This\n"
  683. + "limitation is specific to IronPython.\n"
  684. )]
  685. public void settimeout(object timeout) {
  686. try {
  687. if (timeout == null) {
  688. _socket.Blocking = true;
  689. _socket.SendTimeout = 0;
  690. } else {
  691. double seconds;
  692. seconds = Converter.ConvertToDouble(timeout);
  693. if (seconds < 0) {
  694. throw PythonOps.TypeError("a non-negative float is required");
  695. }
  696. _socket.Blocking = seconds > 0; // 0 timeout means non-blocking mode
  697. _socket.SendTimeout = (int)(seconds * MillisecondsPerSecond);
  698. _timeout = (int)(seconds * MillisecondsPerSecond);
  699. }
  700. } finally {
  701. _socket.ReceiveTimeout = _socket.SendTimeout;
  702. }
  703. }
  704. [Documentation("gettimeout() -> value\n\n"
  705. + "Return the timeout duration in seconds for this socket as a float. If no\n"
  706. + "timeout is set, return None. For more details on timeouts and blocking, see the\n"
  707. + "Python socket module documentation."
  708. )]
  709. public object gettimeout() {
  710. try {
  711. if (_socket.Blocking && _socket.SendTimeout == 0) {
  712. return null;
  713. } else {
  714. return (double)_socket.SendTimeout / MillisecondsPerSecond;
  715. }
  716. } catch (Exception e) {
  717. throw MakeException(_context, e);
  718. }
  719. }
  720. [Documentation("setsockopt(level, optname[, value]) -> None\n\n"
  721. + "Set the value of a socket option. level is one of the SOL_* constants defined\n"
  722. + "in this module, and optname is one of the SO_* constants. value may be either\n"
  723. + "an integer or a string containing a binary structure. The caller is responsible\n"
  724. + "for properly encoding the byte string."
  725. )]
  726. public void setsockopt(int optionLevel, int optionName, object value) {
  727. SocketOptionLevel level = (SocketOptionLevel)Enum.ToObject(typeof(SocketOptionLevel), optionLevel);
  728. if (!Enum.IsDefined(typeof(SocketOptionLevel), level)) {
  729. throw MakeException(_context, new SocketException((int)SocketError.InvalidArgument));
  730. }
  731. SocketOptionName name = (SocketOptionName)Enum.ToObject(typeof(SocketOptionName), optionName);
  732. if (!Enum.IsDefined(typeof(SocketOptionName), name)) {
  733. throw MakeException(_context, new SocketException((int)SocketError.ProtocolOption));
  734. }
  735. try {
  736. int intValue;
  737. if (Converter.TryConvertToInt32(value, out intValue)) {
  738. _socket.SetSocketOption(level, name, intValue);
  739. return;
  740. }
  741. string strValue;
  742. if (Converter.TryConvertToString(value, out strValue)) {
  743. _socket.SetSocketOption(level, name, strValue.MakeByteArray());
  744. return;
  745. }
  746. } catch (Exception e) {
  747. throw MakeException(_context, e);
  748. }
  749. throw PythonOps.TypeError("setsockopt() argument 3 must be int or string");
  750. }
  751. [Documentation("shutdown() -> None\n\n"
  752. + "Return the timeout duration in seconds for this socket as a float. If no\n"
  753. + "timeout is set, return None. For more details on timeouts and blocking, see the\n"
  754. + "Python socket module documentation."
  755. )]
  756. public void shutdown(int how) {
  757. SocketShutdown howValue = (SocketShutdown)Enum.ToObject(typeof(SocketShutdown), how);
  758. if (!Enum.IsDefined(typeof(SocketShutdown), howValue)) {
  759. throw MakeException(_context, new SocketException((int)SocketError.InvalidArgument));
  760. }
  761. try {
  762. _socket.Shutdown(howValue);
  763. } catch (Exception e) {
  764. throw MakeException(_context, e);
  765. }
  766. }
  767. public int family {
  768. get { return (int)_socket.AddressFamily; }
  769. }
  770. public int type {
  771. get { return (int)_socket.SocketType; }
  772. }
  773. public int proto {
  774. get { return (int)_socket.ProtocolType; }
  775. }
  776. public int ioctl(BigInteger cmd, int option) {
  777. return _socket.IOControl((IOControlCode)(long)cmd, BitConverter.GetBytes(option), null);
  778. }
  779. public override string ToString() {
  780. try {
  781. return String.Format("<socket object, fd={0}, family={1}, type={2}, protocol={3}>",
  782. fileno(), family, type, proto);
  783. } catch {
  784. return "<socket object, fd=?, family=?, type=, protocol=>";
  785. }
  786. }
  787. /// <summary>
  788. /// Return the internal System.Net.Sockets.Socket socket object associated with the given
  789. /// handle (as returned by GetHandle()), or null if no corresponding socket exists. This is
  790. /// primarily intended to be used by other modules (such as select) that implement
  791. /// networking primitives. User code should not normally need to call this function.
  792. /// </summary>
  793. internal static Socket HandleToSocket(Int64 handle) {
  794. WeakReference weakref;
  795. lock (_handleToSocket) {
  796. if (_handleToSocket.TryGetValue((IntPtr)handle, out weakref)) {
  797. return (weakref.Target as Socket);
  798. }
  799. }
  800. return null;
  801. }
  802. #endregion
  803. #region IWeakReferenceable Implementation
  804. WeakRefTracker IWeakReferenceable.GetWeakRef() {
  805. return _weakRefTracker;
  806. }
  807. bool IWeakReferenceable.SetWeakRef(WeakRefTracker value) {
  808. _weakRefTracker = value;
  809. return true;
  810. }
  811. void IWeakReferenceable.SetFinalizer(WeakRefTracker value) {
  812. _weakRefTracker = value;
  813. }
  814. #endregion
  815. #region Private Implementation
  816. /// <summary>
  817. /// Create a Python socket object from an existing .NET socket object
  818. /// (like one returned from Socket.Accept())
  819. /// </summary>
  820. private socket(CodeContext/*!*/ context, Socket socket) {
  821. Initialize(context, socket);
  822. }
  823. /// <summary>
  824. /// Perform initialization common to all constructors
  825. /// </summary>
  826. private void Initialize(CodeContext context, Socket socket) {
  827. _socket = socket;
  828. _context = context;
  829. int? defaultTimeout = GetDefaultTimeout(context);
  830. if (defaultTimeout == null) {
  831. settimeout(null);
  832. } else {
  833. settimeout((double)defaultTimeout / MillisecondsPerSecond);
  834. }
  835. lock (_handleToSocket) {
  836. _handleToSocket[socket.Handle] = new WeakReference(socket);
  837. }
  838. }
  839. #endregion
  840. }
  841. #endregion
  842. #region Fields
  843. private const string AnyAddrToken = "";
  844. private const string BroadcastAddrToken = "<broadcast>";
  845. private const string LocalhostAddrToken = "";
  846. private const int IPv4AddrBytes = 4;
  847. private const int IPv6AddrBytes = 16;
  848. private const double MillisecondsPerSecond = 1000.0;
  849. #endregion
  850. #region Public API
  851. public static object _GLOBAL_DEFAULT_TIMEOUT = new object();
  852. [Documentation("Connect to *address* and return the socket object.\n\n"
  853. + "Convenience function. Connect to *address* (a 2-tuple ``(host,\n"
  854. + "port)``) and return the socket object. Passing the optional\n"
  855. + "*timeout* parameter will set the timeout on the socket instance\n"
  856. + "before attempting to connect. If no *timeout* is supplied, the\n"
  857. + "global default timeout setting returned by :func:`getdefaulttimeout`\n"
  858. + "is used.\n"
  859. )]
  860. public static socket create_connection(CodeContext/*!*/ context, PythonTuple address) {
  861. return create_connection(context, address, _GLOBAL_DEFAULT_TIMEOUT);
  862. }
  863. [Documentation("Connect to *address* and return the socket object.\n\n"
  864. + "Convenience function. Connect to *address* (a 2-tuple ``(host,\n"
  865. + "port)``) and return the socket object. Passing the optional\n"
  866. + "*timeout* parameter will set the timeout on the socket instance\n"
  867. + "before attempting to connect. If no *timeout* is supplied, the\n"
  868. + "global default timeout setting returned by :func:`getdefaulttimeout`\n"
  869. + "is used.\n"
  870. )]
  871. public static socket create_connection(CodeContext/*!*/ context, PythonTuple address, object timeout) {
  872. string msg = "getaddrinfo returns an empty list";
  873. string host = Converter.ConvertToString(address[0]);
  874. object port = address[1];
  875. IEnumerator en = getaddrinfo(context, host, port, 0, SOCK_STREAM, (int)ProtocolType.IP, (int)SocketFlags.None).GetEnumerator();
  876. while (en.MoveNext()) {
  877. PythonTuple current = (PythonTuple)en.Current;
  878. int family = Converter.ConvertToInt32(current[0]);
  879. int socktype = Converter.ConvertToInt32(current[1]);
  880. int proto = Converter.ConvertToInt32(current[2]);
  881. string name = Converter.ConvertToString(current[3]);
  882. PythonTuple sockaddress = (PythonTuple)current[4];
  883. socket socket = null;
  884. try {
  885. socket = new socket();
  886. socket.__init__(context, family, socktype, proto, null);
  887. if (timeout != _GLOBAL_DEFAULT_TIMEOUT) {
  888. socket.settimeout(timeout);
  889. }
  890. socket.connect(sockaddress);
  891. return socket;
  892. } catch (Exception ex) {
  893. if (PythonOps.CheckException(context, ex, error(context)) == null) {
  894. continue;
  895. }
  896. if (socket != null) {
  897. socket.close();
  898. }
  899. msg = ex.Message;
  900. }
  901. }
  902. throw PythonExceptions.CreateThrowableForRaise(context, error(context), msg);
  903. }
  904. [Documentation("")]
  905. public static List getaddrinfo(
  906. CodeContext/*!*/ context,
  907. string host,
  908. object port,
  909. [DefaultParameterValue((int)AddressFamily.Unspecified)] int family,
  910. [DefaultParameterValue(0)] int socktype,
  911. [DefaultParameterValue((int)ProtocolType.IP)] int proto,
  912. [DefaultParameterValue((int)SocketFlags.None)] int flags
  913. ) {
  914. int numericPort;
  915. if (port == null) {
  916. numericPort = 0;
  917. } else if (port is int) {
  918. numericPort = (int)port;
  919. } else if (port is Extensible<int>) {
  920. numericPort = ((Extensible<int>)port).Value;
  921. } else if (port is string) {
  922. if (!Int32.TryParse((string)port, out numericPort)) {
  923. // TODO: also should consult GetServiceByName
  924. throw PythonExceptions.CreateThrowable(gaierror(context), "getaddrinfo failed");
  925. }
  926. } else if (port is ExtensibleString) {
  927. if (!Int32.TryParse(((ExtensibleString)port).Value, out numericPort)) {
  928. // TODO: also should consult GetServiceByName
  929. throw PythonExceptions.CreateThrowable(gaierror(context), "getaddrinfo failed");
  930. }
  931. } else {
  932. throw PythonExceptions.CreateThrowable(gaierror(context), "getaddrinfo failed");
  933. }
  934. if (socktype != 0) {
  935. // we just use this to validate; socketType isn't actually used
  936. System.Net.Sockets.SocketType socketType = (System.Net.Sockets.SocketType)Enum.ToObject(typeof(System.Net.Sockets.SocketType), socktype);
  937. if (socketType == System.Net.Sockets.SocketType.Unknown || !Enum.IsDefined(typeof(System.Net.Sockets.SocketType), socketType)) {
  938. throw PythonExceptions.CreateThrowable(gaierror(context), PythonTuple.MakeTuple((int)SocketError.SocketNotSupported, "getaddrinfo failed"));
  939. }
  940. }
  941. AddressFamily addressFamily = (AddressFamily)Enum.ToObject(typeof(AddressFamily), family);
  942. if (!Enum.IsDefined(typeof(AddressFamily), addressFamily)) {
  943. throw PythonExceptions.CreateThrowable(gaierror(context), PythonTuple.MakeTuple((int)SocketError.AddressFamilyNotSupported, "getaddrinfo failed"));
  944. }
  945. // Again, we just validate, but don't actually use protocolType
  946. Enum.ToObject(typeof(ProtocolType), proto);
  947. IPAddress[] ips = HostToAddresses(context, host, addressFamily);
  948. List results = new List();
  949. foreach (IPAddress ip in ips) {
  950. results.append(PythonTuple.MakeTuple(
  951. (int)ip.AddressFamily,
  952. socktype,
  953. proto,
  954. "",
  955. EndPointToTuple(new IPEndPoint(ip, numericPort))
  956. ));
  957. }
  958. return results;
  959. }
  960. private static PythonType gaierror(CodeContext/*!*/ context) {
  961. return (PythonType)PythonContext.GetContext(context).GetModuleState("socketgaierror");
  962. }
  963. [Documentation("getfqdn([hostname_or_ip]) -> hostname\n\n"
  964. + "Return the fully-qualified domain name for the specified hostname or IP\n"
  965. + "address. An unspecified or empty name is interpreted as the local host. If the\n"
  966. + "name lookup fails, the passed-in name is returned as-is."
  967. )]
  968. public static string getfqdn(string host) {
  969. host = host.Trim();
  970. if (host == BroadcastAddrToken) {
  971. return host;
  972. }
  973. try {
  974. IPHostEntry hostEntry = Dns.GetHostEntry(host);
  975. if (hostEntry.HostName.Contains(".")) {
  976. return hostEntry.HostName;
  977. } else {
  978. foreach (string addr in hostEntry.Aliases) {
  979. if (addr.Contains(".")) {
  980. return addr;
  981. }
  982. }
  983. }
  984. } catch (SocketException) {
  985. // ignore and return host below
  986. }
  987. // seems to match CPython behavior, although docs say gethostname() should be returned
  988. return host;
  989. }
  990. [Documentation("")]
  991. public static string getfqdn() {
  992. return getfqdn(LocalhostAddrToken);
  993. }
  994. [Documentation("gethostbyname(hostname) -> ip address\n\n"
  995. + "Return the string IPv4 address associated with the given hostname (e.g.\n"
  996. + "'10.10.0.1'). The hostname is returned as-is if it an IPv4 address. The empty\n"
  997. + "string is treated as the local host.\n"
  998. + "\n"
  999. + "gethostbyname() doesn't support IPv6; for IPv4/IPv6 support, use getaddrinfo()."
  1000. )]
  1001. public static string gethostbyname(CodeContext/*!*/ context, string host) {
  1002. return HostToAddress(context, host, AddressFamily.InterNetwork).ToString();
  1003. }
  1004. [Documentation("gethostbyname_ex(hostname) -> (hostname, aliases, ip_addresses)\n\n"
  1005. + "Return the real host name, a list of aliases, and a list of IP addresses\n"
  1006. + "associated with the given hostname. If the hostname is an IPv4 address, the\n"
  1007. + "tuple ([hostname, [], [hostname]) is returned without doing a DNS lookup.\n"
  1008. + "\n"
  1009. + "gethostbyname_ex() doesn't support IPv6; for IPv4/IPv6 support, use\n"
  1010. + "getaddrinfo()."
  1011. )]
  1012. public static PythonTuple gethostbyname_ex(CodeContext/*!*/ context, string host) {
  1013. string hostname;
  1014. List aliases;
  1015. List ips = PythonOps.MakeList();
  1016. IPAddress addr;
  1017. if (IPAddress.TryParse(host, out addr)) {
  1018. if (AddressFamily.InterNetwork == addr.AddressFamily) {
  1019. hostname = host;
  1020. aliases = PythonOps.MakeEmptyList(0);
  1021. ips.append(host);
  1022. } else {
  1023. throw PythonExceptions.CreateThrowable(gaierror(context), (int)SocketError.HostNotFound, "no IPv4 addresses associated with host");
  1024. }
  1025. } else {
  1026. IPHostEntry hostEntry;
  1027. try {
  1028. hostEntry = Dns.GetHostEntry(host);
  1029. } catch (SocketException e) {
  1030. throw PythonExceptions.CreateThrowable(gaierror(context), e.ErrorCode, "no IPv4 addresses associated with host");
  1031. }
  1032. hostname = hostEntry.HostName;
  1033. aliases = PythonOps.MakeList(hostEntry.Aliases);
  1034. foreach (IPAddress ip in hostEntry.AddressList) {
  1035. if (AddressFamily.InterNetwork == ip.AddressFamily) {
  1036. ips.append(ip.ToString());
  1037. }
  1038. }
  1039. }
  1040. return PythonTuple.MakeTuple(hostname, aliases, ips);
  1041. }
  1042. [Documentation("gethostname() -> hostname\nReturn this machine's hostname")]
  1043. public static string gethostname() {
  1044. return Dns.GetHostName();
  1045. }
  1046. [Documentation("gethostbyaddr(host) -> (hostname, aliases, ipaddrs)\n\n"
  1047. + "Return a tuple of (primary hostname, alias hostnames, ip addresses). host may\n"
  1048. + "be either a hostname or an IP address."
  1049. )]
  1050. public static object gethostbyaddr(CodeContext/*!*/ context, string host) {
  1051. if (host == "") {
  1052. host = gethostname();
  1053. }
  1054. // This conversion seems to match CPython behavior
  1055. host = gethostbyname(context, host);
  1056. IPAddress[] ips = null;
  1057. IPHostEntry hostEntry = null;
  1058. try {
  1059. ips = Dns.GetHostAddresses(host);
  1060. hostEntry = Dns.GetHostEntry(host);
  1061. } catch (Exception e) {
  1062. throw MakeException(context, e);
  1063. }
  1064. List ipStrings = PythonOps.MakeList();
  1065. foreach (IPAddress ip in ips) {
  1066. ipStrings.append(ip.ToString());
  1067. }
  1068. return PythonTuple.MakeTuple(hostEntry.HostName, PythonOps.MakeList(hostEntry.Aliases), ipStrings);
  1069. }
  1070. [Documentation("getnameinfo(socketaddr, flags) -> (host, port)\n"
  1071. + "Given a socket address, the return a tuple of the corresponding hostname and\n"
  1072. + "port. Available flags:\n"
  1073. + " - NI_NOFQDN: Return only the hostname part of the domain name for hosts on the\n"
  1074. + " same domain as the executing machine.\n"
  1075. + " - NI_NUMERICHOST: return the numeric form of the host (e.g. '127.0.0.1' or\n"
  1076. + " '::1' rather than 'localhost').\n"
  1077. + " - NI_NAMEREQD: Raise an error if the hostname cannot be looked up.\n"
  1078. + " - NI_NUMERICSERV: Return string containing the numeric form of the port (e.g.\n"
  1079. + " '80' rather than 'http'). This flag is required (see below).\n"
  1080. + " - NI_DGRAM: Silently ignored (see below).\n"
  1081. + "\n"
  1082. + "Difference from CPython: the following flag behavior differs from CPython\n"
  1083. + "because the .NET framework libraries offer no name-to-port conversion APIs:\n"
  1084. + " - NI_NUMERICSERV: This flag is required because the .NET framework libraries\n"
  1085. + " offer no port-to-name mapping APIs. If it is omitted, getnameinfo() will\n"
  1086. + " raise a NotImplementedError.\n"
  1087. + " - The NI_DGRAM flag is ignored because it only applies when NI_NUMERICSERV is\n"
  1088. + " omitted. It it were supported, it would return the UDP-based port name\n"
  1089. + " rather than the TCP-based port name.\n"
  1090. )]
  1091. public static object getnameinfo(CodeContext/*!*/ context, PythonTuple socketAddr, int flags) {
  1092. if (socketAddr.__len__() < 2 || socketAddr.__len__() > 4) {
  1093. throw PythonOps.TypeError("socket address must be a 2-tuple (IPv4 or IPv6) or 4-tuple (IPv6)");
  1094. }
  1095. if ((flags & (int)NI_NUMERICSERV) == 0) {
  1096. throw PythonOps.NotImplementedError("getnameinfo() required the NI_NUMERICSERV flag (see docstring)");
  1097. }
  1098. string host = Converter.ConvertToString(socketAddr[0]);
  1099. if (host == null) throw PythonOps.TypeError("argument 1 must be string");
  1100. int port = 0;
  1101. try {
  1102. port = (int)socketAddr[1];
  1103. } catch (InvalidCastException) {
  1104. throw PythonOps.TypeError("an integer is required");
  1105. }
  1106. string resultHost = null;
  1107. string resultPort = null;
  1108. // Host
  1109. IPHostEntry hostEntry = null;
  1110. try {
  1111. // Do double lookup to force reverse DNS lookup to match CPython behavior
  1112. hostEntry = Dns.GetHostEntry(host);
  1113. if (hostEntry.AddressList.Length < 1) {
  1114. throw PythonExceptions.CreateThrowable(error(context), "sockaddr resolved to zero addresses");
  1115. }
  1116. hostEntry = Dns.GetHostEntry(hostEntry.AddressList[0]);
  1117. } catch (SocketException e) {
  1118. throw PythonExceptions.CreateThrowable(gaierror(context), e.ErrorCode, e.Message);
  1119. } catch (IndexOutOfRangeException) {
  1120. throw PythonExceptions.CreateThrowable(gaierror(context), "sockaddr resolved to zero addresses");
  1121. }
  1122. IList<IPAddress> addrs = hostEntry.AddressList;
  1123. if (addrs.Count > 1) {
  1124. // ignore non-IPV4 addresses
  1125. List<IPAddress> newAddrs = new List<IPAddress>(addrs.Count);
  1126. foreach (IPAddress addr in hostEntry.AddressList) {
  1127. if (addr.AddressFamily == AddressFamily.InterNetwork) {
  1128. newAddrs.Add(addr);
  1129. }
  1130. }
  1131. if (newAddrs.Count > 1) {
  1132. throw PythonExceptions.CreateThrowable(error(context), "sockaddr resolved to multiple addresses");
  1133. }
  1134. addrs = newAddrs;
  1135. }
  1136. if (addrs.Count < 1) {
  1137. throw PythonExceptions.CreateThrowable(error(context), "sockaddr resolved to zero addresses");
  1138. }
  1139. if ((flags & (int)NI_NUMERICHOST) != 0) {
  1140. resultHost = addrs[0].ToString();
  1141. } else if ((flags & (int)NI_NOFQDN) != 0) {
  1142. resultHost = RemoveLocalDomain(hostEntry.HostName);
  1143. } else {
  1144. resultHost = hostEntry.HostName;
  1145. }
  1146. // Port
  1147. // We don't branch on NI_NUMERICSERV here since we throw above if it's not set
  1148. resultPort = port.ToString();
  1149. return PythonTuple.MakeTuple(resultHost, resultPort);
  1150. }
  1151. [Documentation("getprotobyname(protoname) -> integer proto\n\n"
  1152. + "Given a string protocol name (e.g. \"udp\"), return the associated integer\n"
  1153. + "protocol number, suitable for passing to socket(). The name is case\n"
  1154. + "insensitive.\n"
  1155. + "\n"
  1156. + "Raises socket.error if no protocol number can be found."
  1157. )]
  1158. public static object getprotobyname(CodeContext/*!*/ context, string protocolName) {
  1159. switch (protocolName.ToLower()) {
  1160. case "ah": return IPPROTO_AH;
  1161. case "esp": return IPPROTO_ESP;
  1162. case "dstopts": return IPPROTO_DSTOPTS;
  1163. case "fragment": return IPPROTO_FRAGMENT;
  1164. case "ggp": return IPPROTO_GGP;
  1165. case "icmp": return IPPROTO_ICMP;
  1166. case "icmpv6": return IPPROTO_ICMPV6;
  1167. case "ip": return IPPROTO_IP;
  1168. case "ipv4": return IPPROTO_IPV4;
  1169. case "ipv6": return IPPROTO_IPV6;
  1170. case "nd": return IPPROTO_ND;
  1171. case "none": return IPPROTO_NONE;
  1172. case "pup": return IPPROTO_PUP;
  1173. case "raw": return IPPROTO_RAW;
  1174. case "routing": return IPPROTO_ROUTING;
  1175. case "tcp": return IPPROTO_TCP;
  1176. case "udp": return IPPROTO_UDP;
  1177. default:
  1178. throw PythonExceptions.CreateThrowable(error(context), "protocol not found");
  1179. }
  1180. }
  1181. [Documentation("getservbyname(service_name[, protocol_name]) -> port\n\n"
  1182. + "Not implemented."
  1183. //+ "Given a service name (e.g. 'domain') return the associated protocol number (e.g.\n"
  1184. //+ "53). The protocol name (if specified) must be either 'tcp' or 'udp'."
  1185. )]
  1186. public static int getservbyname(string serviceName, [DefaultParameterValue(null)] string protocolName) {
  1187. // !!! .NET networking libraries don't support this, so we don't either
  1188. throw PythonOps.NotImplementedError("name to service conversion not supported");
  1189. }
  1190. [Documentation("getservbyport(port[, protocol_name]) -> service_name\n\n"
  1191. + "Not implemented."
  1192. //+ "Given a port number (e.g. 53), return the associated protocol name (e.g.\n"
  1193. //+ "'domain'). The protocol name (if specified) must be either 'tcp' or 'udp'."
  1194. )]
  1195. public static string getservbyport(int port, [DefaultParameterValue(null)] string protocolName) {
  1196. // !!! .NET networking libraries don't support this, so we don't either
  1197. throw PythonOps.NotImplementedError("service to name conversion not supported");
  1198. }
  1199. [Documentation("ntohl(x) -> integer\n\nConvert a 32-bit integer from network byte order to host byte order.")]
  1200. public static object ntohl(object x) {
  1201. int res = IPAddress.NetworkToHostOrder(SignInsensitiveToInt32(x));
  1202. if (res < 0) {
  1203. return (BigInteger)(uint)res;
  1204. } else {
  1205. return res;
  1206. }
  1207. }
  1208. [Documentation("ntohs(x) -> integer\n\nConvert a 16-bit integer from network byte order to host byte order.")]
  1209. public static int ntohs(object x) {
  1210. return (int)(ushort)IPAddress.NetworkToHostOrder(SignInsensitiveToInt16(x));
  1211. }
  1212. [Documentation("htonl(x) -> integer\n\nConvert a 32bit integer from host byte order to network byte order.")]
  1213. public static object htonl(object x) {
  1214. int res = IPAddress.HostToNetworkOrder(SignInsensitiveToInt32(x));
  1215. if (res < 0) {
  1216. return (BigInteger)(uint)res;
  1217. } else {
  1218. return res;
  1219. }
  1220. }
  1221. [Documentation("htons(x) -> integer\n\nConvert a 16-bit integer from host byte order to network byte order.")]
  1222. public static int htons(object x) {
  1223. return (int)(ushort)IPAddress.HostToNetworkOrder(SignInsensitiveToInt16(x));
  1224. }
  1225. /// <summary>
  1226. /// Convert an object to a 32-bit integer. This adds two features to Converter.ToInt32:
  1227. /// 1. Sign is ignored. For example, 0xffff0000 converts to 4294901760, where Convert.ToInt32
  1228. /// would throw because 0xffff0000 is less than zero.
  1229. /// 2. Overflow exceptions are thrown. Converter.ToInt32 throws TypeError if x is
  1230. /// an integer, but is bigger than 32 bits. Instead, we throw OverflowException.
  1231. /// </summary>
  1232. private static int SignInsensitiveToInt32(object x) {
  1233. BigInteger bigValue = Converter.ConvertToBigInteger(x);
  1234. if (bigValue < 0) {
  1235. throw PythonOps.OverflowError("can't convert negative number to unsigned long");
  1236. } else if (bigValue <= int.MaxValue) {
  1237. return (int)bigValue;
  1238. } else {
  1239. return (int)(uint)bigValue;
  1240. }
  1241. }
  1242. /// <summary>
  1243. /// Convert an object to a 16-bit integer. This adds two features to Converter.ToInt16:
  1244. /// 1. Sign is ignored. For example, 0xff00 converts to 65280, where Convert.ToInt16
  1245. /// would throw because signed 0xff00 is -256.
  1246. /// 2. Overflow exceptions are thrown. Converter.ToInt16 throws TypeError if x is
  1247. /// an integer, but is bigger than 16 bits. Instead, we throw OverflowException.
  1248. /// </summary>
  1249. private static short SignInsensitiveToInt16(object x) {
  1250. BigInteger bigValue = Converter.ConvertToBigInteger(x);
  1251. if (bigValue < 0) {
  1252. throw PythonOps.OverflowError("can't convert negative number to unsigned long");
  1253. } else if (bigValue <= short.MaxValue) {
  1254. return (short)bigValue;
  1255. } else {
  1256. return (short)(ushort)bigValue;
  1257. }
  1258. }
  1259. [Documentation("inet_pton(addr_family, ip_string) -> packed_ip\n\n"
  1260. + "Convert an IP address (in string format, e.g. '127.0.0.1' or '::1') to a 32-bit\n"
  1261. + "packed binary format, as 4-byte (IPv4) or 16-byte (IPv6) string. The return\n"
  1262. + "format matches the format of the standard C library's in_addr or in6_addr\n"
  1263. + "struct.\n"
  1264. + "\n"
  1265. + "If the address format is invalid, socket.error will be raised. Validity is\n"
  1266. + "determined by the .NET System.Net.IPAddress.Parse() method.\n"
  1267. + "\n"
  1268. + "inet_pton() supports IPv4 and IPv6."
  1269. )]
  1270. public static string inet_pton(CodeContext/*!*/ context, int addressFamily, string ipString) {
  1271. if (addressFamily != (int)AddressFamily.InterNetwork && addressFamily != (int)AddressFamily.InterNetworkV6) {
  1272. throw MakeException(context, new SocketException((int)SocketError.AddressFamilyNotSupported));
  1273. }
  1274. IPAddress ip;
  1275. try {
  1276. ip = IPAddress.Parse(ipString);
  1277. if (addressFamily != (int)ip.AddressFamily) {
  1278. throw MakeException(context, new SocketException((int)SocketError.AddressFamilyNotSupported));
  1279. }
  1280. } catch (FormatException) {
  1281. throw PythonExceptions.CreateThrowable(error(context), "illegal IP address passed to inet_pton");
  1282. }
  1283. return ip.GetAddressBytes().MakeString();
  1284. }
  1285. [Documentation("inet_ntop(address_family, packed_ip) -> ip_string\n\n"
  1286. + "Convert a packed IP address (a 4-byte [IPv4] or 16-byte [IPv6] string) to a\n"
  1287. + "string IP address (e.g. '127.0.0.1' or '::1').\n"
  1288. + "\n"
  1289. + "The input format matches the format of the standard C library's in_addr or\n"
  1290. + "in6_addr struct. If the input string is not exactly 4 bytes or 16 bytes,\n"
  1291. + "socket.error will be raised.\n"
  1292. + "\n"
  1293. + "inet_ntop() supports IPv4 and IPv6."
  1294. )]
  1295. public static string inet_ntop(CodeContext/*!*/ context, int addressFamily, string packedIP) {
  1296. if (!(
  1297. (packedIP.Length == IPv4AddrBytes && addressFamily == (int)AddressFamily.InterNetwork)
  1298. || (packedIP.Length == IPv6AddrBytes && addressFamily == (int)AddressFamily.InterNetworkV6)
  1299. )) {
  1300. throw PythonExceptions.CreateThrowable(error(context), "invalid length of packed IP address string");
  1301. }
  1302. byte[] ipBytes = packedIP.MakeByteArray();
  1303. if (addressFamily == (int)AddressFamily.InterNetworkV6) {
  1304. return IPv6BytesToColonHex(ipBytes);
  1305. }
  1306. return (new IPAddress(ipBytes)).ToString();
  1307. }
  1308. [Documentation("inet_aton(ip_string) -> packed_ip\n"
  1309. + "Convert an IP address (in string dotted quad format, e.g. '127.0.0.1') to a\n"
  1310. + "32-bit packed binary format, as four-character string. The return format\n"
  1311. + "matches the format of the standard C library's in_addr struct.\n"
  1312. + "\n"
  1313. + "If the address format is invalid, socket.error will be raised. Validity is\n"
  1314. + "determined by the .NET System.Net.IPAddress.Parse() method.\n"
  1315. + "\n"
  1316. + "inet_aton() supports only IPv4."
  1317. )]
  1318. public static string inet_aton(CodeContext/*!*/ context, string ipString) {
  1319. return inet_pton(context, (int)AddressFamily.InterNetwork, ipString);
  1320. }
  1321. [Documentation("inet_ntoa(packed_ip) -> ip_string\n\n"
  1322. + "Convert a packed IP address (a 4-byte string) to a string IP address (in dotted\n"
  1323. + "quad format, e.g. '127.0.0.1'). The input format matches the format of the\n"
  1324. + "standard C library's in_addr struct.\n"
  1325. + "\n"
  1326. + "If the input string is not exactly 4 bytes, socket.error will be raised.\n"
  1327. + "\n"
  1328. + "inet_ntoa() supports only IPv4."
  1329. )]
  1330. public static string inet_ntoa(CodeContext/*!*/ context, string packedIP) {
  1331. return inet_ntop(context, (int)AddressFamily.InterNetwork, packedIP);
  1332. }
  1333. [Documentation("getdefaulttimeout() -> timeout\n\n"
  1334. + "Return the default timeout for new socket objects in seconds as a float. A\n"
  1335. + "value of None means that sockets have no timeout and begin in blocking mode.\n"
  1336. + "The default value when the module is imported is None."
  1337. )]
  1338. public static object getdefaulttimeout(CodeContext/*!*/ context) {
  1339. int? defaultTimeout = GetDefaultTimeout(context);
  1340. if (defaultTimeout == null) {
  1341. return null;
  1342. } else {
  1343. return (double)(defaultTimeout.Value) / MillisecondsPerSecond;
  1344. }
  1345. }
  1346. [Documentation("setdefaulttimeout(timeout) -> None\n\n"
  1347. + "Set the default timeout for new socket objects. timeout must be either None,\n"
  1348. + "meaning that sockets have no timeout and start in blocking mode, or a\n"
  1349. + "non-negative float that specifies the default timeout in seconds."
  1350. )]
  1351. public static void setdefaulttimeout(CodeContext/*!*/ context, object timeout) {
  1352. if (timeout == null) {
  1353. SetDefaultTimeout(context, null);
  1354. } else {
  1355. double seconds;
  1356. seconds = Converter.ConvertToDouble(timeout);
  1357. if (seconds < 0) {
  1358. throw PythonOps.ValueError("a non-negative float is required");
  1359. }
  1360. SetDefaultTimeout(context, (int)(seconds * MillisecondsPerSecond));
  1361. }
  1362. }
  1363. #endregion
  1364. #region Exported constants
  1365. public const int AF_APPLETALK = (int)AddressFamily.AppleTalk;
  1366. public const int AF_DECnet = (int)AddressFamily.DecNet;
  1367. public const int AF_INET = (int)AddressFamily.InterNetwork;
  1368. public const int AF_INET6 = (int)AddressFamily.InterNetworkV6;
  1369. public const int AF_IPX = (int)AddressFamily.Ipx;
  1370. public const int AF_IRDA = (int)AddressFamily.Irda;
  1371. public const int AF_SNA = (int)AddressFamily.Sna;
  1372. public const int AF_UNSPEC = (int)AddressFamily.Unspecified;
  1373. public const int AI_CANONNAME = (int)0x2;
  1374. public const int AI_NUMERICHOST = (int)0x4;
  1375. public const int AI_PASSIVE = (int)0x1;
  1376. public const int EAI_AGAIN = (int)SocketError.TryAgain;
  1377. public const int EAI_BADFLAGS = (int)SocketError.InvalidArgument;
  1378. public const int EAI_FAIL = (int)SocketError.NoRecovery;
  1379. public const int EAI_FAMILY = (int)SocketError.AddressFamilyNotSupported;
  1380. public const int EAI_MEMORY = (int)SocketError.NoBufferSpaceAvailable;
  1381. public const int EAI_NODATA = (int)SocketError.HostNotFound; // not SocketError.NoData, like you would think
  1382. public const int EAI_NONAME = (int)SocketError.HostNotFound;
  1383. public const int EAI_SERVICE = (int)SocketError.TypeNotFound;
  1384. public const int EAI_SOCKTYPE = (int)SocketError.SocketNotSupported;
  1385. public const int EAI_SYSTEM = (int)SocketError.SocketError;
  1386. public const int EBADF = (int)0x9;
  1387. public const int INADDR_ALLHOSTS_GROUP = unchecked((int)0xe0000001);
  1388. public const int INADDR_ANY = (int)0x00000000;
  1389. public const int INADDR_BROADCAST = unchecked((int)0xFFFFFFFF);
  1390. public const int INADDR_LOOPBACK = unchecked((int)0x7F000001);
  1391. public const int INADDR_MAX_LOCAL_GROUP = unchecked((int)0xe00000FF);
  1392. public const int INADDR_NONE = unchecked((int)0xFFFFFFFF);
  1393. public const int INADDR_UNSPEC_GROUP = unchecked((int)0xE0000000);
  1394. public const int IPPORT_RESERVED = 1024;
  1395. public const int IPPORT_USERRESERVED = 5000;
  1396. public const int IPPROTO_AH = (int)ProtocolType.IPSecAuthenticationHeader;
  1397. public const int IPPROTO_DSTOPTS = (int)ProtocolType.IPv6DestinationOptions;
  1398. public const int IPPROTO_ESP = (int)ProtocolType.IPSecEncapsulatingSecurityPayload;
  1399. public const int IPPROTO_FRAGMENT = (int)ProtocolType.IPv6FragmentHeader;
  1400. public const int IPPROTO_GGP = (int)ProtocolType.Ggp;
  1401. public const int IPPROTO_HOPOPTS = (int)ProtocolType.IPv6HopByHopOptions;
  1402. public const int IPPROTO_ICMP = (int)ProtocolType.Icmp;
  1403. public const int IPPROTO_ICMPV6 = (int)ProtocolType.IcmpV6;
  1404. public const int IPPROTO_IDP = (int)ProtocolType.Idp;
  1405. public const int IPPROTO_IGMP = (int)ProtocolType.Igmp;
  1406. public const int IPPROTO_IP = (int)ProtocolType.IP;
  1407. public const int IPPROTO_IPV4 = (int)ProtocolType.IPv4;
  1408. public const int IPPROTO_IPV6 = (int)ProtocolType.IPv6;
  1409. public const int IPPROTO_MAX = 256;
  1410. public const int IPPROTO_ND = (int)ProtocolType.ND;
  1411. public const int IPPROTO_NONE = (int)ProtocolType.IPv6NoNextHeader;
  1412. public const int IPPROTO_PUP = (int)ProtocolType.Pup;
  1413. public const int IPPROTO_RAW = (int)ProtocolType.Raw;
  1414. public const int IPPROTO_ROUTING = (int)ProtocolType.IPv6RoutingHeader;
  1415. public const int IPPROTO_TCP = (int)ProtocolType.Tcp;
  1416. public const int IPPROTO_UDP = (int)ProtocolType.Udp;
  1417. public const int IPV6_HOPLIMIT = (int)SocketOptionName.HopLimit;
  1418. public const int IPV6_JOIN_GROUP = (int)SocketOptionName.AddMembership;
  1419. public const int IPV6_LEAVE_GROUP = (int)SocketOptionName.DropMembership;
  1420. public const int IPV6_MULTICAST_HOPS = (int)SocketOptionName.MulticastTimeToLive;
  1421. public const int IPV6_MULTICAST_IF = (int)SocketOptionName.MulticastInterface;
  1422. public const int IPV6_MULTICAST_LOOP = (int)SocketOptionName.MulticastLoopback;
  1423. public const int IPV6_PKTINFO = (int)SocketOptionName.PacketInformation;
  1424. public const int IPV6_UNICAST_HOPS = (int)SocketOptionName.IpTimeToLive;
  1425. public const int IP_ADD_MEMBERSHIP = (int)SocketOptionName.AddMembership;
  1426. public const int IP_DROP_MEMBERSHIP = (int)SocketOptionName.DropMembership;
  1427. public const int IP_HDRINCL = (int)SocketOptionName.HeaderIncluded;
  1428. public const int IP_MULTICAST_IF = (int)SocketOptionName.MulticastInterface;
  1429. public const int IP_MULTICAST_LOOP = (int)SocketOptionName.MulticastLoopback;
  1430. public const int IP_MULTICAST_TTL = (int)SocketOptionName.MulticastTimeToLive;
  1431. public const int IP_OPTIONS = (int)SocketOptionName.IPOptions;
  1432. public const int IP_TOS = (int)SocketOptionName.TypeOfService;
  1433. public const int IP_TTL = (int)SocketOptionName.IpTimeToLive;
  1434. public const int MSG_DONTROUTE = (int)SocketFlags.DontRoute;
  1435. public const int MSG_OOB = (int)SocketFlags.OutOfBand;
  1436. public const int MSG_PEEK = (int)SocketFlags.Peek;
  1437. public const int NI_DGRAM = 0x0010;
  1438. public const int NI_MAXHOST = 1025;
  1439. public const int NI_MAXSERV = 32;
  1440. public const int NI_NAMEREQD = 0x0004;
  1441. public const int NI_NOFQDN = 0x0001;
  1442. public const int NI_NUMERICHOST = 0x0002;
  1443. public const int NI_NUMERICSERV = 0x0008;
  1444. public const int SHUT_RD = (int)SocketShutdown.Receive;
  1445. public const int SHUT_RDWR = (int)SocketShutdown.Both;
  1446. public const int SHUT_WR = (int)SocketShutdown.Send;
  1447. public const int SOCK_DGRAM = (int)System.Net.Sockets.SocketType.Dgram;
  1448. public const int SOCK_RAW = (int)System.Net.Sockets.SocketType.Raw;
  1449. public const int SOCK_RDM = (int)System.Net.Sockets.SocketType.Rdm;
  1450. public const int SOCK_SEQPACKET = (int)System.Net.Sockets.SocketType.Seqpacket;
  1451. public const int SOCK_STREAM = (int)System.Net.Sockets.SocketType.Stream;
  1452. public const int SOL_IP = (int)SocketOptionLevel.IP;
  1453. public const int SOL_IPV6 = (int)SocketOptionLevel.IPv6;
  1454. public const int SOL_SOCKET = (int)SocketOptionLevel.Socket;
  1455. public const int SOL_TCP = (int)SocketOptionLevel.Tcp;
  1456. public const int SOL_UDP = (int)SocketOptionLevel.Udp;
  1457. public const int SOMAXCONN = (int)SocketOptionName.MaxConnections;
  1458. public const int SO_ACCEPTCONN = (int)SocketOptionName.AcceptConnection;
  1459. public const int SO_BROADCAST = (int)SocketOptionName.Broadcast;
  1460. public const int SO_DEBUG = (int)SocketOptionName.Debug;
  1461. public const int SO_DONTROUTE = (int)SocketOptionName.DontRoute;
  1462. public const int SO_ERROR = (int)SocketOptionName.Error;
  1463. public const int SO_EXCLUSIVEADDRUSE = (int)SocketOptionName.ExclusiveAddressUse;
  1464. public const int SO_KEEPALIVE = (int)SocketOptionName.KeepAlive;
  1465. public const int SO_LINGER = (int)SocketOptionName.Linger;
  1466. public const int SO_OOBINLINE = (int)SocketOptionName.OutOfBandInline;
  1467. public const int SO_RCVBUF = (int)SocketOptionName.ReceiveBuffer;
  1468. public const int SO_RCVLOWAT = (int)SocketOptionName.ReceiveLowWater;
  1469. public const int SO_RCVTIMEO = (int)SocketOptionName.ReceiveTimeout;
  1470. public const int SO_REUSEADDR = (int)SocketOptionName.ReuseAddress;
  1471. public const int SO_SNDBUF = (int)SocketOptionName.SendBuffer;
  1472. public const int SO_SNDLOWAT = (int)SocketOptionName.SendLowWater;
  1473. public const int SO_SNDTIMEO = (int)SocketOptionName.SendTimeout;
  1474. public const int SO_TYPE = (int)SocketOptionName.Type;
  1475. public const int SO_USELOOPBACK = (int)SocketOptionName.UseLoopback;
  1476. public const int TCP_NODELAY = (int)SocketOptionName.NoDelay;
  1477. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")]
  1478. public static readonly BigInteger SIO_RCVALL = (long)IOControlCode.ReceiveAll;
  1479. public const int RCVALL_ON = 1;
  1480. public const int RCVALL_OFF = 0;
  1481. public const int RCVALL_SOCKETLEVELONLY = 2;
  1482. public const int RCVALL_MAX = 3;
  1483. public const int has_ipv6 = (int)1;
  1484. #endregion
  1485. #region Private implementation
  1486. /// <summary>
  1487. /// Return a standard socket exception (socket.error) whose message and error code come from a SocketException
  1488. /// This will eventually be enhanced to generate the correct error type (error, herror, gaierror) based on the error code.
  1489. /// </summary>
  1490. internal static Exception MakeException(CodeContext/*!*/ context, Exception exception) {
  1491. // !!! this shouldn't just blindly set the type to error (see summary)
  1492. if (exception is SocketException) {
  1493. SocketException se = (SocketException)exception;
  1494. switch (se.SocketErrorCode) {
  1495. case SocketError.NotConnected: // CPython times out when the socket isn't connected.
  1496. case SocketError.TimedOut:
  1497. return PythonExceptions.CreateThrowable(timeout(context), se.ErrorCode, se.Message);
  1498. default:
  1499. return PythonExceptions.CreateThrowable(error(context), se.ErrorCode, se.Message);
  1500. }
  1501. } else if (exception is ObjectDisposedException) {
  1502. return PythonExceptions.CreateThrowable(error(context), (int)EBADF, "the socket is closed");
  1503. } else if (exception is InvalidOperationException) {
  1504. return MakeException(context, new SocketException((int)SocketError.InvalidArgument));
  1505. } else {
  1506. return exception;
  1507. }
  1508. }
  1509. /// <summary>
  1510. /// Convert an IPv6 address byte array to a string in standard colon-hex notation.
  1511. /// The .NET IPAddress.ToString() method uses dotted-quad for the last 32 bits,
  1512. /// which differs from the normal Python implementation (but is allowed by the IETF);
  1513. /// this method returns the standard (no dotted-quad) colon-hex form.
  1514. /// </summary>
  1515. private static string IPv6BytesToColonHex(byte[] ipBytes) {
  1516. Debug.Assert(ipBytes.Length == IPv6AddrBytes);
  1517. const int bytesPerWord = 2; // in bytes
  1518. const int bitsPerByte = 8;
  1519. int[] words = new int[IPv6AddrBytes / bytesPerWord];
  1520. // Convert to array of 16-bit words
  1521. for (int i = 0; i < words.Length; i++) {
  1522. for (int j = 0; j < bytesPerWord; j++) {
  1523. words[i] <<= bitsPerByte;
  1524. words[i] += ipBytes[i * bytesPerWord + j];
  1525. }
  1526. }
  1527. // Find longest series of 0-valued words (to collapse to ::)
  1528. int longestStart = 0;
  1529. int longestLen = 0;
  1530. for (int i = 0; i < words.Length; i++) {
  1531. if (words[i] == 0) {
  1532. for (int j = i; j < words.Length; j++) {
  1533. if (words[j] != 0) {
  1534. i += longestLen;
  1535. break;
  1536. }
  1537. if (j - i + 1 > longestLen) {
  1538. longestStart = i;
  1539. longestLen = j - i + 1;
  1540. }
  1541. }
  1542. }
  1543. }
  1544. // Build colon-hex string
  1545. StringBuilder result = new StringBuilder(IPv6AddrBytes * 3);
  1546. for (int i = 0; i < words.Length; i++) {
  1547. if (i != 0) result.Append(':');
  1548. if (longestLen > 0 && i == longestStart) {
  1549. if (longestStart == 0) result.Append(':');
  1550. if (longestStart + longestLen == words.Length) result.Append(':');
  1551. i += longestLen - 1;
  1552. continue;
  1553. } else {
  1554. result.Append(words[i].ToString("x"));
  1555. }
  1556. }
  1557. return result.ToString();
  1558. }
  1559. /// <summary>
  1560. /// Handle conversion of "" to INADDR_ANY and "&lt;broadcast&gt;" to INADDR_BROADCAST.
  1561. /// Otherwise returns host unchanged.
  1562. /// </summary>
  1563. private static string ConvertSpecialAddresses(string host) {
  1564. switch (host) {
  1565. case AnyAddrToken:
  1566. return IPAddress.Any.ToString();
  1567. case BroadcastAddrToken:
  1568. return IPAddress.Broadcast.ToString();
  1569. default:
  1570. return host;
  1571. }
  1572. }
  1573. /// <summary>
  1574. /// Return the IP address associated with host, with optional address family checking.
  1575. /// host may be either a name or an IP address (in string form).
  1576. ///
  1577. /// If family is non-null, a gaierror will be thrown if the host's address family is
  1578. /// not the same as the specified family. gaierror is also raised if the hostname cannot be
  1579. /// converted to an IP address (e.g. through a name lookup failure).
  1580. /// </summary>
  1581. private static IPAddress HostToAddress(CodeContext/*!*/ context, string host, AddressFamily family) {
  1582. return HostToAddresses(context, host, family)[0];
  1583. }
  1584. /// <summary>
  1585. /// Return the IP address associated with host, with optional address family checking.
  1586. /// host may be either a name or an IP address (in string form).
  1587. ///
  1588. /// If family is non-null, a gaierror will be thrown if the host's address family is
  1589. /// not the same as the specified family. gaierror is also raised if the hostname cannot be
  1590. /// converted to an IP address (e.g. through a name lookup failure).
  1591. /// </summary>
  1592. private static IPAddress[] HostToAddresses(CodeContext/*!*/ context, string host, AddressFamily family) {
  1593. host = ConvertSpecialAddresses(host);
  1594. try {
  1595. IPAddress addr;
  1596. bool numeric = true;
  1597. int dotCount = 0;
  1598. foreach (char c in host) {
  1599. if (!Char.IsNumber(c) && c != '.') {
  1600. numeric = false;
  1601. } else if (c == '.') {
  1602. dotCount++;
  1603. }
  1604. }
  1605. if (numeric) {
  1606. if (dotCount == 3 && IPAddress.TryParse(host, out addr)) {
  1607. if (family == AddressFamily.Unspecified || family == addr.AddressFamily) {
  1608. return new IPAddress[] { addr };
  1609. }
  1610. }
  1611. // Incorrect family will raise exception below
  1612. } else {
  1613. IPHostEntry hostEntry = Dns.GetHostEntry(host);
  1614. List<IPAddress> addrs = new List<IPAddress>();
  1615. foreach (IPAddress ip in hostEntry.AddressList) {
  1616. if (family == AddressFamily.Unspecified || family == ip.AddressFamily) {
  1617. addrs.Add(ip);
  1618. }
  1619. }
  1620. if (addrs.Count > 0) return addrs.ToArray();
  1621. }
  1622. throw new SocketException((int)SocketError.HostNotFound);
  1623. } catch (SocketException e) {
  1624. throw PythonExceptions.CreateThrowable(gaierror(context), e.ErrorCode, "no addresses of the specified family associated with host");
  1625. }
  1626. }
  1627. /// <summary>
  1628. /// Return fqdn, but with its domain removed if it's on the same domain as the local machine.
  1629. /// </summary>
  1630. private static string RemoveLocalDomain(string fqdn) {
  1631. char[] DNS_SEP = new char[] { '.' };
  1632. string[] myName = getfqdn().Split(DNS_SEP, 2);
  1633. string[] otherName = fqdn.Split(DNS_SEP, 2);
  1634. if (myName.Length < 2 || otherName.Length < 2) return fqdn;
  1635. if (myName[1] == otherName[1]) {
  1636. return otherName[0];
  1637. } else {
  1638. return fqdn;
  1639. }
  1640. }
  1641. /// <summary>
  1642. /// Convert a (host, port) tuple [IPv4] (host, port, flowinfo, scopeid) tuple [IPv6]
  1643. /// to its corresponding IPEndPoint.
  1644. ///
  1645. /// Throws gaierror if host is not a valid address.
  1646. /// Throws ArgumentTypeException if any of the following are true:
  1647. /// - address does not have exactly two elements
  1648. /// - address[0] is not a string
  1649. /// - address[1] is not an int
  1650. /// </summary>
  1651. private static IPEndPoint TupleToEndPoint(CodeContext/*!*/ context, PythonTuple address, AddressFamily family, out string host) {
  1652. if (address.__len__() != 2 && address.__len__() != 4) {
  1653. throw PythonOps.TypeError("address tuple must have exactly 2 (IPv4) or exactly 4 (IPv6) elements");
  1654. }
  1655. try {
  1656. host = Converter.ConvertToString(address[0]);
  1657. } catch (ArgumentTypeException) {
  1658. throw PythonOps.TypeError("host must be string");
  1659. }
  1660. int port;
  1661. try {
  1662. port = PythonContext.GetContext(context).ConvertToInt32(address[1]);
  1663. } catch (ArgumentTypeException) {
  1664. throw PythonOps.TypeError("port must be integer");
  1665. }
  1666. IPAddress ip = HostToAddress(context, host, family);
  1667. if (address.__len__() == 2) {
  1668. return new IPEndPoint(ip, port);
  1669. } else {
  1670. try {
  1671. Converter.ConvertToInt64(address[2]);
  1672. } catch (ArgumentTypeException) {
  1673. throw PythonOps.TypeError("flowinfo must be integer");
  1674. }
  1675. // We don't actually do anything with flowinfo right now, but we validate it
  1676. // in case we want to do something in the future.
  1677. long scopeId;
  1678. try {
  1679. scopeId = Converter.ConvertToInt64(address[3]);
  1680. } catch (ArgumentTypeException) {
  1681. throw PythonOps.TypeError("scopeid must be integer");
  1682. }
  1683. IPEndPoint endPoint = new IPEndPoint(ip, port);
  1684. endPoint.Address.ScopeId = scopeId;
  1685. return endPoint;
  1686. }
  1687. }
  1688. /// <summary>
  1689. /// Convert an IPEndPoint to its corresponding (host, port) [IPv4] or (host, port, flowinfo, scopeid) [IPv6] tuple.
  1690. /// Throws SocketException if the address family is other than IPv4 or IPv6.
  1691. /// </summary>
  1692. private static PythonTuple EndPointToTuple(IPEndPoint endPoint) {
  1693. string ip = endPoint.Address.ToString();
  1694. int port = endPoint.Port;
  1695. switch (endPoint.Address.AddressFamily) {
  1696. case AddressFamily.InterNetwork:
  1697. return PythonTuple.MakeTuple(ip, port);
  1698. case AddressFamily.InterNetworkV6:
  1699. long flowInfo = 0; // RFC 3493 p. 7
  1700. long scopeId = endPoint.Address.ScopeId;
  1701. return PythonTuple.MakeTuple(ip, port, flowInfo, scopeId);
  1702. default:
  1703. throw new SocketException((int)SocketError.AddressFamilyNotSupported);
  1704. }
  1705. }
  1706. class PythonUserSocketStream : Stream {
  1707. private readonly object _userSocket;
  1708. private List<string> _data = new List<string>();
  1709. private int _dataSize;
  1710. private readonly int _bufSize;
  1711. private readonly bool _close;
  1712. private readonly CodeContext/*!*/ _context;
  1713. public PythonUserSocketStream(CodeContext/*!*/ context, object userSocket, int bufferSize, bool close) {
  1714. _userSocket = userSocket;
  1715. _bufSize = bufferSize;
  1716. _close = close;
  1717. _context = context;
  1718. }
  1719. public override bool CanRead {
  1720. get { return true; }
  1721. }
  1722. public override bool CanSeek {
  1723. get { return false; }
  1724. }
  1725. public override bool CanWrite {
  1726. get { return true; }
  1727. }
  1728. public override void Flush() {
  1729. if (_data.Count > 0) {
  1730. StringBuilder res = new StringBuilder();
  1731. foreach (string s in _data) {
  1732. res.Append(s);
  1733. }
  1734. DefaultContext.DefaultPythonContext.CallSplat(PythonOps.GetBoundAttr(DefaultContext.Default, _userSocket, "sendall"), res.ToString());
  1735. _data.Clear();
  1736. }
  1737. }
  1738. public override long Length {
  1739. get { throw new NotImplementedException(); }
  1740. }
  1741. public override long Position {
  1742. get {
  1743. throw new NotImplementedException();
  1744. }
  1745. set {
  1746. throw new NotImplementedException();
  1747. }
  1748. }
  1749. public override int Read(byte[] buffer, int offset, int count) {
  1750. object received = DefaultContext.DefaultPythonContext.CallSplat(PythonOps.GetBoundAttr(DefaultContext.Default, _userSocket, "recv"), count);
  1751. string data = Converter.ConvertToString(received);
  1752. return PythonAsciiEncoding.Instance.GetBytes(data, 0, data.Length, buffer, offset);
  1753. }
  1754. public override long Seek(long offset, SeekOrigin origin) {
  1755. throw new NotImplementedException();
  1756. }
  1757. public override void SetLength(long value) {
  1758. throw new NotImplementedException();
  1759. }
  1760. public override void Write(byte[] buffer, int offset, int count) {
  1761. string strData = new string(PythonAsciiEncoding.Instance.GetChars(buffer, offset, count));
  1762. _data.Add(strData);
  1763. _dataSize += strData.Length;
  1764. if (_dataSize > _bufSize) {
  1765. Flush();
  1766. }
  1767. }
  1768. protected override void Dispose(bool disposing) {
  1769. socket sock = _userSocket as socket;
  1770. if (sock != null) {
  1771. sock.close(false, _close);
  1772. }
  1773. }
  1774. }
  1775. [PythonType]
  1776. public class _fileobject : PythonFile {
  1777. public new const string name = "<socket>";
  1778. private readonly socket _socket = null;
  1779. private readonly bool _close;
  1780. public const string __module__ = "socket";
  1781. public object bufsize = DefaultBufferSize; // Only present for compatibility with CPython public API
  1782. public _fileobject(CodeContext/*!*/ context, object socket, [DefaultParameterValue("rb")]string mode, [DefaultParameterValue(-1)]int bufsize, [DefaultParameterValue(false)]bool close)
  1783. : base(PythonContext.GetContext(context)) {
  1784. _close = close;
  1785. Stream stream;
  1786. // subtypes of socket need to go through the user defined methods
  1787. if (socket != null && socket.GetType() == typeof(socket) && ((socket)socket)._socket.Connected) {
  1788. socket s = (socket as socket);
  1789. _socket = s;
  1790. stream = new NetworkStream(s._socket);
  1791. } else {
  1792. stream = new PythonUserSocketStream(context, socket, GetBufferSize(context, bufsize), close);
  1793. }
  1794. base.__init__(stream, System.Text.Encoding.Default, mode);
  1795. }
  1796. public void __init__(params object[] args) {
  1797. }
  1798. public void __init__([ParamDictionary]IDictionary<object, object> kwargs, params object[] args) {
  1799. }
  1800. public void __del__() {
  1801. }
  1802. private static int GetBufferSize(CodeContext/*!*/ context, int size) {
  1803. if (size == -1) return Converter.ConvertToInt32(Getdefault_bufsize(context));
  1804. return size;
  1805. }
  1806. [SpecialName, PropertyMethod, StaticExtensionMethod]
  1807. public static object Getdefault_bufsize(CodeContext/*!*/ context) {
  1808. return PythonContext.GetContext(context).GetModuleState(_defaultBufsizeKey);
  1809. }
  1810. [SpecialName, PropertyMethod, StaticExtensionMethod]
  1811. public static void Setdefault_bufsize(CodeContext/*!*/ context, object value) {
  1812. PythonContext.GetContext(context).SetModuleState(_defaultBufsizeKey, value);
  1813. }
  1814. protected override void Dispose(bool disposing) {
  1815. base.Dispose(disposing);
  1816. if (_socket != null) {
  1817. _socket.close(false, _close);
  1818. }
  1819. }
  1820. }
  1821. #endregion
  1822. private static int? GetDefaultTimeout(CodeContext/*!*/ context) {
  1823. return (int?)PythonContext.GetContext(context).GetModuleState(_defaultTimeoutKey);
  1824. }
  1825. private static void SetDefaultTimeout(CodeContext/*!*/ context, int? timeout) {
  1826. PythonContext.GetContext(context).SetModuleState(_defaultTimeoutKey, timeout);
  1827. }
  1828. private static PythonType error(CodeContext/*!*/ context) {
  1829. return (PythonType)PythonContext.GetContext(context).GetModuleState("socketerror");
  1830. }
  1831. private static PythonType herror(CodeContext/*!*/ context) {
  1832. return (PythonType)PythonContext.GetContext(context).GetModuleState("socketherror");
  1833. }
  1834. private static PythonType timeout(CodeContext/*!*/ context) {
  1835. return (PythonType)PythonContext.GetContext(context).GetModuleState("sockettimeout");
  1836. }
  1837. public class ssl {
  1838. private readonly SslStream _sslStream;
  1839. private socket _socket;
  1840. private readonly X509Certificate2Collection _certCollection;
  1841. private readonly X509Certificate _cert;
  1842. private readonly int _protocol, _certsMode;
  1843. private readonly bool _validate, _serverSide;
  1844. private readonly CodeContext _context;
  1845. private Exception _validationFailure;
  1846. public ssl(CodeContext context, PythonSocket.socket sock, [DefaultParameterValue(null)] string keyfile, [DefaultParameterValue(null)] string certfile) {
  1847. _context = context;
  1848. _sslStream = new SslStream(new NetworkStream(sock._socket, false), true, CertValidationCallback);
  1849. _socket = sock;
  1850. _certCollection = new X509Certificate2Collection();
  1851. _protocol = -1;
  1852. _validate = false;
  1853. }
  1854. internal ssl(CodeContext context,
  1855. PythonSocket.socket sock,
  1856. bool server_side,
  1857. [DefaultParameterValue(null)] string keyfile,
  1858. [DefaultParameterValue(null)] string certfile,
  1859. [DefaultParameterValue(PythonSsl.CERT_NONE)]int certs_mode,
  1860. [DefaultParameterValue(-1)]int protocol,
  1861. string cacertsfile) {
  1862. if (sock == null) {
  1863. throw PythonOps.TypeError("expected socket object, got None");
  1864. }
  1865. if ((keyfile == null) != (certfile == null)) {
  1866. throw PythonExceptions.CreateThrowable(
  1867. PythonSsl.SSLError(context),
  1868. "When key or certificate is provided both must be provided"
  1869. );
  1870. }
  1871. _serverSide = server_side;
  1872. bool validate;
  1873. _certsMode = certs_mode;
  1874. RemoteCertificateValidationCallback callback;
  1875. switch (certs_mode) {
  1876. case PythonSsl.CERT_NONE:
  1877. validate = false;
  1878. callback = CertValidationCallback;
  1879. break;
  1880. case PythonSsl.CERT_OPTIONAL:
  1881. validate = true;
  1882. callback = CertValidationCallbackOptional;
  1883. break;
  1884. case PythonSsl.CERT_REQUIRED:
  1885. validate = true;
  1886. callback = CertValidationCallbackRequired;
  1887. break;
  1888. default:
  1889. throw new InvalidOperationException(String.Format("bad certs_mode: {0}", certs_mode));
  1890. }
  1891. if (certfile != null) {
  1892. _cert = PythonSsl.ReadCertificate(context, certfile);
  1893. }
  1894. if (server_side) {
  1895. _sslStream = new SslStream(
  1896. new NetworkStream(sock._socket, false),
  1897. true,
  1898. callback
  1899. );
  1900. } else {
  1901. _sslStream = new SslStream(
  1902. new NetworkStream(sock._socket, false),
  1903. true,
  1904. callback,
  1905. CertSelectLocal
  1906. );
  1907. }
  1908. _socket = sock;
  1909. _certCollection = cacertsfile != null ?
  1910. new X509Certificate2Collection(new[] { PythonSsl.ReadCertificate(context, cacertsfile) }) :
  1911. new X509Certificate2Collection();
  1912. _protocol = protocol;
  1913. _validate = validate;
  1914. _context = context;
  1915. }
  1916. internal bool CertValidationCallback(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) {
  1917. return true;
  1918. }
  1919. internal bool CertValidationCallbackOptional(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) {
  1920. if (!_serverSide) {
  1921. if (certificate != null && sslPolicyErrors != SslPolicyErrors.None) {
  1922. ValidateCertificate(certificate, chain, sslPolicyErrors);
  1923. }
  1924. }
  1925. return true;
  1926. }
  1927. internal X509Certificate CertSelectLocal(object sender, string targetHost, X509CertificateCollection collection, X509Certificate remoteCertificate, string[] acceptableIssuers) {
  1928. if (collection.Count > 0) {
  1929. return collection[0];
  1930. }
  1931. return null;
  1932. }
  1933. internal bool CertValidationCallbackRequired(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) {
  1934. if (!_serverSide) {
  1935. // client check
  1936. if (certificate == null) {
  1937. ValidationError(SslPolicyErrors.None);
  1938. } else if (sslPolicyErrors != SslPolicyErrors.None) {
  1939. ValidateCertificate(certificate, chain, sslPolicyErrors);
  1940. }
  1941. }
  1942. return true;
  1943. }
  1944. private void ValidateCertificate(X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) {
  1945. chain = new X509Chain();
  1946. chain.ChainPolicy.ExtraStore.AddRange(_certCollection);
  1947. chain.Build((X509Certificate2)certificate);
  1948. if (chain.ChainStatus.Length > 0) {
  1949. foreach (var elem in chain.ChainStatus) {
  1950. if (elem.Status == X509ChainStatusFlags.UntrustedRoot) {
  1951. bool isOk = false;
  1952. foreach (var cert in _certCollection) {
  1953. if (certificate.Issuer == cert.Subject) {
  1954. isOk = true;
  1955. }
  1956. }
  1957. if (isOk) {
  1958. continue;
  1959. }
  1960. }
  1961. ValidationError(sslPolicyErrors);
  1962. break;
  1963. }
  1964. }
  1965. }
  1966. private void ValidationError(object reason) {
  1967. _validationFailure = PythonExceptions.CreateThrowable(PythonSsl.SSLError(_context), "errors while validating certificate chain: ", reason.ToString());
  1968. }
  1969. public void do_handshake() {
  1970. try {
  1971. // make sure the remote side hasn't shutdown before authenticating so we don't
  1972. // hang if we're in blocking mode.
  1973. int available = _socket._socket.Available;
  1974. } catch (SocketException) {
  1975. throw PythonExceptions.CreateThrowable(PythonExceptions.IOError, "socket closed before handshake");
  1976. }
  1977. try {
  1978. if (_serverSide) {
  1979. _sslStream.AuthenticateAsServer(_cert, _certsMode == PythonSsl.CERT_REQUIRED, GetProtocolTypeServer(_protocol), false);
  1980. } else {
  1981. var collection = new X509CertificateCollection();
  1982. if (_cert != null) {
  1983. collection.Add(_cert);
  1984. }
  1985. _sslStream.AuthenticateAsClient(_socket._hostName, collection, GetProtocolTypeClient(_protocol), false);
  1986. }
  1987. } catch (AuthenticationException e) {
  1988. _socket._socket.Close();
  1989. throw PythonExceptions.CreateThrowable(PythonSsl.SSLError(_context), "errors while performing handshake: ", e.ToString());
  1990. }
  1991. if (_validationFailure != null) {
  1992. throw _validationFailure;
  1993. }
  1994. }
  1995. public socket shutdown() {
  1996. _sslStream.Close();
  1997. return _socket;
  1998. }
  1999. /* supported communication based upon what the client & server specify
  2000. * as per the CPython docs:
  2001. * client / server SSLv2 SSLv3 SSLv23 TLSv1
  2002. SSLv2 yes no yes* no
  2003. SSLv3 yes yes yes no
  2004. SSLv23 yes no yes no
  2005. TLSv1 no no yes yes
  2006. */
  2007. private static SslProtocols GetProtocolTypeServer(int type) {
  2008. switch (type) {
  2009. case PythonSsl.PROTOCOL_SSLv2: return SslProtocols.Ssl2;
  2010. case PythonSsl.PROTOCOL_SSLv3: return SslProtocols.Ssl3;
  2011. case -1:
  2012. case PythonSsl.PROTOCOL_SSLv23: return SslProtocols.Ssl2 | SslProtocols.Ssl3 | SslProtocols.Tls;
  2013. case PythonSsl.PROTOCOL_TLSv1: return SslProtocols.Tls;
  2014. default:
  2015. throw new InvalidOperationException("bad ssl protocol type: " + type);
  2016. }
  2017. }
  2018. private static SslProtocols GetProtocolTypeClient(int type) {
  2019. switch (type) {
  2020. case PythonSsl.PROTOCOL_SSLv2: return SslProtocols.Ssl2;
  2021. case -1:
  2022. case PythonSsl.PROTOCOL_SSLv3: return SslProtocols.Ssl3;
  2023. case PythonSsl.PROTOCOL_SSLv23: return SslProtocols.Ssl3 | SslProtocols.Ssl2;
  2024. case PythonSsl.PROTOCOL_TLSv1: return SslProtocols.Tls;
  2025. default:
  2026. throw new InvalidOperationException("bad ssl protocol type: " + type);
  2027. }
  2028. }
  2029. public PythonTuple cipher() {
  2030. if (_sslStream.IsAuthenticated) {
  2031. return PythonTuple.MakeTuple(
  2032. _sslStream.CipherAlgorithm.ToString(),
  2033. ProtocolToPython(),
  2034. _sslStream.CipherStrength
  2035. );
  2036. }
  2037. return null;
  2038. }
  2039. private string ProtocolToPython() {
  2040. switch (_sslStream.SslProtocol) {
  2041. case SslProtocols.Ssl2: return "SSLv2";
  2042. case SslProtocols.Ssl3: return "TLSv1/SSLv3";
  2043. case SslProtocols.Tls: return "TLSv1";
  2044. default: return _sslStream.SslProtocol.ToString();
  2045. }
  2046. }
  2047. public object peer_certificate(bool binary_form) {
  2048. var peerCert = _sslStream.RemoteCertificate;
  2049. if (peerCert != null) {
  2050. if (binary_form) {
  2051. return peerCert.GetRawCertData().MakeString();
  2052. } else if (_validate) {
  2053. return PythonSsl.CertificateToPython(_context, peerCert, true);
  2054. }
  2055. }
  2056. return null;
  2057. }
  2058. public int pending() {
  2059. return _socket._socket.Available;
  2060. }
  2061. [Documentation("issuer() -> issuer_certificate\n\n"
  2062. + "Returns a string that describes the issuer of the server's certificate. Only useful for debugging purposes."
  2063. )]
  2064. public string issuer() {
  2065. if (_sslStream.IsAuthenticated) {
  2066. X509Certificate remoteCertificate = _sslStream.RemoteCertificate;
  2067. if (remoteCertificate != null) {
  2068. return remoteCertificate.Issuer;
  2069. } else {
  2070. return String.Empty;
  2071. }
  2072. }
  2073. return String.Empty;
  2074. }
  2075. [Documentation("read([n]) -> buffer_read\n\n"
  2076. + "If n is present, reads up to n bytes from the SSL connection. Otherwise, reads to EOF."
  2077. )]
  2078. public string read(CodeContext/*!*/ context, [DefaultParameterValue(Int32.MaxValue)] int n) {
  2079. try {
  2080. byte[] buffer = new byte[2048];
  2081. MemoryStream result = new MemoryStream(n);
  2082. while (true) {
  2083. int readLength = (n < buffer.Length) ? n : buffer.Length;
  2084. int bytes = _sslStream.Read(buffer, 0, readLength);
  2085. if (bytes > 0) {
  2086. result.Write(buffer, 0, bytes);
  2087. n -= bytes;
  2088. }
  2089. if (bytes == 0 || n == 0 || bytes < readLength) {
  2090. return result.ToArray().MakeString();
  2091. }
  2092. }
  2093. } catch (Exception e) {
  2094. throw PythonSocket.MakeException(context, e);
  2095. }
  2096. }
  2097. [Documentation("server() -> server_certificate\n\n"
  2098. + "Returns a string that describes the server's certificate. Only useful for debugging purposes."
  2099. )]
  2100. public string server() {
  2101. if (_sslStream.IsAuthenticated) {
  2102. X509Certificate remoteCertificate = _sslStream.RemoteCertificate;
  2103. if (remoteCertificate != null) {
  2104. return remoteCertificate.Subject;
  2105. }
  2106. }
  2107. return String.Empty;
  2108. }
  2109. [Documentation("write(s) -> bytes_sent\n\n"
  2110. + "Writes the string s through the SSL connection."
  2111. )]
  2112. public int write(CodeContext/*!*/ context, string data) {
  2113. byte[] buffer = data.MakeByteArray();
  2114. try {
  2115. _sslStream.Write(buffer);
  2116. return buffer.Length;
  2117. } catch (Exception e) {
  2118. throw PythonSocket.MakeException(context, e);
  2119. }
  2120. }
  2121. }
  2122. }
  2123. }
  2124. #endif