PageRenderTime 43ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/DICK.B1/IronPython.Modules/select.cs

https://bitbucket.org/williamybs/uidipythontool
C# | 165 lines | 112 code | 20 blank | 33 comment | 14 complexity | cfc10d4b6b27f6bdc3a3caac121ff3bc 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. using System;
  16. using System.Collections;
  17. using System.Collections.Generic;
  18. using System.Runtime.InteropServices;
  19. using Microsoft.Scripting;
  20. using IronPython.Runtime;
  21. using IronPython.Runtime.Exceptions;
  22. using IronPython.Runtime.Operations;
  23. using IronPython.Runtime.Types;
  24. #if !SILVERLIGHT // Sockets
  25. using System.Net.Sockets;
  26. using Microsoft.Scripting.Runtime;
  27. using System.Runtime.CompilerServices;
  28. [assembly: PythonModule("select", typeof(IronPython.Modules.PythonSelect))]
  29. namespace IronPython.Modules {
  30. public static class PythonSelect {
  31. public const string __doc__ = "Provides support for asynchronous socket operations.";
  32. [SpecialName]
  33. public static void PerformModuleReload(PythonContext/*!*/ context, PythonDictionary/*!*/ dict) {
  34. context.EnsureModuleException("selecterror", dict, "error", "select");
  35. }
  36. #if SILVERLIGHT // RunClassConstructor workaround
  37. public static void __cctor() { }
  38. #endif
  39. #region Public API
  40. [Documentation("select(iwtd, owtd, ewtd[, timeout]) -> readlist, writelist, errlist\n\n"
  41. + "Block until sockets are available for reading or writing, until an error\n"
  42. + "occurs, or until a the timeout expires. The first three parameters are\n"
  43. + "sequences of socket objects (opened using the socket module). The last is a\n"
  44. + "timeout value, given in seconds as a float. If timeout is omitted, select()\n"
  45. + "blocks until at least one socket is ready. A timeout of zero never blocks, but\n"
  46. + "can be used for polling.\n"
  47. + "\n"
  48. + "The return value is a tuple of lists of sockets that are ready (subsets of\n"
  49. + "iwtd, owtd, and ewtd). If the timeout occurs before any sockets are ready, a\n"
  50. + "tuple of three empty lists is returned.\n"
  51. + "\n"
  52. + "Note that select() on IronPython works only with sockets; it will not work with\n"
  53. + "files or other objects."
  54. )]
  55. public static PythonTuple select(CodeContext/*!*/ context, object iwtd, object owtd, object ewtd, [DefaultParameterValue(null)] object timeout) {
  56. List readerList, writerList, errorList;
  57. Dictionary<Socket, object> readerOriginals, writerOriginals, errorOriginals;
  58. ProcessSocketSequence(context, iwtd, out readerList, out readerOriginals);
  59. ProcessSocketSequence(context, owtd, out writerList, out writerOriginals);
  60. ProcessSocketSequence(context, ewtd, out errorList, out errorOriginals);
  61. int timeoutMicroseconds;
  62. if (timeout == null) {
  63. // -1 doesn't really work as infinite, but it appears that any other negative value does
  64. timeoutMicroseconds = -2;
  65. } else {
  66. double timeoutSeconds;
  67. if (!Converter.TryConvertToDouble(timeout, out timeoutSeconds)) {
  68. throw PythonOps.TypeErrorForTypeMismatch("float or None", timeout);
  69. }
  70. timeoutMicroseconds = (int) (1000000 * timeoutSeconds);
  71. }
  72. try {
  73. Socket.Select(readerList, writerList, errorList, timeoutMicroseconds);
  74. } catch (ArgumentNullException) {
  75. throw MakeException(context, SocketExceptionToTuple(new SocketException((int)SocketError.InvalidArgument)));
  76. } catch (SocketException e) {
  77. throw MakeException(context, SocketExceptionToTuple(e));
  78. }
  79. // Convert back to what the user originally passed in
  80. for (int i = 0; i < readerList.__len__(); i++) readerList[i] = readerOriginals[(Socket)readerList[i]];
  81. for (int i = 0; i < writerList.__len__(); i++) writerList[i] = writerOriginals[(Socket)writerList[i]];
  82. for (int i = 0; i < errorList.__len__(); i++) errorList[i] = errorOriginals[(Socket)errorList[i]];
  83. return PythonTuple.MakeTuple(readerList, writerList, errorList);
  84. }
  85. private static PythonTuple SocketExceptionToTuple(SocketException e) {
  86. return PythonTuple.MakeTuple(e.ErrorCode, e.Message);
  87. }
  88. private static Exception MakeException(CodeContext/*!*/ context, object value) {
  89. return PythonExceptions.CreateThrowable((PythonType)PythonContext.GetContext(context).GetModuleState("selecterror"), value);
  90. }
  91. /// <summary>
  92. /// Process a sequence of objects that are compatible with ObjectToSocket(). Return two
  93. /// things as out params: an in-order List of sockets that correspond to the original
  94. /// objects in the passed-in sequence, and a mapping of these socket objects to their
  95. /// original objects.
  96. ///
  97. /// The socketToOriginal mapping is generated because the CPython select module supports
  98. /// passing to select either file descriptor numbers or an object with a fileno() method.
  99. /// We try to be faithful to what was originally requested when we return.
  100. /// </summary>
  101. private static void ProcessSocketSequence(CodeContext context, object sequence, out List socketList, out Dictionary<Socket, object> socketToOriginal) {
  102. socketToOriginal = new Dictionary<Socket, object>();
  103. socketList = new List();
  104. IEnumerator cursor = PythonOps.GetEnumerator(sequence);
  105. while (cursor.MoveNext()) {
  106. object original = cursor.Current;
  107. Socket socket = ObjectToSocket(context, original);
  108. socketList.append(socket);
  109. socketToOriginal[socket] = original;
  110. }
  111. }
  112. /// <summary>
  113. /// Return the System.Net.Sockets.Socket object that corresponds to the passed-in
  114. /// object. obj can be a System.Net.Sockets.Socket, a PythonSocket.SocketObj, a
  115. /// long integer (representing a socket handle), or a Python object with a fileno()
  116. /// method (whose result is used to look up an existing PythonSocket.SocketObj,
  117. /// which is in turn converted to a Socket.
  118. /// </summary>
  119. private static Socket ObjectToSocket(CodeContext context, object obj) {
  120. Socket socket;
  121. PythonSocket.socket pythonSocket = obj as PythonSocket.socket;
  122. if (pythonSocket != null) {
  123. return pythonSocket._socket;
  124. }
  125. Int64 handle;
  126. if (!Converter.TryConvertToInt64(obj, out handle)) {
  127. object userSocket = obj;
  128. object filenoCallable = PythonOps.GetBoundAttr(context, userSocket, "fileno");
  129. object fileno = PythonCalls.Call(context, filenoCallable);
  130. handle = Converter.ConvertToInt64(fileno);
  131. }
  132. if (handle < 0) {
  133. throw PythonOps.ValueError("file descriptor cannot be a negative number ({0})", handle);
  134. }
  135. socket = PythonSocket.socket.HandleToSocket(handle);
  136. if (socket == null) {
  137. SocketException e = new SocketException((int)SocketError.NotSocket);
  138. throw PythonExceptions.CreateThrowable((PythonType)PythonContext.GetContext(context).GetModuleState("selecterror"), PythonTuple.MakeTuple(e.ErrorCode, e.Message));
  139. }
  140. return socket;
  141. }
  142. #endregion
  143. }
  144. }
  145. #endif