def __init__(self, format): self._format = format self._minsize = 0 self._count = 0 if not format: self._pairs = [] self._initsize = 0 elif not isinstance(format, bytes): raise TypeError("NetStruct() format must be a byte string.") else: # Make sure there aren't any back-to-back strings and/or arrays. if b"$$" in format: raise error("invalid sequence in netstruct format") # Break the format down. self._pairs = pairs = [] if format[:1] in b"@=<>!": byte_order = format[:1] format = format[1:] else: byte_order = b"!" while format: segment, sep, format = format.partition(b"$") if sep and (not segment or not segment[-1:] in b"bBhHiIlLqQP"): raise error("bad char in struct format") st = _Struct(byte_order + segment) self._minsize += st.size count = _count(segment) self._count += count pairs.append((st, count, sep)) self._initsize = pairs[0][0].size
class Socket(object): """Class wrapping nanomsg socket. protocol should be a nanomsg protocol constant e.g. nanomsg.PAIR This class supports being used as a context manager which should guarantee it is closed. e.g.: import time from nanomsg import PUB, Socket with Socket(PUB) as pub_socket: pub_socket.bind('tcp://127.0.0.1:49234') for i in range(100): pub_socket.send(b'hello all') time.sleep(0.5) #pub_socket is closed Socket.bind and Socket.connect return subclass of Endpoint which allow you to shutdown selected endpoints. The constructor also allows you to wrap existing sockets by passing in the socket fd instead of the protocol e.g.: from nanomsg import AF_SP, PAIR, Socket from nanomsg import wrapper as nn socket_fd = nn.nn_socket(AF_SP, PAIR) socket = Socket(socket_fd=socket_fd) """ _INT_PACKER = _Struct(str('i')) class _Endpoint(object): def __init__(self, socket, endpoint_id, address): self._endpoint_id = endpoint_id self._fdocket = socket self._address = address @property def address(self): return self._address def shutdown(self): self._fdocket._endpoints.remove(self) _nn_check_positive_rtn( nn_shutdown(self._fdocket._s, self._endpoint_id)) def __repr__(self): return '<%s socket %r, id %r, addresss %r>' % ( self.__class__.__name__, self._fdocket, self._endpoint_id, self._address) class BindEndpoint(_Endpoint): pass class ConnectEndpoint(_Endpoint): pass class NanoconfigEndpoint(_Endpoint): def shutdown(self): raise NotImplementedError( "Shutdown of nanoconfig endpoint is not supported") def __init__(self, protocol=None, socket_fd=None, domain=AF_SP): if protocol is not None and socket_fd is not None: raise NanoMsgError('Only one of protocol or socket_fd should be ' 'passed to the Socket constructor') if protocol is not None: self._fd = _nn_check_positive_rtn( wrapper.nn_socket(domain, protocol)) else: self._fd = socket_fd self._endpoints = [] def _get_send_fd(self): return self.get_int_option(SOL_SOCKET, SNDFD) def _get_recv_fd(self): return self.get_int_option(SOL_SOCKET, RCVFD) def _get_linger(self): return self.get_int_option(SOL_SOCKET, LINGER) def _set_linger(self, value): return self.set_int_option(SOL_SOCKET, LINGER, value) def _get_send_buffer_size(self): return self.get_int_option(SOL_SOCKET, SNDBUF) def _set_send_buffer_size(self, value): return self.set_int_option(SOL_SOCKET, SNDBUF, value) def _get_recv_buffer_size(self): return self.get_int_option(SOL_SOCKET, RCVBUF) def _set_recv_buffer_size(self, value): return self.set_int_option(SOL_SOCKET, RCVBUF, value) def _get_recv_max_size(self): return self.get_int_option(SOL_SOCKET, RCVMAXSIZE) def _set_recv_max_size(self, value): return self.set_int_option(SOL_SOCKET, RCVMAXSIZE, value) def _get_send_timeout(self): return self.get_int_option(SOL_SOCKET, SNDTIMEO) def _set_send_timeout(self, value): return self.set_int_option(SOL_SOCKET, SNDTIMEO, value) def _get_recv_timeout(self): return self.get_int_option(SOL_SOCKET, RCVTIMEO) def _set_recv_timeout(self, value): return self.set_int_option(SOL_SOCKET, RCVTIMEO, value) def _get_reconnect_interval(self): return self.get_int_option(SOL_SOCKET, RECONNECT_IVL) def _set_reconnect_interval(self, value): return self.set_int_option(SOL_SOCKET, RECONNECT_IVL, value) def _get_reconnect_interval_max(self): return self.get_int_option(SOL_SOCKET, RECONNECT_IVL_MAX) def _set_reconnect_interval_max(self, value): return self.set_int_option(SOL_SOCKET, RECONNECT_IVL_MAX, value) send_fd = property(_get_send_fd, doc='Send file descripter') recv_fd = property(_get_recv_fd, doc='Receive file descripter') linger = property(_get_linger, _set_linger, doc='Socket linger in ' 'milliseconds (0.001 seconds)') recv_buffer_size = property(_get_recv_buffer_size, _set_recv_buffer_size, doc='Receive buffer size in bytes') recv_max_size = property( _get_recv_max_size, _set_recv_max_size, doc='Maximum message size that can be received in bytes') send_buffer_size = property(_get_send_buffer_size, _set_send_timeout, doc='Send buffer size in bytes') send_timeout = property(_get_send_timeout, _set_send_timeout, doc='Send timeout in milliseconds (0.001 seconds)') recv_timeout = property(_get_recv_timeout, _set_recv_timeout, doc='Receive timeout in milliseconds (0.001 ' 'seconds)') reconnect_interval = property( _get_reconnect_interval, _set_reconnect_interval, doc='Base interval between connection failure and reconnect' ' attempt in milliseconds (0.001 seconds).') reconnect_interval_max = property( _get_reconnect_interval_max, _set_reconnect_interval_max, doc='Max reconnect interval - see C API documentation.') @property def fd(self): """Socket file descripter. Not this is not an OS file descripter (see .send_fd, .recv_fd). """ return self._fd @property def endpoints(self): """Endpoints list """ return list(self._endpoints) @property def uses_nanoconfig(self): return (self._endpoints and isinstance(self._endpoints[0], Socket.NanoconfigEndpoint)) def bind(self, address): """Add a local endpoint to the socket""" if self.uses_nanoconfig: raise ValueError("Nanoconfig address must be sole endpoint") endpoint_id = _nn_check_positive_rtn(wrapper.nn_bind( self._fd, address)) ep = Socket.BindEndpoint(self, endpoint_id, address) self._endpoints.append(ep) return ep def connect(self, address): """Add a remote endpoint to the socket""" if self.uses_nanoconfig: raise ValueError("Nanoconfig address must be sole endpoint") endpoint_id = _nn_check_positive_rtn( wrapper.nn_connect(self.fd, address)) ep = Socket.ConnectEndpoint(self, endpoint_id, address) self._endpoints.append(ep) return ep def configure(self, address): """Configure socket's addresses with nanoconfig""" global nanoconfig_started if len(self._endpoints): raise ValueError("Nanoconfig address must be sole endpoint") endpoint_id = _nn_check_positive_rtn( wrapper.nc_configure(self.fd, address)) if not nanoconfig_started: nanoconfig_started = True ep = Socket.NanoconfigEndpoint(self, endpoint_id, address) self._endpoints.append(ep) return ep def close(self): """Close the socket""" if self.is_open(): fd = self._fd self._fd = -1 if self.uses_nanoconfig: wrapper.nc_close(fd) else: _nn_check_positive_rtn(wrapper.nn_close(fd)) def is_open(self): """Returns true if the socket has a valid socket id. If the underlying socket is closed by some other means than Socket.close this method may return True when the socket is actually closed. """ return self.fd >= 0 def recv(self, buf=None, flags=0): """Recieve a message.""" if buf is None: rtn, out_buf = wrapper.nn_recv(self.fd, flags) else: rtn, out_buf = wrapper.nn_recv(self.fd, buf, flags) _nn_check_positive_rtn(rtn) return bytes(buffer(out_buf))[:rtn] def set_string_option(self, level, option, value): _nn_check_positive_rtn( wrapper.nn_setsockopt(self.fd, level, option, value)) def set_int_option(self, level, option, value): buf = create_writable_buffer(Socket._INT_PACKER.size) Socket._INT_PACKER.pack_into(buf, 0, value) _nn_check_positive_rtn( wrapper.nn_setsockopt(self.fd, level, option, buf)) def get_int_option(self, level, option): size = Socket._INT_PACKER.size buf = create_writable_buffer(size) rtn, length = wrapper.nn_getsockopt(self._fd, level, option, buf) _nn_check_positive_rtn(rtn) if length != size: raise NanoMsgError(('Returned option size (%r) should be the same' ' as size of int (%r)') % (rtn, size)) return Socket._INT_PACKER.unpack_from(buffer(buf))[0] def get_string_option(self, level, option, max_len=16 * 1024): buf = create_writable_buffer(max_len) rtn, length = wrapper.nn_getsockopt(self._fd, level, option, buf) _nn_check_positive_rtn(rtn) return bytes(buffer(buf))[:length] def send(self, msg, flags=0): """Send a message""" _nn_check_positive_rtn(wrapper.nn_send(self.fd, msg, flags)) def __enter__(self): return self def __exit__(self, *args): self.close() def __repr__(self): return '<%s fd %r, connected to %r, bound to %r>' % ( self.__class__.__name__, self.fd, [ i.address for i in self.endpoints if type(i) is Socket.BindEndpoint ], [ i.address for i in self.endpoints if type(i) is Socket.ConnectEndpoint ], ) def __del__(self): try: self.close() except NanoMsgError: pass
def __init__(self, id, fmt): self.id = id self.struct = _Struct(fmt)
#!/usr/bin/env python3 from struct import Struct as _Struct short_unpackf = _Struct('!H').unpack_from short_unpack = _Struct('!H').unpack long_unpack = _Struct('!L').unpack byte_pack = _Struct('!B').pack short_pack = _Struct('!H').pack long_pack = _Struct('!L').pack int_unpack = _Struct('I').unpack double_bite_unpack = _Struct('!2B').unpack_from double_short_unpack = _Struct('!2H').unpack_from double_byte_pack = _Struct('!2B').pack double_short_pack = _Struct('!2H').pack checksum_pack = _Struct('<H').pack fcntl_pack = _Struct('24s').pack mac_unpack = _Struct('!6s').unpack mac_pack = _Struct('!6s').pack eth_header_pack = _Struct('!6s6sH').pack ip_header_pack = _Struct('!2B3H2B2s4s4s').pack udp_header_pack = _Struct('!4H').pack icmp_header_pack = _Struct('!2B2s2H').pack tcp_header_pack = _Struct('!2H2L2BH2sH').pack pseudo_header_pack = _Struct('!4s4s2BH').pack ip_header_override_pack = _Struct('!10s2s4s4s').pack
#!/usr/bin/env python3 # if anyone is worndering, the undescores are here to prevent namespace conflictions. import os as _os import sys as _sys import time as _time import socket as _socket from struct import Struct as _Struct from ipaddress import IPv4Address as _IPv4Address # assigning variables to direct function references. _fast_time = _time.time _write_err = _sys.stdout.write tcp_header_unpack = _Struct('!2H2LB').unpack_from udp_header_unpack = _Struct('!4H').unpack_from class RawPacket: '''tcp/ip packet represented in class form. packet fields can be accessed via their corresponding attribute.''' def __init__(self, data): self.timestamp = _fast_time() self.protocol = 0 self._name = self.__class__.__name__ self._dlen = len(data) # parsing ethernet header here because it is more efficient self.dst_mac = data[:6].hex()
def __init__(self, format_string): self._struct = _Struct(format_string)
FIVE_MIN = 300 KEEPALIVE_INTERVAL = 8 # namedtuples RELAY_CONN = _namedtuple('relay_conn', 'remote_ip sock') DNS_CACHE = _namedtuple('dns_cache', 'ttl records') DNS_SERVERS = _namedtuple('dns_server', 'primary secondary') CACHED_RECORD = _namedtuple('cached_record', 'expire ttl records') # byte container RESOURCE_RECORD = _ByteContainer('resource_record', 'name qtype qclass ttl data') # COMPILED STRUCTS dns_header_unpack = _Struct('!6H').unpack dns_header_pack = _Struct('!6H').pack resource_record_pack = _Struct('!3HLH4s').pack short_unpackf = _Struct('!H').unpack_from byte_pack = _Struct('!B').pack short_unpack = _Struct('!H').unpack short_pack = _Struct('!H').pack long_pack = _Struct('!L').pack long_unpack = _Struct('!L').unpack double_short_unpack = _Struct('!2H').unpack_from double_short_pack = _Struct('!2H').pack
def __init__(self,format_string): self._struct = _Struct(format_string)
from __future__ import print_function import io as _io import sys as _sys # Used for debugging. import gzip as _gzip import json as _json from struct import Struct as _Struct _TYPE_NAMES = {} _TYPE_IDS = {} _READERS = {} _WRITERS = {} # Todo: better name. _STRUCTS = {fmt: _Struct(fmt) for fmt in ['>b', '>h', '>i', '>q', '>f', '>d']} END = 0 class Collection(object): """Common base class for Compound and List. Used for isinstance(). """ pass class Compound(dict, Collection): def __init__(self, *args, **kw): self.types = {} dict.__init__(self, *args, **kw) def get_type(self, name): return self.types[name]
class Socket(object): packet = _Struct('BB8s') def __init__(self, sockname): self.sockname = sockname self.sock = None if self.sockname: self.attach() def attach(self, sockname=None): if not sockname: sockname = self.sockname self.sockname = sockname if not self.sockname: raise ValueError("sockname is required!") self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) self.sock.connect(self.sockname) self.fd = self.sock.fileno() os.write(self.fileno(), self.packet.pack(MSG_ATTACH, 0, '')) #self.redraw(ctrl_l=True) def detach(self): if not self.sock: return try: os.write(self.fileno(), self.packet.pack(MSG_DETACH, 0, '')) except OSError: pass # The socket is closed on the other end already self.sock.close() self.sock = None self.fd = -1 close = detach def fileno(self): if self.sock: return self.sock.fileno() return -1 def read(self, cnt=None): if not self.sock: raise NotAttachedError("Not attached to dtach.Daemon!") if not cnt or cnt < 0: cnt = BUFSIZE return os.read(self.fileno(), cnt) recv = read def getch(self): return self.read(1) def write(self, buf): if not self.sock: raise NotAttachedError("Not attached to master!") nr = 0 while len(buf): if len(buf) > 8: b = buf[:8] l = 8 else: b = buf[:] l = len(b) os.write(self.fileno(), self.packet.pack(MSG_PUSH, l, b)) nr += len(b) buf = buf[l:] return nr send = write def setwinsize(self, ws): if not self.sock: raise NotAttachedError("Not attached to master!") os.write(self.fileno(), self.packet.pack(MSG_REDRAW, REDRAW_WINCH, ws)) def redraw(self, x=None, y=None, ctrl_l=None): if not self.sock: raise NotAttachedError("Not attached to master!") if ctrl_l: if x is not None or y is not None: raise ValueError("Only one of (x,y) or ctrl_l supported!") subtype = REDRAW_CTRL_L ws = '\x00' * 8 else: if x is None or y is None: raise ValueError("Both (x,y) required!") subtype = REDRAW_WINCH ws = struct.pack('HHHH', x, y, 0, 0) os.write(self.fileno(), self.packet.pack(MSG_REDRAW, subtype, ws)) def __getattr__(self, name): if hasattr(self, 'sock'): return getattr(self.sock, name) raise AttributeError("no such attribute: %s" % name)