o bhC@sdZddlZddlZddlmZddlmZmZmZm Z m Z m Z m Z m Z ddlmZddlmZddlmZddlmZdd lmZdd lmZdd lmZmZmZmZdd lm Z d Z!ddZ"dZ#ddZ$ddZ%ddZ&GdddZ'ddZ(eeGdddZ)GdddZ*dS)zD Tools for automated testing of L{twisted.pair}-based applications. N)deque)EAGAINEBADFEINTREINVALENOBUFSENOSYSEPERM EWOULDBLOCKwraps) implementer)DatagramProtocol)EthernetProtocol) IPProtocol)RawUDPProtocol) _IFNAMSIZ _TUNSETIFF TunnelFlags_IInputOutputSystem) nativeStringcCs td|S)z Pack an integer into a network-order two-byte string. @param n: The integer to pack. Only values that fit into 16 bits are supported. @return: The packed representation of the integer. @rtype: L{bytes} z>H)structpack)nr6/usr/lib/python3/dist-packages/twisted/pair/testing.py_Hs rcCs||t||S)a Construct an ethernet frame. @param src: The source ethernet address, encoded. @type src: L{bytes} @param dst: The destination ethernet address, encoded. @type dst: L{bytes} @param protocol: The protocol number of the payload of this datagram. @type protocol: L{int} @param payload: The content of the ethernet frame (such as an IP datagram). @type payload: L{bytes} @return: The full ethernet frame. @rtype: L{bytes} )rsrcdstprotocolpayloadrrr _ethernet.sr$cCsdtdt|dtdttjt|ttjt|}ttd|}|d?}|d@|}|dA}|dd t d ||d d}||S) a Construct an IP datagram with the given source, destination, and application payload. @param src: The source IPv4 address as a dotted-quad string. @type src: L{bytes} @param dst: The destination IPv4 address as a dotted-quad string. @type dst: L{bytes} @param payload: The content of the IP datagram (such as a UDP datagram). @type payload: L{bytes} @return: An IP datagram header and payload. @rtype: L{bytes} sEs@rz!10HiN z!H ) rlensocket inet_ptonAF_INETrsumrunpackr)r r!r#ipHeader checksumStep1carry checksumStep2 checksumStep3rrr_ipDs$   $r4cCs0t|t|tt|dtd}||S)a~ Construct a UDP datagram with the given source, destination, and application payload. @param src: The source port number. @type src: L{int} @param dst: The destination port number. @type dst: L{int} @param payload: The content of the UDP datagram. @type payload: L{bytes} @return: A UDP datagram header and payload. @rtype: L{bytes} r)rr))r r!r# udpHeaderrrr_udpvs r7c@sreZdZdZdZeedZee dZ ee dZ eZ dZddZed d Zed d Zd dZddZddZdS)Tunnelz An in-memory implementation of a tun or tap device. @cvar _DEVICE_NAME: A string representing the conventional filesystem entry for the tunnel factory character special device. @type _DEVICE_NAME: C{bytes} s /dev/net/tunz Resource temporarily unavailablezOperation would blockzInterrupted function callicCs:||_||_d|_d|_d|_t|_t|_t|_dS)a @param system: An L{_IInputOutputSystem} provider to use to perform I/O. @param openFlags: Any flags to apply when opening the tunnel device. See C{os.O_*}. @type openFlags: L{int} @param fileMode: ignored N) system openFlags tunnelMode requestedNamenamer readBuffer writeBufferpendingSignals)selfr9r:fileModerrr__init__s  zTunnel.__init__cCs|j|jj@ S)zx If the file descriptor for this tunnel is open in blocking mode, C{True}. C{False} otherwise. )r:r9 O_NONBLOCKrArrrblockingszTunnel.blockingcCst|j|jj@S)zz If the file descriptor for this tunnel is marked as close-on-exec, C{True}. C{False} otherwise. )boolr:r9 O_CLOEXECrErrr closeOnExecszTunnel.closeOnExeccCs.|jtjj@rtddt|d}|j|dS)aI Deliver a datagram to this tunnel's read buffer. This makes it available to be read later using the C{read} method. @param datagram: The IPv4 datagram to deliver. If the mode of this tunnel is TAP then ethernet framing will be added automatically. @type datagram: L{bytes} ssrN)r;rIFF_TAPvaluer$_IPv4r>appendrAdatagramrrraddToReadBuffers  zTunnel.addToReadBuffercCsR|jr |jtjj@r d}ndt}|d8}||jd|S|jr&t|j )a Read a datagram out of this tunnel. @param limit: The maximum number of bytes from the datagram to return. If the next datagram is larger than this, extra bytes are dropped and lost forever. @type limit: L{int} @raise OSError: Any of the usual I/O problems can result in this exception being raised with some particular error number set. @raise IOError: Any of the usual I/O problems can result in this exception being raised with some particular error number set. @return: The datagram which was read from the tunnel. If the tunnel mode does not include L{TunnelFlags.IFF_NO_PI} then the datagram is prefixed with a 4 byte PI header. @rtype: L{bytes} rN) r>r;r IFF_NO_PIrK_PI_SIZEpopleftrFNotImplementedErrornonBlockingExceptionStyle)rAlimitheaderrrrreadsz Tunnel.readcCsF|jr |jttdt||jkrttd|j|t|S)a{ Write a datagram into this tunnel. @param datagram: The datagram to write. @type datagram: L{bytes} @raise IOError: Any of the usual I/O problems can result in this exception being raised with some particular error number set. @return: The number of bytes of the datagram which were written. @rtype: L{int} zInterrupted system callzNo buffer space available) r@rUOSErrorrr)SEND_BUFFER_SIZErr?rMrNrrrwrites    z Tunnel.writeN)__name__ __module__ __qualname____doc__ _DEVICE_NAMEIOErrorr EAGAIN_STYLEr[r EWOULDBLOCK_STYLEr EINTR_STYLErWr\rCpropertyrFrIrPrZr]rrrrr8s       #r8cstfdd}|S)a| Wrap a L{MemoryIOSystem} method with permission-checking logic. The returned function will check C{self.permissions} and raise L{IOError} with L{errno.EPERM} if the function name is not listed as an available permission. @param original: The L{MemoryIOSystem} instance to wrap. @return: A wrapper around C{original} that applies permission checks. cs,j|jvr ttd|g|Ri|S)NzOperation not permitted)r^ permissionsr[r )rAargskwargsoriginalrrpermissionChecker+s  z&_privileged..permissionCheckerr )rlrmrrkr _privilegeds rnc@szeZdZdZdZdZdZdZddZdd Z d d Z e dd dZ ddZ ddZddZe ddZddZddZd S)MemoryIOSystemz An in-memory implementation of basic I/O primitives, useful in the context of unit testing as a drop-in replacement for parts of the C{os} module. @ivar _devices: @ivar _openFiles: @ivar permissions: @ivar _counter: i rcCsi|_i|_ddh|_dS)Nopenioctl)_devices _openFilesrhrErrrrCGszMemoryIOSystem.__init__cCs|j|S)aX Get the L{Tunnel} object associated with the given L{TuntapPort}. @param port: A L{TuntapPort} previously initialized using this L{MemoryIOSystem}. @return: The tunnel object created by a prior use of C{open} on this object on the tunnel special device file. @rtype: L{Tunnel} )rufileno)rAportrrr getTunnelL zMemoryIOSystem.getTunnelcCs||j|<dS)a1 Specify a class which will be used to handle I/O to a device of a particular name. @param name: The filesystem path name of the device. @type name: L{bytes} @param cls: A class (like L{Tunnel}) to instantiated whenever this device is opened. N)rt)rAr=clsrrrregisterSpecialDeviceYryz$MemoryIOSystem.registerSpecialDeviceNcCsD||jvr|j}|jd7_|j|||||j|<|Sttd)a A replacement for C{os.open}. This initializes state in this L{MemoryIOSystem} which will be reflected in the behavior of the other file descriptor-related methods (eg L{MemoryIOSystem.read}, L{MemoryIOSystem.write}, etc). @param name: A string giving the name of the file to open. @type name: C{bytes} @param flags: The flags with which to open the file. @type flags: C{int} @param mode: The mode with which to open the file. @type mode: C{int} @raise OSError: With C{ENOSYS} if the file is not a recognized special device file. @return: A file descriptor associated with the newly opened file description. @rtype: L{int} rpzFunction not implemented)rt_counterrur[r)rAr=flagsmodefdrrrrrfs  zMemoryIOSystem.opencC,z |j||WStyttdw)z Try to read some bytes out of one of the in-memory buffers which may previously have been populated by C{write}. @see: L{os.read} Bad file descriptor)rurZKeyErrorr[r)rArrXrrrrZ   zMemoryIOSystem.readcCr)z Try to add some bytes to one of the in-memory buffers to be accessed by a later C{read} call. @see: L{os.write} r)rur]rr[r)rArdatarrrr]rzMemoryIOSystem.writecCs(z|j|=WdStyttdw)z Discard the in-memory buffer and other in-memory state for the given file descriptor. @see: L{os.close} rN)rurr[r)rArrrrcloses   zMemoryIOSystem.closecCsz|j|}Wn tyttdw|tkrttdtdtf|\}}||_ ||_ |dtdd|_ t dtf|j |S)z Perform some configuration change to the in-memory state for the given file descriptor. @see: L{fcntl.ioctl} rzRequest or args is not valid.z%dsHNs123) rurr[rrrrr.rr;r<r=r)rArrequestritunnelr=r~rrrrss   zMemoryIOSystem.ioctlcCsLd}d}t||dt||d|dd}t|j}|d|||fS)ah Write an ethernet frame containing an ip datagram containing a udp datagram containing the given payload, addressed to the given address, to a tunnel device previously opened on this I/O system. @param datagram: A UDP datagram payload to send. @type datagram: L{bytes} @param address: The destination to which to send the datagram. @type address: L{tuple} of (L{bytes}, L{int}) @return: A two-tuple giving the address from which gives the address from which the datagram was sent. @rtype: L{tuple} of (L{bytes}, L{int}) z10.1.2.3iaSrrp)r r!r#)r4r7listruvaluesrP)rArOaddresssrcIPsrcPort serialized openFilesrrrsendUDPszMemoryIOSystem.sendUDPcCs t||S)aa Get a socket-like object which can be used to receive a datagram sent from the given address. @param fileno: A file descriptor representing a tunnel device which the datagram will be received via. @type fileno: L{int} @param host: The IPv4 address to which the datagram was sent. @type host: L{bytes} @param port: The UDP port number to which the datagram was sent. received. @type port: L{int} @return: A L{socket.socket}-like object which can be used to receive the specified datagram. ) _FakePort)rArvhostrwrrr receiveUDPs zMemoryIOSystem.receiveUDPN)r^r_r`rar|O_RDWRrDrHrCrxr{rnrrrZr]rrsrrrrrrro4s$       roc@s eZdZdZddZddZdS)rz A socket-like object which can be used to read UDP datagrams from tunnel-like file descriptors managed by a L{MemoryIOSystem}. cCs||_||_dSr)_system_fileno)rAr9rvrrrrCs z_FakePort.__init__c s|jj|jj}gt}fdd}||_t}|d|t d||jj|jj }|t j j @rEt}|d|j}nfdd}|t jj @ } | rZ|td}||d d|S) a_ Receive a datagram sent to this port using the L{MemoryIOSystem} which created this object. This behaves like L{socket.socket.recv} but the data being I{sent} and I{received} only passes through various memory buffers managed by this object and L{MemoryIOSystem}. @see: L{socket.socket.recv} cs|dSr)rM)rOr) datagramsrrcapturesz_FakePort.recv..capturei90rcs|ddddSr)datagramReceived)r)iprr s z _FakePort.recv..Nr)rrurr?rUrrraddProtorr;rrJrKrrSrT) rAnbytesrreceiverrudpr~etherr dataHasPIr)rrrrecvs(        z_FakePort.recvN)r^r_r`rarCrrrrrrs r)+rar*r collectionsrerrnorrrrrrr r functoolsr zope.interfacer twisted.internet.protocolrtwisted.pair.ethernetrtwisted.pair.iprtwisted.pair.rawudprtwisted.pair.tuntaprrrrtwisted.python.compatrrTrrLr$r4r7r8rnrorrrrrs4 (        2 A