blob: 1c7d3906b36fb1bc7c6f5e894560d11d16db258d [file] [log] [blame]
Cheng Tang05eec9b2013-07-09 09:33:37 +08001# -*- coding: utf-8
2"""
3agentlink 模块,提供与 swagent 通讯协议的封装
4"""
5import codecs
6import socket
7import struct
8import random
9import time
10import os
11import traceback
12
13__all__ = ['VERSION', 'SWAgentLink']
14
15VERSION = "4.0.0"
16
17
18class SWAgentLink(object):
19 """
20 agentlink 协议封装
21 """
22 MSG_LEN_FMT = '!H'
23 MSG_HEADER_FMT = '!IIIBB'
24 MSG_HEADER_DESC = ('major_version', 'minor_version', 'unique_no', 'msg_type', 'retcode')
25 # 协议版本号定义
26 MAJOR_VERSION = 1
27 MINOR_VERSION = 1
28
29 def __init__(self):
30 self.sock = None
31 self.ip = None
32 self.port = None
33 self.timeout = 10.0
34 self._is_login = False
35 self.unique_no = None
36 self.connection_id = None
37 random.seed(time.time())
38
39 def connect(self, ip, port):
40 self.close()
41 try:
42 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
43 sock.settimeout(self.timeout)
44 sock.connect((ip, port))
45 self.sock = sock
46 self.ip = ip
47 self.port = port
48 return True
49 except socket.error:
50 return False
51
52 def login(self):
53 msg_type = 0x30
54 process_id = struct.pack('!I', os.getpid())
55 message_header = self._new_message(msg_type)
56 login_data = self._pack_request(message_header, process_id)
57 data = self._send_and_recv(login_data, 5.0)
58 if not data:
59 return False
60 login_resp = self._unpack_request(data)
61 if not self._check_response(message_header, login_resp):
62 print u"Login response error"
63 return False
64 if login_resp['retcode'] != 0:
65 print u"Login error retcode={0}".format(login_resp['retcode'])
66 return False
67 self.connection_id = login_resp['data']
68 self._is_login = True
69 return True
70
71 def _send_and_recv(self, request, timeout):
72 header_len = struct.calcsize(self.MSG_LEN_FMT)
73 try:
74 self.sock.settimeout(timeout)
75 self.sock.send(request)
76 # print u"Send[{0}]".format(codecs.encode(request, 'hex'))
77 header = self.sock.recv(header_len)
78 if not header:
79 return None
80 body_len = struct.unpack(self.MSG_LEN_FMT, header)[0]
81 body = self.sock.recv(body_len)
82 # print u"Recv[{0}]".format(codecs.encode(body, 'hex'))
83 return body
84 except socket.error as e:
85 print u"socket send and recv error, error: <{0}>".format(e)
86 traceback.print_exc()
87 self.sock.close()
88 self.sock = None
89 self._is_login = False
90 return None
91
92 def get_data(self):
93 msg_type = 0x32
94 message_header = self._new_message(msg_type)
95 req_data = self._pack_request(message_header, self.connection_id)
96 data = self._send_and_recv(req_data, None)
97 if not data:
98 return False
99 getdata_resp = self._unpack_request(data)
100 if not self._check_response(message_header, getdata_resp):
101 print u"get data error"
102 return None
103 if getdata_resp['retcode'] != 0:
104 print u"GetData error retcode={0}".format(getdata_resp['retcode'])
105 return None
106 data = getdata_resp['data']
107 # print codecs.encode(data, 'hex')
108 data_head_len = struct.calcsize('!I')
109 data_len = struct.unpack('!I', data[:data_head_len])[0]
110 if data_len != len(data) - data_head_len:
111 return None
112 return data[data_head_len: data_head_len + data_len]
113
114 def answer_data(self, response):
115 msg_type = 0x34
116 message_header = self._new_message(msg_type)
117 req_data = self._pack_request(message_header, self.connection_id + response)
118 data = self._send_and_recv(req_data, None)
119 answer_resp = self._unpack_request(data)
120 if not self._check_response(message_header, answer_resp):
121 print u"answer data error"
122 return False
123 if answer_resp['retcode'] != 0:
124 print u"Answer error retcode={0}".format(answer_resp['retcode'])
125 return False
126 return True
127
128 def _new_message(self, msg_type):
129 unique_no = random.randint(0x10000000, 0xFFFFFFFF)
130 return dict(major_version=self.MAJOR_VERSION, minor_version=self.MINOR_VERSION,
131 unique_no=unique_no, msg_type=msg_type, retcode=0)
132
133 def _pack_request(self, message_header, data):
134 header = struct.pack(self.MSG_HEADER_FMT, message_header['major_version'],
135 message_header['minor_version'], message_header['unique_no'],
136 message_header['msg_type'], message_header['retcode'])
137 r = []
138 if not data:
139 r.append(struct.pack(self.MSG_LEN_FMT, len(header)))
140 r.append(data)
141 else:
142 r.append(struct.pack(self.MSG_LEN_FMT, (len(header) + len(data))))
143 r.append(header)
144 r.append(data)
145 return ''.join(r)
146
147 def close(self):
148 if self.sock:
149 self.sock.close()
150 self.sock = None
151 self._is_login = False
152
153 def is_ok(self):
154 if not self.sock:
155 return False
156 if not self._is_login:
157 return False
158 return True
159
160 def _unpack_request(self, data):
161 if not data:
162 return None
163 header_len = struct.calcsize(self.MSG_HEADER_FMT)
164 if header_len > len(data):
165 return None
166 resp = struct.unpack(self.MSG_HEADER_FMT, data[:header_len])
167 resp_dict = dict(zip(self.MSG_HEADER_DESC, resp))
168 resp_dict['data'] = data[header_len:]
169 return resp_dict
170
171 def _check_response(self, message_header, response):
172 if not response:
173 return False
174 if (message_header['major_version'] != response['major_version']
175 or message_header['minor_version'] != response['minor_version']
176 or message_header['unique_no'] != response['unique_no']
177 or message_header['msg_type'] != response['msg_type']):
178 return False
179 return True