PageRenderTime 62ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 1ms

/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

Large files files are truncated, but you can click here to view the full 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"

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