From d2c150c11ed9522469ecc5fca44b42ef0d81b154 Mon Sep 17 00:00:00 2001 From: Teddy Date: Sun, 25 Aug 2013 09:52:41 +0800 Subject: ptp revised --- server/piztor/exc.py | 5 ++++- server/piztor/model.py | 1 + server/ptp.rst | 24 ++++++++++++------------ 3 files changed, 17 insertions(+), 13 deletions(-) (limited to 'server') diff --git a/server/piztor/exc.py b/server/piztor/exc.py index 5daf420..2c53dbf 100644 --- a/server/piztor/exc.py +++ b/server/piztor/exc.py @@ -1,6 +1,9 @@ class PiztorError(Exception): pass +class DBCurruptedError(PiztorError): + pass + class ConnectionError(PiztorError): pass @@ -10,5 +13,5 @@ class ReqReadError(ConnectionError): class BadReqError(ConnectionError): pass -class InvalidTokenError(ConnectionError): +class BadTokenError(ConnectionError): pass diff --git a/server/piztor/model.py b/server/piztor/model.py index d869c32..70ca431 100644 --- a/server/piztor/model.py +++ b/server/piztor/model.py @@ -3,6 +3,7 @@ from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import relationship, backref Base = declarative_base() + _SALT_LEN = 16 _TOKEN_LEN = 16 diff --git a/server/ptp.rst b/server/ptp.rst index 4092399..e835bd7 100644 --- a/server/ptp.rst +++ b/server/ptp.rst @@ -33,9 +33,9 @@ Piztor Transmission Protocol v0.1 :: - +--1b---+-----4b-----+---1b----+ - | 0x00 | USER_TOKEN | STATUS | - +-uchar-+-----int----+--uchar--+ + +--1b---+---1b---+---4b----+----16b-----+ + | 0x00 | STATUS | USER_ID | USER_TOKEN | + +-uchar-+--uchar-+---int---+----raw-----+ ``STATUS`` : @@ -48,9 +48,9 @@ Piztor Transmission Protocol v0.1 :: - +--1b---+------4b------+-----8b-----+------8b-----+ - | 0x02 | SENDER_TOKEN | LATITUDE | LONGITUDE | - +-uchar-+------int-----+---double---+---double----+ + +--1b---+-----16b------+-----8b-----+------8b-----+ + | 0x02 | USER_TOKEN | LATITUDE | LONGITUDE | + +-uchar-+------raw-----+---double---+---double----+ - Response @@ -71,17 +71,17 @@ Piztor Transmission Protocol v0.1 :: - +--1b---+-----4b-------+------4b-----+ - | 0x03 | SENDER_TOKEN | GROUP_ID | - +-uchar-+-----int------+-----int-----+ + +--1b---+-----16b------+------4b-----+ + | 0x03 | USER_TOKEN | GROUP_ID | + +-uchar-+-----raw------+-----int-----+ - Response :: - +--1b---+-----4b----+------20b-------+-----+ - | 0x03 | ENTRY_CNT | LOCATION_ENTRY | ... | - +-uchar-+---int-----+----------------+-----+ + +--1b---+---1b---+-----4b----+------20b-------+-----+ + | 0x03 | STATUS | ENTRY_CNT | LOCATION_ENTRY | ... | + +-uchar-+-uchar--+----int----+----------------+-----+ ``LOCATION_ENTRY`` : -- cgit v1.2.3 From 3943a3743bbba32bc7c04bf1c3e85eb775790e2a Mon Sep 17 00:00:00 2001 From: Teddy Date: Sun, 25 Aug 2013 10:10:44 +0800 Subject: ptp v0.2 --- server/ptp.rst | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'server') diff --git a/server/ptp.rst b/server/ptp.rst index e835bd7..bbbcf7a 100644 --- a/server/ptp.rst +++ b/server/ptp.rst @@ -1,4 +1,4 @@ -Piztor Transmission Protocol v0.1 +Piztor Transmission Protocol v0.2 --------------------------------- - General @@ -7,17 +7,19 @@ Piztor Transmission Protocol v0.1 :: - +---1b---+-------?b--------+ - | OPT ID | SPECIFIC DATA | - +-uchar--+-----------------+ + +---4b---+---1b---+-------?b--------+ + | LENGTH | OPT ID | SPECIFIC DATA | + +--int---+-uchar--+-----------------+ - Response :: - +---1b---+------?b---------+ - | OPT ID | SPECIFIC DATA | - +-uchar--+-----------------+ + +---4b---+---1b---+------?b---------+ + | LENGTH | OPT ID | SPECIFIC DATA | + +--int---+-uchar--+-----------------+ + + Notice that in following sections, ``LENGTH`` part is left out for clarity. - Authentication -- cgit v1.2.3 From a53f4d21238d2bccd58a22d7485e54f495dbd55d Mon Sep 17 00:00:00 2001 From: Teddy Date: Sun, 25 Aug 2013 10:30:55 +0800 Subject: ptp: add TODO --- server/ptp.rst | 1 + 1 file changed, 1 insertion(+) (limited to 'server') diff --git a/server/ptp.rst b/server/ptp.rst index bbbcf7a..8aef2b7 100644 --- a/server/ptp.rst +++ b/server/ptp.rst @@ -20,6 +20,7 @@ Piztor Transmission Protocol v0.2 +--int---+-uchar--+-----------------+ Notice that in following sections, ``LENGTH`` part is left out for clarity. + TODO: All secure requests should have username or uid provided. - Authentication -- cgit v1.2.3 From ac7633d8149a28af288ac0b850850cef9b13c151 Mon Sep 17 00:00:00 2001 From: sjtufs Date: Sun, 25 Aug 2013 15:45:55 +0800 Subject: This is alpha --- server/README.rst | 1 - server/client.py | 58 ------------ server/piztor/exc.py | 17 ---- server/piztor/import.py | 44 --------- server/piztor/model.py | 79 ---------------- server/piztor_server.py | 234 ------------------------------------------------ server/ptp.rst | 96 -------------------- server/rush.py | 14 --- 8 files changed, 543 deletions(-) delete mode 100644 server/README.rst delete mode 100644 server/client.py delete mode 100644 server/piztor/exc.py delete mode 100644 server/piztor/import.py delete mode 100644 server/piztor/model.py delete mode 100644 server/piztor_server.py delete mode 100644 server/ptp.rst delete mode 100644 server/rush.py (limited to 'server') diff --git a/server/README.rst b/server/README.rst deleted file mode 100644 index e88c745..0000000 --- a/server/README.rst +++ /dev/null @@ -1 +0,0 @@ -Here is the folder of server-side implementation diff --git a/server/client.py b/server/client.py deleted file mode 100644 index 15f4bbc..0000000 --- a/server/client.py +++ /dev/null @@ -1,58 +0,0 @@ -import socket -import sys -from struct import * -from random import random -from time import sleep - -def get_hex(data): - return "".join([hex(ord(c))[2:].zfill(2) for c in data]) - -HOST, PORT = "localhost", 9990 - -def gen_auth(username, password): - data = pack("!B", 0) - data += username - data += "\0" - data += password - return data - -def gen_update_location(token, lat, lont): - return pack("!BLdd", 2, token, lat, lont) - -def gen_request_location(token, gid): - return pack("!BLL", 3, token, gid) - -def send(data): - try: - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - sock.connect((HOST, PORT)) -# print "Client " + str(sys.argv[1]) + ": connected" - sock.sendall(data) - print get_hex(data) -# print "Client " + str(sys.argv[1]) + ": sent" -# sock.shutdown(socket.SHUT_WR) -# print "Client " + str(sys.argv[1]) + ": shutdown" - received = sock.recv(1024) - finally: - print "adf" - sock.close() - - print "Sent {}".format(get_hex(data)) - print "Received: {}".format(get_hex(data)) - return received - -#print "Client spawned:" + str(sys.argv[1]) -rec = send(gen_auth("hello", "world")) -opt, token, status = unpack("!BLB", rec) - -rec = send(gen_update_location(token, random(), random())) -opc, status = unpack("!BB", rec) - -rec = send(gen_request_location(token, 1)) -opc, length = unpack("!BL", rec[:5]) -idx = 5 -for i in xrange(length): - uid, lat, lng = unpack("!Ldd", rec[idx:idx + 20]) - print (uid, lat, lng) - idx += 20 -# sleep(60) diff --git a/server/piztor/exc.py b/server/piztor/exc.py deleted file mode 100644 index 2c53dbf..0000000 --- a/server/piztor/exc.py +++ /dev/null @@ -1,17 +0,0 @@ -class PiztorError(Exception): - pass - -class DBCurruptedError(PiztorError): - pass - -class ConnectionError(PiztorError): - pass - -class ReqReadError(ConnectionError): - pass - -class BadReqError(ConnectionError): - pass - -class BadTokenError(ConnectionError): - pass diff --git a/server/piztor/import.py b/server/piztor/import.py deleted file mode 100644 index 1521849..0000000 --- a/server/piztor/import.py +++ /dev/null @@ -1,44 +0,0 @@ -from sqlalchemy import create_engine -from sqlalchemy.orm import sessionmaker -from model import * - -path = "piztor.sqlite" - -class UserData: - def __init__(self, username, password, sex): - self.username = username - self.password = password - self.sex = sex - -def create_database(): - engine = create_engine('sqlite:///' + path, echo = True) - Base.metadata.drop_all(engine) - Base.metadata.create_all(engine) - -def import_user_data(data): - engine = create_engine('sqlite:///' + path, echo = True) - Session = sessionmaker(bind = engine) - session = Session() - for user in data: - um = UserModel(username = user.username, sex = user.sex) - um.auth = UserAuth(user.password) - um.location = LocationInfo(lat = 0, lng = 0) - session.add(um) - session.commit() - -if __name__ == '__main__': - - from sys import argv, exit - if len(argv) != 2: - print "Usage: " + argv[0] + " FILE" - exit(0) - - data = list() - with open(argv[1], 'r') as f: - while True: - line = f.readline().split() - if len(line) == 0: break - data.append(UserData(line[0], line[1], line[2])) - - create_database() - import_user_data(data) diff --git a/server/piztor/model.py b/server/piztor/model.py deleted file mode 100644 index 70ca431..0000000 --- a/server/piztor/model.py +++ /dev/null @@ -1,79 +0,0 @@ -from sqlalchemy import Column, Integer, String, Float, ForeignKey, LargeBinary, Boolean -from sqlalchemy.ext.declarative import declarative_base -from sqlalchemy.orm import relationship, backref - -Base = declarative_base() - -_SALT_LEN = 16 -_TOKEN_LEN = 16 - -class _TableName: # avoid typoes - UserModel = 'users' - LocationInfo = 'location_info' - UserAuth = 'user_auth' - -class UserModel(Base): - __tablename__ = _TableName.UserModel - - id = Column(Integer, primary_key = True) - username = Column(String) - sex = Column(Boolean) - location = None - auth = None - -class LocationInfo(Base): - __tablename__ = _TableName.LocationInfo - - uid = Column(Integer, ForeignKey('users.id'), primary_key = True) - lat = Column(Float(precesion = 64)) - lng = Column(Float(precesion = 64)) - user = relationship("UserModel", uselist = False, - backref = backref("location", uselist = False, - cascade = "all, delete-orphan")) - - # More: last_update - -from hashlib import sha256 -from os import urandom - -def _sprinkle_salt(uauth, passwd): - data = sha256(uauth.salt) - data.update(chr(0)) - data.update(passwd) - return data.digest() - -def _random_binary_string(length): - return urandom(length) - -class UserAuth(Base): - __tablename__ = _TableName.UserAuth - - uid = Column(Integer, ForeignKey('users.id'), primary_key = True) - password = Column(LargeBinary) - salt = Column(LargeBinary) - token = Column(LargeBinary) - - user = relationship("UserModel", uselist = False, - backref = backref("auth", uselist = False, - cascade = "all, delete-orphan")) - - def regen_token(self): - self.token = sha256(_random_binary_string(_TOKEN_LEN)).digest() - - def __init__(self, passwd): - self.set_password(passwd) - - def set_password(self, passwd): - self.salt = _random_binary_string(_SALT_LEN) - self.password = _sprinkle_salt(self, passwd) - self.regen_token() - - def check_password(self, passwd): - passwd = _sprinkle_salt(self, passwd) - return passwd == self.password - - def check_token(self, tk): - return self.token == tk - - def get_token(self): - return self.token diff --git a/server/piztor_server.py b/server/piztor_server.py deleted file mode 100644 index 514f95f..0000000 --- a/server/piztor_server.py +++ /dev/null @@ -1,234 +0,0 @@ -import sqlalchemy -import SocketServer, socket, select -import struct -import os - -from sqlalchemy import create_engine -from sqlalchemy import Column, Integer, String, Float -from sqlalchemy.ext.declarative import declarative_base -from sqlalchemy.orm import sessionmaker -from random import randint - -engine = create_engine('sqlite:///t.sqlite', echo = False) -Base = declarative_base() -Session = sessionmaker(bind=engine) - -def get_hex(data): - return "".join([hex(ord(c))[2:].zfill(2) for c in data]) - -class PiztorError(Exception): - def __init__(self, msg): - self.err_msg = msg - def __str__(self, msg): - return self.err_msg - -class ConnectionError(PiztorError): - pass - -class ReqReadError(ConnectionError): - def __init__(self): - super(ReqReadError, self).__init__("Error while reading request") - -class ReqInvalidError(ConnectionError): - def __init__(self): - super(ReqInvalidError, self).__init__("Invalid request") - -class TokenInvalidError(ConnectionError): - def __init__(self): - super(TokenInvalidError, self).__init__("Invalid token") - -class DataManager(object): - def __init__(self, piz_srv): - self.piz_srv = piz_srv - -class UserManager(DataManager): - - class User(Base): - __tablename__ = 'users' - id = Column(Integer, primary_key = True) - gid = Column(Integer) - username = Column(String) - password = Column(String) - token = Column(Integer) - - def get_user_by_token(self, token): - session = Session() - User = UserManager.User - entries = session.query(User).filter(User.token == token).all() - if len(entries) == 0: - raise TokenInvalidError() - return entries[0] - - def authentication_handle(self, opt_type, data): - print "Parsing User Data" - pos = -1 - for i in xrange(0, len(data)): - if data[i] == '\0': - print i - if pos != -1: - raise ReqInvalidError() - pos = i - break - if pos == -1: - raise ReqInvalidError() - username = data[0:pos] - password = data[pos + 1:] - - print "Trying to login with following info:" - print (username, password) - - session = Session() - entries = session.query(UserManager.User). \ - filter(UserManager.User.username == username).all() - if len(entries) == 0: - return struct.pack("!BLB", 0, 0, 1) - entry = entries[0] - if entry.password != password: # Auth failed - print "Login failed!" - return struct.pack("!BLB", 0, 0, 1) - else: # Succeeded - print "Logged in sucessfully!" - entry.token = randint(0, 2147483647) - session.commit() - return struct.pack("!BLB", 0, entry.token, 0) - - -class MesgManager(DataManager): - def mesg_sending_handle(self, opt_type, data): - print "Parsing Mesg Data" - try: - if len(data) < 8: - raise ReqInvalidError() - sender_token, recv_id = struct.unpack("!LL", data[:8]) - msg = data[8:] - print (sender_token, recv_id, msg) - return struct.pack("!B", 1) - except struct.error: - raise ReqInvalidError() - -class LocationManager(DataManager): - - class LocationInfo(Base): - __tablename__ = "location_info" - uid = Column(Integer, primary_key = True) - lat = Column(Float(precesion = 64)) - lng = Column(Float(precesion = 64)) - # More: last_update - - def location_update_handle(self, opt_type, data): - print "Parsing a Location Update" - try: - if len(data) < 8: - raise ReqInvalidError() - sender_token, lat, lng = struct.unpack("!Ldd", data) - print "Updating location data with following info:" - print (sender_token, lat, lng) - - user = self.piz_srv. \ - user_mgr.get_user_by_token(sender_token) - session = Session() - LInfo = LocationManager.LocationInfo - q = session.query(LInfo).filter(LInfo.uid == user.id) - entry = q.first() - entry.lat = lat - entry.lng = lng - session.commit() - print "Location update succeeded!" - return struct.pack("!BB", 2, 0) - except TokenInvalidError: - print "Location update failed!" - return struct.pack("!BB", 2, 1) - except struct.error: - raise ReqInvalidError() - - def location_request_handle(self, opt_type, data): - print "Parsing a Location Request" - try: - if len(data) != 8: - raise ReqInvalidError() - sender_token, gid = struct.unpack("!LL", data) - print "Requesting location data with following info:" - print (sender_token, gid) - session = Session() - UInfo = UserManager.User - LInfo = LocationManager.LocationInfo - user_list = session.query(UInfo).filter(UInfo.gid == gid).all() - reply = struct.pack("!BL", 3, len(user_list)) - for user in user_list: - loc = session.query(LInfo).filter(LInfo.uid == user.id).first() - reply += struct.pack("!Ldd", user.id, loc.lat, loc.lng) - print get_hex(reply) - return reply - except struct.error: - raise ReqInvalidError() - -class PiztorServer(): - - - class GenericHandler(SocketServer.StreamRequestHandler): - - def handle(self): - print self.piz_srv - sock = self.request - sock.settimeout(100) -# sock.setblocking(0) - data = "" - try: - while True: -# ready = select.select([sock], [], [], 10) -# if not ready[0]: -# raise ReqReadError() - buff = sock.recv(4096) - if len(buff) == 0: - break # terminated - else: - data += buff - sock.shutdown(socket.SHUT_RD) - - print "Got the data:" + get_hex(data) - - if len(data) < 1: - print "invalid length" - raise ReqInvalidError() - opt_id = struct.unpack("!B", data[0])[0] - print opt_id - reply = self.piz_srv.mgr_map[opt_id](opt_id, data[1:]) - sock.sendall(reply) - finally: - sock.close() - - class ForkingEchoServer(SocketServer.ForkingMixIn, SocketServer.TCPServer): - pass - - def __init__(self, host, port): - PiztorServer.GenericHandler.piz_srv = self - srv = PiztorServer.ForkingEchoServer((host, port), - PiztorServer.GenericHandler) - srv.request_queue_size = 100 -# srv.timeout = 2 - self.server = srv - - self.user_mgr = UserManager(self) - self.mesg_mgr = MesgManager(self) - self.location_mgr = LocationManager(self) - - self.mgr_map = [ self.user_mgr.authentication_handle, - self.mesg_mgr.mesg_sending_handle, - self.location_mgr.location_update_handle, - self.location_mgr.location_request_handle] - - Base.metadata.create_all(engine) - - - def run(self): - try: - self.server.serve_forever() - except KeyboardInterrupt: - print "Exiting..." - self.server.shutdown() - print "Server shutdown" - -if __name__ == "__main__": - - ps = PiztorServer("localhost", 9990) - ps.run() diff --git a/server/ptp.rst b/server/ptp.rst deleted file mode 100644 index 8aef2b7..0000000 --- a/server/ptp.rst +++ /dev/null @@ -1,96 +0,0 @@ -Piztor Transmission Protocol v0.2 ---------------------------------- - -- General - - - Request - - :: - - +---4b---+---1b---+-------?b--------+ - | LENGTH | OPT ID | SPECIFIC DATA | - +--int---+-uchar--+-----------------+ - - - Response - - :: - - +---4b---+---1b---+------?b---------+ - | LENGTH | OPT ID | SPECIFIC DATA | - +--int---+-uchar--+-----------------+ - - Notice that in following sections, ``LENGTH`` part is left out for clarity. - TODO: All secure requests should have username or uid provided. - -- Authentication - - - Request - - :: - - +--1b---+-----?b------+-----?b-----+ - | 0x00 | USERNAME | PASSWORD | - +-uchar-+-------------+------------+ - - - Response - - :: - - +--1b---+---1b---+---4b----+----16b-----+ - | 0x00 | STATUS | USER_ID | USER_TOKEN | - +-uchar-+--uchar-+---int---+----raw-----+ - - ``STATUS`` : - - - 0x00 for success - - 0x01 for failure - -- Location Update - - - Request - - :: - - +--1b---+-----16b------+-----8b-----+------8b-----+ - | 0x02 | USER_TOKEN | LATITUDE | LONGITUDE | - +-uchar-+------raw-----+---double---+---double----+ - - - Response - - :: - - +--1b---+---1b---+ - | 0x02 | STATUS | - +-uchar-+--uchar-+ - - ``STATUS`` : - - - 0x00 for success - - 0x01 for invalid token - -- Location Information - - - Request - - :: - - +--1b---+-----16b------+------4b-----+ - | 0x03 | USER_TOKEN | GROUP_ID | - +-uchar-+-----raw------+-----int-----+ - - - Response - - :: - - +--1b---+---1b---+-----4b----+------20b-------+-----+ - | 0x03 | STATUS | ENTRY_CNT | LOCATION_ENTRY | ... | - +-uchar-+-uchar--+----int----+----------------+-----+ - - ``LOCATION_ENTRY`` : - - :: - - +---4b----+----8b----+-----8b----+ - | USER_ID | LATITUDE | LONGITUDE | - +---int---+--double--+--double---+ - diff --git a/server/rush.py b/server/rush.py deleted file mode 100644 index f01804c..0000000 --- a/server/rush.py +++ /dev/null @@ -1,14 +0,0 @@ -from subprocess import Popen -procs = [] - -try: - for i in xrange(10): - p = Popen(["python", "client.py", str(i)]) - procs.append(p) - #p.wait() - print "done" - -except KeyboardInterrupt: - print "killing" - for p in procs: - p.kill() -- cgit v1.2.3 From f74999631c4f83a0c8532d6b7adb348dcd5d5205 Mon Sep 17 00:00:00 2001 From: Teddy Date: Sun, 25 Aug 2013 17:54:38 +0800 Subject: ptp v0.3 and std-compliant new server! --- server/piztor/import.py | 7 +- server/piztor/model.py | 5 +- server/piztor/prob.py | 76 ++++++++++++ server/piztor/server.py | 311 ++++++++++++++++++++++++++++++++++++++++++++++++ server/piztor_server.py | 2 +- server/ptp.rst | 51 ++++---- 6 files changed, 425 insertions(+), 27 deletions(-) create mode 100644 server/piztor/prob.py create mode 100644 server/piztor/server.py (limited to 'server') diff --git a/server/piztor/import.py b/server/piztor/import.py index 1521849..84c990f 100644 --- a/server/piztor/import.py +++ b/server/piztor/import.py @@ -5,9 +5,10 @@ from model import * path = "piztor.sqlite" class UserData: - def __init__(self, username, password, sex): + def __init__(self, username, password, gid, sex): self.username = username self.password = password + self.gid = gid self.sex = sex def create_database(): @@ -20,7 +21,7 @@ def import_user_data(data): Session = sessionmaker(bind = engine) session = Session() for user in data: - um = UserModel(username = user.username, sex = user.sex) + um = UserModel(username = user.username, gid = user.gid, sex = user.sex) um.auth = UserAuth(user.password) um.location = LocationInfo(lat = 0, lng = 0) session.add(um) @@ -38,7 +39,7 @@ if __name__ == '__main__': while True: line = f.readline().split() if len(line) == 0: break - data.append(UserData(line[0], line[1], line[2])) + data.append(UserData(line[0], line[1], line[2], line[3])) create_database() import_user_data(data) diff --git a/server/piztor/model.py b/server/piztor/model.py index 70ca431..4621bbe 100644 --- a/server/piztor/model.py +++ b/server/piztor/model.py @@ -16,6 +16,7 @@ class UserModel(Base): __tablename__ = _TableName.UserModel id = Column(Integer, primary_key = True) + gid = Column(Integer) username = Column(String) sex = Column(Boolean) location = None @@ -24,7 +25,7 @@ class UserModel(Base): class LocationInfo(Base): __tablename__ = _TableName.LocationInfo - uid = Column(Integer, ForeignKey('users.id'), primary_key = True) + uid = Column(Integer, ForeignKey(_TableName.UserModel + '.id'), primary_key = True) lat = Column(Float(precesion = 64)) lng = Column(Float(precesion = 64)) user = relationship("UserModel", uselist = False, @@ -48,7 +49,7 @@ def _random_binary_string(length): class UserAuth(Base): __tablename__ = _TableName.UserAuth - uid = Column(Integer, ForeignKey('users.id'), primary_key = True) + uid = Column(Integer, ForeignKey(_TableName.UserModel + '.id'), primary_key = True) password = Column(LargeBinary) salt = Column(LargeBinary) token = Column(LargeBinary) diff --git a/server/piztor/prob.py b/server/piztor/prob.py new file mode 100644 index 0000000..1f9bdb7 --- /dev/null +++ b/server/piztor/prob.py @@ -0,0 +1,76 @@ +import socket +from struct import * +from random import random + +def get_hex(data): + return "".join([hex(ord(c))[2:].zfill(2) for c in data]) + +host = "localhost" +port = 9990 + +def gen_auth(username, password): + length = 4 + 1 + len(username) + 1 + len(password) + data = pack("!LB", length, 0x00) + data += username + data += "\0" + data += password + return data + +def gen_update_location(token, username, lat, lng): + length = 4 + 1 + 32 + 8 + 8 + len(username) + 1 + data = pack("!LB32s", length, 0x01, token) + data += username + data += chr(0) + data += pack("!dd", lat, lng) + return data + +def gen_request_location(token, username, gid): + length = 4 + 1 + 32 + 4 + len(username) + 1 + data = pack("!LB32s", length, 0x02, token) + data += username + data += chr(0) + data += pack("!L", gid) + return data + + +def send(data): + received = None + try: + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.connect((host, port)) + print len(data) + sock.sendall(data) + received = sock.recv(1024) + finally: + sock.close() + return received + +username = "hello" +password = "world" +gid = 1 + +resp = send(gen_auth(username, password)) +pl, optcode, status, uid, token = unpack("!LBBL32s", resp) +print "size: " + str((pl, len(resp))) +print "opt: " + str(optcode) +print "status: " + str(status) +print "uid: " + str(uid) +print "token: " + get_hex(token) + +resp = send(gen_update_location(token, username, random(), random())) +pl, optcode, status = unpack("!LBB", resp) +print "size: " + str((pl, len(resp))) +print "opt: " + str(optcode) +print "status: " + str(status) + +resp = send(gen_request_location(token, username, gid)) +print len(resp) +pl, optcode, status, length = unpack("!LBBL", resp[:10]) +print "size: " + str((pl, len(resp))) +idx = 10 +print "length: " + str(len(resp[10:])) +for i in xrange(length): + print len(resp[idx:idx + 20]) + uid, lat, lng = unpack("!Ldd", resp[idx:idx + 20]) + idx += 20 + print (uid, lat, lng) diff --git a/server/piztor/server.py b/server/piztor/server.py new file mode 100644 index 0000000..5c3160b --- /dev/null +++ b/server/piztor/server.py @@ -0,0 +1,311 @@ +from twisted.internet.protocol import Protocol +from twisted.internet.protocol import Factory +from twisted.internet.endpoints import TCP4ServerEndpoint +from twisted.internet import reactor + +from sqlalchemy import create_engine +from sqlalchemy.orm import sessionmaker +from sqlalchemy.orm.exc import NoResultFound, MultipleResultsFound + +import struct +import os +import logging + +from exc import * +from model import * + +def get_hex(data): + return "".join([hex(ord(c))[2:].zfill(2) for c in data]) + +def print_datagram(data): + print "==================================" + print "Received datagram:" + print get_hex(data) + print "==================================" + +db_path = "piztor.sqlite" +FORMAT = "%(asctime)-15s %(message)s" +logging.basicConfig(format = FORMAT) +logger = logging.getLogger('piztor_server') +logger.setLevel(logging.INFO) + + +class _SectionSize: + LENGTH = 4 + OPT_ID = 1 + STATUS = 1 + USER_ID = 4 + USER_TOKEN = 32 + GROUP_ID = 4 + ENTRY_CNT = 4 + LATITUDE = 8 + LONGITUDE = 8 + LOCATION_ENTRY = USER_ID + LATITUDE + LONGITUDE + PADDING = 1 + +class _OptCode: + user_auth = 0x00 + location_update = 0x02 + location_request= 0x03 + +class _StatusCode: + sucess = 0x00 + failure = 0x01 + +class RequestHandler(object): + def __init__(self): + self.engine = create_engine('sqlite:///' + db_path, echo = False) + self.Session = sessionmaker(bind = self.engine) + + @classmethod + def get_uauth(cls, token, username, session): + try: + uauth = session.query(UserAuth) \ + .filter(UserAuth.token == token).one() + + if uauth.user.username != username: + logger.warning("Toke and username mismatch") + return None + + return uauth + + except NoResultFound: + logger.warning("Incorrect token") + return None + + except MultipleResultsFound: + raise DBCorruptedError() + + @classmethod + def trunc_padding(cls, data): + leading = bytes() + for i in xrange(len(data)): + ch = data[i] + if ch == '\x00': + print get_hex(leading), get_hex(data[i + 1:]) + return (leading, data[i + 1:]) + else: + leading += ch + # padding not found + return (None, data) + +class UserAuthHandler(RequestHandler): + + _user_auth_response_size = \ + _SectionSize.LENGTH + \ + _SectionSize.OPT_ID + \ + _SectionSize.STATUS + \ + _SectionSize.USER_ID + \ + _SectionSize.USER_TOKEN + + def handle(self, tr_data): + logger.info("Reading auth data...") + pos = -1 + for i in xrange(0, len(tr_data)): + if tr_data[i] == '\x00': + pos = i + break + if pos == -1: + raise BadReqError("Authentication: Malformed request body") + + username = tr_data[0:pos] + password = tr_data[pos + 1:] + logger.info("Trying to login with " \ + "(username = {0}, password = {1})" \ + .format(username, password)) + + session = self.Session() + try: + user = session.query(UserModel) \ + .filter(UserModel.username == username).one() + except NoResultFound: + logger.info("No such user: {0}".format(username)) + return struct.pack("!LBBL32s", UserAuthHandler \ + ._user_auth_response_size, + _OptCode.user_auth, + _StatusCode.failure, + 0, + bytes('\x00' * 32)) + + except MultipleResultsFound: + raise DBCorruptedError() + + uauth = user.auth + if uauth is None: + raise DBCorruptedError() + if not uauth.check_password(password): + logger.info("Incorrect password: {0}".format(username)) + return struct.pack("!LBBL32s", UserAuthHandler \ + ._user_auth_response_size, + _OptCode.user_auth, + _StatusCode.failure, + 0, + bytes('\x00' * 32)) + else: + logger.info("Logged in sucessfully: {0}".format(username)) + uauth.regen_token() + session.commit() + print "new token generated: " + get_hex(uauth.token) + return struct.pack("!LBBL32s", UserAuthHandler \ + ._user_auth_response_size, + _OptCode.user_auth, + _StatusCode.sucess, + user.id, + uauth.token) + + +class LocationUpdateHandler(RequestHandler): + +# _location_update_size = \ +# _SectionSize.AUTH_HEAD + \ +# _SectionSize.LATITUDE + \ +# _SectionSize.LONGITUDE + + _location_update_response_size = \ + _SectionSize.LENGTH + \ + _SectionSize.OPT_ID + \ + _SectionSize.STATUS + + def handle(self, tr_data): + logger.info("Reading location update data...") + + try: + token, = struct.unpack("!32s", tr_data[:32]) + username, tail = RequestHandler.trunc_padding(tr_data[32:]) + if username is None: + raise struct.error + lat, lng = struct.unpack("!dd", tail) + except struct.error: + raise BadReqError("Location update: Malformed request body") + + logger.info("Trying to update location with " + "(token = {0}, username = {1}, lat = {2}, lng = {3})"\ + .format(get_hex(token), username, lat, lng)) + + session = self.Session() + uauth = RequestHandler.get_uauth(token, username, session) + # Authentication failure + if uauth is None: + logger.warning("Authentication failure") + return struct.pack("!LBB", LocationUpdateHandler \ + ._location_update_response_size, + _OptCode.location_update, + _StatusCode.failure) + + ulocation = uauth.user.location + ulocation.lat = lat + ulocation.lng = lng + session.commit() + + logger.info("Location is updated sucessfully") + return struct.pack("!LBB", LocationUpdateHandler \ + ._location_update_response_size, + _OptCode.location_update, + _StatusCode.sucess) + +class LocationRequestHandler(RequestHandler): + +# _location_request_size = \ +# _SectionSize.AUTH_HEAD + \ +# _SectionSize.GROUP_ID + + @classmethod + def _location_request_response_size(cls, item_num): + return _SectionSize.LENGTH + \ + _SectionSize.OPT_ID + \ + _SectionSize.STATUS + \ + _SectionSize.ENTRY_CNT + \ + _SectionSize.LOCATION_ENTRY * item_num + + def handle(self, tr_data): + logger.info("Reading location request data..") + + try: + token, = struct.unpack("!32s", tr_data[:32]) + username, tail = RequestHandler.trunc_padding(tr_data[32:]) + if username is None: + raise struct.error + gid, = struct.unpack("!L", tail) + except struct.error: + raise BadReqError("Location request: Malformed request body") + + logger.info("Trying to request locatin with " \ + "(token = {0}, gid = {1})" \ + .format(get_hex(token), gid)) + + session = self.Session() + uauth = RequestHandler.get_uauth(token, username, session) + # Auth failure + if uauth is None: + logger.warning("Authentication failure") + return struct.pack("!LBBL", LocationRequestHandler \ + ._location_request_response_size(0), + _OptCode.location_request, + _StatusCode.failure, + 0) + + ulist = session.query(UserModel).filter(UserModel.gid == gid).all() + reply = struct.pack( + "!LBBL", + LocationRequestHandler._location_request_response_size(len(ulist)), + _OptCode.location_request, + _StatusCode.sucess, + len(ulist)) + + for user in ulist: + loc = user.location + reply += struct.pack("!Ldd", user.id, loc.lat, loc.lng) + + return reply + +handlers = [UserAuthHandler, + LocationUpdateHandler, + LocationRequestHandler] + +def check_header(header): + return 0 <= header < len(handlers) + +class PTP(Protocol): + + def __init__(self): + self.buff = bytes() + self.length = -1 + + def connectionMade(self): + logger.info("A new connection is made") + + def dataReceived(self, data): + self.buff += data + print len(self.buff) + if len(self.buff) > 4: + try: + self.length, self.optcode = struct.unpack("!LB", self.buff[:5]) + if not check_header(self.optcode): # invalid header + raise struct.error + except struct.error: + logger.warning("Invalid request header") + raise BadReqError("Malformed request header") + print self.length + if len(self.buff) == self.length: + h = handlers[self.optcode]() + reply = h.handle(self.buff[5:]) + logger.info("Wrote: %s", get_hex(reply)) + self.transport.write(reply) + self.transport.loseConnection() + + elif len(self.buff) > self.length: + self.transport.loseConnection() + + + def connectionLost(self, reason): + logger.info("The connection is lost") + +class PTPFactory(Factory): + def __init__(self): + pass + def buildProtocol(self, addr): + return PTP() + +endpoint = TCP4ServerEndpoint(reactor, 9990) +endpoint.listen(PTPFactory()) +reactor.run() diff --git a/server/piztor_server.py b/server/piztor_server.py index 514f95f..81805b3 100644 --- a/server/piztor_server.py +++ b/server/piztor_server.py @@ -230,5 +230,5 @@ class PiztorServer(): if __name__ == "__main__": - ps = PiztorServer("localhost", 9990) + ps = PiztorServer("localhost", 9999) ps.run() diff --git a/server/ptp.rst b/server/ptp.rst index 8aef2b7..7c40a3b 100644 --- a/server/ptp.rst +++ b/server/ptp.rst @@ -1,4 +1,4 @@ -Piztor Transmission Protocol v0.2 +Piztor Transmission Protocol v0.3 --------------------------------- - General @@ -8,7 +8,7 @@ Piztor Transmission Protocol v0.2 :: +---4b---+---1b---+-------?b--------+ - | LENGTH | OPT ID | SPECIFIC DATA | + | LENGTH | OPT_ID | SPECIFIC DATA | +--int---+-uchar--+-----------------+ - Response @@ -16,11 +16,20 @@ Piztor Transmission Protocol v0.2 :: +---4b---+---1b---+------?b---------+ - | LENGTH | OPT ID | SPECIFIC DATA | + | LENGTH | OPT_ID | SPECIFIC DATA | +--int---+-uchar--+-----------------+ - Notice that in following sections, ``LENGTH`` part is left out for clarity. - TODO: All secure requests should have username or uid provided. + Notice: + + - In following sections, ``LENGTH`` part is left out for clarity. + - ``PADDING`` has value ``0``. + - ``AUTH_HEAD`` structure: + + :: + + +----32b-----+----?b----+----1b---+ + | USER_TOKEN | USERNAME | PADDING | + +----raw-----+----------+---------+ - Authentication @@ -28,22 +37,22 @@ Piztor Transmission Protocol v0.2 :: - +--1b---+-----?b------+-----?b-----+ - | 0x00 | USERNAME | PASSWORD | - +-uchar-+-------------+------------+ + +--1b---+-----?b------+----1b----+-----?b-----+ + | 0x00 | USERNAME | PADDING | PASSWORD | + +-uchar-+-------------+----------+------------+ - Response :: - +--1b---+---1b---+---4b----+----16b-----+ + +--1b---+---1b---+---4b----+----32b-----+ | 0x00 | STATUS | USER_ID | USER_TOKEN | +-uchar-+--uchar-+---int---+----raw-----+ ``STATUS`` : - - 0x00 for success - - 0x01 for failure + - ``0x00`` for success + - ``0x01`` for failure - Location Update @@ -51,22 +60,22 @@ Piztor Transmission Protocol v0.2 :: - +--1b---+-----16b------+-----8b-----+------8b-----+ - | 0x02 | USER_TOKEN | LATITUDE | LONGITUDE | - +-uchar-+------raw-----+---double---+---double----+ + +--1b---+-----?b------+----8b------+------8b-----+ + | 0x01 | AUTH_HEAD | LATITUDE | LONGITUDE | + +-uchar-+-------------+---double---+---double----+ - Response :: +--1b---+---1b---+ - | 0x02 | STATUS | + | 0x01 | STATUS | +-uchar-+--uchar-+ ``STATUS`` : - - 0x00 for success - - 0x01 for invalid token + - ``0x00`` for success + - ``0x01`` for invalid token - Location Information @@ -74,16 +83,16 @@ Piztor Transmission Protocol v0.2 :: - +--1b---+-----16b------+------4b-----+ - | 0x03 | USER_TOKEN | GROUP_ID | - +-uchar-+-----raw------+-----int-----+ + +--1b---+------?b------+------4b-----+ + | 0x02 | AUTH_HEAD | GROUP_ID | + +-uchar-+--------------+-----int-----+ - Response :: +--1b---+---1b---+-----4b----+------20b-------+-----+ - | 0x03 | STATUS | ENTRY_CNT | LOCATION_ENTRY | ... | + | 0x02 | STATUS | ENTRY_CNT | LOCATION_ENTRY | ... | +-uchar-+-uchar--+----int----+----------------+-----+ ``LOCATION_ENTRY`` : -- cgit v1.2.3 From 596da92743ceade7eba90d1397847f464a2efee8 Mon Sep 17 00:00:00 2001 From: Teddy Date: Sun, 25 Aug 2013 19:32:05 +0800 Subject: place the lastest server files in the correct location --- server/piztor/exc.py | 17 +++++++++++ server/piztor/import.py | 45 ++++++++++++++++++++++++++++ server/piztor/model.py | 80 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 142 insertions(+) create mode 100644 server/piztor/exc.py create mode 100644 server/piztor/import.py create mode 100644 server/piztor/model.py (limited to 'server') diff --git a/server/piztor/exc.py b/server/piztor/exc.py new file mode 100644 index 0000000..2c53dbf --- /dev/null +++ b/server/piztor/exc.py @@ -0,0 +1,17 @@ +class PiztorError(Exception): + pass + +class DBCurruptedError(PiztorError): + pass + +class ConnectionError(PiztorError): + pass + +class ReqReadError(ConnectionError): + pass + +class BadReqError(ConnectionError): + pass + +class BadTokenError(ConnectionError): + pass diff --git a/server/piztor/import.py b/server/piztor/import.py new file mode 100644 index 0000000..84c990f --- /dev/null +++ b/server/piztor/import.py @@ -0,0 +1,45 @@ +from sqlalchemy import create_engine +from sqlalchemy.orm import sessionmaker +from model import * + +path = "piztor.sqlite" + +class UserData: + def __init__(self, username, password, gid, sex): + self.username = username + self.password = password + self.gid = gid + self.sex = sex + +def create_database(): + engine = create_engine('sqlite:///' + path, echo = True) + Base.metadata.drop_all(engine) + Base.metadata.create_all(engine) + +def import_user_data(data): + engine = create_engine('sqlite:///' + path, echo = True) + Session = sessionmaker(bind = engine) + session = Session() + for user in data: + um = UserModel(username = user.username, gid = user.gid, sex = user.sex) + um.auth = UserAuth(user.password) + um.location = LocationInfo(lat = 0, lng = 0) + session.add(um) + session.commit() + +if __name__ == '__main__': + + from sys import argv, exit + if len(argv) != 2: + print "Usage: " + argv[0] + " FILE" + exit(0) + + data = list() + with open(argv[1], 'r') as f: + while True: + line = f.readline().split() + if len(line) == 0: break + data.append(UserData(line[0], line[1], line[2], line[3])) + + create_database() + import_user_data(data) diff --git a/server/piztor/model.py b/server/piztor/model.py new file mode 100644 index 0000000..4621bbe --- /dev/null +++ b/server/piztor/model.py @@ -0,0 +1,80 @@ +from sqlalchemy import Column, Integer, String, Float, ForeignKey, LargeBinary, Boolean +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.orm import relationship, backref + +Base = declarative_base() + +_SALT_LEN = 16 +_TOKEN_LEN = 16 + +class _TableName: # avoid typoes + UserModel = 'users' + LocationInfo = 'location_info' + UserAuth = 'user_auth' + +class UserModel(Base): + __tablename__ = _TableName.UserModel + + id = Column(Integer, primary_key = True) + gid = Column(Integer) + username = Column(String) + sex = Column(Boolean) + location = None + auth = None + +class LocationInfo(Base): + __tablename__ = _TableName.LocationInfo + + uid = Column(Integer, ForeignKey(_TableName.UserModel + '.id'), primary_key = True) + lat = Column(Float(precesion = 64)) + lng = Column(Float(precesion = 64)) + user = relationship("UserModel", uselist = False, + backref = backref("location", uselist = False, + cascade = "all, delete-orphan")) + + # More: last_update + +from hashlib import sha256 +from os import urandom + +def _sprinkle_salt(uauth, passwd): + data = sha256(uauth.salt) + data.update(chr(0)) + data.update(passwd) + return data.digest() + +def _random_binary_string(length): + return urandom(length) + +class UserAuth(Base): + __tablename__ = _TableName.UserAuth + + uid = Column(Integer, ForeignKey(_TableName.UserModel + '.id'), primary_key = True) + password = Column(LargeBinary) + salt = Column(LargeBinary) + token = Column(LargeBinary) + + user = relationship("UserModel", uselist = False, + backref = backref("auth", uselist = False, + cascade = "all, delete-orphan")) + + def regen_token(self): + self.token = sha256(_random_binary_string(_TOKEN_LEN)).digest() + + def __init__(self, passwd): + self.set_password(passwd) + + def set_password(self, passwd): + self.salt = _random_binary_string(_SALT_LEN) + self.password = _sprinkle_salt(self, passwd) + self.regen_token() + + def check_password(self, passwd): + passwd = _sprinkle_salt(self, passwd) + return passwd == self.password + + def check_token(self, tk): + return self.token == tk + + def get_token(self): + return self.token -- cgit v1.2.3 From 2111f8aaac6351fb303986b39add99a012633ac2 Mon Sep 17 00:00:00 2001 From: Teddy Date: Sun, 25 Aug 2013 20:51:39 +0800 Subject: ptp v3.0a & server timeout support --- server/piztor/prob.py | 5 ++ server/piztor/ptp.rst | 135 ++++++++++++++++++++++++++++++++++++++++++++++++ server/piztor/server.py | 24 ++++++--- 3 files changed, 157 insertions(+), 7 deletions(-) create mode 100644 server/piztor/ptp.rst (limited to 'server') diff --git a/server/piztor/prob.py b/server/piztor/prob.py index 1f9bdb7..4ccc957 100644 --- a/server/piztor/prob.py +++ b/server/piztor/prob.py @@ -45,6 +45,11 @@ def send(data): sock.close() return received +from sys import argv + +if len(argv) == 2: + host = argv[1] + username = "hello" password = "world" gid = 1 diff --git a/server/piztor/ptp.rst b/server/piztor/ptp.rst new file mode 100644 index 0000000..c12cf65 --- /dev/null +++ b/server/piztor/ptp.rst @@ -0,0 +1,135 @@ +Piztor Transmission Protocol v0.3a +---------------------------------- + +- General + + - Request + + :: + + +---4b---+---1b---+-------?b--------+ + | LENGTH | OPT_ID | SPECIFIC DATA | + +--int---+-uchar--+-----------------+ + + - Response + + :: + + +---4b---+---1b---+------?b---------+ + | LENGTH | OPT_ID | SPECIFIC DATA | + +--int---+-uchar--+-----------------+ + + Notice: + + - In following sections, ``LENGTH`` part is left out for clarity. + - ``PADDING`` has value ``0``. + - ``AUTH_HEAD`` structure: + + :: + + +----32b-----+----?b----+----1b---+ + | USER_TOKEN | USERNAME | PADDING | + +----raw-----+----------+---------+ + +- Authentication + + - Request + + :: + + +--1b---+-----?b------+----1b----+-----?b-----+ + | 0x00 | USERNAME | PADDING | PASSWORD | + +-uchar-+-------------+----------+------------+ + + - Response + + :: + + +--1b---+---1b---+---4b----+----32b-----+ + | 0x00 | STATUS | USER_ID | USER_TOKEN | + +-uchar-+--uchar-+---int---+----raw-----+ + + ``STATUS`` : + + - ``0x00`` for success + - ``0x01`` for failure + +- Location Update + + - Request + + :: + + +--1b---+-----?b------+----8b------+------8b-----+ + | 0x01 | AUTH_HEAD | LATITUDE | LONGITUDE | + +-uchar-+-------------+---double---+---double----+ + + - Response + + :: + + +--1b---+---1b---+ + | 0x01 | STATUS | + +-uchar-+--uchar-+ + + ``STATUS`` : + + - ``0x00`` for success + - ``0x01`` for invalid token + +- Location Information + + - Request + + :: + + +--1b---+------?b------+------4b-----+ + | 0x02 | AUTH_HEAD | GROUP_ID | + +-uchar-+--------------+-----int-----+ + + - Response + + :: + + +--1b---+---1b---+-----4b----+------20b-------+-----+ + | 0x02 | STATUS | ENTRY_CNT | LOCATION_ENTRY | ... | + +-uchar-+-uchar--+----int----+----------------+-----+ + + ``LOCATION_ENTRY`` : + + :: + + +---4b----+----8b----+-----8b----+ + | USER_ID | LATITUDE | LONGITUDE | + +---int---+--double--+--double---+ + +- User Information + + - Request + + :: + + +--1b---+------?b------+------4b-----+ + | 0x02 | AUTH_HEAD | USER_ID | + +-uchar-+--------------+-----int-----+ + + - Response + + :: + + +--1b---+---1b---+------?b-----+-----+ + | 0x03 | STATUS | UINFO_ENTRY | ... | + +-uchar-+-uchar--+-------------+-----+ + + ``UINFO_ENTRY`` : + + :: + + +----1b----+-----?b-----+ + | INFO_KEY | INFO_VALUE | + +--uchar---+------------+ + + ``INFO_KEY`` : + + :``0x00``: gid (value is a 4-byte ``long int``) + :``0x01``: sex (value is a 1-byte ``boolean``: ``True`` for male, ``False`` for female) diff --git a/server/piztor/server.py b/server/piztor/server.py index 5c3160b..2397225 100644 --- a/server/piztor/server.py +++ b/server/piztor/server.py @@ -2,6 +2,7 @@ from twisted.internet.protocol import Protocol from twisted.internet.protocol import Factory from twisted.internet.endpoints import TCP4ServerEndpoint from twisted.internet import reactor +from twisted.protocols.policies import TimeoutMixin from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker @@ -45,8 +46,8 @@ class _SectionSize: class _OptCode: user_auth = 0x00 - location_update = 0x02 - location_request= 0x03 + location_update = 0x01 + location_request= 0x02 class _StatusCode: sucess = 0x00 @@ -265,17 +266,23 @@ handlers = [UserAuthHandler, def check_header(header): return 0 <= header < len(handlers) -class PTP(Protocol): +class PTP(Protocol, TimeoutMixin): - def __init__(self): + def __init__(self, factory): self.buff = bytes() self.length = -1 + self.factory = factory + + def timeoutConnection(self): + logger.info("The connection times out") def connectionMade(self): logger.info("A new connection is made") + self.setTimeout(self.factory.timeout) def dataReceived(self, data): self.buff += data + self.resetTimeout() print len(self.buff) if len(self.buff) > 4: try: @@ -286,6 +293,8 @@ class PTP(Protocol): logger.warning("Invalid request header") raise BadReqError("Malformed request header") print self.length + if self.length == -1: + return if len(self.buff) == self.length: h = handlers[self.optcode]() reply = h.handle(self.buff[5:]) @@ -299,12 +308,13 @@ class PTP(Protocol): def connectionLost(self, reason): logger.info("The connection is lost") + self.setTimeout(None) class PTPFactory(Factory): - def __init__(self): - pass + def __init__(self, timeout = 10): + self.timeout = timeout def buildProtocol(self, addr): - return PTP() + return PTP(self) endpoint = TCP4ServerEndpoint(reactor, 9990) endpoint.listen(PTPFactory()) -- cgit v1.2.3 From 951907736830aadaebf8088433401b6d752e1cec Mon Sep 17 00:00:00 2001 From: Teddy Date: Sun, 25 Aug 2013 20:52:48 +0800 Subject: ptp v3.0a fixed --- server/piztor/ptp.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'server') diff --git a/server/piztor/ptp.rst b/server/piztor/ptp.rst index c12cf65..004bbd9 100644 --- a/server/piztor/ptp.rst +++ b/server/piztor/ptp.rst @@ -125,9 +125,9 @@ Piztor Transmission Protocol v0.3a :: - +----1b----+-----?b-----+ - | INFO_KEY | INFO_VALUE | - +--uchar---+------------+ + +----1b----+-----?b-----+---1b----+ + | INFO_KEY | INFO_VALUE | PADDING | + +--uchar---+------------+---------+ ``INFO_KEY`` : -- cgit v1.2.3