async def _handleSocketAccept( self, request: networking.MsgSocketAcceptRequest ) -> networking.MsgResponse: debug( f'socketAccept handle={request.handle} timeout={request.timeout}') responseMsg = networking.MsgResponse() response = responseMsg.socketAcceptResponse response.handle = -1 response.address.port = 0 response.address.ip = 0 try: handle = self._getFreeHandle() socketCtx = self._getSocketCtx(request.handle) socketCtx.setTimeoutMsec(request.timeout) (connection, address) = await runInThread(lambda: socketCtx.socket.accept()) self._sockets[handle] = SocketContext(connection, socketCtx.type) response.handle = handle serializeAddress(address, response.address) response.err = 0 except Exception as ex: response.err = logAndConvertException( f'socketAccept failed handle={request.handle}', ex) return responseMsg
async def _handleGetHostByName( self, request: networking.MsgGetHostByNameRequest ) -> networking.MsgResponse: debug(f'getHostByNameRequest name={request.name}') responseMsg = networking.MsgResponse() response = responseMsg.getHostByNameResponse response.name = "" try: hostname, aliases, addresses = await runInThread( lambda: socket.gethostbyname_ex(request.name)) response.name = hostname if len(aliases) > 0: response.alias = aliases[0] response.addresses[:] = [ cast(int, serializeIp(x)) for x in addresses if serializeIp(x) is not None ][:3] response.err = 0 except Exception as ex: response.err = logAndConvertException( f'failed to resolve host {request.name}', ex) return responseMsg
async def _handeSocketReceive( self, request: networking.MsgSocketReceiveRequest ) -> networking.MsgResponse: debug( f'socketReceiveRequest: handle={request.handle} flags={request.flags} timeout={request.timeout} maxLength={request.maxLen} addressRequested={request.addressRequested}' ) responseMsg = networking.MsgResponse() response = responseMsg.socketReceiveResponse response.data = b'' try: socketCtx = self._getSocketCtx(request.handle) flags = translateFlags(request.flags) socketCtx.setTimeoutMsec(request.timeout) data, address = await runInThread( lambda: socketCtx.socket.recvfrom(request.maxLen, flags)) if address != None and request.addressRequested: serializeAddress(address, response.address) response.data = data response.err = 0 logPayload(response.data) except socket.timeout: response.err = err.netErrTimeout except Exception as ex: response.err = logAndConvertException("failed to receive", ex) return responseMsg
async def _handleSocketClose( self, request: networking.MsgSocketCloseRequest ) -> networking.MsgResponse: debug( f'socketCloseRequest: handle={request.handle} timeout={request.timeout}' ) responseMsg = networking.MsgResponse() response = responseMsg.socketCloseResponse try: socketContext = self._getSocketCtx(request.handle) self._sockets[request.handle] = None socketContext.setTimeoutMsec(request.timeout) await socketContext.close() response.err = 0 except socket.timeout: response.err = err.netErrTimeout except Exception as ex: response.err = logAndConvertException( f'failed to close socket {request.handle}', ex) return responseMsg
async def _handleSocketBind( self, request: networking.MsgSocketBindRequest ) -> networking.MsgResponse: debug( f'socketBindRequest: handle={request.handle} address={deserializeAddress(request.address)} timeout={request.timeout}' ) responseMsg = networking.MsgResponse() response = responseMsg.socketBindResponse try: socketCtx = self._getSocketCtx(request.handle) socketCtx.setTimeoutMsec(request.timeout) await runInThread(lambda: socketCtx.socket.bind( deserializeAddress(request.address) if self._forceBindAddress is None else self._forceBindAddress)) socketCtx.bound = True response.err = 0 except socket.timeout: response.err = err.netErrTimeout except Exception as ex: response.err = logAndConvertException("failed to bind socket", ex) return responseMsg
async def _handleSocketSend( self, request: networking.MsgSocketSendRequest ) -> networking.MsgResponse: debug( f'socketSendRequest: handle={request.handle} len={len(request.data)} flags={request.flags} timeout={request.timeout} {f"address={deserializeAddress(request.address)}" if request.HasField("address") else ""}' ) logPayload(request.data) responseMsg = networking.MsgResponse() response = responseMsg.socketSendResponse response.bytesSent = -1 try: socketCtx = self._getSocketCtx(request.handle) sock = socketCtx.socket flags = translateFlags(request.flags) socketCtx.setTimeoutMsec(request.timeout) if socketCtx.type == socket.SOCK_RAW: data = removeIpHeader(request.data, socketCtx) address = deserializeAddress( request.address) if request.HasField("address") else ( ipFromIpPacket(request.data), 1) response.bytesSent = await runInThread(lambda: sock.sendto( data, flags, address) + len(request.data) - len(data)) elif request.HasField("address"): response.bytesSent = await runInThread(lambda: sock.sendto( request.data, flags, deserializeAddress(request.address))) else: response.bytesSent = await runInThread( lambda: sock.send(request.data, flags)) response.err = 0 except socket.timeout: response.err = err.netErrTimeout except Exception as ex: response.err = logAndConvertException("failed to send", ex) return responseMsg
async def _handleSocketAddr( self, request: networking.MsgSocketAddrRequest ) -> networking.MsgResponse: debug( f'socketAddrRequest: handle={request.handle} requestAddressLocal={request.requestAddressLocal} requestAddressRemote={request.requestAddressRemote} timeout={request.timeout}' ) responseMsg = networking.MsgResponse() response = responseMsg.socketAddrResponse try: socketCtx = self._getSocketCtx(request.handle) sock = socketCtx.socket socketCtx.setTimeoutMsec(request.timeout) if request.requestAddressLocal: try: serializeAddress( await runInThread(lambda: sock.getsockname()), response.addressLocal) except OSError as ex: if ex.errno in errno.errorcode and errno.errorcode[ ex.errno] == "WSAEINVAL": response.addressLocal.port = 0 response.addressLocal.ip = 0 else: raise ex socketCtx.updateTimeout() if request.requestAddressRemote: serializeAddress(await runInThread(lambda: sock.getpeername()), response.addressRemote) response.err = 0 except socket.timeout: response.err = err.netErrTimeout except Exception as ex: response.err = logAndConvertException( "failed to get socket addresses", ex) return responseMsg
async def _handleSocketOpen( self, request: networking.MsgSocketOpenRequest ) -> networking.MsgResponse: debug( f'socketOpenRequest: type={request.type} protocol={request.protocol}' ) responseMsg = networking.MsgResponse() response = responseMsg.socketOpenResponse response.handle = -1 if not request.type in SOCKET_TYPE: response.err = err.netErrParamErr return responseMsg try: sockType = SOCKET_TYPE[request.type] sockProtocol = 0 if sockType == socket.SOCK_RAW: if request.protocol == 255 or request.protocol == 1: sockProtocol = socket.IPPROTO_ICMP else: warning( f'unsupported protocol for RAW socket: {request.protocol}' ) response.err = err.netErrParamErr return responseMsg handle = self._getFreeHandle() sock = await runInThread( lambda: socket.socket(socket.AF_INET, sockType, sockProtocol)) self._sockets[handle] = SocketContext(sock, sockType) response.handle = handle response.err = 0 except Exception as ex: response.err = logAndConvertException("failed to open socket", ex) return responseMsg
async def _handleSocketOptionSet( self, request: networking.MsgSocketOptionSetRequest ) -> networking.MsgResponse: value = sockopt.sockoptValue(request) debug( f'socketOptionSet handle={request.handle} level={request.level} option={request.option} value={value} timeout={request.timeout}' ) # type: ignore responseMsg = networking.MsgResponse() response = responseMsg.socketOptionSetResponse response.err = 0 try: socketCtx = self._getSocketCtx(request.handle) socket = socketCtx.socket if request.level == netSocketOptLevelSocket and request.option == netSocketOptSockNonBlocking: await runInThread(lambda: socketCtx.setNonblocking(bool(value)) ) else: level = sockopt.translateSockoptLevel(request.level) option = sockopt.translateSockoptOption( request.level, request.option) if level is None or option is None: response.err = err.netErrParamErr else: socketCtx.setTimeoutMsec(request.timeout) # https://github.com/python/mypy/issues/4297 _level = level _option = option await runInThread( lambda: socket.setsockopt(_level, _option, value)) except Exception as ex: response.err = logAndConvertException( f'socketOptionSet failed handle={request.handle}', ex) return responseMsg
async def _handleSocketListen( self, request: networking.MsgSocketListenRequest ) -> networking.MsgResponse: debug( f'socketOptionListen handle={request.handle} backlock={request.backlog} timeout={request.timeout}' ) responseMsg = networking.MsgResponse() response = responseMsg.socketListenResponse try: socketCtx = self._getSocketCtx(request.handle) socketCtx.setTimeoutMsec(request.timeout) await runInThread(lambda: socketCtx.socket.listen(request.backlog)) response.err = 0 except Exception as ex: response.err = logAndConvertException( f'socketListen failed handle={request.handle}', ex) return responseMsg
async def _handleGetServByName( self, request: networking.MsgGetServByNameRequest ) -> networking.MsgResponse: debug( f'getServByNameRequest name={request.name} protocol={request.protocol}' ) responseMsg = networking.MsgResponse() response = responseMsg.getServByNameResponse response.port = 0 try: response.port = await runInThread( lambda: socket.getservbyname(request.name, request.protocol)) response.err = 0 except Exception as ex: info(f'failed to resolve service: {formatException(ex)}') response.err = err.netErrUnknownService return responseMsg
async def _handleSettingGet( self, request: networking.MsgSettingGetRequest ) -> networking.MsgResponse: debug(f'settingGet setting={request.setting}') responseMsg = networking.MsgResponse() response = responseMsg.settingGetResponse response.err = 0 try: if request.setting == netSettingHostName: response.strval = socket.gethostname() elif request.setting in [ netSettingPrimaryDNS, netSettingSecondaryDNS, netSettingRTPrimaryDNS, netSettingRTSecondaryDNS ]: resolver = dns.resolver.Resolver() if self._nameserver is None: for nameserver in resolver.nameservers: ip = serializeIp(nameserver) if ip != None: break else: ip = self._nameserver response.uint32val = ip if ip is not None else 0x08080808 else: response.err = err.netErrParamErr except Exception as ex: response.err = logAndConvertException('settingGet failed', ex) return responseMsg
async def _handleSocketConnect( self, request: networking.MsgSocketConnectRequest ) -> networking.MsgResponse: debug( f'socketConnectRequest handle={request.handle} address={deserializeAddress(request.address)} timeout={request.timeout}' ) responseMsg = networking.MsgResponse() response = responseMsg.socketConnectResponse try: socketContext = self._getSocketCtx(request.handle) socketContext.setTimeoutMsec(request.timeout) if self._forceBindAddress is not None and not socketContext.bound: forceBindAddress = self._forceBindAddress await runInThread( lambda: socketContext.socket.bind(forceBindAddress)) socketContext.bound = True socketContext.updateTimeout() await runInThread(lambda: socketContext.socket.connect( deserializeAddress(request.address))) response.err = 0 except socket.timeout: response.err = err.netErrTimeout except Exception as ex: response.err = logAndConvertException('failed to connect socket', ex) return responseMsg
async def _handleSelect( self, request: networking.MsgSelectRequest) -> networking.MsgResponse: debug( f'select width={request.width} readFDs={self._fdSetToHandles(request.readFDs, request.width)} writeFDs={self._fdSetToHandles(request.writeFDs, request.width)} exceptFDs={self._fdSetToHandles(request.exceptFDs, request.width)} timeout={request.timeout}' ) responseMsg = networking.MsgResponse() response = responseMsg.selectResponse try: response.readFDs = 0 response.writeFDs = 0 response.exceptFDs = 0 response.err = err.netErrInternal timeout = min( MAX_TIMEOUT, request.timeout / 1000 if request.timeout >= 0 else MAX_TIMEOUT) rlist, wlist, xlist = await runInThread(lambda: select.select( self._fdSetToSockets(request.readFDs, request.width), self._fdSetToSockets(request.writeFDs, request.width), self._fdSetToSockets(request.exceptFDs, request.width), timeout )) response.readFDs = self._socketsToFdSet(rlist) response.writeFDs = self._socketsToFdSet(wlist) response.exceptFDs = self._socketsToFdSet(xlist) response.err = 0 except Exception as ex: response.err = logAndConvertException('select failed', ex) return responseMsg
async def _handleSocketOptionGet( self, request: networking.MsgSocketOptionGetRequest ) -> networking.MsgResponse: debug( f'socketOptionGet handle={request.handle} level={request.level} option={request.option} timeout={request.timeout}' ) responseMsg = networking.MsgResponse() response = responseMsg.socketOptionGetResponse response.err = 0 try: socketCtx = self._getSocketCtx(request.handle) socket = socketCtx.socket level = sockopt.translateSockoptLevel(request.level) option = sockopt.translateSockoptOption(request.level, request.option) if request.level == netSocketOptLevelSocket and request.option == netSocketOptSockNonBlocking: response.intval = socketCtx.getNonblocking() elif level == None or option == None: response.err = err.netErrParamErr elif request.level == netSocketOptLevelSocket and request.option == netSocketOptSockLinger: socketCtx.setTimeoutMsec(request.timeout) # https://github.com/python/mypy/issues/4297 assert level is not None and option is not None _level = level _option = option (onoff, linger) = unpack( 'ii', await runInThread(lambda: socket.getsockopt(_level, _option, 8))) response.intval = (onoff & 0xffff) | ((linger & 0xffff) << 16) elif request.level == netSocketOptLevelIP: socketCtx.setTimeoutMsec(request.timeout) # https://github.com/python/mypy/issues/4297 assert level is not None and option is not None _level = level _option = option response.bufval = await runInThread( lambda: socket.getsockopt(_level, _option, 40)) else: socketCtx.setTimeoutMsec(request.timeout) # https://github.com/python/mypy/issues/4297 assert level is not None and option is not None _level = level _option = option response.intval = await runInThread( lambda: socket.getsockopt(_level, _option)) except Exception as ex: response.err = logAndConvertException( f'socketOptionGet failed handle={request.handle}', ex) return responseMsg
async def _handleMessage(self, message: bytes, ws: WebSocketResponse): request = networking.MsgRequest() request.ParseFromString(message) requestType = request.WhichOneof("payload") if requestType == "socketOpenRequest": response = await self._handleSocketOpen(request.socketOpenRequest) elif requestType == "socketBindRequest": response = await self._handleSocketBind(request.socketBindRequest) elif requestType == "socketAddrRequest": response = await self._handleSocketAddr(request.socketAddrRequest) elif requestType == "socketSendRequest": response = await self._handleSocketSend(request.socketSendRequest) elif requestType == "socketReceiveRequest": response = await self._handeSocketReceive( request.socketReceiveRequest) elif requestType == "socketCloseRequest": response = await self._handleSocketClose(request.socketCloseRequest ) elif requestType == "getHostByNameRequest": response = await self._handleGetHostByName( request.getHostByNameRequest) elif requestType == "getServByNameRequest": response = await self._handleGetServByName( request.getServByNameRequest) elif requestType == "socketConnectRequest": response = await self._handleSocketConnect( request.socketConnectRequest) elif requestType == "selectRequest": response = await self._handleSelect(request.selectRequest) elif requestType == "settingGetRequest": response = await self._handleSettingGet(request.settingGetRequest) elif requestType == "socketOptionSetRequest": response = await self._handleSocketOptionSet( request.socketOptionSetRequest) elif requestType == "socketOptionGetRequest": response = await self._handleSocketOptionGet( request.socketOptionGetRequest) elif requestType == "socketListenRequest": response = await self._handleSocketListen( request.socketListenRequest) elif requestType == "socketAcceptRequest": response = await self._handleSocketAccept( request.socketAcceptRequest) else: response = networking.MsgResponse() response.invalidRequestResponse.tag = True error(f'unknown request {requestType}') response.id = request.id await ws.send_bytes(response.SerializeToString())