diff options
Diffstat (limited to 'net/common.py')
-rw-r--r-- | net/common.py | 106 |
1 files changed, 106 insertions, 0 deletions
diff --git a/net/common.py b/net/common.py new file mode 100644 index 0000000..a589b44 --- /dev/null +++ b/net/common.py @@ -0,0 +1,106 @@ +import time +import socket +import asyncore +from logging import DEBUG +from construct import Struct, ULInt16, String, Enum, Byte +from dispatcher import dispatch +from loggers import netlog + + +def StringZ(name, length, **kw): + kw['padchar'] = "\x00" + kw['paddir'] = "right" + return String(name, length, **kw) + + +def Gender(name): + return Enum(Byte(name), BOY=1, GIRL=0, UNSPECIFIED=2, OTHER=3) + + +class SocketWrapper(asyncore.dispatcher_with_send): + """ + socket wrapper with file-like read() and write() methods + """ + def __init__(self, host=None, port=0, + protodef={}, onerror=None, sock=None): + asyncore.dispatcher_with_send.__init__(self, sock) + self.read_buffer = '' + if sock is None: + self.create_socket(socket.AF_INET, socket.SOCK_STREAM) + self.socket.setblocking(1) + self.socket.settimeout(0.7) + + self.protodef = protodef + self.raw = False + self.onerror = onerror + if protodef == {}: + netlog.warning("protodef is empty") + if host is not None: + self.connect((host, port)) + + def handle_read(self): + try: + self.read_buffer += self.recv(2) + except socket.error: + return + while len(self.read_buffer) > 0: + dispatch(self, self.protodef) + + def handle_error(self): + if self.onerror is not None: + self.onerror() + else: + raise + + def read(self, n=-1): + data = '' + if n < 0: + data = self.read_buffer + self.read_buffer = '' + else: + tries = 0 + while len(self.read_buffer) < n: + try: + self.read_buffer += self.recv(n - len(self.read_buffer)) + except socket.error as e: + tries += 1 + if tries < 10: + netlog.error("socket.error %s", e) + time.sleep(0.2) + else: + raise + + data = self.read_buffer[:n] + self.read_buffer = self.read_buffer[n:] + + if netlog.isEnabledFor(DEBUG): + netlog.debug("read " + + ":".join("{:02x}".format(ord(c)) for c in data)) + return data + + def write(self, data): + if netlog.isEnabledFor(DEBUG): + netlog.debug("write " + + ":".join("{:02x}".format(ord(c)) for c in data)) + if self.raw: + self.socket.sendall(data) + else: + self.send(data) + + +def send_packet(srv, opcode_, *fields): + class C: + opcode = opcode_ + + ms = [ULInt16("opcode")] + + for macro, value in fields: + setattr(C, macro.name, value) + ms.append(macro) + + d = Struct("packet", *ms) + d.build_stream(C, srv) + + +def distance(x1, y1, x2, y2): + return max(abs(x2 - x1), abs(y2 - y1)) |