PageRenderTime 79ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/CoolEngine/IronPython/Src/IronPython.Modules/socket.cs

#
C# | 1715 lines | 1422 code | 172 blank | 121 comment | 186 complexity | 636155de9ac01bb0d7edad2af9e81902 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.Runtime.InteropServices;
  24. using System.Text;
  25. using Microsoft.Scripting;
  26. using Microsoft.Scripting.Actions;
  27. using Microsoft.Scripting.Math;
  28. using Microsoft.Scripting.Runtime;
  29. using IronPython.Runtime;
  30. using IronPython.Runtime.Calls;
  31. using IronPython.Runtime.Types;
  32. using IronPython.Runtime.Operations;
  33. using IronPython.Runtime.Exceptions;
  34. using SpecialNameAttribute = System.Runtime.CompilerServices.SpecialNameAttribute;
  35. [assembly: PythonModule("socket", typeof(IronPython.Modules.PythonSocket))]
  36. namespace IronPython.Modules {
  37. public static class PythonSocket {
  38. private static readonly object _defaultTimeoutKey = new object();
  39. private static readonly object _defaultBufsizeKey = new object();
  40. private const int DefaultBufferSize = 8192;
  41. [SpecialName]
  42. public static void PerformModuleReload(PythonContext/*!*/ context, IAttributesCollection/*!*/ dict) {
  43. if (!context.HasModuleState(_defaultTimeoutKey)) {
  44. context.SetModuleState(_defaultTimeoutKey, null);
  45. }
  46. context.SetModuleState(_defaultBufsizeKey, DefaultBufferSize);
  47. }
  48. public const string __doc__ = "Implementation module for socket operations.\n\n"
  49. + "This module is a loose wrapper around the .NET System.Net.Sockets API, so you\n"
  50. + "may find the corresponding MSDN documentation helpful in decoding error\n"
  51. + "messages and understanding corner cases.\n"
  52. + "\n"
  53. + "This implementation of socket differs slightly from the standard CPython\n"
  54. + "socket module. Many of these differences are due to the implementation of the\n"
  55. + ".NET socket libraries. These differences are summarized below. For full\n"
  56. + "details, check the docstrings of the functions mentioned.\n"
  57. + " - s.accept(), s.connect(), and s.connect_ex() do not support timeouts.\n"
  58. + " - Timeouts in s.sendall() don't work correctly.\n"
  59. + " - s.dup() is not implemented.\n"
  60. + " - getservbyname() and getservbyport() are not implemented.\n"
  61. + " - SSL support is not implemented."
  62. + "\n"
  63. + "An Extra IronPython-specific function is exposed only if the clr module is\n"
  64. + "imported:\n"
  65. + " - s.HandleToSocket() returns the System.Net.Sockets.Socket object associated\n"
  66. + " with a particular \"file descriptor number\" (as returned by s.fileno()).\n"
  67. ;
  68. #region Socket object
  69. public static PythonType SocketType = DynamicHelpers.GetPythonTypeFromType(typeof(socket));
  70. [PythonSystemType]
  71. [Documentation("socket([family[, type[, proto]]]) -> socket object\n\n"
  72. + "Create a socket (a network connection endpoint) of the given family, type,\n"
  73. + "and protocol. socket() accepts keyword arguments.\n"
  74. + " - family (address family) defaults to AF_INET\n"
  75. + " - type (socket type) defaults to SOCK_STREAM\n"
  76. + " - proto (protocol type) defaults to 0, which specifies the default protocol\n"
  77. + "\n"
  78. + "This module supports only IP sockets. It does not support raw or Unix sockets.\n"
  79. + "Both IPv4 and IPv6 are supported.")]
  80. public class socket : IWeakReferenceable {
  81. #region Fields
  82. /// <summary>
  83. /// handleToSocket allows us to translate from Python's idea of a socket resource (file
  84. /// descriptor numbers) to .NET's idea of a socket resource (System.Net.Socket objects).
  85. /// In particular, this allows the select module to convert file numbers (as returned by
  86. /// fileno()) and convert them to Socket objects so that it can do something useful with them.
  87. /// </summary>
  88. private static readonly Dictionary<IntPtr, List<Socket>> handleToSocket = new Dictionary<IntPtr, List<Socket>>();
  89. private const int DefaultAddressFamily = (int)AddressFamily.InterNetwork;
  90. private const int DefaultSocketType = (int)System.Net.Sockets.SocketType.Stream;
  91. private const int DefaultProtocolType = (int)ProtocolType.Unspecified;
  92. internal Socket _socket;
  93. private WeakRefTracker weakRefTracker = null;
  94. #endregion
  95. #region Public API
  96. public socket(CodeContext/*!*/ context, [DefaultParameterValue(DefaultAddressFamily)] int addressFamily,
  97. [DefaultParameterValue(DefaultSocketType)] int socketType,
  98. [DefaultParameterValue(DefaultProtocolType)] int protocolType) {
  99. System.Net.Sockets.SocketType type = (System.Net.Sockets.SocketType)Enum.ToObject(typeof(System.Net.Sockets.SocketType), socketType);
  100. if (!Enum.IsDefined(typeof(System.Net.Sockets.SocketType), type)) {
  101. throw MakeException(new SocketException((int)SocketError.SocketNotSupported));
  102. }
  103. AddressFamily family = (AddressFamily)Enum.ToObject(typeof(AddressFamily), addressFamily);
  104. if (!Enum.IsDefined(typeof(AddressFamily), family)) {
  105. throw MakeException(new SocketException((int)SocketError.AddressFamilyNotSupported));
  106. }
  107. ProtocolType proto = (ProtocolType)Enum.ToObject(typeof(ProtocolType), protocolType);
  108. if (!Enum.IsDefined(typeof(ProtocolType), proto)) {
  109. throw MakeException(new SocketException((int)SocketError.ProtocolNotSupported));
  110. }
  111. Socket newSocket;
  112. try {
  113. newSocket = new Socket(family, type, proto);
  114. } catch (SocketException e) {
  115. throw MakeException(e);
  116. }
  117. Initialize(context, newSocket);
  118. }
  119. [Documentation("accept() -> (conn, address)\n\n"
  120. + "Accept a connection. The socket must be bound and listening before calling\n"
  121. + "accept(). conn is a new socket object connected to the remote host, and\n"
  122. + "address is the remote host's address (e.g. a (host, port) tuple for IPv4).\n"
  123. + "\n"
  124. + "Difference from CPython: accept() does not support timeouts in blocking mode.\n"
  125. + "If a timeout is set and the socket is in blocking mode, accept() will block\n"
  126. + "indefinitely until a connection is ready."
  127. )]
  128. public PythonTuple accept(CodeContext/*!*/ context) {
  129. socket wrappedRemoteSocket;
  130. Socket realRemoteSocket;
  131. try {
  132. realRemoteSocket = _socket.Accept();
  133. } catch (Exception e) {
  134. throw MakeException(e);
  135. }
  136. wrappedRemoteSocket = new socket(context, realRemoteSocket);
  137. return PythonTuple.MakeTuple(wrappedRemoteSocket, wrappedRemoteSocket.getpeername());
  138. }
  139. [Documentation("bind(address) -> None\n\n"
  140. + "Bind to an address. If the socket is already bound, socket.error is raised.\n"
  141. + "For IP sockets, address is a (host, port) tuple. Raw sockets are not\n"
  142. + "supported.\n"
  143. + "\n"
  144. + "If you do not care which local address is assigned, set host to INADDR_ANY and\n"
  145. + "the system will assign the most appropriate network address. Similarly, if you\n"
  146. + "set port to 0, the system will assign an available port number between 1024\n"
  147. + "and 5000."
  148. )]
  149. public void bind(PythonTuple address) {
  150. IPEndPoint localEP = TupleToEndPoint(address, _socket.AddressFamily);
  151. try {
  152. _socket.Bind(localEP);
  153. } catch (Exception e) {
  154. throw MakeException(e);
  155. }
  156. }
  157. [Documentation("close() -> None\n\nClose the socket. It cannot be used after being closed.")]
  158. public void close() {
  159. RemoveHandleSocketMapping(this);
  160. }
  161. internal static void RemoveHandleSocketMapping(socket socket) {
  162. lock (handleToSocket) {
  163. List<Socket> sockets;
  164. if (handleToSocket.TryGetValue((IntPtr)socket._socket.Handle, out sockets)) {
  165. for (int i = sockets.Count-1; i >= 0; i--) {
  166. if (sockets[i] == socket._socket) {
  167. sockets.RemoveAt(i);
  168. break;
  169. }
  170. }
  171. if (sockets.Count == 0) {
  172. handleToSocket.Remove(socket._socket.Handle);
  173. try {
  174. socket._socket.Close();
  175. } catch (Exception e) {
  176. throw MakeException(e);
  177. }
  178. }
  179. }
  180. }
  181. }
  182. [Documentation("connect(address) -> None\n\n"
  183. + "Connect to a remote socket at the given address. IP addresses are expressed\n"
  184. + "as (host, port).\n"
  185. + "\n"
  186. + "Raises socket.error if the socket has been closed, the socket is listening, or\n"
  187. + "another connection error occurred."
  188. + "\n"
  189. + "Difference from CPython: connect() does not support timeouts in blocking mode.\n"
  190. + "If a timeout is set and the socket is in blocking mode, connect() will block\n"
  191. + "indefinitely until a connection is made or an error occurs."
  192. )]
  193. public void connect(PythonTuple address) {
  194. IPEndPoint remoteEP = TupleToEndPoint(address, _socket.AddressFamily);
  195. try {
  196. _socket.Connect(remoteEP);
  197. } catch (Exception e) {
  198. throw MakeException(e);
  199. }
  200. }
  201. [Documentation("connect_ex(address) -> error_code\n\n"
  202. + "Like connect(), but return an error code insted of raising an exception for\n"
  203. + "socket exceptions raised by the underlying system Connect() call. Note that\n"
  204. + "exceptions other than SocketException generated by the system Connect() call\n"
  205. + "will still be raised.\n"
  206. + "\n"
  207. + "A return value of 0 indicates that the connect call was successful."
  208. + "\n"
  209. + "Difference from CPython: connect_ex() does not support timeouts in blocking\n"
  210. + "mode. If a timeout is set and the socket is in blocking mode, connect_ex() will\n"
  211. + "block indefinitely until a connection is made or an error occurs."
  212. )]
  213. public int connect_ex(PythonTuple address) {
  214. IPEndPoint remoteEP = TupleToEndPoint(address, _socket.AddressFamily);
  215. try {
  216. _socket.Connect(remoteEP);
  217. } catch (SocketException e) {
  218. return e.ErrorCode;
  219. }
  220. return (int)SocketError.Success;
  221. }
  222. [Documentation("fileno() -> file_handle\n\n"
  223. + "Return the underlying system handle for this socket (a 64-bit integer)."
  224. )]
  225. public Int64 fileno() {
  226. try {
  227. return _socket.Handle.ToInt64();
  228. } catch (Exception e) {
  229. throw MakeException(e);
  230. }
  231. }
  232. [Documentation("getpeername() -> address\n\n"
  233. + "Return the address of the remote end of this socket. The address format is\n"
  234. + "family-dependent (e.g. a (host, port) tuple for IPv4)."
  235. )]
  236. public PythonTuple getpeername() {
  237. try {
  238. IPEndPoint remoteEP = _socket.RemoteEndPoint as IPEndPoint;
  239. if (remoteEP == null) {
  240. throw MakeException(new SocketException((int)SocketError.AddressFamilyNotSupported));
  241. }
  242. return EndPointToTuple(remoteEP);
  243. } catch (Exception e) {
  244. throw MakeException(e);
  245. }
  246. }
  247. [Documentation("getsockname() -> address\n\n"
  248. + "Return the address of the local end of this socket. The address format is\n"
  249. + "family-dependent (e.g. a (host, port) tuple for IPv4)."
  250. )]
  251. public PythonTuple getsockname() {
  252. try {
  253. IPEndPoint localEP = _socket.LocalEndPoint as IPEndPoint;
  254. if (localEP == null) {
  255. throw MakeException(new SocketException((int)SocketError.InvalidArgument));
  256. }
  257. return EndPointToTuple(localEP);
  258. } catch (Exception e) {
  259. throw MakeException(e);
  260. }
  261. }
  262. [Documentation("getsockopt(level, optname[, buflen]) -> value\n\n"
  263. + "Return the value of a socket option. level is one of the SOL_* constants\n"
  264. + "defined in this module, and optname is one of the SO_* constants. If buflen is\n"
  265. + "omitted or zero, an integer value is returned. If it is present, a byte string\n"
  266. + "whose maximum length is buflen bytes) is returned. The caller must the decode\n"
  267. + "the resulting byte string."
  268. )]
  269. public object getsockopt(int optionLevel, int optionName, [DefaultParameterValue(0)] int optionLength) {
  270. SocketOptionLevel level = (SocketOptionLevel)Enum.ToObject(typeof(SocketOptionLevel), optionLevel);
  271. if (!Enum.IsDefined(typeof(SocketOptionLevel), level)) {
  272. throw MakeException(new SocketException((int)SocketError.InvalidArgument));
  273. }
  274. SocketOptionName name = (SocketOptionName)Enum.ToObject(typeof(SocketOptionName), optionName);
  275. if (!Enum.IsDefined(typeof(SocketOptionName), name)) {
  276. throw MakeException(new SocketException((int)SocketError.ProtocolOption));
  277. }
  278. try {
  279. if (optionLength == 0) {
  280. // Integer return value
  281. return (int)_socket.GetSocketOption(level, name);
  282. } else {
  283. // Byte string return value
  284. return StringOps.FromByteArray(_socket.GetSocketOption(level, name, optionLength));
  285. }
  286. } catch (Exception e) {
  287. throw MakeException(e);
  288. }
  289. }
  290. [Documentation("listen(backlog) -> None\n\n"
  291. + "Listen for connections on the socket. Backlog is the maximum length of the\n"
  292. + "pending connections queue. The maximum value is system-dependent."
  293. )]
  294. public void listen(int backlog) {
  295. try {
  296. _socket.Listen(backlog);
  297. } catch (Exception e) {
  298. throw MakeException(e);
  299. }
  300. }
  301. [Documentation("makefile([mode[, bufsize]]) -> file object\n\n"
  302. + "Return a regular file object corresponding to the socket. The mode\n"
  303. + "and bufsize arguments are as for the built-in open() function.")]
  304. public PythonFile makefile(CodeContext/*!*/ context, [DefaultParameterValue("r")]string mode, [DefaultParameterValue(8192)]int bufSize) {
  305. AddHandleMapping(this); // dup our handle
  306. return new _fileobject(context, this, mode, bufSize);
  307. }
  308. [Documentation("recv(bufsize[, flags]) -> string\n\n"
  309. + "Receive data from the socket, up to bufsize bytes. For connection-oriented\n"
  310. + "protocols (e.g. SOCK_STREAM), you must first call either connect() or\n"
  311. + "accept(). Connectionless protocols (e.g. SOCK_DGRAM) may also use recvfrom().\n"
  312. + "\n"
  313. + "recv() blocks until data is available, unless a timeout was set using\n"
  314. + "settimeout(). If the timeout was exceeded, socket.timeout is raised."
  315. + "recv() returns immediately with zero bytes when the connection is closed."
  316. )]
  317. public string recv(int maxBytes, [DefaultParameterValue(0)] int flags) {
  318. int bytesRead;
  319. byte[] buffer = new byte[maxBytes];
  320. try {
  321. bytesRead = _socket.Receive(buffer, (SocketFlags)flags);
  322. } catch (Exception e) {
  323. throw MakeException(e);
  324. }
  325. return StringOps.FromByteArray(buffer, bytesRead);
  326. }
  327. [Documentation("recvfrom(bufsize[, flags]) -> (string, address)\n\n"
  328. + "Receive data from the socket, up to bufsize bytes. string is the data\n"
  329. + "received, and address (whose format is protocol-dependent) is the address of\n"
  330. + "the socket from which the data was received."
  331. )]
  332. public PythonTuple recvfrom(int maxBytes, [DefaultParameterValue(0)] int flags) {
  333. int bytesRead;
  334. byte[] buffer = new byte[maxBytes];
  335. IPEndPoint remoteIPEP = new IPEndPoint(IPAddress.Any, 0);
  336. EndPoint remoteEP = remoteIPEP;
  337. try {
  338. bytesRead = _socket.ReceiveFrom(buffer, (SocketFlags)flags, ref remoteEP);
  339. } catch (Exception e) {
  340. throw MakeException(e);
  341. }
  342. string data = StringOps.FromByteArray(buffer, bytesRead);
  343. PythonTuple remoteAddress = EndPointToTuple((IPEndPoint)remoteEP);
  344. return PythonTuple.MakeTuple(data, remoteAddress);
  345. }
  346. [Documentation("send(string[, flags]) -> bytes_sent\n\n"
  347. + "Send data to the remote socket. The socket must be connected to a remote\n"
  348. + "socket (by calling either connect() or accept(). Returns the number of bytes\n"
  349. + "sent to the remote socket.\n"
  350. + "\n"
  351. + "Note that the successful completion of a send() call does not mean that all of\n"
  352. + "the data was sent. The caller must keep track of the number of bytes sent and\n"
  353. + "retry the operation until all of the data has been sent.\n"
  354. + "\n"
  355. + "Also note that there is no guarantee that the data you send will appear on the\n"
  356. + "network immediately. To increase network efficiency, the underlying system may\n"
  357. + "delay transmission until a significant amount of outgoing data is collected. A\n"
  358. + "successful completion of the Send method means that the underlying system has\n"
  359. + "had room to buffer your data for a network send"
  360. )]
  361. public int send(string data, [DefaultParameterValue(0)] int flags) {
  362. byte[] buffer = StringOps.ToByteArray(data);
  363. try {
  364. return _socket.Send(buffer, (SocketFlags)flags);
  365. } catch (Exception e) {
  366. throw MakeException(e);
  367. }
  368. }
  369. [Documentation("sendall(string[, flags]) -> None\n\n"
  370. + "Send data to the remote socket. The socket must be connected to a remote\n"
  371. + "socket (by calling either connect() or accept().\n"
  372. + "\n"
  373. + "Unlike send(), sendall() blocks until all of the data has been sent or until a\n"
  374. + "timeout or an error occurs. None is returned on success. If an error occurs,\n"
  375. + "there is no way to tell how much data, if any, was sent.\n"
  376. + "\n"
  377. + "Difference from CPython: timeouts do not function as you would expect. The\n"
  378. + "function is implemented using multiple calls to send(), so the timeout timer\n"
  379. + "is reset after each of those calls. That means that the upper bound on the\n"
  380. + "time that it will take for sendall() to return is the number of bytes in\n"
  381. + "string times the timeout interval.\n"
  382. + "\n"
  383. + "Also note that there is no guarantee that the data you send will appear on the\n"
  384. + "network immediately. To increase network efficiency, the underlying system may\n"
  385. + "delay transmission until a significant amount of outgoing data is collected. A\n"
  386. + "successful completion of the Send method means that the underlying system has\n"
  387. + "had room to buffer your data for a network send"
  388. )]
  389. public void sendall(string data, [DefaultParameterValue(0)] int flags) {
  390. byte[] buffer = StringOps.ToByteArray(data);
  391. try {
  392. int bytesTotal = buffer.Length;
  393. int bytesRemaining = bytesTotal;
  394. while (bytesRemaining > 0) {
  395. bytesRemaining -= _socket.Send(buffer, bytesTotal - bytesRemaining, bytesRemaining, (SocketFlags)flags);
  396. }
  397. } catch (Exception e) {
  398. throw MakeException(e);
  399. }
  400. }
  401. [Documentation("sendto(string[, flags], address) -> bytes_sent\n\n"
  402. + "Send data to the remote socket. The socket does not need to be connected to a\n"
  403. + "remote socket since the address is specified in the call to sendto(). Returns\n"
  404. + "the number of bytes sent to the remote socket.\n"
  405. + "\n"
  406. + "Blocking sockets will block until the all of the bytes in the buffer are sent.\n"
  407. + "Since a nonblocking Socket completes immediately, it might not send all of the\n"
  408. + "bytes in the buffer. It is your application's responsibility to keep track of\n"
  409. + "the number of bytes sent and to retry the operation until the application sends\n"
  410. + "all of the bytes in the buffer.\n"
  411. + "\n"
  412. + "Note that there is no guarantee that the data you send will appear on the\n"
  413. + "network immediately. To increase network efficiency, the underlying system may\n"
  414. + "delay transmission until a significant amount of outgoing data is collected. A\n"
  415. + "successful completion of the Send method means that the underlying system has\n"
  416. + "had room to buffer your data for a network send"
  417. )]
  418. public int sendto(string data, int flags, PythonTuple address) {
  419. byte[] buffer = StringOps.ToByteArray(data);
  420. EndPoint remoteEP = TupleToEndPoint(address, _socket.AddressFamily);
  421. try {
  422. return _socket.SendTo(buffer, (SocketFlags)flags, remoteEP);
  423. } catch (Exception e) {
  424. throw MakeException(e);
  425. }
  426. }
  427. [Documentation("")]
  428. public int sendto(string data, PythonTuple address) {
  429. return sendto(data, 0, address);
  430. }
  431. [Documentation("setblocking(flag) -> None\n\n"
  432. + "Set the blocking mode of the socket. If flag is 0, the socket will be set to\n"
  433. + "non-blocking mode; otherwise, it will be set to blocking mode. If the socket is\n"
  434. + "in blocking mode, and a method is called (such as send() or recv() which does\n"
  435. + "not complete immediately, the caller will block execution until the requested\n"
  436. + "operation completes. In non-blocking mode, a socket.timeout exception would\n"
  437. + "would be raised in this case.\n"
  438. + "\n"
  439. + "Note that changing blocking mode also affects the timeout setting:\n"
  440. + "setblocking(0) is equivalent to settimeout(0), and setblocking(1) is equivalent\n"
  441. + "to settimeout(None)."
  442. )]
  443. public void setblocking(int shouldBlock) {
  444. if (shouldBlock == 0) {
  445. settimeout(0);
  446. } else {
  447. settimeout(null);
  448. }
  449. }
  450. [Documentation("settimeout(value) -> None\n\n"
  451. + "Set a timeout on blocking socket methods. value may be either None or a\n"
  452. + "non-negative float, with one of the following meanings:\n"
  453. + " - None: disable timeouts and block indefinitely"
  454. + " - 0.0: don't block at all (return immediately if the operation can be\n"
  455. + " completed; raise socket.error otherwise)\n"
  456. + " - float > 0.0: block for up to the specified number of seconds; raise\n"
  457. + " socket.timeout if the operation cannot be completed in time\n"
  458. + "\n"
  459. + "settimeout(None) is equivalent to setblocking(1), and settimeout(0.0) is\n"
  460. + "equivalent to setblocking(0)."
  461. + "\n"
  462. + "If the timeout is non-zero and is less than 0.5, it will be set to 0.5. This\n"
  463. + "limitation is specific to IronPython.\n"
  464. )]
  465. public void settimeout(object timeout) {
  466. try {
  467. if (timeout == null) {
  468. _socket.Blocking = true;
  469. _socket.SendTimeout = 0;
  470. } else {
  471. double seconds;
  472. seconds = Converter.ConvertToDouble(timeout);
  473. if (seconds < 0) {
  474. throw PythonOps.TypeError("a non-negative float is required");
  475. }
  476. _socket.Blocking = seconds > 0; // 0 timeout means non-blocking mode
  477. _socket.SendTimeout = (int)(seconds * MillisecondsPerSecond);
  478. }
  479. } finally {
  480. _socket.ReceiveTimeout = _socket.SendTimeout;
  481. }
  482. }
  483. [Documentation("gettimeout() -> value\n\n"
  484. + "Return the timeout duration in seconds for this socket as a float. If no\n"
  485. + "timeout is set, return None. For more details on timeouts and blocking, see the\n"
  486. + "Python socket module documentation."
  487. )]
  488. public object gettimeout() {
  489. try {
  490. if (_socket.Blocking && _socket.SendTimeout == 0) {
  491. return null;
  492. } else {
  493. return (double)_socket.SendTimeout / MillisecondsPerSecond;
  494. }
  495. } catch (Exception e) {
  496. throw MakeException(e);
  497. }
  498. }
  499. [Documentation("setsockopt(level, optname[, value]) -> None\n\n"
  500. + "Set the value of a socket option. level is one of the SOL_* constants defined\n"
  501. + "in this module, and optname is one of the SO_* constants. value may be either\n"
  502. + "an integer or a string containing a binary structure. The caller is responsible\n"
  503. + "for properly encoding the byte string."
  504. )]
  505. public void setsockopt(int optionLevel, int optionName, object value) {
  506. SocketOptionLevel level = (SocketOptionLevel)Enum.ToObject(typeof(SocketOptionLevel), optionLevel);
  507. if (!Enum.IsDefined(typeof(SocketOptionLevel), level)) {
  508. throw MakeException(new SocketException((int)SocketError.InvalidArgument));
  509. }
  510. SocketOptionName name = (SocketOptionName)Enum.ToObject(typeof(SocketOptionName), optionName);
  511. if (!Enum.IsDefined(typeof(SocketOptionName), name)) {
  512. throw MakeException(new SocketException((int)SocketError.ProtocolOption));
  513. }
  514. try {
  515. int intValue;
  516. if (Converter.TryConvertToInt32(value, out intValue)) {
  517. _socket.SetSocketOption(level, name, intValue);
  518. return;
  519. }
  520. string strValue;
  521. if (Converter.TryConvertToString(value, out strValue)) {
  522. _socket.SetSocketOption(level, name, StringOps.ToByteArray(strValue));
  523. return;
  524. }
  525. } catch (Exception e) {
  526. throw MakeException(e);
  527. }
  528. throw PythonOps.TypeError("setsockopt() argument 3 must be int or string");
  529. }
  530. [Documentation("shutdown() -> None\n\n"
  531. + "Return the timeout duration in seconds for this socket as a float. If no\n"
  532. + "timeout is set, return None. For more details on timeouts and blocking, see the\n"
  533. + "Python socket module documentation."
  534. )]
  535. public void shutdown(int how) {
  536. SocketShutdown howValue = (SocketShutdown)Enum.ToObject(typeof(SocketShutdown), how);
  537. if (!Enum.IsDefined(typeof(SocketShutdown), howValue)) {
  538. throw MakeException(new SocketException((int)SocketError.InvalidArgument));
  539. }
  540. try {
  541. _socket.Shutdown(howValue);
  542. } catch (Exception e) {
  543. throw MakeException(e);
  544. }
  545. }
  546. public override string ToString() {
  547. try {
  548. return "<socket object, fd=" + fileno().ToString()
  549. + ", family=" + ((int)_socket.AddressFamily).ToString()
  550. + ", type=" + ((int)_socket.SocketType).ToString()
  551. + ", protocol=" + ((int)_socket.ProtocolType).ToString()
  552. + ">"
  553. ;
  554. } catch {
  555. return "<socket object, fd=?, family=?, type=, protocol=>";
  556. }
  557. }
  558. /// <summary>
  559. /// Return the internal System.Net.Sockets.Socket socket object associated with the given
  560. /// handle (as returned by GetHandle()), or null if no corresponding socket exists. This is
  561. /// primarily intended to be used by other modules (such as select) that implement
  562. /// networking primitives. User code should not normally need to call this function.
  563. /// </summary>
  564. internal static Socket HandleToSocket(Int64 handle) {
  565. List<Socket> sockets;
  566. lock (handleToSocket) {
  567. if (handleToSocket.TryGetValue((IntPtr)handle, out sockets)) {
  568. return sockets[sockets.Count - 1];
  569. }
  570. }
  571. return null;
  572. }
  573. #endregion
  574. #region IWeakReferenceable Implementation
  575. WeakRefTracker IWeakReferenceable.GetWeakRef() {
  576. return weakRefTracker;
  577. }
  578. bool IWeakReferenceable.SetWeakRef(WeakRefTracker value) {
  579. weakRefTracker = value;
  580. return true;
  581. }
  582. void IWeakReferenceable.SetFinalizer(WeakRefTracker value) {
  583. weakRefTracker = value;
  584. }
  585. #endregion
  586. #region Private Implementation
  587. /// <summary>
  588. /// Create a Python socket object from an existing .NET socket object
  589. /// (like one returned from Socket.Accept())
  590. /// </summary>
  591. private socket(CodeContext/*!*/ context, Socket socket) {
  592. Initialize(context, socket);
  593. }
  594. /// <summary>
  595. /// Perform initialization common to all constructors
  596. /// </summary>
  597. private void Initialize(CodeContext/*!*/ context, Socket socket) {
  598. this._socket = socket;
  599. int? defaultTimeout = GetDefaultTimeout(context);
  600. if (defaultTimeout == null) {
  601. settimeout(null);
  602. } else {
  603. settimeout((double)defaultTimeout / MillisecondsPerSecond);
  604. }
  605. AddHandleMapping(this);
  606. }
  607. private static void AddHandleMapping(socket socket) {
  608. lock (handleToSocket) {
  609. if (!handleToSocket.ContainsKey(socket._socket.Handle)) {
  610. handleToSocket[socket._socket.Handle] = new List<Socket>(1);
  611. }
  612. handleToSocket[socket._socket.Handle].Add(socket._socket);
  613. }
  614. }
  615. #endregion
  616. }
  617. #endregion
  618. #region Fields
  619. public static PythonType error = PythonExceptions.CreateSubType(PythonExceptions.Exception, "error", "socket", "");
  620. public static PythonType herror = PythonExceptions.CreateSubType(error, "herror", "socket", "");
  621. public static PythonType gaierror = PythonExceptions.CreateSubType(error, "gaierror", "socket", "");
  622. public static PythonType timeout = PythonExceptions.CreateSubType(error, "timeout", "socket", "");
  623. private const string AnyAddrToken = "";
  624. private const string BroadcastAddrToken = "<broadcast>";
  625. private const string LocalhostAddrToken = "";
  626. private const int IPv4AddrBytes = 4;
  627. private const int IPv6AddrBytes = 16;
  628. private const double MillisecondsPerSecond = 1000.0;
  629. #endregion
  630. #region Public API
  631. [Documentation("")]
  632. public static List getaddrinfo(
  633. string host,
  634. object port,
  635. [DefaultParameterValue((int)AddressFamily.Unspecified)] int family,
  636. [DefaultParameterValue(0)] int socktype,
  637. [DefaultParameterValue((int)ProtocolType.IP)] int proto,
  638. [DefaultParameterValue((int)SocketFlags.None)] int flags
  639. ) {
  640. int numericPort;
  641. if (port == null) {
  642. numericPort = 0;
  643. } else if (port is int) {
  644. numericPort = (int)port;
  645. } else if (port is Extensible<int>) {
  646. numericPort = ((Extensible<int>)port).Value;
  647. } else if (port is string) {
  648. if (!Int32.TryParse((string)port, out numericPort)) {
  649. // TODO: also should consult GetServiceByName
  650. throw PythonExceptions.CreateThrowable(gaierror, "getaddrinfo failed");
  651. }
  652. } else if (port is ExtensibleString) {
  653. if (!Int32.TryParse(((ExtensibleString)port).Value, out numericPort)) {
  654. // TODO: also should consult GetServiceByName
  655. throw PythonExceptions.CreateThrowable(gaierror, "getaddrinfo failed");
  656. }
  657. } else {
  658. throw PythonExceptions.CreateThrowable(gaierror, "getaddrinfo failed");
  659. }
  660. if (socktype != 0) {
  661. // we just use this to validate; socketType isn't actually used
  662. System.Net.Sockets.SocketType socketType = (System.Net.Sockets.SocketType)Enum.ToObject(typeof(System.Net.Sockets.SocketType), socktype);
  663. if (socketType == System.Net.Sockets.SocketType.Unknown || !Enum.IsDefined(typeof(System.Net.Sockets.SocketType), socketType)) {
  664. throw PythonExceptions.CreateThrowable(gaierror, PythonTuple.MakeTuple((int)SocketError.SocketNotSupported, "getaddrinfo failed"));
  665. }
  666. }
  667. AddressFamily addressFamily = (AddressFamily)Enum.ToObject(typeof(AddressFamily), family);
  668. if (!Enum.IsDefined(typeof(AddressFamily), addressFamily)) {
  669. throw PythonExceptions.CreateThrowable(gaierror, PythonTuple.MakeTuple((int)SocketError.AddressFamilyNotSupported, "getaddrinfo failed"));
  670. }
  671. // Again, we just validate, but don't actually use protocolType
  672. ProtocolType protocolType = (ProtocolType)Enum.ToObject(typeof(ProtocolType), proto);
  673. IPAddress[] ips = HostToAddresses(host, addressFamily);
  674. List results = new List();
  675. foreach (IPAddress ip in ips) {
  676. results.append(PythonTuple.MakeTuple(
  677. (int)ip.AddressFamily,
  678. socktype,
  679. proto,
  680. "",
  681. EndPointToTuple(new IPEndPoint(ip, numericPort))
  682. ));
  683. }
  684. return results;
  685. }
  686. [Documentation("getfqdn([hostname_or_ip]) -> hostname\n\n"
  687. + "Return the fully-qualified domain name for the specified hostname or IP\n"
  688. + "address. An unspecified or empty name is interpreted as the local host. If the\n"
  689. + "name lookup fails, the passed-in name is returned as-is."
  690. )]
  691. public static string getfqdn(string host) {
  692. host = host.Trim();
  693. if (host == BroadcastAddrToken) {
  694. return host;
  695. }
  696. try {
  697. IPHostEntry hostEntry = Dns.GetHostEntry(host);
  698. if (hostEntry.HostName.Contains(".")) {
  699. return hostEntry.HostName;
  700. } else {
  701. foreach (string addr in hostEntry.Aliases) {
  702. if (addr.Contains(".")) {
  703. return addr;
  704. }
  705. }
  706. }
  707. } catch (SocketException) {
  708. // ignore and return host below
  709. }
  710. // seems to match CPython behavior, although docs say gethostname() should be returned
  711. return host;
  712. }
  713. [Documentation("")]
  714. public static string getfqdn() {
  715. return getfqdn(LocalhostAddrToken);
  716. }
  717. [Documentation("gethostbyname(hostname) -> ip address\n\n"
  718. + "Return the string IPv4 address associated with the given hostname (e.g.\n"
  719. + "'10.10.0.1'). The hostname is returned as-is if it an IPv4 address. The empty\n"
  720. + "string is treated as the local host.\n"
  721. + "\n"
  722. + "gethostbyname() doesn't support IPv6; for IPv4/IPv6 support, use getaddrinfo()."
  723. )]
  724. public static string gethostbyname(string host) {
  725. return HostToAddress(host, AddressFamily.InterNetwork).ToString();
  726. }
  727. [Documentation("gethostbyname_ex(hostname) -> (hostname, aliases, ip_addresses)\n\n"
  728. + "Return the real host name, a list of aliases, and a list of IP addresses\n"
  729. + "associated with the given hostname. If the hostname is an IPv4 address, the\n"
  730. + "tuple ([hostname, [], [hostname]) is returned without doing a DNS lookup.\n"
  731. + "\n"
  732. + "gethostbyname_ex() doesn't support IPv6; for IPv4/IPv6 support, use\n"
  733. + "getaddrinfo()."
  734. )]
  735. public static PythonTuple gethostbyname_ex(string host) {
  736. string hostname;
  737. List aliases;
  738. List ips = PythonOps.MakeList();
  739. IPAddress addr;
  740. if (IPAddress.TryParse(host, out addr)) {
  741. if (AddressFamily.InterNetwork == addr.AddressFamily) {
  742. hostname = host;
  743. aliases = PythonOps.MakeEmptyList(0);
  744. ips.append(host);
  745. } else {
  746. throw PythonExceptions.CreateThrowable(gaierror, (int)SocketError.HostNotFound, "no IPv4 addresses associated with host");
  747. }
  748. } else {
  749. IPHostEntry hostEntry;
  750. try {
  751. hostEntry = Dns.GetHostEntry(host);
  752. } catch (SocketException e) {
  753. throw PythonExceptions.CreateThrowable(gaierror, e.ErrorCode, "no IPv4 addresses associated with host");
  754. }
  755. hostname = hostEntry.HostName;
  756. aliases = PythonOps.MakeList(hostEntry.Aliases);
  757. foreach (IPAddress ip in hostEntry.AddressList) {
  758. if (AddressFamily.InterNetwork == ip.AddressFamily) {
  759. ips.append(ip.ToString());
  760. }
  761. }
  762. }
  763. return PythonTuple.MakeTuple(hostname, aliases, ips);
  764. }
  765. [Documentation("gethostname() -> hostname\nReturn this machine's hostname")]
  766. public static string gethostname() {
  767. return Dns.GetHostName();
  768. }
  769. [Documentation("gethostbyaddr(host) -> (hostname, aliases, ipaddrs)\n\n"
  770. + "Return a tuple of (primary hostname, alias hostnames, ip addresses). host may\n"
  771. + "be either a hostname or an IP address."
  772. )]
  773. public static object gethostbyaddr(string host) {
  774. if (host == "") {
  775. host = gethostname();
  776. }
  777. // This conversion seems to match CPython behavior
  778. host = gethostbyname(host);
  779. IPAddress[] ips = null;
  780. IPHostEntry hostEntry = null;
  781. try {
  782. ips = Dns.GetHostAddresses(host);
  783. hostEntry = Dns.GetHostEntry(host);
  784. } catch (Exception e) {
  785. throw MakeException(e);
  786. }
  787. List ipStrings = PythonOps.MakeList();
  788. foreach (IPAddress ip in ips) {
  789. ipStrings.append(ip.ToString());
  790. }
  791. return PythonTuple.MakeTuple(hostEntry.HostName, PythonOps.MakeList(hostEntry.Aliases), ipStrings);
  792. }
  793. [Documentation("getnameinfo(socketaddr, flags) -> (host, port)\n"
  794. + "Given a socket address, the return a tuple of the corresponding hostname and\n"
  795. + "port. Available flags:\n"
  796. + " - NI_NOFQDN: Return only the hostname part of the domain name for hosts on the\n"
  797. + " same domain as the executing machine.\n"
  798. + " - NI_NUMERICHOST: return the numeric form of the host (e.g. '127.0.0.1' or\n"
  799. + " '::1' rather than 'localhost').\n"
  800. + " - NI_NAMEREQD: Raise an error if the hostname cannot be looked up.\n"
  801. + " - NI_NUMERICSERV: Return string containing the numeric form of the port (e.g.\n"
  802. + " '80' rather than 'http'). This flag is required (see below).\n"
  803. + " - NI_DGRAM: Silently ignored (see below).\n"
  804. + "\n"
  805. + "Difference from CPython: the following flag behavior differs from CPython\n"
  806. + "because the .NET framework libraries offer no name-to-port conversion APIs:\n"
  807. + " - NI_NUMERICSERV: This flag is required because the .NET framework libraries\n"
  808. + " offer no port-to-name mapping APIs. If it is omitted, getnameinfo() will\n"
  809. + " raise a NotImplementedError.\n"
  810. + " - The NI_DGRAM flag is ignored because it only applies when NI_NUMERICSERV is\n"
  811. + " omitted. It it were supported, it would return the UDP-based port name\n"
  812. + " rather than the TCP-based port name.\n"
  813. )]
  814. public static object getnameinfo(PythonTuple socketAddr, int flags) {
  815. if (socketAddr.__len__() < 2 || socketAddr.__len__() > 4) {
  816. throw PythonOps.TypeError("socket address must be a 2-tuple (IPv4 or IPv6) or 4-tuple (IPv6)");
  817. }
  818. if ((flags & (int)NI_NUMERICSERV) == 0) {
  819. throw PythonOps.NotImplementedError("getnameinfo() required the NI_NUMERICSERV flag (see docstring)");
  820. }
  821. string host = Converter.ConvertToString(socketAddr[0]);
  822. if (host == null) throw PythonOps.TypeError("argument 1 must be string");
  823. int port = 0;
  824. try {
  825. port = (int)socketAddr[1];
  826. } catch (InvalidCastException) {
  827. throw PythonOps.TypeError("an integer is required");
  828. }
  829. string resultHost = null;
  830. string resultPort = null;
  831. // Host
  832. IPHostEntry hostEntry = null;
  833. try {
  834. // Do double lookup to force reverse DNS lookup to match CPython behavior
  835. hostEntry = Dns.GetHostEntry(host);
  836. if (hostEntry.AddressList.Length < 1) {
  837. throw PythonExceptions.CreateThrowable(error, "sockaddr resolved to zero addresses");
  838. }
  839. hostEntry = Dns.GetHostEntry(hostEntry.AddressList[0]);
  840. } catch (SocketException e) {
  841. throw PythonExceptions.CreateThrowable(gaierror, e.ErrorCode, e.Message);
  842. } catch (IndexOutOfRangeException) {
  843. throw PythonExceptions.CreateThrowable(gaierror, "sockaddr resolved to zero addresses");
  844. }
  845. IList<IPAddress> addrs = hostEntry.AddressList;
  846. if (addrs.Count > 1) {
  847. // ignore non-IPV4 addresses
  848. List<IPAddress> newAddrs = new List<IPAddress>(addrs.Count);
  849. foreach (IPAddress addr in hostEntry.AddressList) {
  850. if (addr.AddressFamily == AddressFamily.InterNetwork) {
  851. newAddrs.Add(addr);
  852. }
  853. }
  854. if (newAddrs.Count > 1) {
  855. throw PythonExceptions.CreateThrowable(error, "sockaddr resolved to multiple addresses");
  856. }
  857. addrs = newAddrs;
  858. }
  859. if (addrs.Count < 1) {
  860. throw PythonExceptions.CreateThrowable(error, "sockaddr resolved to zero addresses");
  861. }
  862. if ((flags & (int)NI_NUMERICHOST) != 0) {
  863. resultHost = addrs[0].ToString();
  864. } else if ((flags & (int)NI_NOFQDN) != 0) {
  865. resultHost = RemoveLocalDomain(hostEntry.HostName);
  866. } else {
  867. resultHost = hostEntry.HostName;
  868. }
  869. // Port
  870. // We don't branch on NI_NUMERICSERV here since we throw above if it's not set
  871. resultPort = port.ToString();
  872. return PythonTuple.MakeTuple(resultHost, resultPort);
  873. }
  874. [Documentation("getprotobyname(protoname) -> integer proto\n\n"
  875. + "Given a string protocol name (e.g. \"udp\"), return the associated integer\n"
  876. + "protocol number, suitable for passing to socket(). The name is case\n"
  877. + "insensitive.\n"
  878. + "\n"
  879. + "Raises socket.error if no protocol number can be found."
  880. )]
  881. public static object getprotobyname(string protocolName) {
  882. switch (protocolName.ToLower()) {
  883. case "ah": return IPPROTO_AH;
  884. case "esp": return IPPROTO_ESP;
  885. case "dstopts": return IPPROTO_DSTOPTS;
  886. case "fragment": return IPPROTO_FRAGMENT;
  887. case "ggp": return IPPROTO_GGP;
  888. case "icmp": return IPPROTO_ICMP;
  889. case "icmpv6": return IPPROTO_ICMPV6;
  890. case "ip": return IPPROTO_IP;
  891. case "ipv4": return IPPROTO_IPV4;
  892. case "ipv6": return IPPROTO_IPV6;
  893. case "nd": return IPPROTO_ND;
  894. case "none": return IPPROTO_NONE;
  895. case "pup": return IPPROTO_PUP;
  896. case "raw": return IPPROTO_RAW;
  897. case "routing": return IPPROTO_ROUTING;
  898. case "tcp": return IPPROTO_TCP;
  899. case "udp": return IPPROTO_UDP;
  900. default:
  901. throw PythonExceptions.CreateThrowable(error, "protocol not found");
  902. }
  903. }
  904. [Documentation("getservbyname(service_name[, protocol_name]) -> port\n\n"
  905. + "Not implemented."
  906. //+ "Given a service name (e.g. 'domain') return the associated protocol number (e.g.\n"
  907. //+ "53). The protocol name (if specified) must be either 'tcp' or 'udp'."
  908. )]
  909. public static int getservbyname(string serviceName, [DefaultParameterValue(null)] string protocolName) {
  910. // !!! .NET networking libraries don't support this, so we don't either
  911. throw PythonOps.NotImplementedError("name to service conversion not supported");
  912. }
  913. [Documentation("getservbyport(port[, protocol_name]) -> service_name\n\n"
  914. + "Not implemented."
  915. //+ "Given a port number (e.g. 53), return the associated protocol name (e.g.\n"
  916. //+ "'domain'). The protocol name (if specified) must be either 'tcp' or 'udp'."
  917. )]
  918. public static string getservbyport(int port, [DefaultParameterValue(null)] string protocolName) {
  919. // !!! .NET networking libraries don't support this, so we don't either
  920. throw PythonOps.NotImplementedError("service to name conversion not supported");
  921. }
  922. [Documentation("ntohl(x) -> integer\n\nConvert a 32-bit integer from network byte order to host byte order.")]
  923. public static int ntohl(object x) {
  924. return IPAddress.NetworkToHostOrder(SignInsenstitiveToInt32(x));
  925. }
  926. [Documentation("ntohs(x) -> integer\n\nConvert a 16-bit integer from network byte order to host byte order.")]
  927. public static short ntohs(object x) {
  928. return IPAddress.NetworkToHostOrder(SignInsenstitiveToInt16(x));
  929. }
  930. [Documentation("htonl(x) -> integer\n\nConvert a 32bit integer from host byte order to network byte order.")]
  931. public static int htonl(object x) {
  932. return IPAddress.HostToNetworkOrder(SignInsenstitiveToInt32(x));
  933. }
  934. /// <summary>
  935. /// Convert an object to a 32-bit integer. This adds two features to Converter.ToInt32:
  936. /// 1. Sign is ignored. For example, 0xffff0000 converts to 4294901760, where Convert.ToInt32
  937. /// would throw because 0xffff000 is less than zero.
  938. /// 2. Overflow exceptions are thrown. Converter.ToInt32 throws TypeError if x is
  939. /// an integer, but is bigger than 32 bits. Instead, we throw OverflowException.
  940. /// </summary>
  941. private static int SignInsenstitiveToInt32(object x) {
  942. BigInteger bigValue = Converter.ConvertToBigInteger(x);
  943. try {
  944. return bigValue.ToInt32(null);
  945. } catch (OverflowException) {
  946. return (int)bigValue.ToUInt32(null);
  947. }
  948. }
  949. /// <summary>
  950. /// Convert an object to a 16-bit integer. This adds two features to Converter.ToInt16:
  951. /// 1. Sign is ignored. For example, 0xff00 converts to 65280, where Convert.ToInt16
  952. /// would throw because signed 0xff00 is -256.
  953. /// 2. Overflow exceptions are thrown. Converter.ToInt16 throws TypeError if x is
  954. /// an integer, but is bigger than 16 bits. Instead, we throw OverflowException.
  955. /// </summary>
  956. private static short SignInsenstitiveToInt16(object x) {
  957. BigInteger bigValue = Converter.ConvertToBigInteger(x);
  958. try {
  959. return bigValue.ToInt16(null);
  960. } catch (OverflowException) {
  961. return (short)bigValue.ToUInt16(null);
  962. }
  963. }
  964. [Documentation("htons(x) -> integer\n\nConvert a 16-bit integer from host byte order to network byte order.")]
  965. public static short htons(object x) {
  966. return IPAddress.HostToNetworkOrder(SignInsenstitiveToInt16(x));
  967. }
  968. [Documentation("inet_pton(addr_family, ip_string) -> packed_ip\n\n"
  969. + "Convert an IP address (in string format, e.g. '127.0.0.1' or '::1') to a 32-bit\n"
  970. + "packed binary format, as 4-byte (IPv4) or 16-byte (IPv6) string. The return\n"
  971. + "format matches the format of the standard C library's in_addr or in6_addr\n"
  972. + "struct.\n"
  973. + "\n"
  974. + "If the address format is invalid, socket.error will be raised. Validity is\n"
  975. + "determined by the .NET System.Net.IPAddress.Parse() method.\n"
  976. + "\n"
  977. + "inet_pton() supports IPv4 and IPv6."
  978. )]
  979. public static string inet_pton(int addressFamily, string ipString) {
  980. if (addressFamily != (int)AddressFamily.InterNetwork && addressFamily != (int)AddressFamily.InterNetworkV6) {
  981. throw MakeException(new SocketException((int)SocketError.AddressFamilyNotSupported));
  982. }
  983. IPAddress ip;
  984. try {
  985. ip = IPAddress.Parse(ipString);
  986. if (addressFamily != (int)ip.AddressFamily) {
  987. throw MakeException(new SocketException((int)SocketError.AddressFamilyNotSupported));
  988. }
  989. } catch (FormatException) {
  990. throw PythonExceptions.CreateThrowable(error, "illegal IP address passed to inet_pton");
  991. }
  992. return StringOps.FromByteArray(ip.GetAddressBytes());
  993. }
  994. [Documentation("inet_ntop(address_family, packed_ip) -> ip_string\n\n"
  995. + "Convert a packed IP address (a 4-byte [IPv4] or 16-byte [IPv6] string) to a\n"
  996. + "string IP address (e.g. '127.0.0.1' or '::1').\n"
  997. + "\n"
  998. + "The input format matches the format of the standard C library's in_addr or\n"
  999. + "in6_addr struct. If the input string is not exactly 4 bytes or 16 bytes,\n"
  1000. + "socket.error will be raised.\n"
  1001. + "\n"
  1002. + "inet_ntop() supports IPv4 and IPv6."
  1003. )]
  1004. public static string inet_ntop(int addressFamily, string packedIP) {
  1005. if (!(
  1006. (packedIP.Length == IPv4AddrBytes && addressFamily == (int)AddressFamily.InterNetwork)
  1007. || (packedIP.Length == IPv6AddrBytes && addressFamily == (int)AddressFamily.InterNetworkV6)
  1008. )) {
  1009. throw PythonExceptions.CreateThrowable(error, "invalid length of packed IP address string");
  1010. }
  1011. byte[] ipBytes = StringOps.ToByteArray(packedIP);
  1012. if (addressFamily == (int)AddressFamily.InterNetworkV6) {
  1013. return IPv6BytesToColonHex(ipBytes);
  1014. }
  1015. return (new IPAddress(ipBytes)).ToString();
  1016. }
  1017. [Documentation("inet_aton(ip_string) -> packed_ip\n"
  1018. + "Convert an IP address (in string dotted quad format, e.g. '127.0.0.1') to a\n"
  1019. + "32-bit packed binary format, as four-character string. The return format\n"
  1020. + "matches the format of the standard C library's in_addr struct.\n"
  1021. + "\n"
  1022. + "If the address format is invalid, socket.error will be raised. Validity is\n"
  1023. + "determined by the .NET System.Net.IPAddress.Parse() method.\n"
  1024. + "\n"
  1025. + "inet_aton() supports only IPv4."
  1026. )]
  1027. public static string inet_aton(string ipString) {
  1028. return inet_pton((int)AddressFamily.InterNetwork, ipString);
  1029. }
  1030. [Documentation("inet_ntoa(packed_ip) -> ip_string\n\n"
  1031. + "Convert a packed IP address (a 4-byte string) to a string IP address (in dotted\n"
  1032. + "quad format, e.g. '127.0.0.1'). The input format matches the format of the\n"
  1033. + "standard C library's in_addr struct.\n"
  1034. + "\n"
  1035. + "If the input string is not exactly 4 bytes, socket.error will be raised.\n"
  1036. + "\n"
  1037. + "inet_ntoa() supports only IPv4."
  1038. )]
  1039. public static string inet_ntoa(string packedIP) {
  1040. return inet_ntop((int)AddressFamily.InterNetwork, packedIP);
  1041. }
  1042. [Documentation("getdefaulttimeout() -> timeout\n\n"
  1043. + "Return the default timeout for new socket objects in seconds as a float. A\n"
  1044. + "value of None means that sockets have no timeout and begin in blocking mode.\n"
  1045. + "The default value when the module is imported is None."
  1046. )]
  1047. public static object getdefaulttimeout(CodeContext/*!*/ context) {
  1048. int? defaultTimeout = GetDefaultTimeout(context);
  1049. if (defaultTimeout == null) {
  1050. return null;
  1051. } else {
  1052. return (double)(defaultTimeout.Value) / MillisecondsPerSecond;
  1053. }
  1054. }
  1055. [Documentation("setdefaulttimeout(timeout) -> None\n\n"
  1056. + "Set the default timeout for new socket objects. timeout must be either None,\n"
  1057. + "meaning that sockets have no timeout and start in blocking mode, or a\n"
  1058. + "non-negative float that specifies the default timeout in seconds."
  1059. )]
  1060. public static void setdefaulttimeout(CodeContext/*!*/ context, object timeout) {
  1061. if (timeout == null) {
  1062. SetDefaultTimeout(context, null);
  1063. } else {
  1064. double seconds;
  1065. seconds = Converter.ConvertToDouble(timeout);
  1066. if (seconds < 0) {
  1067. throw PythonOps.ValueError("a non-negative float is required");
  1068. }
  1069. SetDefaultTimeout(context, (int)(seconds * MillisecondsPerSecond));
  1070. }
  1071. }
  1072. #endregion
  1073. #region Exported constants
  1074. public const int AF_APPLETALK = (int)AddressFamily.AppleTalk;
  1075. public const int AF_DECnet = (int)AddressFamily.DecNet;
  1076. public const int AF_INET = (int)AddressFamily.InterNetwork;
  1077. public const int AF_INET6 = (int)AddressFamily.InterNetworkV6;
  1078. public const int AF_IPX = (int)AddressFamily.Ipx;
  1079. public const int AF_IRDA = (int)AddressFamily.Irda;
  1080. public const int AF_SNA = (int)AddressFamily.Sna;
  1081. public const int AF_UNSPEC = (int)AddressFamily.Unspecified;
  1082. public const int AI_CANONNAME = (int)0x2;
  1083. public const int AI_NUMERICHOST = (int)0x4;
  1084. public const int AI_PASSIVE = (int)0x1;
  1085. public const int EAI_AGAIN = (int)SocketError.TryAgain;
  1086. public const int EAI_BADFLAGS = (int)SocketError.InvalidArgument;
  1087. public const int EAI_FAIL = (int)SocketError.NoRecovery;
  1088. public const int EAI_FAMILY = (int)SocketError.AddressFamilyNotSupported;
  1089. public const int EAI_MEMORY = (int)SocketError.NoBufferSpaceAvailable;
  1090. public const int EAI_NODATA = (int)SocketError.HostNotFound; // not SocketError.NoData, like you would think
  1091. public const int EAI_NONAME = (int)SocketError.HostNotFound;
  1092. public const int EAI_SERVICE = (int)SocketError.TypeNotFound;
  1093. public const int EAI_SOCKTYPE = (int)SocketError.SocketNotSupported;
  1094. public const int EAI_SYSTEM = (int)SocketError.SocketError;
  1095. public const int EBADF = (int)0x9;
  1096. public const int INADDR_ALLHOSTS_GROUP = unchecked((int)0xe0000001);
  1097. public const int INADDR_ANY = (int)0x00000000;
  1098. public const int INADDR_BROADCAST = unchecked((int)0xFFFFFFFF);
  1099. public const int INADDR_LOOPBACK = unchecked((int)0x7F000001);
  1100. public const int INADDR_MAX_LOCAL_GROUP = unchecked((int)0xe00000FF);
  1101. public const int INADDR_NONE = unchecked((int)0xFFFFFFFF);
  1102. public const int INADDR_UNSPEC_GROUP = unchecked((int)0xE0000000);
  1103. public const int IPPORT_RESERVED = 1024;
  1104. public const int IPPORT_USERRESERVED = 5000;
  1105. public const int IPPROTO_AH = (int)ProtocolType.IPSecAuthenticationHeader;
  1106. public const int IPPROTO_DSTOPTS = (int)ProtocolType.IPv6DestinationOptions;
  1107. public const int IPPROTO_ESP = (int)ProtocolType.IPSecEncapsulatingSecurityPayload;
  1108. public const int IPPROTO_FRAGMENT = (int)ProtocolType.IPv6FragmentHeader;
  1109. public const int IPPROTO_GGP = (int)ProtocolType.Ggp;
  1110. public const int IPPROTO_HOPOPTS = (int)ProtocolType.IPv6HopByHopOptions;
  1111. public const int IPPROTO_ICMP = (int)ProtocolType.Icmp;
  1112. public const int IPPROTO_ICMPV6 = (int)ProtocolType.IcmpV6;
  1113. public const int IPPROTO_IDP = (int)ProtocolType.Idp;
  1114. public const int IPPROTO_IGMP = (int)ProtocolType.Igmp;
  1115. public const int IPPROTO_IP = (int)ProtocolType.IP;
  1116. public const int IPPROTO_IPV4 = (int)ProtocolType.IPv4;
  1117. public const int IPPROTO_IPV6 = (int)ProtocolType.IPv6;
  1118. public const int IPPROTO_MAX = 256;
  1119. public const int IPPROTO_ND = (int)ProtocolType.ND;
  1120. public const int IPPROTO_NONE = (int)ProtocolType.IPv6NoNextHeader;
  1121. public const int IPPROTO_PUP = (int)ProtocolType.Pup;
  1122. public const int IPPROTO_RAW = (int)ProtocolType.Raw;
  1123. public const int IPPROTO_ROUTING = (int)ProtocolType.IPv6RoutingHeader;
  1124. public const int IPPROTO_TCP = (int)ProtocolType.Tcp;
  1125. public const int IPPROTO_UDP = (int)ProtocolType.Udp;
  1126. public const int IPV6_HOPLIMIT = (int)SocketOptionName.HopLimit;
  1127. public const int IPV6_JOIN_GROUP = (int)SocketOptionName.AddMembership;
  1128. public const int IPV6_LEAVE_GROUP = (int)SocketOptionName.DropMembership;
  1129. public const int IPV6_MULTICAST_HOPS = (int)SocketOptionName.MulticastTimeToLive;
  1130. public const int IPV6_MULTICAST_IF = (int)SocketOptionName.MulticastInterface;
  1131. public const int IPV6_MULTICAST_LOOP = (int)SocketOptionName.MulticastLoopback;
  1132. public const int IPV6_PKTINFO = (int)SocketOptionName.PacketInformation;
  1133. public const int IPV6_UNICAST_HOPS = (int)SocketOptionName.IpTimeToLive;
  1134. public const int IP_ADD_MEMBERSHIP = (int)SocketOptionName.AddMembership;
  1135. public const int IP_DROP_MEMBERSHIP = (int)SocketOptionName.DropMembership;
  1136. public const int IP_HDRINCL = (int)SocketOptionName.HeaderIncluded;
  1137. public const int IP_MULTICAST_IF = (int)SocketOptionName.MulticastInterface;
  1138. public const int IP_MULTICAST_LOOP = (int)SocketOptionName.MulticastLoopback;
  1139. public const int IP_MULTICAST_TTL = (int)SocketOptionName.MulticastTimeToLive;
  1140. public const int IP_OPTIONS = (int)SocketOptionName.IPOptions;
  1141. public const int IP_TOS = (int)SocketOptionName.TypeOfService;
  1142. public const int IP_TTL = (int)SocketOptionName.IpTimeToLive;
  1143. public const int MSG_DONTROUTE = (int)SocketFlags.DontRoute;
  1144. public const int MSG_OOB = (int)SocketFlags.OutOfBand;
  1145. public const int MSG_PEEK = (int)SocketFlags.Peek;
  1146. public const int NI_DGRAM = 0x0010;
  1147. public const int NI_MAXHOST = 1025;
  1148. public const int NI_MAXSERV = 32;
  1149. public const int NI_NAMEREQD = 0x0004;
  1150. public const int NI_NOFQDN = 0x0001;
  1151. public const int NI_NUMERICHOST = 0x0002;
  1152. public const int NI_NUMERICSERV = 0x0008;
  1153. public const int SHUT_RD = (int)SocketShutdown.Receive;
  1154. public const int SHUT_RDWR = (int)SocketShutdown.Both;
  1155. public const int SHUT_WR = (int)SocketShutdown.Send;
  1156. public const int SOCK_DGRAM = (int)System.Net.Sockets.SocketType.Dgram;
  1157. public const int SOCK_RAW = (int)System.Net.Sockets.SocketType.Raw;
  1158. public const int SOCK_RDM = (int)System.Net.Sockets.SocketType.Rdm;
  1159. public const int SOCK_SEQPACKET = (int)System.Net.Sockets.SocketType.Seqpacket;
  1160. public const int SOCK_STREAM = (int)System.Net.Sockets.SocketType.Stream;
  1161. public const int SOL_IP = (int)SocketOptionLevel.IP;
  1162. public const int SOL_IPV6 = (int)SocketOptionLevel.IPv6;
  1163. public const int SOL_SOCKET = (int)SocketOptionLevel.Socket;
  1164. public const int SOL_TCP = (int)SocketOptionLevel.Tcp;
  1165. public const int SOL_UDP = (int)SocketOptionLevel.Udp;
  1166. public const int SOMAXCONN = (int)SocketOptionName.MaxConnections;
  1167. public const int SO_ACCEPTCONN = (int)SocketOptionName.AcceptConnection;
  1168. public const int SO_BROADCAST = (int)SocketOptionName.Broadcast;
  1169. public const int SO_DEBUG = (int)SocketOptionName.Debug;
  1170. public const int SO_DONTROUTE = (int)SocketOptionName.DontRoute;
  1171. public const int SO_ERROR = (int)SocketOptionName.Error;
  1172. public const int SO_EXCLUSIVEADDRUSE = (int)SocketOptionName.ExclusiveAddressUse;
  1173. public const int SO_KEEPALIVE = (int)SocketOptionName.KeepAlive;
  1174. public const int SO_LINGER = (int)SocketOptionName.Linger;
  1175. public const int SO_OOBINLINE = (int)SocketOptionName.OutOfBandInline;
  1176. public const int SO_RCVBUF = (int)SocketOptionName.ReceiveBuffer;
  1177. public const int SO_RCVLOWAT = (int)SocketOptionName.ReceiveLowWater;
  1178. public const int SO_RCVTIMEO = (int)SocketOptionName.ReceiveTimeout;
  1179. public const int SO_REUSEADDR = (int)SocketOptionName.ReuseAddress;
  1180. public const int SO_SNDBUF = (int)SocketOptionName.SendBuffer;
  1181. public const int SO_SNDLOWAT = (int)SocketOptionName.SendLowWater;
  1182. public const int SO_SNDTIMEO = (int)SocketOptionName.SendTimeout;
  1183. public const int SO_TYPE = (int)SocketOptionName.Type;
  1184. public const int SO_USELOOPBACK = (int)SocketOptionName.UseLoopback;
  1185. public const int TCP_NODELAY = (int)SocketOptionName.NoDelay;
  1186. public const int has_ipv6 = (int)1;
  1187. #endregion
  1188. #region Private implementation
  1189. /// <summary>
  1190. /// Return a standard socket exception (socket.error) whose message and error code come from a SocketException
  1191. /// This will eventually be enhanced to generate the correct error type (error, herror, gaierror) based on the error code.
  1192. /// </summary>
  1193. private static Exception MakeException(Exception exception) {
  1194. // !!! this shouldn't just blindly set the type to error (see summary)
  1195. if (exception is SocketException) {
  1196. SocketException se = (SocketException)exception;
  1197. switch (se.SocketErrorCode) {
  1198. case SocketError.NotConnected: // CPython times out when the socket isn't connected.
  1199. case SocketError.TimedOut:
  1200. return PythonExceptions.CreateThrowable(timeout, se.ErrorCode, se.Message);
  1201. default:
  1202. return PythonExceptions.CreateThrowable(error, se.ErrorCode, se.Message);
  1203. }
  1204. } else if (exception is ObjectDisposedException) {
  1205. return PythonExceptions.CreateThrowable(error, (int)EBADF, "the socket is closed");
  1206. } else if (exception is InvalidOperationException) {
  1207. return MakeException(new SocketException((int)SocketError.InvalidArgument));
  1208. } else {
  1209. return exception;
  1210. }
  1211. }
  1212. /// <summary>
  1213. /// Convert an IPv6 address byte array to a string in standard colon-hex notation.
  1214. /// The .NET IPAddress.ToString() method uses dotted-quad for the last 32 bits,
  1215. /// which differs from the normal Python implementation (but is allowed by the IETF);
  1216. /// this method returns the standard (no dotted-quad) colon-hex form.
  1217. /// </summary>
  1218. private static string IPv6BytesToColonHex(byte[] ipBytes) {
  1219. Debug.Assert(ipBytes.Length == IPv6AddrBytes);
  1220. const int bytesPerWord = 2; // in bytes
  1221. const int bitsPerByte = 8;
  1222. int[] words = new int[IPv6AddrBytes / bytesPerWord];
  1223. // Convert to array of 16-bit words
  1224. for (int i = 0; i < words.Length; i++) {
  1225. for (int j = 0; j < bytesPerWord; j++) {
  1226. words[i] <<= bitsPerByte;
  1227. words[i] += ipBytes[i * bytesPerWord + j];
  1228. }
  1229. }
  1230. // Find longest series of 0-valued words (to collapse to ::)
  1231. int longestStart = 0;
  1232. int longestLen = 0;
  1233. for (int i = 0; i < words.Length; i++) {
  1234. if (words[i] == 0) {
  1235. for (int j = i; j < words.Length; j++) {
  1236. if (words[j] != 0) {
  1237. i += longestLen;
  1238. break;
  1239. }
  1240. if (j - i + 1 > longestLen) {
  1241. longestStart = i;
  1242. longestLen = j - i + 1;
  1243. }
  1244. }
  1245. }
  1246. }
  1247. // Build colon-hex string
  1248. StringBuilder result = new StringBuilder(IPv6AddrBytes * 3);
  1249. for (int i = 0; i < words.Length; i++) {
  1250. if (i != 0) result.Append(':');
  1251. if (longestLen > 0 && i == longestStart) {
  1252. if (longestStart == 0) result.Append(':');
  1253. if (longestStart + longestLen == words.Length) result.Append(':');
  1254. i += longestLen - 1;
  1255. continue;
  1256. } else {
  1257. result.Append(words[i].ToString("x"));
  1258. }
  1259. }
  1260. return result.ToString();
  1261. }
  1262. /// <summary>
  1263. /// Handle conversion of "" to INADDR_ANY and "&lt;broadcast&gt;" to INADDR_BROADCAST.
  1264. /// Otherwise returns host unchanged.
  1265. /// </summary>
  1266. private static string ConvertSpecialAddresses(string host) {
  1267. switch (host) {
  1268. case AnyAddrToken:
  1269. return IPAddress.Any.ToString();
  1270. case BroadcastAddrToken:
  1271. return IPAddress.Broadcast.ToString();
  1272. default:
  1273. return host;
  1274. }
  1275. }
  1276. /// <summary>
  1277. /// Return the IP address associated with host, with optional address family checking.
  1278. /// host may be either a name or an IP address (in string form).
  1279. ///
  1280. /// If family is non-null, a gaierror will be thrown if the host's address family is
  1281. /// not the same as the specified family. gaierror is also raised if the hostname cannot be
  1282. /// converted to an IP address (e.g. through a name lookup failure).
  1283. /// </summary>
  1284. private static IPAddress HostToAddress(string host, AddressFamily family) {
  1285. return HostToAddresses(host, family)[0];
  1286. }
  1287. /// <summary>
  1288. /// Return the IP address associated with host, with optional address family checking.
  1289. /// host may be either a name or an IP address (in string form).
  1290. ///
  1291. /// If family is non-null, a gaierror will be thrown if the host's address family is
  1292. /// not the same as the specified family. gaierror is also raised if the hostname cannot be
  1293. /// converted to an IP address (e.g. through a name lookup failure).
  1294. /// </summary>
  1295. private static IPAddress[] HostToAddresses(string host, AddressFamily family) {
  1296. host = ConvertSpecialAddresses(host);
  1297. try {
  1298. IPAddress addr;
  1299. bool numeric = true;
  1300. int dotCount = 0;
  1301. foreach (char c in host) {
  1302. if (!Char.IsNumber(c) && c != '.') {
  1303. numeric = false;
  1304. } else if (c == '.') {
  1305. dotCount++;
  1306. }
  1307. }
  1308. if (numeric) {
  1309. if (dotCount == 3 && IPAddress.TryParse(host, out addr)) {
  1310. if (family == AddressFamily.Unspecified || family == addr.AddressFamily) {
  1311. return new IPAddress[] { addr };
  1312. }
  1313. }
  1314. // Incorrect family will raise exception below
  1315. } else {
  1316. IPHostEntry hostEntry = Dns.GetHostEntry(host);
  1317. List<IPAddress> addrs = new List<IPAddress>();
  1318. foreach (IPAddress ip in hostEntry.AddressList) {
  1319. if (family == AddressFamily.Unspecified || family == ip.AddressFamily) {
  1320. addrs.Add(ip);
  1321. }
  1322. }
  1323. if (addrs.Count > 0) return addrs.ToArray();
  1324. }
  1325. throw new SocketException((int)SocketError.HostNotFound);
  1326. } catch (SocketException e) {
  1327. throw PythonExceptions.CreateThrowable(gaierror, e.ErrorCode, "no addresses of the specified family associated with host");
  1328. }
  1329. }
  1330. /// <summary>
  1331. /// Return fqdn, but with its domain removed if it's on the same domain as the local machine.
  1332. /// </summary>
  1333. private static string RemoveLocalDomain(string fqdn) {
  1334. char[] DNS_SEP = new char[] { '.' };
  1335. string[] myName = getfqdn().Split(DNS_SEP, 2);
  1336. string[] otherName = fqdn.Split(DNS_SEP, 2);
  1337. if (myName.Length < 2 || otherName.Length < 2) return fqdn;
  1338. if (myName[1] == otherName[1]) {
  1339. return otherName[0];
  1340. } else {
  1341. return fqdn;
  1342. }
  1343. }
  1344. /// <summary>
  1345. /// Convert a (host, port) tuple [IPv4] (host, port, flowinfo, scopeid) tuple [IPv6]
  1346. /// to its corresponding IPEndPoint.
  1347. ///
  1348. /// Throws gaierror if host is not a valid address.
  1349. /// Throws ArgumentTypeException if any of the following are true:
  1350. /// - address does not have exactly two elements
  1351. /// - address[0] is not a string
  1352. /// - address[1] is not an int
  1353. /// </summary>
  1354. private static IPEndPoint TupleToEndPoint(PythonTuple address, AddressFamily family) {
  1355. if (address.__len__() != 2 && address.__len__() != 4) {
  1356. throw PythonOps.TypeError("address tuple must have exactly 2 (IPv4) or exactly 4 (IPv6) elements");
  1357. }
  1358. string host;
  1359. try {
  1360. host = Converter.ConvertToString(address[0]);
  1361. } catch (ArgumentTypeException) {
  1362. throw PythonOps.TypeError("host must be string");
  1363. }
  1364. int port;
  1365. try {
  1366. port = Converter.ConvertToInt32(address[1]);
  1367. } catch (ArgumentTypeException) {
  1368. throw PythonOps.TypeError("port must be integer");
  1369. }
  1370. IPAddress ip = HostToAddress(host, family);
  1371. if (address.__len__() == 2) {
  1372. return new IPEndPoint(ip, port);
  1373. } else {
  1374. long flowInfo;
  1375. try {
  1376. flowInfo = Converter.ConvertToInt64(address[2]);
  1377. } catch (ArgumentTypeException) {
  1378. throw PythonOps.TypeError("flowinfo must be integer");
  1379. }
  1380. // We don't actually do anything with flowinfo right now, but we validate it
  1381. // in case we want to do something in the future.
  1382. long scopeId;
  1383. try {
  1384. scopeId = Converter.ConvertToInt64(address[3]);
  1385. } catch (ArgumentTypeException) {
  1386. throw PythonOps.TypeError("scopeid must be integer");
  1387. }
  1388. IPEndPoint endPoint = new IPEndPoint(ip, port);
  1389. endPoint.Address.ScopeId = scopeId;
  1390. return endPoint;
  1391. }
  1392. }
  1393. /// <summary>
  1394. /// Convert an IPEndPoint to its corresponding (host, port) [IPv4] or (host, port, flowinfo, scopeid) [IPv6] tuple.
  1395. /// Throws SocketException if the address family is other than IPv4 or IPv6.
  1396. /// </summary>
  1397. private static PythonTuple EndPointToTuple(IPEndPoint endPoint) {
  1398. string ip = endPoint.Address.ToString();
  1399. int port = endPoint.Port;
  1400. switch (endPoint.Address.AddressFamily) {
  1401. case AddressFamily.InterNetwork:
  1402. return PythonTuple.MakeTuple(ip, port);
  1403. case AddressFamily.InterNetworkV6:
  1404. long flowInfo = 0; // RFC 3493 p. 7
  1405. long scopeId = endPoint.Address.ScopeId;
  1406. return PythonTuple.MakeTuple(ip, port, flowInfo, scopeId);
  1407. default:
  1408. throw new SocketException((int)SocketError.AddressFamilyNotSupported);
  1409. }
  1410. }
  1411. class PythonUserSocketStream : Stream {
  1412. private object _userSocket;
  1413. private List<string> _data = new List<string>();
  1414. private int _dataSize, _bufSize;
  1415. private static readonly DynamicSite<object, object, object> _sendAllSite = CallSiteFactory.CreateSimpleCallSite<object, object, object>(DefaultContext.DefaultPythonBinder);
  1416. private static readonly DynamicSite<object, object, string> _recvSite = CallSiteFactory.CreateSimpleCallSite<object, object, string>(DefaultContext.DefaultPythonBinder);
  1417. public PythonUserSocketStream(object userSocket, int bufferSize) {
  1418. _userSocket = userSocket;
  1419. _bufSize = bufferSize;
  1420. }
  1421. public override bool CanRead {
  1422. get { return true; }
  1423. }
  1424. public override bool CanSeek {
  1425. get { return false; }
  1426. }
  1427. public override bool CanWrite {
  1428. get { return true; }
  1429. }
  1430. public override void Flush() {
  1431. if (_data.Count > 0) {
  1432. StringBuilder res = new StringBuilder();
  1433. foreach (string s in _data) {
  1434. res.Append(s);
  1435. }
  1436. _sendAllSite.Invoke(DefaultContext.Default, PythonOps.GetBoundAttr(DefaultContext.Default, _userSocket, SymbolTable.StringToId("sendall")), res.ToString());
  1437. _data.Clear();
  1438. }
  1439. }
  1440. public override long Length {
  1441. get { throw new NotImplementedException(); }
  1442. }
  1443. public override long Position {
  1444. get {
  1445. throw new NotImplementedException();
  1446. }
  1447. set {
  1448. throw new NotImplementedException();
  1449. }
  1450. }
  1451. public override int Read(byte[] buffer, int offset, int count) {
  1452. int size = count;
  1453. string data = _recvSite.Invoke(DefaultContext.Default, PythonOps.GetBoundAttr(DefaultContext.Default, _userSocket, SymbolTable.StringToId("recv")), count);
  1454. return PythonAsciiEncoding.Instance.GetBytes(data, 0, data.Length, buffer, offset);
  1455. }
  1456. public override long Seek(long offset, SeekOrigin origin) {
  1457. throw new NotImplementedException();
  1458. }
  1459. public override void SetLength(long value) {
  1460. throw new NotImplementedException();
  1461. }
  1462. public override void Write(byte[] buffer, int offset, int count) {
  1463. string strData = new string(PythonAsciiEncoding.Instance.GetChars(buffer, offset, count));
  1464. _data.Add(strData);
  1465. _dataSize += strData.Length;
  1466. if (_dataSize > _bufSize) {
  1467. Flush();
  1468. }
  1469. }
  1470. public object _sock {
  1471. get {
  1472. return _userSocket;
  1473. }
  1474. }
  1475. protected override void Dispose(bool disposing) {
  1476. socket sock = _userSocket as socket;
  1477. if (sock != null) {
  1478. socket.RemoveHandleSocketMapping(sock);
  1479. }
  1480. }
  1481. }
  1482. [PythonSystemType]
  1483. public class _fileobject : PythonFile {
  1484. public new const string name = "<socket>";
  1485. private socket _socket = null;
  1486. public _fileobject(CodeContext/*!*/ context, socket socket)
  1487. : this(context, socket, "rb", -1, false) {
  1488. }
  1489. public _fileobject(CodeContext/*!*/ context, socket socket, string mode)
  1490. : this(context, socket, mode, -1, false) {
  1491. }
  1492. public _fileobject(CodeContext/*!*/ context, socket socket, string mode, int bufsize)
  1493. : this(context, socket, mode, bufsize, false) {
  1494. }
  1495. public _fileobject(CodeContext/*!*/ context, socket socket, string mode, int bufsize, bool close)
  1496. : base(PythonContext.GetContext(context)) {
  1497. _socket = socket;
  1498. base.__init__(new NetworkStream(socket._socket), System.Text.Encoding.Default, mode);
  1499. }
  1500. public _fileobject(CodeContext/*!*/ context, object socket)
  1501. : this(context, socket, "rb", -1, false) {
  1502. }
  1503. public _fileobject(CodeContext/*!*/ context, object socket, string mode)
  1504. : this(context, socket, mode, -1, false) {
  1505. }
  1506. public _fileobject(CodeContext/*!*/ context, object socket, string mode, int bufsize)
  1507. : this(context, socket, mode, bufsize, false) {
  1508. }
  1509. public _fileobject(CodeContext/*!*/ context, object socket, string mode, int bufsize, bool close)
  1510. : base(PythonContext.GetContext(context)) {
  1511. base.__init__(new PythonUserSocketStream(socket, GetBufferSize(context, bufsize)), System.Text.Encoding.Default, mode);
  1512. }
  1513. public void __init__(params object[] args) {
  1514. }
  1515. private static int GetBufferSize(CodeContext/*!*/ context, int size) {
  1516. if (size == -1) return Converter.ConvertToInt32(Getdefault_bufsize(context));
  1517. return size;
  1518. }
  1519. [SpecialName, PropertyMethod, StaticExtensionMethod]
  1520. public static object Getdefault_bufsize(CodeContext/*!*/ context) {
  1521. return PythonContext.GetContext(context).GetModuleState(_defaultBufsizeKey);
  1522. }
  1523. [SpecialName, PropertyMethod, StaticExtensionMethod]
  1524. public static void Setdefault_bufsize(CodeContext/*!*/ context, object value) {
  1525. PythonContext.GetContext(context).SetModuleState(_defaultBufsizeKey, value);
  1526. }
  1527. protected override void Dispose(bool disposing) {
  1528. base.Dispose(disposing);
  1529. if (_socket != null) {
  1530. socket.RemoveHandleSocketMapping(_socket);
  1531. }
  1532. }
  1533. }
  1534. #endregion
  1535. private static int? GetDefaultTimeout(CodeContext/*!*/ context) {
  1536. return (int?)PythonContext.GetContext(context).GetModuleState(_defaultTimeoutKey);
  1537. }
  1538. private static void SetDefaultTimeout(CodeContext/*!*/ context, int? timeout) {
  1539. PythonContext.GetContext(context).SetModuleState(_defaultTimeoutKey, timeout);
  1540. }
  1541. }
  1542. }
  1543. #endif