| #!/usr/bin/env python |
| # |
| # Copyright 2007 Google Inc. |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| # |
| |
| |
| |
| |
| """Socket Module. |
| |
| This file is intended to provide the equivalent of |
| python/Modules/socketmodule.c rather than python/Lib/socket.py which amongst |
| other things adds a buffered file-like interface. |
| """ |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| import errno |
| import os |
| import re |
| import struct |
| import time |
| import weakref |
| |
| from google.appengine.api import apiproxy_stub_map |
| from google.appengine.api.remote_socket import remote_socket_service_pb |
| |
| from google.appengine.api.remote_socket._remote_socket_addr import * |
| |
| from google.appengine.api.remote_socket._remote_socket_error import * |
| from google.appengine.runtime import apiproxy_errors |
| |
| has_ipv6 = True |
| |
| SOCK_STREAM = 1 |
| SOCK_DGRAM = 2 |
| |
| SOMAXCONN = 128 |
| |
| MSG_PEEK = 2 |
| MSG_WAITALL = 256 |
| |
| IPPROTO_IP = 0 |
| IPPROTO_ICMP = 1 |
| IPPROTO_TCP = 6 |
| IPPROTO_UDP = 17 |
| |
| IPPORT_RESERVED = 1024 |
| IPPORT_USERRESERVED = 5000 |
| |
| INADDR_ANY = 0x00000000 |
| INADDR_BROADCAST = 0xffffffff |
| INADDR_LOOPBACK = 0x7f000001 |
| INADDR_NONE = 0xffffffff |
| |
| (AI_PASSIVE, AI_CANONNAME, AI_NUMERICHOST, AI_NUMERICSERV, AI_V4MAPPED, AI_ALL, |
| AI_ADDRCONFIG) = map(lambda x: 1 << x, range(7)) |
| |
| RemoteSocketServiceError = remote_socket_service_pb.RemoteSocketServiceError |
| |
| |
| def _ImportSymbols(protobuf, symbols, prefix='SOCKET_'): |
| """Import symbols defined in a protobuf into the global namespace.""" |
| for sym in symbols: |
| globals()[sym] = getattr(protobuf, prefix + sym) |
| |
| |
| _ImportSymbols(remote_socket_service_pb.ResolveReply, ( |
| 'EAI_ADDRFAMILY', 'EAI_AGAIN', 'EAI_BADFLAGS', 'EAI_FAIL', 'EAI_FAMILY', |
| 'EAI_MEMORY', 'EAI_NODATA', 'EAI_NONAME', 'EAI_SERVICE', 'EAI_SOCKTYPE', |
| 'EAI_SYSTEM', 'EAI_BADHINTS', 'EAI_PROTOCOL', 'EAI_OVERFLOW', 'EAI_MAX')) |
| |
| _ImportSymbols(remote_socket_service_pb.ShutDownRequest, ( |
| 'SHUT_RD', 'SHUT_WR', 'SHUT_RDWR')) |
| |
| _ImportSymbols(remote_socket_service_pb.SocketOption, ( |
| |
| 'SOL_SOCKET', 'SOL_IP', 'SOL_TCP', 'SOL_UDP', |
| |
| 'SO_DEBUG', 'SO_REUSEADDR', 'SO_TYPE', 'SO_ERROR', 'SO_DONTROUTE', |
| 'SO_BROADCAST', 'SO_SNDBUF', 'SO_RCVBUF', 'SO_KEEPALIVE', |
| |
| 'IP_TOS', 'IP_TTL', 'IP_HDRINCL', 'IP_OPTIONS', |
| |
| 'TCP_NODELAY', 'TCP_MAXSEG', 'TCP_CORK', 'TCP_KEEPIDLE', 'TCP_KEEPINTVL', |
| 'TCP_KEEPCNT', 'TCP_SYNCNT', 'TCP_LINGER2', 'TCP_DEFER_ACCEPT', |
| 'TCP_WINDOW_CLAMP', 'TCP_INFO', 'TCP_QUICKACK')) |
| |
| _ImportSymbols(remote_socket_service_pb.PollEvent, ( |
| 'POLLNONE', 'POLLIN', 'POLLPRI', 'POLLOUT', 'POLLERR', 'POLLHUP', |
| 'POLLNVAL', 'POLLRDNORM', 'POLLRDBAND', 'POLLWRNORM', 'POLLWRBAND', |
| 'POLLMSG', 'POLLREMOVE', 'POLLRDHUP')) |
| |
| |
| _GLOBAL_DEFAULT_TIMEOUT = object() |
| _GLOBAL_TIMEOUT_VALUE = -1.0 |
| |
| _GLOBAL_SOCKET_NEXT_FILENO = 2**32 |
| _GLOBAL_SOCKET_MAP = weakref.WeakValueDictionary() |
| |
| _SERVICES = { |
| 'ftp': [('tcp', 21), ('udp', 21)], |
| 'ftp-data': [('tcp', 20), ('udp', 20)], |
| 'http': [('tcp', 80), ('udp', 80)], |
| 'pop3': [('tcp', 110), ('udp', 110)], |
| 'pop3s': [('tcp', 995), ('udp', 995)], |
| 'smtp': [('tcp', 25), ('udp', 25)], |
| 'telnet': [('tcp', 23), ('udp', 23)], |
| 'www': [('tcp', 80), ('udp', 80)], |
| 'www-http': [('tcp', 80), ('udp', 80)], |
| } |
| |
| _ERROR_MAP = { |
| RemoteSocketServiceError.PERMISSION_DENIED: errno.EACCES, |
| RemoteSocketServiceError.INVALID_REQUEST: errno.EINVAL, |
| RemoteSocketServiceError.SOCKET_CLOSED: errno.EPIPE, |
| } |
| |
| _SOCK_PROTO_MAP = { |
| (SOCK_STREAM, IPPROTO_TCP): 'tcp', |
| (SOCK_DGRAM, IPPROTO_UDP): 'udp', |
| } |
| |
| _ADDRESS_FAMILY_MAP = { |
| AF_INET: remote_socket_service_pb.CreateSocketRequest.IPv4, |
| AF_INET6: remote_socket_service_pb.CreateSocketRequest.IPv6, |
| } |
| |
| _ADDRESS_FAMILY_LENGTH_MAP = { |
| 4: AF_INET, |
| 16: AF_INET6, |
| } |
| |
| |
| class SocketApiNotImplementedError(NotImplementedError, error): |
| pass |
| |
| |
| def _SystemExceptionFromAppError(e): |
| app_error = e.application_error |
| if app_error in (RemoteSocketServiceError.SYSTEM_ERROR, |
| RemoteSocketServiceError.GAI_ERROR): |
| error_detail = RemoteSocketServiceError() |
| try: |
| error_detail.ParseASCII(e.error_detail) |
| except NotImplementedError: |
| |
| |
| m = re.match( |
| r'system_error:\s*(-?\d+)\s*,?\s*error_detail:\s*"([^"]*)"\s*', |
| e.error_detail) |
| if m: |
| error_detail.set_system_error(int(m.group(1))) |
| error_detail.set_error_detail(m.group(2)) |
| else: |
| error_detail.set_system_error(-1) |
| error_detail.set_error_detail(e.error_detail) |
| if app_error == RemoteSocketServiceError.SYSTEM_ERROR: |
| return error(error_detail.system_error(), |
| (error_detail.error_detail() or |
| os.strerror(error_detail.system_error()))) |
| elif app_error == RemoteSocketServiceError.GAI_ERROR: |
| return gaierror(error_detail.system_error(), |
| error_detail.error_detail()) |
| elif app_error in _ERROR_MAP: |
| return error(_ERROR_MAP[app_error], os.strerror(_ERROR_MAP[app_error])) |
| else: |
| return e |
| |
| |
| def _IsAddr(family, addr): |
| try: |
| inet_pton(family, addr) |
| except Exception: |
| return False |
| return True |
| |
| |
| |
| |
| def _Resolve(name, families, use_dns=True, canonical=False): |
| for family in families: |
| if _IsAddr(family, name): |
| |
| return (name, [], [name]) |
| |
| |
| if use_dns: |
| canon, aliases, addresses = _ResolveName(name, families) |
| if addresses: |
| return (canon, aliases, addresses) |
| |
| raise gaierror(EAI_NONAME, 'nodename nor servname provided, or not known') |
| |
| |
| |
| |
| def _ResolveName(name, address_families=(AF_INET6, AF_INET)): |
| request = remote_socket_service_pb.ResolveRequest() |
| request.set_name(name) |
| for af in address_families: |
| request.add_address_families(_ADDRESS_FAMILY_MAP[af]) |
| |
| reply = remote_socket_service_pb.ResolveReply() |
| |
| try: |
| apiproxy_stub_map.MakeSyncCall('remote_socket', 'Resolve', request, reply) |
| except apiproxy_errors.ApplicationError, e: |
| raise _SystemExceptionFromAppError(e) |
| |
| canonical_name = reply.canonical_name() |
| aliases = reply.aliases_list() |
| addresses = [inet_ntop(_ADDRESS_FAMILY_LENGTH_MAP[len(a)], a) |
| for a in reply.packed_address_list()] |
| return canonical_name, aliases, addresses |
| |
| |
| def _ResolveService(servicename, protocolname, numeric_only=False): |
| try: |
| return (protocolname, int(servicename)) |
| except ValueError: |
| pass |
| |
| if not numeric_only: |
| for protocol, port in _SERVICES.get(servicename, []): |
| if not protocolname or protocol == protocolname: |
| return (protocol, port) |
| |
| raise gaierror(EAI_SERVICE, '') |
| |
| |
| def gethostbyname(host): |
| """gethostbyname(host) -> address |
| |
| Return the IP address (a string of the form '255.255.255.255') for a host. |
| """ |
| return _Resolve(host, [AF_INET])[2][0] |
| |
| |
| def gethostbyname_ex(host): |
| """gethostbyname_ex(host) -> (name, aliaslist, addresslist) |
| |
| Return the true host name, a list of aliases, and a list of IP addresses, |
| for a host. The host argument is a string giving a host name or IP number. |
| """ |
| return _Resolve(host, [AF_INET]) |
| |
| |
| def gethostbyaddr(addr): |
| |
| raise SocketApiNotImplementedError() |
| |
| |
| def gethostname(): |
| """gethostname() -> string |
| |
| Return the current host name. |
| """ |
| return os.environ.get('HTTP_HOST', 'www.appspot.com') |
| |
| |
| def getprotobyname(protocolname): |
| raise SocketApiNotImplementedError() |
| |
| |
| def getservbyname(servicename, protocolname=None): |
| """getservbyname(servicename[, protocolname]) -> integer |
| |
| Return a port number from a service name and protocol name. |
| The optional protocol name, if given, should be 'tcp' or 'udp', |
| otherwise any protocol will match. |
| """ |
| return _ResolveService(servicename, protocolname)[1] |
| |
| |
| def getservbyport(portnumber, protocolname=0): |
| raise SocketApiNotImplementedError() |
| |
| |
| |
| |
| def getaddrinfo(host, service, family=AF_UNSPEC, socktype=0, proto=0, flags=0): |
| """getaddrinfo(host, port [, family, socktype, proto, flags]) |
| -> list of (family, socktype, proto, canonname, sockaddr) |
| |
| Resolve host and port into addrinfo struct. |
| """ |
| if isinstance(host, unicode): |
| host = host.encode('idna') |
| if host == '*': |
| host = '' |
| if service == '*': |
| service = '' |
| if not host and not service: |
| raise gaierror(EAI_NONAME, 'nodename nor servname provided, or not known') |
| |
| families = [f for f in _ADDRESS_FAMILY_MAP.keys() |
| if family in (AF_UNSPEC, f)] |
| if not families: |
| raise gaierror(EAI_FAMILY, 'ai_family not supported') |
| |
| sock_proto = [sp for sp in _SOCK_PROTO_MAP.keys() |
| if socktype in (0, sp[0]) and proto in (0, sp[1])] |
| if not sock_proto: |
| raise gaierror(EAI_BADHINTS, 'Bad hints') |
| |
| canon = '' |
| sock_proto_port = [] |
| family_addresses = [] |
| |
| |
| if host: |
| canon, _, addresses = _Resolve( |
| host, families, |
| use_dns=~(flags & AI_NUMERICHOST), |
| canonical=(flags & AI_CANONNAME)) |
| family_addresses = [(f, a) |
| for f in families |
| for a in addresses if _IsAddr(f, a)] |
| else: |
| if flags & AI_PASSIVE: |
| canon = 'anyaddr' |
| if AF_INET6 in families: |
| family_addresses.append((AF_INET6, '::')) |
| if AF_INET in families: |
| family_addresses.append((AF_INET, '0.0.0.0')) |
| else: |
| canon = 'localhost' |
| if AF_INET6 in families: |
| family_addresses.append((AF_INET6, '::1')) |
| if AF_INET in families: |
| family_addresses.append((AF_INET, '127.0.0.1')) |
| |
| |
| if service: |
| sock_proto_port = [ |
| sp + (_ResolveService(service, _SOCK_PROTO_MAP[sp], |
| flags & AI_NUMERICSERV)[1],) |
| for sp in sock_proto] |
| else: |
| sock_proto_port = [sp + (0,) for sp in sock_proto] |
| |
| return [(fa[0], spp[0], spp[1], canon, (fa[1], spp[2])) |
| for fa in family_addresses |
| for spp in sock_proto_port] |
| |
| |
| def getnameinfo(): |
| |
| raise SocketApiNotImplementedError() |
| |
| |
| def getdefaulttimeout(): |
| """getdefaulttimeout() -> timeout |
| |
| Returns the default timeout in floating seconds for new socket objects. |
| A value of None indicates that new socket objects have no timeout. |
| When the socket module is first imported, the default is None. |
| """ |
| |
| if _GLOBAL_TIMEOUT_VALUE < 0.0: |
| return None |
| return _GLOBAL_TIMEOUT_VALUE |
| |
| |
| |
| |
| def setdefaulttimeout(timeout): |
| """setdefaulttimeout(timeout) |
| |
| Set the default timeout in floating seconds for new socket objects. |
| A value of None indicates that new socket objects have no timeout. |
| When the socket module is first imported, the default is None. |
| """ |
| |
| if timeout is None: |
| timeout = -1.0 |
| else: |
| try: |
| timeout = 0.0 + timeout |
| except TypeError: |
| raise TypeError('a float is required') |
| if timeout < 0.0: |
| raise ValueError('Timeout value out of range') |
| |
| |
| global _GLOBAL_TIMEOUT_VALUE |
| _GLOBAL_TIMEOUT_VALUE = timeout |
| |
| |
| def _GetSocket(value): |
| if isinstance(value, (int, long)): |
| fileno = value |
| else: |
| try: |
| fileno = value.fileno() |
| except AttributeError: |
| raise TypeError('argument must be an int, or have a fileno() method.') |
| try: |
| return _GLOBAL_SOCKET_MAP[fileno] |
| except KeyError: |
| raise ValueError('select only supported on socket objects.') |
| |
| |
| |
| |
| |
| |
| def select(rlist, wlist, xlist, timeout=None): |
| """select(rlist, wlist, xlist[, timeout]) -> (rlist, wlist, xlist) |
| |
| Wait until one or more file descriptors are ready for some kind of I/O. |
| The first three arguments are sequences of file descriptors to be waited for: |
| rlist -- wait until ready for reading |
| wlist -- wait until ready for writing |
| xlist -- wait for an ``exceptional condition'' |
| If only one kind of condition is required, pass [] for the other lists. |
| A file descriptor is either a socket or file object, or a small integer |
| gotten from a fileno() method call on one of those. |
| |
| The optional 4th argument specifies a timeout in seconds; it may be |
| a floating point number to specify fractions of seconds. If it is absent |
| or None, the call will never time out. |
| |
| The return value is a tuple of three lists corresponding to the first three |
| arguments; each contains the subset of the corresponding file descriptors |
| that are ready. |
| """ |
| if not rlist and not wlist and not xlist: |
| if timeout: |
| time.sleep(timeout) |
| return ([], [], []) |
| |
| state_map = {} |
| rlist_out, wlist_out, xlist_out = [], [], [] |
| |
| def _SetState(request, sock, event): |
| socket_descriptor = sock._SocketDescriptor() |
| state = state_map.setdefault(socket_descriptor, { 'observed_events': 0, }) |
| |
| if ((event == POLLIN and sock._shutdown_read) or |
| (event == POLLOUT and sock._shutdown_write)): |
| state['observed_events'] |= event |
| request.set_timeout_seconds(0.0) |
| return |
| |
| poll_event = state.get('poll_event') |
| if not poll_event: |
| poll_event = request.add_events() |
| poll_event.set_socket_descriptor(socket_descriptor) |
| poll_event.set_observed_events(0) |
| state['poll_event'] = poll_event |
| poll_event.set_requested_events(poll_event.requested_events()|event) |
| |
| request = remote_socket_service_pb.PollRequest() |
| if timeout is not None: |
| request.set_timeout_seconds(timeout) |
| |
| for value in rlist: |
| _SetState(request, _GetSocket(value), POLLIN) |
| for value in wlist: |
| _SetState(request, _GetSocket(value), POLLOUT) |
| |
| if request.events_size(): |
| reply = remote_socket_service_pb.PollReply() |
| |
| try: |
| apiproxy_stub_map.MakeSyncCall('remote_socket', 'Poll', request, reply) |
| except apiproxy_errors.ApplicationError, e: |
| raise _SystemExceptionFromAppError(e) |
| |
| for event in reply.events_list(): |
| state_map[event.socket_descriptor()][ |
| 'observed_events'] |= event.observed_events() |
| |
| for value in rlist: |
| state = state_map[_GetSocket(value)._SocketDescriptor()] |
| if state['observed_events'] & POLLIN: |
| rlist_out.append(value) |
| for value in wlist: |
| state = state_map[_GetSocket(value)._SocketDescriptor()] |
| if state['observed_events'] & POLLOUT: |
| wlist_out.append(value) |
| |
| return (rlist_out, wlist_out, xlist_out) |
| |
| |
| class socket(object): |
| """socket([family[, type[, proto]]]) -> socket object |
| |
| Open a socket of the given type. The family argument specifies the |
| address family; it defaults to AF_INET. The type argument specifies |
| whether this is a stream (SOCK_STREAM, this is the default) |
| or datagram (SOCK_DGRAM) socket. The protocol argument defaults to 0, |
| specifying the default protocol. Keyword arguments are accepted. |
| |
| A socket object represents one endpoint of a network connection. |
| """ |
| |
| def __del__(self): |
| if not self._serialized: |
| self.close() |
| |
| def __getstate__(self): |
| self._serialized = True |
| return self.__dict__ |
| |
| |
| |
| def __init__(self, family=AF_INET, type=SOCK_STREAM, proto=0, _create=False): |
| if family not in (AF_INET, AF_INET6): |
| raise error(errno.EAFNOSUPPORT, os.strerror(errno.EAFNOSUPPORT)) |
| |
| if type not in (SOCK_STREAM, SOCK_DGRAM): |
| raise error(errno.EPROTONOSUPPORT, os.strerror(errno.EPROTONOSUPPORT)) |
| |
| if proto: |
| if ((proto not in (IPPROTO_TCP, IPPROTO_UDP)) or |
| (proto == IPPROTO_TCP and type != SOCK_STREAM) or |
| (proto == IPPROTO_UDP and type != SOCK_DGRAM)): |
| raise error(errno.EPROTONOSUPPORT, os.strerror(errno.EPROTONOSUPPORT)) |
| |
| self.family = family |
| self.type = type |
| self.proto = proto |
| self._created = False |
| self._fileno = None |
| self._serialized = False |
| self.settimeout(getdefaulttimeout()) |
| self._Clear() |
| |
| if _create: |
| self._CreateSocket() |
| |
| def _Clear(self): |
| self._socket_descriptor = None |
| self._bound = False |
| self._listen = False |
| self._connected = False |
| self._connect_in_progress = False |
| self._shutdown_read = False |
| self._shutdown_write = False |
| self._setsockopt = [] |
| self._stream_offset = 0 |
| |
| def _CreateSocket(self, address=None, bind_address=None, |
| address_hostname_hint=None): |
| assert not self._created |
| self._created = True |
| |
| request = remote_socket_service_pb.CreateSocketRequest() |
| |
| if self.family == AF_INET: |
| request.set_family(remote_socket_service_pb.CreateSocketRequest.IPv4) |
| elif self.family == AF_INET6: |
| request.set_family(remote_socket_service_pb.CreateSocketRequest.IPv6) |
| |
| if self.type == SOCK_STREAM: |
| request.set_protocol(remote_socket_service_pb.CreateSocketRequest.TCP) |
| elif self.type == SOCK_DGRAM: |
| request.set_protocol(remote_socket_service_pb.CreateSocketRequest.UDP) |
| |
| if address: |
| assert self.gettimeout() is None, ( |
| 'Non-blocking connect not supported by CreateSocket') |
| self._SetProtoFromAddr(request.mutable_remote_ip(), address, |
| address_hostname_hint) |
| |
| if bind_address: |
| self._SetProtoFromAddr(request.mutable_proxy_external_ip(), bind_address) |
| |
| for level, option, value in self._setsockopt: |
| o = request.add_socket_options() |
| o.set_level(level) |
| o.set_option(option) |
| if isinstance(value, (int, long)): |
| o.set_value(struct.pack('=L', value)) |
| else: |
| o.set_value(value) |
| self._setsockopt = [] |
| |
| reply = remote_socket_service_pb.CreateSocketReply() |
| |
| try: |
| apiproxy_stub_map.MakeSyncCall( |
| 'remote_socket', 'CreateSocket', request, reply) |
| except apiproxy_errors.ApplicationError, e: |
| raise _SystemExceptionFromAppError(e) |
| |
| self._socket_descriptor = reply.socket_descriptor() |
| if bind_address: |
| self._bound = True |
| if address: |
| self._bound = True |
| self._connected = True |
| |
| def _GetPackedAddr(self, addr): |
| if addr == '<broadcast>': |
| if self.family == AF_INET6: |
| return '\xff' * 16 |
| else: |
| return '\xff' * 4 |
| for res in getaddrinfo(addr, '0', |
| self.family, self.type, self.proto, |
| AI_NUMERICSERV|AI_PASSIVE): |
| return inet_pton(self.family, res[4][0]) |
| |
| def _SetProtoFromAddr(self, proto, address, hostname_hint=None): |
| address, port = address |
| proto.set_packed_address(self._GetPackedAddr(address)) |
| proto.set_port(port) |
| proto.set_hostname_hint(hostname_hint or address) |
| |
| def fileno(self): |
| """fileno() -> integer |
| |
| Return the integer file descriptor of the socket. |
| """ |
| global _GLOBAL_SOCKET_MAP |
| global _GLOBAL_SOCKET_NEXT_FILENO |
| if self._fileno is None: |
| self._fileno = _GLOBAL_SOCKET_NEXT_FILENO |
| _GLOBAL_SOCKET_NEXT_FILENO += 1 |
| _GLOBAL_SOCKET_MAP[self._fileno] = self |
| assert _GLOBAL_SOCKET_MAP.get(self._fileno) == self, ( |
| "fileno mismatch in _GLOBAL_SOCKET_MAP") |
| return self._fileno |
| |
| def bind(self, address): |
| """bind(address) |
| |
| Bind the socket to a local address. For IP sockets, the address is a |
| pair (host, port); the host must refer to the local host. For raw packet |
| sockets the address is a tuple (ifname, proto [,pkttype [,hatype]]) |
| """ |
| if not self._created: |
| self._CreateSocket(bind_address=address) |
| return |
| if not self._socket_descriptor: |
| raise error(errno.EBADF, os.strerror(errno.EBADF)) |
| if self._bound: |
| raise error(errno.EINVAL, os.strerror(errno.EINVAL)) |
| |
| request = remote_socket_service_pb.BindRequest() |
| request.set_socket_descriptor(self._socket_descriptor) |
| self._SetProtoFromAddr(request.mutable_proxy_external_ip(), address) |
| |
| reply = remote_socket_service_pb.BindReply() |
| |
| try: |
| apiproxy_stub_map.MakeSyncCall('remote_socket', 'Bind', request, reply) |
| except apiproxy_errors.ApplicationError, e: |
| raise _SystemExceptionFromAppError(e) |
| |
| def listen(self, backlog): |
| """listen(backlog) |
| |
| Enable a server to accept connections. The backlog argument must be at |
| least 1; it specifies the number of unaccepted connection that the system |
| will allow before refusing new connections. |
| """ |
| if not self._created: |
| self._CreateSocket(bind_address=('', 0)) |
| if not self._socket_descriptor: |
| raise error(errno.EBADF, os.strerror(errno.EBADF)) |
| if self._connected: |
| raise error(errno.EINVAL, os.strerror(errno.EINVAL)) |
| if self.type != SOCK_STREAM: |
| raise error(errno.EOPNOTSUPP, os.strerror(errno.EOPNOTSUPP)) |
| self._bound = True |
| self._listen = True |
| |
| request = remote_socket_service_pb.ListenRequest() |
| request.set_socket_descriptor(self._socket_descriptor) |
| request.set_backlog(backlog) |
| |
| reply = remote_socket_service_pb.ListenReply() |
| |
| try: |
| apiproxy_stub_map.MakeSyncCall('remote_socket', 'Listen', request, reply) |
| except apiproxy_errors.ApplicationError, e: |
| raise _SystemExceptionFromAppError(e) |
| |
| def accept(self): |
| """accept() -> (socket object, address info) |
| |
| Wait for an incoming connection. Return a new socket representing the |
| connection, and the address of the client. For IP sockets, the address |
| info is a pair (hostaddr, port). |
| """ |
| if not self._created: |
| self._CreateSocket() |
| if not self._socket_descriptor: |
| raise error(errno.EBADF, os.strerror(errno.EBADF)) |
| if not self._listen: |
| raise error(errno.EINVAL, os.strerror(errno.EINVAL)) |
| |
| request = remote_socket_service_pb.AcceptRequest() |
| request.set_socket_descriptor(self._socket_descriptor) |
| if self.gettimeout() is not None: |
| request.set_timeout_seconds(self.gettimeout()) |
| |
| reply = remote_socket_service_pb.AcceptReply() |
| |
| try: |
| apiproxy_stub_map.MakeSyncCall('remote_socket', 'Accept', request, reply) |
| except apiproxy_errors.ApplicationError, e: |
| raise _SystemExceptionFromAppError(e) |
| |
| ret = socket(self.family, self.type, self.proto) |
| ret._socket_descriptor = reply.new_socket_descriptor() |
| ret._created = True |
| ret._bound = True |
| ret._connected = True |
| return ret |
| |
| |
| |
| |
| def connect(self, address, _hostname_hint=None): |
| """connect(address) |
| |
| Connect the socket to a remote address. For IP sockets, the address |
| is a pair (host, port). |
| """ |
| if not self._created: |
| if self.gettimeout() is None: |
| self._CreateSocket(address=address, |
| address_hostname_hint=_hostname_hint) |
| return |
| else: |
| |
| |
| |
| |
| self._CreateSocket() |
| if not self._socket_descriptor: |
| raise error(errno.EBADF, os.strerror(errno.EBADF)) |
| if self._connected: |
| raise error(errno.EISCONN, os.strerror(errno.EISCONN)) |
| |
| request = remote_socket_service_pb.ConnectRequest() |
| request.set_socket_descriptor(self._socket_descriptor) |
| self._SetProtoFromAddr(request.mutable_remote_ip(), address, _hostname_hint) |
| if self.gettimeout() is not None: |
| request.set_timeout_seconds(self.gettimeout()) |
| |
| reply = remote_socket_service_pb.ConnectReply() |
| |
| try: |
| apiproxy_stub_map.MakeSyncCall('remote_socket', 'Connect', request, reply) |
| except apiproxy_errors.ApplicationError, e: |
| translated_e = _SystemExceptionFromAppError(e) |
| if translated_e.errno == errno.EISCONN: |
| self._bound = True |
| self._connected = True |
| elif translated_e.errno == errno.EINPROGRESS: |
| self._connect_in_progress = True |
| raise translated_e |
| |
| self._bound = True |
| self._connected = True |
| |
| def connect_ex(self, address): |
| """connect_ex(address) -> errno |
| |
| This is like connect(address), but returns an error code (the errno value) |
| instead of raising an exception when an error occurs. |
| """ |
| try: |
| self.connect(address) |
| except error, e: |
| return e.errno |
| return 0 |
| |
| def getpeername(self): |
| """getpeername() -> address info |
| |
| Return the address of the remote endpoint. For IP sockets, the address |
| info is a pair (hostaddr, port). |
| """ |
| if not self._created: |
| self._CreateSocket() |
| if not self._socket_descriptor: |
| raise error(errno.EBADF, os.strerror(errno.EBADF)) |
| if not (self._connected or self._connect_in_progress): |
| raise error(errno.ENOTCONN, os.strerror(errno.ENOTCONN)) |
| |
| request = remote_socket_service_pb.GetPeerNameRequest() |
| request.set_socket_descriptor(self._socket_descriptor) |
| |
| reply = remote_socket_service_pb.GetPeerNameReply() |
| |
| try: |
| apiproxy_stub_map.MakeSyncCall( |
| 'remote_socket', 'GetPeerName', request, reply) |
| except apiproxy_errors.ApplicationError, e: |
| raise _SystemExceptionFromAppError(e) |
| |
| if self._connect_in_progress: |
| self._connect_in_progress = False |
| self._connected = True |
| |
| return ( |
| inet_ntop(self.family, reply.peer_ip().packed_address()), |
| reply.peer_ip().port()) |
| |
| def getsockname(self): |
| """getsockname() -> address info |
| |
| Return the address of the local endpoint. For IP sockets, the address |
| info is a pair (hostaddr, port). |
| """ |
| if not self._created: |
| self._CreateSocket() |
| if not self._socket_descriptor: |
| raise error(errno.EBADF, os.strerror(errno.EBADF)) |
| |
| request = remote_socket_service_pb.GetSocketNameRequest() |
| request.set_socket_descriptor(self._socket_descriptor) |
| |
| reply = remote_socket_service_pb.GetSocketNameReply() |
| |
| try: |
| apiproxy_stub_map.MakeSyncCall( |
| 'remote_socket', 'GetSocketName', request, reply) |
| except apiproxy_errors.ApplicationError, e: |
| raise _SystemExceptionFromAppError(e) |
| |
| return ( |
| inet_ntop(self.family, reply.proxy_external_ip().packed_address()), |
| reply.proxy_external_ip().port()) |
| |
| def recv(self, buffersize, flags=0): |
| """recv(buffersize[, flags]) -> data |
| |
| Receive up to buffersize bytes from the socket. For the optional flags |
| argument, see the Unix manual. When no data is available, block until |
| at least one byte is available or until the remote end is closed. When |
| the remote end is closed and all data is read, return the empty string. |
| """ |
| return self.recvfrom(buffersize, flags)[0] |
| |
| def recv_into(self, buf, nbytes=0, flags=0): |
| """recv_into(buffer, [nbytes[, flags]]) -> nbytes_read |
| |
| A version of recv() that stores its data into a buffer rather than |
| creating a new string. Receive up to buffersize bytes from the socket. |
| If buffersize is not specified (or 0), receive up to the size available |
| in the given buffer. |
| |
| See recv() for documentation about the flags. |
| """ |
| raise SocketApiNotImplementedError() |
| |
| def recvfrom(self, buffersize, flags=0): |
| """recvfrom(buffersize[, flags]) -> (data, address info) |
| |
| Like recv(buffersize, flags) but also return the sender's address info. |
| """ |
| if not self._created: |
| self._CreateSocket() |
| if not self._socket_descriptor: |
| raise error(errno.EBADF, os.strerror(errno.EBADF)) |
| |
| request = remote_socket_service_pb.ReceiveRequest() |
| request.set_socket_descriptor(self._socket_descriptor) |
| request.set_data_size(buffersize) |
| request.set_flags(flags) |
| if self.type == SOCK_STREAM: |
| if not (self._connected or self._connect_in_progress): |
| raise error(errno.ENOTCONN, os.strerror(errno.ENOTCONN)) |
| if self._shutdown_read: |
| request.set_timeout_seconds(0.0) |
| elif self.gettimeout() is not None: |
| request.set_timeout_seconds(self.gettimeout()) |
| |
| reply = remote_socket_service_pb.ReceiveReply() |
| |
| try: |
| apiproxy_stub_map.MakeSyncCall('remote_socket', 'Receive', request, reply) |
| except apiproxy_errors.ApplicationError, e: |
| e = _SystemExceptionFromAppError(e) |
| if not self._shutdown_read or e.errno != errno.EAGAIN: |
| raise e |
| |
| if self._connect_in_progress: |
| self._connect_in_progress = False |
| self._connected = True |
| |
| address = None |
| if reply.has_received_from(): |
| address = ( |
| inet_ntop(self.family, reply.received_from().packed_address()), |
| reply.received_from().port()) |
| |
| return reply.data(), address |
| |
| |
| |
| def recvfrom_into(self, buffer, nbytes=0, flags=0): |
| """recvfrom_into(buffer[, nbytes[, flags]]) -> (nbytes, address info) |
| |
| Like recv_into(buffer[, nbytes[, flags]]) but also return the |
| sender's address info. |
| """ |
| |
| raise SocketApiNotImplementedError() |
| |
| def send(self, data, flags=0): |
| """send(data[, flags]) -> count |
| |
| Send a data string to the socket. For the optional flags |
| argument, see the Unix manual. Return the number of bytes |
| sent; this may be less than len(data) if the network is busy. |
| """ |
| return self.sendto(data, flags, None) |
| |
| def sendall(self, data, flags=0): |
| """sendall(data[, flags]) |
| |
| Send a data string to the socket. For the optional flags |
| argument, see the Unix manual. This calls send() repeatedly |
| until all data is sent. If an error occurs, it's impossible |
| to tell how much data has been sent. |
| """ |
| offset = 0 |
| while offset < len(data): |
| offset += self.sendto(data[offset:], flags, None) |
| |
| def sendto(self, data, *args): |
| """sendto(data[, flags], address) -> count |
| |
| Like send(data, flags) but allows specifying the destination address. |
| For IP sockets, the address is a pair (hostaddr, port). |
| """ |
| if len(args) == 1: |
| flags, address = 0, args[0] |
| elif len(args) == 2: |
| flags, address = args |
| |
| if not self._created: |
| self._CreateSocket() |
| if not self._socket_descriptor: |
| raise error(errno.EBADF, os.strerror(errno.EBADF)) |
| if self._shutdown_write: |
| raise error(errno.EPIPE, os.strerror(errno.EPIPE)) |
| |
| request = remote_socket_service_pb.SendRequest() |
| request.set_socket_descriptor(self._socket_descriptor) |
| |
| if len(data) > 512*1024: |
| request.set_data(data[:512*1024]) |
| else: |
| request.set_data(data) |
| request.set_flags(flags) |
| request.set_stream_offset(self._stream_offset) |
| |
| if address: |
| if self._connected: |
| raise error(errno.EISCONN, os.strerror(errno.EISCONN)) |
| if self.type != SOCK_DGRAM: |
| raise error(errno.ENOTCONN, os.strerror(errno.ENOTCONN)) |
| self._SetProtoFromAddr(request.mutable_send_to(), address) |
| else: |
| if not (self._connected or self._connect_in_progress): |
| raise error(errno.ENOTCONN, os.strerror(errno.ENOTCONN)) |
| |
| if self.gettimeout() is not None: |
| request.set_timeout_seconds(self.gettimeout()) |
| |
| reply = remote_socket_service_pb.SendReply() |
| |
| try: |
| apiproxy_stub_map.MakeSyncCall('remote_socket', 'Send', request, reply) |
| except apiproxy_errors.ApplicationError, e: |
| raise _SystemExceptionFromAppError(e) |
| |
| if self._connect_in_progress: |
| self._connect_in_progress = False |
| self._connected = True |
| |
| nbytes = reply.data_sent() |
| assert nbytes >= 0 |
| if self.type == SOCK_STREAM: |
| self._stream_offset += nbytes |
| return nbytes |
| |
| def setblocking(self, block): |
| """setblocking(flag) |
| |
| Set the socket to blocking (flag is true) or non-blocking (false). |
| setblocking(True) is equivalent to settimeout(None); |
| setblocking(False) is equivalent to settimeout(0.0). |
| """ |
| if block: |
| self._timeout = -1.0 |
| else: |
| self._timeout = 0.0 |
| |
| def settimeout(self, timeout): |
| """settimeout(timeout) |
| |
| Set a timeout on socket operations. 'timeout' can be a float, |
| giving in seconds, or None. Setting a timeout of None disables |
| the timeout feature and is equivalent to setblocking(1). |
| Setting a timeout of zero is the same as setblocking(0). |
| """ |
| if timeout is None: |
| self._timeout = -1.0 |
| else: |
| try: |
| self._timeout = 0.0 + timeout |
| except: |
| raise TypeError('a float is required') |
| if self._timeout < 0.0: |
| raise ValueError('Timeout value out of range') |
| |
| def gettimeout(self): |
| """gettimeout() -> timeout |
| |
| Returns the timeout in floating seconds associated with socket |
| operations. A timeout of None indicates that timeouts on socket |
| operations are disabled. |
| """ |
| if self._timeout < 0.0: |
| return None |
| return self._timeout |
| |
| def setsockopt(self, level, option, value): |
| """setsockopt(level, option, value) |
| |
| Set a socket option. See the Unix manual for level and option. |
| The value argument can either be an integer or a string. |
| """ |
| |
| |
| |
| if not self._created: |
| self._setsockopt.append((level, option, value)) |
| self._CreateSocket() |
| return |
| if not self._socket_descriptor: |
| raise error(errno.EBADF, os.strerror(errno.EBADF)) |
| |
| request = remote_socket_service_pb.SetSocketOptionsRequest() |
| request.set_socket_descriptor(self._socket_descriptor) |
| |
| o = request.add_options() |
| o.set_level(level) |
| o.set_option(option) |
| if isinstance(value, (int, long)): |
| o.set_value(struct.pack('=L', value)) |
| else: |
| o.set_value(value) |
| |
| reply = remote_socket_service_pb.SetSocketOptionsReply() |
| |
| try: |
| apiproxy_stub_map.MakeSyncCall( |
| 'remote_socket', 'SetSocketOptions', request, reply) |
| except apiproxy_errors.ApplicationError, e: |
| raise _SystemExceptionFromAppError(e) |
| |
| def getsockopt(self, level, option, buffersize=0): |
| """getsockopt(level, option[, buffersize]) -> value |
| |
| Get a socket option. See the Unix manual for level and option. |
| If a nonzero buffersize argument is given, the return value is a |
| string of that length; otherwise it is an integer. |
| """ |
| if not self._created: |
| self._CreateSocket() |
| if not self._socket_descriptor: |
| raise error(errno.EBADF, os.strerror(errno.EBADF)) |
| |
| request = remote_socket_service_pb.GetSocketOptionsRequest() |
| request.set_socket_descriptor(self._socket_descriptor) |
| o = request.add_options() |
| o.set_level(level) |
| o.set_option(option) |
| o.set_value('') |
| |
| reply = remote_socket_service_pb.GetSocketOptionsReply() |
| |
| try: |
| apiproxy_stub_map.MakeSyncCall( |
| 'remote_socket', 'GetSocketOptions', request, reply) |
| except apiproxy_errors.ApplicationError, e: |
| raise _SystemExceptionFromAppError(e) |
| |
| if not buffersize: |
| return struct.unpack('=L', reply.options(0).value())[0] |
| else: |
| return reply.options(0).value()[:buffersize] |
| |
| def shutdown(self, flag): |
| """shutdown(flag) |
| |
| Shut down the reading side of the socket (flag == SHUT_RD), the writing side |
| of the socket (flag == SHUT_WR), or both ends (flag == SHUT_RDWR). |
| """ |
| if not flag in (SHUT_RD, SHUT_WR, SHUT_RDWR): |
| raise error(errno.EINVAL, os.strerror(errno.EINVAL)) |
| if not self._created: |
| self._CreateSocket() |
| if not self._socket_descriptor: |
| raise error(errno.EBADF, os.strerror(errno.EBADF)) |
| if (not self._connected or |
| (self._shutdown_read and flag in (SHUT_RD, SHUT_RDWR)) or |
| (self._shutdown_write and flag in (SHUT_RD, SHUT_RDWR))): |
| raise error(errno.ENOTCONN, os.strerror(errno.ENOTCONN)) |
| |
| request = remote_socket_service_pb.ShutDownRequest() |
| request.set_socket_descriptor(self._socket_descriptor) |
| request.set_how(flag) |
| request.set_send_offset(self._stream_offset) |
| |
| reply = remote_socket_service_pb.ShutDownReply() |
| |
| try: |
| apiproxy_stub_map.MakeSyncCall( |
| 'remote_socket', 'ShutDown', request, reply) |
| except apiproxy_errors.ApplicationError, e: |
| raise _SystemExceptionFromAppError(e) |
| |
| if flag == SHUT_RD or flag == SHUT_RDWR: |
| self._shutdown_read = True |
| if flag == SHUT_WR or flag == SHUT_RDWR: |
| self._shutdown_write = True |
| |
| def close(self): |
| """close() |
| |
| Close the socket. It cannot be used after this call. |
| """ |
| self._created = True |
| if not self._socket_descriptor: |
| return |
| |
| request = remote_socket_service_pb.CloseRequest() |
| request.set_socket_descriptor(self._socket_descriptor) |
| |
| reply = remote_socket_service_pb.CloseReply() |
| |
| try: |
| apiproxy_stub_map.MakeSyncCall('remote_socket', 'Close', request, reply) |
| except apiproxy_errors.ApplicationError, e: |
| raise _SystemExceptionFromAppError(e) |
| |
| self._Clear() |
| |
| def _SocketDescriptor(self): |
| if not self._created: |
| self._CreateSocket() |
| if not self._socket_descriptor: |
| raise error(errno.EBADF, os.strerror(errno.EBADF)) |
| return self._socket_descriptor |