summaryrefslogtreecommitdiff
path: root/net/common.py
diff options
context:
space:
mode:
Diffstat (limited to 'net/common.py')
-rw-r--r--net/common.py106
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))