PageRenderTime 51ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

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

http://github.com/IronLanguages/main
C# | 3078 lines | 2579 code | 348 blank | 151 comment | 580 complexity | 5c961e9e4e7e991a8290db1150c646e3 MD5 | raw file
Possible License(s): CPL-1.0, BSD-3-Clause, ISC, GPL-2.0, MPL-2.0-no-copyleft-exception

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 Apache License, Version 2.0. A
  6. * copy of the license can be found in the License.html file at the root of this distribution. If
  7. * you cannot locate the Apache License, Version 2.0, please send an email to
  8. * ironpy@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
  9. * by the terms of the Apache License, Version 2.0.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. *
  14. * ***************************************************************************/
  15. #if FEATURE_FULL_NET
  16. using System;
  17. using System.Collections;
  18. using System.Collections.Generic;
  19. using System.Diagnostics;
  20. using System.IO;
  21. using System.Net;
  22. using System.Net.Sockets;
  23. using System.Net.Security;
  24. using System.Runtime.InteropServices;
  25. using System.Security.Cryptography.X509Certificates;
  26. using System.Security.Authentication;
  27. using System.Runtime.CompilerServices;
  28. using System.Text;
  29. using Microsoft.Scripting;
  30. using Microsoft.Scripting.Runtime;
  31. using IronPython.Runtime;
  32. using IronPython.Runtime.Exceptions;
  33. using IronPython.Runtime.Operations;
  34. using IronPython.Runtime.Types;
  35. #if FEATURE_NUMERICS
  36. using System.Numerics;
  37. #else
  38. using Microsoft.Scripting.Math;
  39. #endif
  40. using PythonArray = IronPython.Modules.ArrayModule.array;
  41. using SpecialNameAttribute = System.Runtime.CompilerServices.SpecialNameAttribute;
  42. using Microsoft.Scripting.Utils;
  43. #if NETCOREAPP1_0
  44. using Environment = System.FakeEnvironment;
  45. #endif
  46. [assembly: PythonModule("socket", typeof(IronPython.Modules.PythonSocket))]
  47. namespace IronPython.Modules {
  48. public static class PythonSocket {
  49. private static readonly object _defaultTimeoutKey = new object();
  50. private static readonly object _defaultBufsizeKey = new object();
  51. private const int DefaultBufferSize = 8192;
  52. public static PythonTuple _delegate_methods = PythonTuple.MakeTuple("recv", "recvfrom", "recv_into", "recvfrom_into", "send", "sendto");
  53. [SpecialName]
  54. public static void PerformModuleReload(PythonContext/*!*/ context, PythonDictionary/*!*/ dict) {
  55. if (!context.HasModuleState(_defaultTimeoutKey)) {
  56. context.SetModuleState(_defaultTimeoutKey, null);
  57. }
  58. context.SetModuleState(_defaultBufsizeKey, DefaultBufferSize);
  59. PythonType socketErr = GetSocketError(context, dict);
  60. context.EnsureModuleException("socketherror", socketErr, dict, "herror", "socket");
  61. context.EnsureModuleException("socketgaierror", socketErr, dict, "gaierror", "socket");
  62. context.EnsureModuleException("sockettimeout", socketErr, dict, "timeout", "socket");
  63. }
  64. internal static PythonType GetSocketError(PythonContext context, PythonDictionary dict) {
  65. return context.EnsureModuleException("socketerror", PythonExceptions.IOError, dict, "error", "socket");
  66. }
  67. #if NETSTANDARD
  68. private static ConditionalWeakTable<Socket, object> fakeHandles = new ConditionalWeakTable<Socket, object>();
  69. private static long maxHandle = 0;
  70. #endif
  71. private static IntPtr GetHandle(this Socket socket)
  72. {
  73. #if NETSTANDARD
  74. object handle;
  75. lock (fakeHandles) {
  76. if (!fakeHandles.TryGetValue(socket, out handle)) {
  77. handle = (IntPtr)maxHandle++;
  78. fakeHandles.Add(socket, handle);
  79. }
  80. }
  81. return (IntPtr)handle;
  82. #else
  83. return socket.Handle;
  84. #endif
  85. }
  86. public const string __doc__ = "Implementation module for socket operations.\n\n"
  87. + "This module is a loose wrapper around the .NET System.Net.Sockets API, so you\n"
  88. + "may find the corresponding MSDN documentation helpful in decoding error\n"
  89. + "messages and understanding corner cases.\n"
  90. + "\n"
  91. + "This implementation of socket differs slightly from the standard CPython\n"
  92. + "socket module. Many of these differences are due to the implementation of the\n"
  93. + ".NET socket libraries. These differences are summarized below. For full\n"
  94. + "details, check the docstrings of the functions mentioned.\n"
  95. + " - s.accept(), s.connect(), and s.connect_ex() do not support timeouts.\n"
  96. + " - Timeouts in s.sendall() don't work correctly.\n"
  97. + " - s.dup() is not implemented.\n"
  98. + " - SSL support is not implemented."
  99. + "\n"
  100. + "An Extra IronPython-specific function is exposed only if the clr module is\n"
  101. + "imported:\n"
  102. + " - s.HandleToSocket() returns the System.Net.Sockets.Socket object associated\n"
  103. + " with a particular \"file descriptor number\" (as returned by s.fileno()).\n"
  104. ;
  105. #region Socket object
  106. public static PythonType SocketType = DynamicHelpers.GetPythonTypeFromType(typeof(socket));
  107. [PythonType]
  108. [Documentation("socket([family[, type[, proto]]]) -> socket object\n\n"
  109. + "Create a socket (a network connection endpoint) of the given family, type,\n"
  110. + "and protocol. socket() accepts keyword arguments.\n"
  111. + " - family (address family) defaults to AF_INET\n"
  112. + " - type (socket type) defaults to SOCK_STREAM\n"
  113. + " - proto (protocol type) defaults to 0, which specifies the default protocol\n"
  114. + "\n"
  115. + "This module supports only IP sockets. It does not support raw or Unix sockets.\n"
  116. + "Both IPv4 and IPv6 are supported.")]
  117. public class socket : IWeakReferenceable {
  118. #region Fields
  119. /// <summary>
  120. /// handleToSocket allows us to translate from Python's idea of a socket resource (file
  121. /// descriptor numbers) to .NET's idea of a socket resource (System.Net.Socket objects).
  122. /// In particular, this allows the select module to convert file numbers (as returned by
  123. /// fileno()) and convert them to Socket objects so that it can do something useful with them.
  124. /// </summary>
  125. private static readonly Dictionary<IntPtr, WeakReference> _handleToSocket = new Dictionary<IntPtr, WeakReference>();
  126. private const int DefaultAddressFamily = (int)AddressFamily.InterNetwork;
  127. private const int DefaultSocketType = (int)System.Net.Sockets.SocketType.Stream;
  128. private const int DefaultProtocolType = (int)ProtocolType.Unspecified;
  129. internal Socket _socket;
  130. internal string _hostName;
  131. private WeakRefTracker _weakRefTracker = null;
  132. private int _referenceCount = 1;
  133. public const string __module__ = "socket";
  134. internal CodeContext/*!*/ _context;
  135. private int _timeout;
  136. #endregion
  137. #region Public API
  138. public socket() {
  139. }
  140. public void __init__(CodeContext/*!*/ context, [DefaultParameterValue(DefaultAddressFamily)] int addressFamily,
  141. [DefaultParameterValue(DefaultSocketType)] int socketType,
  142. [DefaultParameterValue(DefaultProtocolType)] int protocolType,
  143. [DefaultParameterValue(null)]socket _sock) {
  144. System.Net.Sockets.SocketType type = (System.Net.Sockets.SocketType)Enum.ToObject(typeof(System.Net.Sockets.SocketType), socketType);
  145. if (!Enum.IsDefined(typeof(System.Net.Sockets.SocketType), type)) {
  146. throw MakeException(context, new SocketException((int)SocketError.SocketNotSupported));
  147. }
  148. AddressFamily family = (AddressFamily)Enum.ToObject(typeof(AddressFamily), addressFamily);
  149. if (!Enum.IsDefined(typeof(AddressFamily), family)) {
  150. throw MakeException(context, new SocketException((int)SocketError.AddressFamilyNotSupported));
  151. }
  152. ProtocolType proto = (ProtocolType)Enum.ToObject(typeof(ProtocolType), protocolType);
  153. if (!Enum.IsDefined(typeof(ProtocolType), proto)) {
  154. throw MakeException(context, new SocketException((int)SocketError.ProtocolNotSupported));
  155. }
  156. if (_sock == null) {
  157. Socket newSocket;
  158. try {
  159. newSocket = new Socket(family, type, proto);
  160. } catch (SocketException e) {
  161. throw MakeException(context, e);
  162. }
  163. Initialize(context, newSocket);
  164. } else {
  165. _socket = _sock._socket;
  166. _hostName = _sock._hostName;
  167. // we now own the lifetime of the socket
  168. GC.SuppressFinalize(_sock);
  169. Initialize(context, _socket);
  170. }
  171. }
  172. public void __del__() {
  173. _close();
  174. }
  175. ~socket() {
  176. _close();
  177. }
  178. public socket _sock {
  179. get {
  180. return this;
  181. }
  182. }
  183. #if !NETSTANDARD
  184. private IAsyncResult _acceptResult;
  185. #endif
  186. [Documentation("accept() -> (conn, address)\n\n"
  187. + "Accept a connection. The socket must be bound and listening before calling\n"
  188. + "accept(). conn is a new socket object connected to the remote host, and\n"
  189. + "address is the remote host's address (e.g. a (host, port) tuple for IPv4).\n"
  190. + "\n"
  191. )]
  192. public PythonTuple accept() {
  193. socket wrappedRemoteSocket;
  194. Socket realRemoteSocket;
  195. try {
  196. #if NETSTANDARD
  197. // TODO: support timeout != 0
  198. realRemoteSocket = _socket.Accept();
  199. #else
  200. if (_acceptResult != null && _acceptResult.IsCompleted) {
  201. // previous async result has completed
  202. realRemoteSocket = _socket.EndAccept(_acceptResult);
  203. } else {
  204. int timeoutTime = _timeout;
  205. if (timeoutTime != 0) {
  206. // use the existing or create a new async request
  207. var asyncResult = _acceptResult ?? _socket.BeginAccept((x) => { }, null);
  208. if (asyncResult.AsyncWaitHandle.WaitOne(timeoutTime)) {
  209. // it's completed, end and throw it away
  210. realRemoteSocket = _socket.EndAccept(asyncResult);
  211. _acceptResult = null;
  212. } else {
  213. // save the async result for later incase it completes
  214. _acceptResult = asyncResult;
  215. throw PythonExceptions.CreateThrowable(timeout(_context), 0, "timeout");
  216. }
  217. } else {
  218. realRemoteSocket = _socket.Accept();
  219. }
  220. }
  221. #endif
  222. } catch (Exception e) {
  223. throw MakeException(_context, e);
  224. }
  225. wrappedRemoteSocket = new socket(_context, realRemoteSocket);
  226. return PythonTuple.MakeTuple(wrappedRemoteSocket, wrappedRemoteSocket.getpeername());
  227. }
  228. [Documentation("bind(address) -> None\n\n"
  229. + "Bind to an address. If the socket is already bound, socket.error is raised.\n"
  230. + "For IP sockets, address is a (host, port) tuple. Raw sockets are not\n"
  231. + "supported.\n"
  232. + "\n"
  233. + "If you do not care which local address is assigned, set host to INADDR_ANY and\n"
  234. + "the system will assign the most appropriate network address. Similarly, if you\n"
  235. + "set port to 0, the system will assign an available port number between 1024\n"
  236. + "and 5000."
  237. )]
  238. public void bind(PythonTuple address) {
  239. IPEndPoint localEP = TupleToEndPoint(_context, address, _socket.AddressFamily, out _hostName);
  240. try {
  241. _socket.Bind(localEP);
  242. } catch (Exception e) {
  243. throw MakeException(_context, e);
  244. }
  245. }
  246. [Documentation("close() -> None\n\nClose the socket. It cannot be used after being closed.")]
  247. public void close() {
  248. var refs = System.Threading.Interlocked.Decrement(ref _referenceCount);
  249. // Don't actually close the socket if other file objects are
  250. // still referring to this socket.
  251. if (refs < 1) {
  252. _close();
  253. }
  254. }
  255. internal void _close() {
  256. if (_socket != null) {
  257. lock (_handleToSocket) {
  258. WeakReference weakref;
  259. if (_handleToSocket.TryGetValue(_socket.GetHandle(), out weakref)) {
  260. Socket target = (weakref.Target as Socket);
  261. if (target == _socket || target == null) {
  262. _handleToSocket.Remove(_socket.GetHandle());
  263. }
  264. }
  265. }
  266. ((IDisposable)_socket).Dispose();
  267. _referenceCount = 0;
  268. }
  269. }
  270. [Documentation("connect(address) -> None\n\n"
  271. + "Connect to a remote socket at the given address. IP addresses are expressed\n"
  272. + "as (host, port).\n"
  273. + "\n"
  274. + "Raises socket.error if the socket has been closed, the socket is listening, or\n"
  275. + "another connection error occurred."
  276. + "\n"
  277. + "Difference from CPython: connect() does not support timeouts in blocking mode.\n"
  278. + "If a timeout is set and the socket is in blocking mode, connect() will block\n"
  279. + "indefinitely until a connection is made or an error occurs."
  280. )]
  281. public void connect(PythonTuple address) {
  282. IPEndPoint remoteEP = TupleToEndPoint(_context, address, _socket.AddressFamily, out _hostName);
  283. try {
  284. _socket.Connect(remoteEP);
  285. } catch (Exception e) {
  286. throw MakeException(_context, e);
  287. }
  288. }
  289. [Documentation("connect_ex(address) -> error_code\n\n"
  290. + "Like connect(), but return an error code insted of raising an exception for\n"
  291. + "socket exceptions raised by the underlying system Connect() call. Note that\n"
  292. + "exceptions other than SocketException generated by the system Connect() call\n"
  293. + "will still be raised.\n"
  294. + "\n"
  295. + "A return value of 0 indicates that the connect call was successful."
  296. + "\n"
  297. + "Difference from CPython: connect_ex() does not support timeouts in blocking\n"
  298. + "mode. If a timeout is set and the socket is in blocking mode, connect_ex() will\n"
  299. + "block indefinitely until a connection is made or an error occurs."
  300. )]
  301. public int connect_ex(PythonTuple address) {
  302. IPEndPoint remoteEP = TupleToEndPoint(_context, address, _socket.AddressFamily, out _hostName);
  303. try {
  304. _socket.Connect(remoteEP);
  305. } catch (SocketException e) {
  306. return (int)e.SocketErrorCode;
  307. }
  308. return (int)SocketError.Success;
  309. }
  310. [Documentation("fileno() -> file_handle\n\n"
  311. + "Return the underlying system handle for this socket (a 64-bit integer)."
  312. )]
  313. public Int64 fileno() {
  314. try {
  315. return _socket.GetHandle().ToInt64();
  316. } catch (Exception e) {
  317. throw MakeException(_context, e);
  318. }
  319. }
  320. [Documentation("getpeername() -> address\n\n"
  321. + "Return the address of the remote end of this socket. The address format is\n"
  322. + "family-dependent (e.g. a (host, port) tuple for IPv4)."
  323. )]
  324. public PythonTuple getpeername() {
  325. try {
  326. IPEndPoint remoteEP = _socket.RemoteEndPoint as IPEndPoint;
  327. if (remoteEP == null) {
  328. throw MakeException(_context, new SocketException((int)SocketError.AddressFamilyNotSupported));
  329. }
  330. return EndPointToTuple(remoteEP);
  331. } catch (Exception e) {
  332. throw MakeException(_context, e);
  333. }
  334. }
  335. [Documentation("getsockname() -> address\n\n"
  336. + "Return the address of the local end of this socket. The address format is\n"
  337. + "family-dependent (e.g. a (host, port) tuple for IPv4)."
  338. )]
  339. public PythonTuple getsockname() {
  340. try {
  341. IPEndPoint localEP = _socket.LocalEndPoint as IPEndPoint;
  342. if (localEP == null) {
  343. throw MakeException(_context, new SocketException((int)SocketError.InvalidArgument));
  344. }
  345. return EndPointToTuple(localEP);
  346. } catch (Exception e) {
  347. throw MakeException(_context, e);
  348. }
  349. }
  350. [Documentation("getsockopt(level, optname[, buflen]) -> value\n\n"
  351. + "Return the value of a socket option. level is one of the SOL_* constants\n"
  352. + "defined in this module, and optname is one of the SO_* constants. If buflen is\n"
  353. + "omitted or zero, an integer value is returned. If it is present, a byte string\n"
  354. + "whose maximum length is buflen bytes) is returned. The caller must the decode\n"
  355. + "the resulting byte string."
  356. )]
  357. public object getsockopt(int optionLevel, int optionName, [DefaultParameterValue(0)] int optionLength) {
  358. SocketOptionLevel level = (SocketOptionLevel)Enum.ToObject(typeof(SocketOptionLevel), optionLevel);
  359. if (!Enum.IsDefined(typeof(SocketOptionLevel), level)) {
  360. throw MakeException(_context, new SocketException((int)SocketError.InvalidArgument));
  361. }
  362. SocketOptionName name = (SocketOptionName)Enum.ToObject(typeof(SocketOptionName), optionName);
  363. if (!Enum.IsDefined(typeof(SocketOptionName), name)) {
  364. throw MakeException(_context, new SocketException((int)SocketError.ProtocolOption));
  365. }
  366. try {
  367. if (optionLength == 0) {
  368. // Integer return value
  369. return (int)_socket.GetSocketOption(level, name);
  370. } else {
  371. // Byte string return value
  372. return _socket.GetSocketOption(level, name, optionLength).MakeString();
  373. }
  374. } catch (Exception e) {
  375. throw MakeException(_context, e);
  376. }
  377. }
  378. [Documentation("listen(backlog) -> None\n\n"
  379. + "Listen for connections on the socket. Backlog is the maximum length of the\n"
  380. + "pending connections queue. The maximum value is system-dependent."
  381. )]
  382. public void listen(int backlog) {
  383. try {
  384. _socket.Listen(backlog);
  385. } catch (Exception e) {
  386. throw MakeException(_context, e);
  387. }
  388. }
  389. [Documentation("makefile([mode[, bufsize]]) -> file object\n\n"
  390. + "Return a regular file object corresponding to the socket. The mode\n"
  391. + "and bufsize arguments are as for the built-in open() function.")]
  392. public PythonFile makefile([DefaultParameterValue("r")]string mode, [DefaultParameterValue(8192)]int bufSize) {
  393. System.Threading.Interlocked.Increment(ref _referenceCount); // dup our handle
  394. return new _fileobject(_context, this, mode, bufSize, false);
  395. }
  396. [Documentation("recv(bufsize[, flags]) -> string\n\n"
  397. + "Receive data from the socket, up to bufsize bytes. For connection-oriented\n"
  398. + "protocols (e.g. SOCK_STREAM), you must first call either connect() or\n"
  399. + "accept(). Connectionless protocols (e.g. SOCK_DGRAM) may also use recvfrom().\n"
  400. + "\n"
  401. + "recv() blocks until data is available, unless a timeout was set using\n"
  402. + "settimeout(). If the timeout was exceeded, socket.timeout is raised."
  403. + "recv() returns immediately with zero bytes when the connection is closed."
  404. )]
  405. public string recv(int maxBytes, [DefaultParameterValue(0)] int flags) {
  406. int bytesRead;
  407. if (maxBytes < 0)
  408. throw PythonOps.ValueError("negative buffersize in recv");
  409. byte[] buffer = new byte[maxBytes];
  410. try {
  411. bytesRead = _socket.Receive(buffer, (SocketFlags)flags);
  412. } catch (Exception e) {
  413. throw MakeRecvException(e, SocketError.NotConnected);
  414. }
  415. return PythonOps.MakeString(buffer, bytesRead);
  416. }
  417. [Documentation("recv_into(buffer, [nbytes[, flags]]) -> nbytes_read\n\n"
  418. + "A version of recv() that stores its data into a buffer rather than creating\n"
  419. + "a new string. Receive up to buffersize bytes from the socket. If buffersize\n"
  420. + "is not specified (or 0), receive up to the size available in the given buffer.\n\n"
  421. + "See recv() for documentation about the flags.\n"
  422. )]
  423. public int recv_into(PythonBuffer buffer, [DefaultParameterValue(0)]int nbytes, [DefaultParameterValue(0)]int flags) {
  424. if (nbytes < 0) {
  425. throw PythonOps.ValueError("negative buffersize in recv_into");
  426. }
  427. throw PythonOps.TypeError("buffer is read-only");
  428. }
  429. [Documentation("recv_into(buffer, [nbytes[, flags]]) -> nbytes_read\n\n"
  430. + "A version of recv() that stores its data into a buffer rather than creating\n"
  431. + "a new string. Receive up to buffersize bytes from the socket. If buffersize\n"
  432. + "is not specified (or 0), receive up to the size available in the given buffer.\n\n"
  433. + "See recv() for documentation about the flags.\n"
  434. )]
  435. public int recv_into(string buffer, [DefaultParameterValue(0)]int nbytes, [DefaultParameterValue(0)]int flags) {
  436. throw PythonOps.TypeError("Cannot use string as modifiable buffer");
  437. }
  438. [Documentation("recv_into(buffer, [nbytes[, flags]]) -> nbytes_read\n\n"
  439. + "A version of recv() that stores its data into a buffer rather than creating\n"
  440. + "a new string. Receive up to buffersize bytes from the socket. If buffersize\n"
  441. + "is not specified (or 0), receive up to the size available in the given buffer.\n\n"
  442. + "See recv() for documentation about the flags.\n"
  443. )]
  444. public int recv_into(PythonArray buffer, [DefaultParameterValue(0)]int nbytes, [DefaultParameterValue(0)]int flags) {
  445. int bytesRead;
  446. byte[] byteBuffer = new byte[byteBufferSize("recv_into", nbytes, buffer.__len__(), buffer.itemsize)];
  447. try {
  448. bytesRead = _socket.Receive(byteBuffer, (SocketFlags)flags);
  449. } catch (Exception e) {
  450. throw MakeRecvException(e, SocketError.NotConnected);
  451. }
  452. buffer.FromStream(new MemoryStream(byteBuffer), 0);
  453. return bytesRead;
  454. }
  455. [Documentation("recv_into(bytearray, [nbytes[, flags]]) -> nbytes_read\n\n"
  456. + "A version of recv() that stores its data into a bytearray rather than creating\n"
  457. + "a new string. Receive up to buffersize bytes from the socket. If buffersize\n"
  458. + "is not specified (or 0), receive up to the size available in the given buffer.\n\n"
  459. + "See recv() for documentation about the flags.\n"
  460. )]
  461. public int recv_into(ByteArray buffer, [DefaultParameterValue(0)]int nbytes, [DefaultParameterValue(0)]int flags) {
  462. int bytesRead;
  463. byte[] byteBuffer = new byte[byteBufferSize("recv_into", nbytes, buffer.Count, 1)];
  464. try {
  465. bytesRead = _socket.Receive(byteBuffer, (SocketFlags)flags);
  466. } catch (Exception e) {
  467. throw MakeRecvException(e, SocketError.NotConnected);
  468. }
  469. for (int i = 0; i < bytesRead; i++) {
  470. buffer[i] = byteBuffer[i];
  471. }
  472. return bytesRead;
  473. }
  474. [Documentation("recv_into(memoryview, [nbytes[, flags]]) -> nbytes_read\n\n"
  475. + "A version of recv() that stores its data into a bytearray rather than creating\n"
  476. + "a new string. Receive up to buffersize bytes from the socket. If buffersize\n"
  477. + "is not specified (or 0), receive up to the size available in the given buffer.\n\n"
  478. + "See recv() for documentation about the flags.\n"
  479. )]
  480. public int recv_into(MemoryView buffer, [DefaultParameterValue(0)]int nbytes, [DefaultParameterValue(0)]int flags) {
  481. int bytesRead;
  482. byte[] byteBuffer = buffer.tobytes().ToByteArray();
  483. try {
  484. bytesRead = _socket.Receive(byteBuffer, (SocketFlags)flags);
  485. }
  486. catch (Exception e) {
  487. if (_socket.SendTimeout == 0) {
  488. var s = new SocketException((int)SocketError.NotConnected);
  489. throw PythonExceptions.CreateThrowable(error(_context), (int)SocketError.NotConnected, s.Message);
  490. }
  491. else
  492. throw MakeException(_context, e);
  493. }
  494. buffer[new Slice(0, bytesRead)] = byteBuffer.Slice(new Slice(0, bytesRead));
  495. return bytesRead;
  496. }
  497. public int recv_into(object buffer, [DefaultParameterValue(0)]int nbytes, [DefaultParameterValue(0)]int flags){
  498. throw PythonOps.TypeError(string.Format("recv_into() argument 1 must be read-write buffer, not {0}",PythonOps.GetPythonTypeName(buffer)));
  499. }
  500. [Documentation("recvfrom(bufsize[, flags]) -> (string, address)\n\n"
  501. + "Receive data from the socket, up to bufsize bytes. string is the data\n"
  502. + "received, and address (whose format is protocol-dependent) is the address of\n"
  503. + "the socket from which the data was received."
  504. )]
  505. public PythonTuple recvfrom(int maxBytes, [DefaultParameterValue(0)] int flags) {
  506. if (maxBytes < 0) {
  507. throw PythonOps.ValueError("negative buffersize in recvfrom");
  508. }
  509. int bytesRead;
  510. byte[] buffer = new byte[maxBytes];
  511. IPEndPoint remoteIPEP = new IPEndPoint(IPAddress.Any, 0);
  512. EndPoint remoteEP = remoteIPEP;
  513. try {
  514. bytesRead = _socket.ReceiveFrom(buffer, (SocketFlags)flags, ref remoteEP);
  515. } catch (Exception e) {
  516. throw MakeRecvException(e, SocketError.InvalidArgument);
  517. }
  518. string data = PythonOps.MakeString(buffer, bytesRead);
  519. PythonTuple remoteAddress = EndPointToTuple((IPEndPoint)remoteEP);
  520. return PythonTuple.MakeTuple(data, remoteAddress);
  521. }
  522. [Documentation("recvfrom_into(buffer[, nbytes[, flags]]) -> (nbytes, address info)\n\n"
  523. + "Like recv_into(buffer[, nbytes[, flags]]) but also return the sender's address info.\n"
  524. )]
  525. public PythonTuple recvfrom_into(PythonBuffer buffer, [DefaultParameterValue(0)]int nbytes, [DefaultParameterValue(0)]int flags) {
  526. if (nbytes < 0) {
  527. throw PythonOps.ValueError("negative buffersize in recvfrom_into");
  528. }
  529. throw PythonOps.TypeError("buffer is read-only");
  530. }
  531. [Documentation("recvfrom_into(buffer[, nbytes[, flags]]) -> (nbytes, address info)\n\n"
  532. + "Like recv_into(buffer[, nbytes[, flags]]) but also return the sender's address info.\n"
  533. )]
  534. public PythonTuple recvfrom_into(string buffer, [DefaultParameterValue(0)]int nbytes, [DefaultParameterValue(0)]int flags) {
  535. throw PythonOps.TypeError("Cannot use string as modifiable buffer");
  536. }
  537. [Documentation("recvfrom_into(buffer[, nbytes[, flags]]) -> (nbytes, address info)\n\n"
  538. + "Like recv_into(buffer[, nbytes[, flags]]) but also return the sender's address info.\n"
  539. )]
  540. public PythonTuple recvfrom_into(PythonArray buffer, [DefaultParameterValue(0)]int nbytes, [DefaultParameterValue(0)]int flags) {
  541. int bytesRead;
  542. byte[] byteBuffer = new byte[byteBufferSize("recvfrom_into", nbytes, buffer.__len__(), buffer.itemsize)];
  543. IPEndPoint remoteIPEP = new IPEndPoint(IPAddress.Any, 0);
  544. EndPoint remoteEP = remoteIPEP;
  545. try {
  546. bytesRead = _socket.ReceiveFrom(byteBuffer, (SocketFlags)flags, ref remoteEP);
  547. } catch (Exception e) {
  548. throw MakeRecvException(e, SocketError.InvalidArgument);
  549. }
  550. buffer.FromStream(new MemoryStream(byteBuffer), 0);
  551. PythonTuple remoteAddress = EndPointToTuple((IPEndPoint)remoteEP);
  552. return PythonTuple.MakeTuple(bytesRead, remoteAddress);
  553. }
  554. [Documentation("recvfrom_into(buffer[, nbytes[, flags]]) -> (nbytes, address info)\n\n"
  555. + "Like recv_into(buffer[, nbytes[, flags]]) but also return the sender's address info.\n"
  556. )]
  557. public PythonTuple recvfrom_into(MemoryView buffer, [DefaultParameterValue(0)]int nbytes, [DefaultParameterValue(0)]int flags){
  558. int bytesRead;
  559. byte[] byteBuffer = buffer.tobytes().ToByteArray();
  560. IPEndPoint remoteIPEP = new IPEndPoint(IPAddress.Any, 0);
  561. EndPoint remoteEP = remoteIPEP;
  562. try {
  563. bytesRead = _socket.ReceiveFrom(byteBuffer, (SocketFlags)flags, ref remoteEP);
  564. }
  565. catch (Exception e) {
  566. throw MakeRecvException(e, SocketError.InvalidArgument);
  567. }
  568. buffer[new Slice(0, bytesRead)] = byteBuffer.Slice(new Slice(0, bytesRead));
  569. PythonTuple remoteAddress = EndPointToTuple((IPEndPoint)remoteEP);
  570. return PythonTuple.MakeTuple(bytesRead, remoteAddress);
  571. }
  572. [Documentation("recvfrom_into(buffer[, nbytes[, flags]]) -> (nbytes, address info)\n\n"
  573. + "Like recv_into(buffer[, nbytes[, flags]]) but also return the sender's address info.\n"
  574. )]
  575. public PythonTuple recvfrom_into(IList<byte> buffer, [DefaultParameterValue(0)]int nbytes, [DefaultParameterValue(0)]int flags) {
  576. int bytesRead;
  577. byte[] byteBuffer = new byte[byteBufferSize("recvfrom_into", nbytes, buffer.Count, 1)];
  578. IPEndPoint remoteIPEP = new IPEndPoint(IPAddress.Any, 0);
  579. EndPoint remoteEP = remoteIPEP;
  580. try {
  581. bytesRead = _socket.ReceiveFrom(byteBuffer, (SocketFlags)flags, ref remoteEP);
  582. } catch (Exception e) {
  583. throw MakeRecvException(e, SocketError.InvalidArgument);
  584. }
  585. for (int i = 0; i < byteBuffer.Length; i++) {
  586. buffer[i] = byteBuffer[i];
  587. }
  588. PythonTuple remoteAddress = EndPointToTuple((IPEndPoint)remoteEP);
  589. return PythonTuple.MakeTuple(bytesRead, remoteAddress);
  590. }
  591. public PythonTuple recvfrom_into(object buffer, [DefaultParameterValue(0)]int nbytes, [DefaultParameterValue(0)]int flags) {
  592. throw PythonOps.TypeError(string.Format("recvfrom_into() argument 1 must be read-write buffer, not {0}", PythonOps.GetPythonTypeName(buffer)));
  593. }
  594. private static int byteBufferSize(string funcName, int nbytes, int bufLength, int itemSize) {
  595. if (nbytes < 0) {
  596. throw PythonOps.ValueError("negative buffersize in " + funcName);
  597. } else if (nbytes == 0) {
  598. return bufLength * itemSize;
  599. } else {
  600. int remainder = nbytes % itemSize;
  601. return Math.Min(remainder == 0 ? nbytes : nbytes + itemSize - remainder,
  602. bufLength * itemSize);
  603. }
  604. }
  605. private Exception MakeRecvException(Exception e, SocketError errorCode = SocketError.InvalidArgument) {
  606. // on the socket recv throw a special socket error code when SendTimeout is zero
  607. if (_socket.SendTimeout == 0) {
  608. var s = new SocketException((int)errorCode);
  609. return PythonExceptions.CreateThrowable(error(_context), (int)SocketError.InvalidArgument, s.Message);
  610. }
  611. else
  612. return MakeException(_context, e);
  613. }
  614. [Documentation("send(string[, flags]) -> bytes_sent\n\n"
  615. + "Send data to the remote socket. The socket must be connected to a remote\n"
  616. + "socket (by calling either connect() or accept(). Returns the number of bytes\n"
  617. + "sent to the remote socket.\n"
  618. + "\n"
  619. + "Note that the successful completion of a send() call does not mean that all of\n"
  620. + "the data was sent. The caller must keep track of the number of bytes sent and\n"
  621. + "retry the operation until all of the data has been sent.\n"
  622. + "\n"
  623. + "Also note that there is no guarantee that the data you send will appear on the\n"
  624. + "network immediately. To increase network efficiency, the underlying system may\n"
  625. + "delay transmission until a significant amount of outgoing data is collected. A\n"
  626. + "successful completion of the Send method means that the underlying system has\n"
  627. + "had room to buffer your data for a network send"
  628. )]
  629. public int send(string data, [DefaultParameterValue(0)] int flags) {
  630. byte[] buffer = data.MakeByteArray();
  631. try {
  632. return _socket.Send(buffer, (SocketFlags)flags);
  633. } catch (Exception e) {
  634. throw MakeException(_context, e);
  635. }
  636. }
  637. [Documentation("send(string[, flags]) -> bytes_sent\n\n"
  638. + "Send data to the remote socket. The socket must be connected to a remote\n"
  639. + "socket (by calling either connect() or accept(). Returns the number of bytes\n"
  640. + "sent to the remote socket.\n"
  641. + "\n"
  642. + "Note that the successful completion of a send() call does not mean that all of\n"
  643. + "the data was sent. The caller must keep track of the number of bytes sent and\n"
  644. + "retry the operation until all of the data has been sent.\n"
  645. + "\n"
  646. + "Also note that there is no guarantee that the data you send will appear on the\n"
  647. + "network immediately. To increase network efficiency, the underlying system may\n"
  648. + "delay transmission until a significant amount of outgoing data is collected. A\n"
  649. + "successful completion of the Send method means that the underlying system has\n"
  650. + "had room to buffer your data for a network send"
  651. )]
  652. public int send(Bytes data, [DefaultParameterValue(0)] int flags) {
  653. byte[] buffer = data.GetUnsafeByteArray();
  654. try {
  655. return _socket.Send(buffer, (SocketFlags)flags);
  656. } catch (Exception e) {
  657. throw MakeException(_context, e);
  658. }
  659. }
  660. [Documentation("send(string[, flags]) -> bytes_sent\n\n"
  661. + "Send data to the remote socket. The socket must be connected to a remote\n"
  662. + "socket (by calling either connect() or accept(). Returns the number of bytes\n"
  663. + "sent to the remote socket.\n"
  664. + "\n"
  665. + "Note that the successful completion of a send() call does not mean that all of\n"
  666. + "the data was sent. The caller must keep track of the number of bytes sent and\n"
  667. + "retry the operation until all of the data has been sent.\n"
  668. + "\n"
  669. + "Also note that there is no guarantee that the data you send will appear on the\n"
  670. + "network immediately. To increase network efficiency, the underlying system may\n"
  671. + "delay transmission until a significant amount of outgoing data is collected. A\n"
  672. + "successful completion of the Send method means that the underlying system has\n"
  673. + "had room to buffer your data for a network send"
  674. )]
  675. public int send(PythonBuffer data, [DefaultParameterValue(0)] int flags) {
  676. byte[] buffer = data.byteCache;
  677. try {
  678. return _socket.Send(buffer, (SocketFlags)flags);
  679. } catch (Exception e) {
  680. throw MakeException(_context, e);
  681. }
  682. }
  683. [Documentation("sendall(string[, flags]) -> None\n\n"
  684. + "Send data to the remote socket. The socket must be connected to a remote\n"
  685. + "socket (by calling either connect() or accept().\n"
  686. + "\n"
  687. + "Unlike send(), sendall() blocks until all of the data has been sent or until a\n"
  688. + "timeout or an error occurs. None is returned on success. If an error occurs,\n"
  689. + "there is no way to tell how much data, if any, was sent.\n"
  690. + "\n"
  691. + "Difference from CPython: timeouts do not function as you would expect. The\n"
  692. + "function is implemented using multiple calls to send(), so the timeout timer\n"
  693. + "is reset after each of those calls. That means that the upper bound on the\n"
  694. + "time that it will take for sendall() to return is the number of bytes in\n"
  695. + "string times the timeout interval.\n"
  696. + "\n"
  697. + "Also note that there is no guarantee that the data you send will appear on the\n"
  698. + "network immediately. To increase network efficiency, the underlying system may\n"
  699. + "delay transmission until a significant amount of outgoing data is collected. A\n"
  700. + "successful completion of the Send method means that the underlying system has\n"
  701. + "had room to buffer your data for a network send"
  702. )]
  703. public void sendall(string data, [DefaultParameterValue(0)] int flags) {
  704. sendallWorker(data.MakeByteArray(), flags);
  705. }
  706. [Documentation("sendall(string[, flags]) -> None\n\n"
  707. + "Send data to the remote socket. The socket must be connected to a remote\n"
  708. + "socket (by calling either connect() or accept().\n"
  709. + "\n"
  710. + "Unlike send(), sendall() blocks until all of the data has been sent or until a\n"
  711. + "timeout or an error occurs. None is returned on success. If an error occurs,\n"
  712. + "there is no way to tell how much data, if any, was sent.\n"
  713. + "\n"
  714. + "Difference from CPython: timeouts do not function as you would expect. The\n"
  715. + "function is implemented using multiple calls to send(), so the timeout timer\n"
  716. + "is reset after each of those calls. That means that the upper bound on the\n"
  717. + "time that it will take for sendall() to return is the number of bytes in\n"
  718. + "string times the timeout interval.\n"
  719. + "\n"
  720. + "Also note that there is no guarantee that the data you send will appear on the\n"
  721. + "network immediately. To increase network efficiency, the underlying system may\n"
  722. + "delay transmission until a significant amount of outgoing data is collected. A\n"
  723. + "successful completion of the Send method means that the underlying system has\n"
  724. + "had room to buffer your data for a network send"
  725. )]
  726. public void sendall(Bytes data, [DefaultParameterValue(0)] int flags) {
  727. sendallWorker(data.GetUnsafeByteArray(), flags);
  728. }
  729. [Documentation("sendall(string[, flags]) -> None\n\n"
  730. + "Send data to the remote socket. The socket must be connected to a remote\n"
  731. + "socket (by calling either connect() or accept().\n"
  732. + "\n"
  733. + "Unlike send(), sendall() blocks until all of the data has been sent or until a\n"
  734. + "timeout or an error occurs. None is returned on success. If an error occurs,\n"
  735. + "there is no way to tell how much data, if any, was sent.\n"
  736. + "\n"
  737. + "Difference from CPython: timeouts do not function as you would expect. The\n"
  738. + "function is implemented using multiple calls to send(), so the timeout timer\n"
  739. + "is reset after each of those calls. That means that the upper bound on the\n"
  740. + "time that it will take for sendall() to return is the number of bytes in\n"
  741. + "string times the timeout interval.\n"
  742. + "\n"
  743. + "Also note that there is no guarantee that the data you send will appear on the\n"
  744. + "network immediately. To increase network efficiency, the underlying system may\n"
  745. + "delay transmission until a significant amount of outgoing data is collected. A\n"
  746. + "successful completion of the Send method means that the underlying system has\n"
  747. + "had room to buffer your data for a network send"
  748. )]
  749. public void sendall(PythonBuffer data, [DefaultParameterValue(0)] int flags) {
  750. sendallWorker(data.byteCache, flags);
  751. }
  752. private void sendallWorker(byte[] buffer, int flags) {
  753. try {
  754. int bytesTotal = buffer.Length;
  755. int bytesRemaining = bytesTotal;
  756. while (bytesRemaining > 0) {
  757. bytesRemaining -= _socket.Send(buffer, bytesTotal - bytesRemaining, bytesRemaining, (SocketFlags)flags);
  758. }
  759. } catch (Exception e) {
  760. throw MakeException(_context, e);
  761. }
  762. }
  763. [Documentation("sendto(string[, flags], address) -> bytes_sent\n\n"
  764. + "Send data to the remote socket. The socket does not need to be connected to a\n"
  765. + "remote socket since the address is specified in the call to sendto(). Returns\n"
  766. + "the number of bytes sent to the remote socket.\n"
  767. + "\n"
  768. + "Blocking sockets will block until the all of the bytes in the buffer are sent.\n"
  769. + "Since a nonblocking Socket completes immediately, it might not send all of the\n"
  770. + "bytes in the buffer. It is your application's responsibility to keep track of\n"
  771. + "the number of bytes sent and to retry the operation until the application sends\n"
  772. + "all of the bytes in the buffer.\n"
  773. + "\n"
  774. + "Note that there is no guarantee that the data you send will appear on the\n"
  775. + "network immediately. To increase network efficiency, the underlying system may\n"
  776. + "delay transmission until a significant amount of outgoing data is collected. A\n"
  777. + "successful completion of the Send method means that the underlying system has\n"
  778. + "had room to buffer your data for a network send"
  779. )]
  780. public int sendto(string data, int flags, PythonTuple address) {
  781. byte[] buffer = data.MakeByteArray();
  782. EndPoint remoteEP = TupleToEndPoint(_context, address, _socket.AddressFamily, out _hostName);
  783. try {
  784. return _socket.SendTo(buffer, (SocketFlags)flags, remoteEP);
  785. } catch (Exception e) {
  786. throw MakeException(_context, e);
  787. }
  788. }
  789. [Documentation("sendto(string[, flags], address) -> bytes_sent\n\n"
  790. + "Send data to the remote socket. The socket does not need to be connected to a\n"
  791. + "remote socket since the address is specified in the call to sendto(). Returns\n"
  792. + "the number of bytes sent to the remote socket.\n"
  793. + "\n"
  794. + "Blocking sockets will block until the all of the bytes in the buffer are sent.\n"
  795. + "Since a nonblocking Socket completes immediately, it might not send all of the\n"
  796. + "bytes in the buffer. It is your application's responsibility to keep track of\n"
  797. + "the number of bytes sent and to retry the operation until the application sends\n"
  798. + "all of the bytes in the buffer.\n"
  799. + "\n"
  800. + "Note that there is no guarantee that the data you send will appear on the\n"
  801. + "network immediately. To increase network efficiency, the underlying system may\n"
  802. + "delay transmission until a significant amount of outgoing data is collected. A\n"
  803. + "successful completion of the Send method means that the underlying system has\n"
  804. + "had room to buffer your data for a network send"
  805. )]
  806. public int sendto(Bytes data, int flags, PythonTuple address) {
  807. byte[] buffer = data.GetUnsafeByteArray();
  808. EndPoint remoteEP = TupleToEndPoint(_context, address, _socket.AddressFamily, out _hostName);
  809. try {
  810. return _socket.SendTo(buffer, (SocketFlags)flags, remoteEP);
  811. } catch (Exception e) {
  812. throw MakeException(_context, e);
  813. }
  814. }
  815. [Documentation("")]
  816. public int sendto(string data, PythonTuple address) {
  817. return sendto(data, 0, address);
  818. }
  819. [Documentation("")]
  820. public int sendto(Bytes data, PythonTuple address) {
  821. return sendto(data, 0, address);
  822. }
  823. [Documentation("setblocking(flag) -> None\n\n"
  824. + "Set the blocking mode of the socket. If flag is 0, the socket will be set to\n"
  825. + "non-blocking mode; otherwise, it will be set to blocking mode. If the socket is\n"
  826. + "in blocking mode, and a method is called (such as send() or recv() which does\n"
  827. + "not complete immediately, the caller will block execution until the requested\n"
  828. + "operation completes. In non-blocking mode, a socket.timeout exception would\n"
  829. + "would be raised in this case.\n"
  830. + "\n"
  831. + "Note that changing blocking mode also affects the timeout setting:\n"
  832. + "setblocking(0) is equivalent to settimeout(0), and setblocking(1) is equivalent\n"
  833. + "to settimeout(None)."
  834. )]
  835. public void setblocking(int shouldBlock) {
  836. if (shouldBlock == 0) {
  837. settimeout(0);
  838. } else {
  839. settimeo

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