PageRenderTime 32ms CodeModel.GetById 0ms RepoModel.GetById 0ms app.codeStats 0ms

/synce-sync-engine-0.15.1/SyncEngine/dtptserver.py

#
Python | 845 lines | 705 code | 108 blank | 32 comment | 62 complexity | 6f2e1db838b3032306f98d95d0d4d3b7 MD5 | raw file
Possible License(s): GPL-2.0
  1. # -*- coding: utf-8 -*-
  2. ###############################################################################
  3. # DTPTSERVER.py
  4. #
  5. # Adapted from Ole's original stand-alone DTPT server, this version is started
  6. # by sync-engine if both the global config and the partnership config allow
  7. # it.
  8. #
  9. # Original DTPT.py (C) 2006 Ole Andr?Š Vadla Ravn??s <oleavr@gmail.com>
  10. #
  11. # Dr J A Gow 28/11/2007
  12. #
  13. ###############################################################################
  14. import socket
  15. import thread
  16. import threading
  17. import struct
  18. import random
  19. import select
  20. import os
  21. import logging
  22. import util
  23. DTPT_PORT = 5721
  24. DUMMY_PTR = 0xDEADBEEF
  25. SVCID_INET_HOSTADDRBYNAME = "{0002A803-0000-0000-C000-000000000046}"
  26. WSAEFAULT = 10014
  27. WSAHOST_NOT_FOUND = 11001
  28. logger = logging.getLogger("engine.syncengine.dtptserver")
  29. #
  30. # DTPTServer
  31. #
  32. # The DTPTServer is now a threaded server that we can actually stop cleanly
  33. # when the sync-engine is stopped. We track all spun off server threads and
  34. # ensure that all is stopped before exitting.
  35. #
  36. class DTPTServer(threading.Thread):
  37. def __init__(self, bindaddr):
  38. threading.Thread.__init__(self)
  39. s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  40. s.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
  41. s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  42. s.bind((bindaddr, DTPT_PORT))
  43. s.listen(5)
  44. self._sock = s
  45. self.threads = {}
  46. self.threadlock = threading.Lock()
  47. self.pr,self.pw = os.pipe()
  48. self.evtShutdown = threading.Event()
  49. def AddServer(self,tid,th):
  50. self.threadlock.acquire()
  51. self.evtShutdown.clear()
  52. rc = len(self.threads)
  53. self.threads[tid]=th
  54. self.threadlock.release()
  55. return rc
  56. def RemoveServer(self,tid):
  57. logger.info("removing thread")
  58. self.threadlock.acquire()
  59. del self.threads[tid]
  60. if len(self.threads)==0:
  61. self.evtShutdown.set()
  62. self.threadlock.release()
  63. def _CloseAllThreads(self):
  64. self.threadlock.acquire()
  65. for tid,thd in self.threads.items():
  66. os.write(thd.pw,"stop")
  67. thd.s.shutdown(0)
  68. thd.s.close()
  69. self.threadlock.release()
  70. def run(self):
  71. self._running = True
  72. ip = [self._sock, self.pr]
  73. self.evtShutdown.set()
  74. while self._running:
  75. irdy,ordy,xptrdy = select.select(ip,[],[])
  76. for sck in irdy:
  77. if sck == self._sock:
  78. try:
  79. (s, address) = self._sock.accept()
  80. s.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
  81. # TODO: we should check here that tid doesn't already exist in thread list keys
  82. tid = util.generate_id()
  83. thd=DTPTThread(s,self,tid)
  84. ix = self.AddServer(tid,thd)
  85. thd.start()
  86. except:
  87. self._running=0
  88. return
  89. elif sck == self.pr:
  90. dump=os.read(self.pr,4)
  91. logger.info("DTPT server shutdown request actioned")
  92. self._running = 0
  93. else:
  94. continue
  95. self._sock.close()
  96. logger.info("shutting down DTPT threads")
  97. self._CloseAllThreads()
  98. logger.info("waiting for final shutdown")
  99. self.evtShutdown.wait()
  100. os.close(self.pr)
  101. os.close(self.pw)
  102. def shutdown(self):
  103. try:
  104. os.write(self.pw,"stop")
  105. logger.info("DTPT server shutdown request posted")
  106. except Exception,e:
  107. logger.info("error shutting down DTPT server: %s" % e)
  108. pass
  109. #
  110. # DTPTThread
  111. #
  112. # Represents individual server threads which can be one of two types.
  113. # This is the bottom thread layer of the threaded architecture.
  114. #
  115. class DTPTThread(threading.Thread):
  116. def __init__(self, socket,handler,tid):
  117. threading.Thread.__init__(self)
  118. self.s = socket
  119. self.handler=handler
  120. self.tid = tid
  121. self.pr,self.pw = os.pipe()
  122. def __del__(self):
  123. os.close(self.pr)
  124. os.close(self.pw)
  125. def run(self):
  126. ip = [self.s, self.pr]
  127. irdy,ordy,xptrdy = select.select(ip,[],[])
  128. for fd in irdy:
  129. if fd==self.s:
  130. buf = self.s.recv(2, socket.MSG_PEEK | socket.MSG_WAITALL)
  131. if len(buf) > 0:
  132. if ord(buf[0]) != 1:
  133. logger.debug("invalid DTPT protocol")
  134. else:
  135. session = None
  136. if ord(buf[1]) == 9:
  137. NSPSession(self.s,self.pr).run()
  138. elif ord(buf[1]) == 1:
  139. ConnectionSession(self.s,self.pr).run()
  140. else:
  141. logger.debug("unknown session type %d" % ord(buf[1]))
  142. self.s.close()
  143. self.handler.RemoveServer(self.tid)
  144. class NSPSession:
  145. def __init__(self, s, pr):
  146. self.socket = s
  147. self.pr = pr
  148. self.initialize()
  149. self.ip = [self.socket, self.pr]
  150. def initialize(self):
  151. self.handle = None
  152. self.request = None
  153. self.response = None
  154. def run(self):
  155. logger.info("starting NSP session")
  156. while True:
  157. irdy,ordy,xptrdy = select.select(self.ip,[],[])
  158. for sc in irdy:
  159. if sc == self.socket:
  160. buf = self.socket.recv(20, socket.MSG_WAITALL)
  161. if len(buf) != 20:
  162. if len(buf) != 0:
  163. logger.error("NSPSession: read %d bytes, expected %d - exitting" % (len(buf), 20))
  164. return
  165. ver, type, qv, dv1, dv2 = struct.unpack("<BBxxQII", buf)
  166. if ver != 1:
  167. raise ValueError("ver=%d, expected 1" % ver)
  168. logger.info("dispatching %d %d %d %d %d" % (ver,type,qv,dv1,dv2))
  169. if type == 9:
  170. self._handle_lookup_begin(qv, dv1, dv2)
  171. elif type == 11:
  172. self._handle_lookup_next(qv, dv1, dv2)
  173. elif type == 13:
  174. self.initialize()
  175. else:
  176. logger.error("NSPSession: unhandled type=%d - exitting" % type)
  177. else:
  178. dump = os.read(self.pr,4)
  179. logger.info("NSPSession: connection terminated")
  180. return
  181. def _handle_lookup_begin(self, q_value, control_flags, payload_size):
  182. irdy,ordy,xptrdy = select.select(self.ip,[],[])
  183. for x in irdy:
  184. if x==self.socket:
  185. buf = self.socket.recv(payload_size, socket.MSG_WAITALL)
  186. if len(buf) != payload_size:
  187. logger.error("_handle_nsp_lookup_begin: read %d bytes, expected %d" % (len(buf), payload_size))
  188. return
  189. if self.handle != None:
  190. logger.error("_handle_nsp_lookup_begin: called twice")
  191. self.socket.close()
  192. return
  193. qs = QuerySet()
  194. qs.unserialize(buf)
  195. if qs.service_class_id != SVCID_INET_HOSTADDRBYNAME:
  196. logger.error("NSPSession - unsupported ServiceClassId %s" % qs.service_class_id)
  197. # FIXME: return a proper error here
  198. self._send_reply(10, 0, 0xDEADBEEF, 0)
  199. return
  200. self.handle = random.randint(2**10, 2**31)
  201. self.request = qs
  202. self._send_reply(10, self.handle, 0, 0)
  203. else:
  204. return
  205. def _handle_lookup_next(self, handle, dvalue1, buffer_size):
  206. if self.response == None:
  207. logger.debug("Resolving %s" % self.request.service_instance_name)
  208. qs = QuerySet()
  209. qs.service_instance_name = self.request.service_instance_name
  210. qs.namespace = 12
  211. try:
  212. results = socket.getaddrinfo(qs.service_instance_name, None)
  213. except:
  214. self._send_reply(12, 0, WSAHOST_NOT_FOUND, 0)
  215. return
  216. qs.blob = None
  217. for result in results:
  218. family, socket_type, proto, canonname, sockaddr = result
  219. ai = CSAddrInfo()
  220. if (family == socket.AF_INET):
  221. ai.local_addr = (family, "0.0.0.0", 0)
  222. elif (family == socket.AF_INET6):
  223. # We don't handle that yet, but don't bail out, keep
  224. # looking for a v4 address
  225. continue
  226. else:
  227. raise NotImplementedError("Unhandled family %d" % family)
  228. ai.remote_addr = (family, sockaddr[0], sockaddr[1])
  229. ai.socket_type = socket_type
  230. ai.protocol = proto
  231. if qs.blob == None:
  232. qs.blob = Hostent(family)
  233. qs.blob.h_name = qs.service_instance_name
  234. # All addresses in Hostent must be of the same family.
  235. # Every address should appear only once.
  236. if family == qs.blob.h_addrtype and (not sockaddr[0] in qs.blob.h_addr_list):
  237. qs.blob.h_addr_list.append(sockaddr[0])
  238. qs.cs_addrs.append(ai)
  239. self.response = qs.serialize()
  240. if len(self.response) <= buffer_size:
  241. self._send_reply(12, 0, 0, len(self.response))
  242. self.socket.sendall(self.response)
  243. else:
  244. self._send_reply(12, 0, WSAEFAULT, len(self.response))
  245. def _send_reply(self, msg_type, qvalue, dvalue1, dvalue2):
  246. buf = struct.pack("<BBxxQII", 1, msg_type, qvalue, dvalue1, dvalue2)
  247. self.socket.sendall(buf)
  248. class ConnectionSession:
  249. def __init__(self, s, pr):
  250. self.socket = s
  251. self.pr = pr
  252. self.ext_socket = None
  253. self.ip = [self.socket, self.pr]
  254. def run(self):
  255. logger.info("starting connection session")
  256. self._initialize_connection()
  257. self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 0)
  258. while True:
  259. rfds, wfds, xfds = select.select([self.socket, self.ext_socket, self.pr], [], [])
  260. for fd in rfds:
  261. if fd == self.socket:
  262. other_fd = self.ext_socket
  263. elif fd == self.ext_socket:
  264. other_fd = self.socket
  265. else:
  266. logger.info("ConnectionSession: quitting")
  267. dump=os.read(self.pr,4)
  268. return
  269. try:
  270. buf = fd.recv(2048)
  271. if len(buf) == 0:
  272. logger.info("ConnectionSession - zero bytes received - exitting")
  273. return
  274. other_fd.sendall(buf)
  275. except Exception,e:
  276. logger.info("ConnectionSession - exception in socket processing :%s" % e)
  277. return
  278. def _initialize_connection(self):
  279. irdy,ordy,xptrdy = select.select(self.ip,[],[])
  280. for s in irdy:
  281. if s==self.socket:
  282. buf = self.socket.recv(36, socket.MSG_WAITALL)
  283. if len(buf) != 36:
  284. if len(buf) != 0:
  285. logger.error("ConnectionSession: read %d bytes, expected %d" % (len(buf), 36))
  286. return
  287. else:
  288. logger.info("ConnectionSession: quitting initialize connection")
  289. dump=os.read(self.pr,4)
  290. return
  291. family = struct.unpack("<L", buf[2:6])[0]
  292. if family != socket.AF_INET:
  293. raise NotImplementedError("Unhandled family %d" % family)
  294. port = struct.unpack(">H", buf[10:12])[0]
  295. addr = socket.inet_ntoa(buf[12:16])
  296. logger.debug("Connecting to %s:%s" % (addr, port))
  297. ext_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  298. errno = ext_socket.connect_ex((addr, port))
  299. local_addr, local_port = ext_socket.getsockname()
  300. if errno == 0:
  301. msg_type = 0x5A
  302. else:
  303. msg_type = 0x5B
  304. head = struct.pack("<BBLxxxx", 1, msg_type, family)
  305. body = struct.pack(">H", local_port)
  306. body += socket.inet_aton(local_addr)
  307. body += struct.pack("xxxxxxxxxxxxxxxx")
  308. tail = struct.pack("<L", errno) # FIXME: translate errno to WSAError
  309. reply = head + body + tail
  310. self.socket.sendall(reply)
  311. self.ext_socket = ext_socket
  312. class RPCStream:
  313. def __init__(self, data=""):
  314. self.initialize(data)
  315. def initialize(self, data):
  316. self._data = data
  317. self._offset = 0
  318. def get_data(self):
  319. return self._data
  320. def get_offset(self):
  321. return self._offset
  322. def get_length(self):
  323. return len(self._data)
  324. def read_dword(self):
  325. dw = struct.unpack("<I", self._data[self._offset:self._offset + 4])[0]
  326. self._offset += 4
  327. return dw
  328. def write_dword(self, dw):
  329. self._data += struct.pack("<I", dw)
  330. def read_n_bytes(self, n):
  331. buf = self._data[self._offset:self._offset + n]
  332. if len(buf) % 4 != 0:
  333. align = 4 - (len(buf) % 4)
  334. else:
  335. align = 0
  336. self._offset += n + align
  337. return buf
  338. def write_bytes(self, data):
  339. self._data += data
  340. if len(data) % 4 != 0:
  341. align = 4 - (len(data) % 4)
  342. for i in xrange(align):
  343. self._data += "\x00"
  344. def read_field(self, expected_size=-1):
  345. size = self.read_dword()
  346. if size == 0:
  347. return None
  348. data = self.read_n_bytes(size)
  349. if expected_size != -1 and len(data) != expected_size:
  350. raise ValueError("expected_size=%d, size=%d" % (expected_size, len(data)))
  351. return data
  352. def write_field(self, data):
  353. self.write_dword(len(data))
  354. self.write_bytes(data)
  355. def read_string(self):
  356. s = self.read_field()
  357. if s == None:
  358. return s
  359. return s.decode("utf_16_le").rstrip("\0")
  360. def write_string(self, s):
  361. if s != None:
  362. self.write_field(s.encode("utf_16_le") + "\x00\x00")
  363. else:
  364. self.write_dword(0)
  365. def read_guid(self):
  366. data = self.read_field(16)
  367. if data == None:
  368. return data
  369. v1, v2, v3 = struct.unpack("<LHH", data[0:8])
  370. return "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}" % \
  371. (v1, v2, v3, ord(data[8]), ord(data[9]), ord(data[10]),
  372. ord(data[11]), ord(data[12]), ord(data[13]), ord(data[14]),
  373. ord(data[15]))
  374. def write_guid(self, guid):
  375. if guid != None:
  376. data = struct.pack("<LHHBBBBBBBB",
  377. int(guid[1:9], 16), int(guid[10:14], 16),
  378. int(guid[15:19], 16), int(guid[20:22], 16),
  379. int(guid[22:24], 16), int(guid[25:27], 16),
  380. int(guid[27:29], 16), int(guid[29:31], 16),
  381. int(guid[31:33], 16), int(guid[33:35], 16),
  382. int(guid[35:37], 16))
  383. self.write_field(data)
  384. else:
  385. self.write_dword(0)
  386. class QuerySet:
  387. def __init__(self):
  388. self.service_instance_name = None
  389. self.service_class_id = None
  390. self.version = 0
  391. self.comment = None
  392. self.namespace = None
  393. self.ns_provider_id = None
  394. self.context = None
  395. self.num_protocols = 0
  396. self.query_string = None
  397. self.cs_addrs = []
  398. self.output_flags = 0
  399. self.blob = None
  400. self.blob_size = 0
  401. def unserialize(self, data):
  402. s = RPCStream(data)
  403. raw_flat = s.read_field(60)
  404. size = struct.unpack("<I", raw_flat[0:4])[0]
  405. assert size == 60
  406. self.service_instance_name = s.read_string()
  407. self.service_class_id = s.read_guid()
  408. self.version = struct.unpack("<L", raw_flat[12:16])[0]
  409. self.comment = s.read_string()
  410. self.namespace = struct.unpack("<L", raw_flat[20:24])[0]
  411. self.ns_provider_id = s.read_guid()
  412. self.context = s.read_string()
  413. self.num_protocols = s.read_dword()
  414. if self.num_protocols > 0:
  415. self.len_protocols = s.read_dword()
  416. for p in range(0,self.num_protocols):
  417. iAddressFamily = s.read_dword()
  418. iProtocol = s.read_dword()
  419. # Forget it.
  420. self.num_protocols = 0
  421. self.query_string = s.read_string()
  422. self.cs_addrs = []
  423. count = s.read_dword()
  424. if count > 0:
  425. data = s.read_field(count * 24)
  426. offset = 0
  427. for i in xrange(len(data) / 24):
  428. local_data = s.read_field()
  429. remote_data = s.read_field()
  430. ai = CSAddrInfo()
  431. ai.unserialize(data[offset:offset + 24], local_data, remote_data)
  432. self.cs_addrs.append(ai)
  433. offset += 24
  434. self.output_flags = struct.unpack("<L", raw_flat[52:56])[0]
  435. self.blob_size = s.read_dword()
  436. assert s.get_offset() == s.get_length()
  437. def serialize(self):
  438. s = RPCStream()
  439. if self.service_instance_name != None:
  440. svc_name_ptr = DUMMY_PTR
  441. else:
  442. svc_name_ptr = 0
  443. if self.service_class_id != None:
  444. svc_cls_id_ptr = DUMMY_PTR
  445. else:
  446. svc_cls_id_ptr = 0
  447. if self.comment != None:
  448. comment_ptr = DUMMY_PTR
  449. else:
  450. comment_ptr = 0
  451. if self.ns_provider_id != None:
  452. ns_provider_id_ptr = DUMMY_PTR
  453. else:
  454. ns_provider_id_ptr = 0
  455. if self.context != None:
  456. context_ptr = DUMMY_PTR
  457. else:
  458. context_ptr = 0
  459. if self.num_protocols > 0:
  460. protocols_ptr = DUMMY_PTR
  461. else:
  462. protocols_ptr = 0
  463. if self.query_string != None:
  464. query_string_ptr = DUMMY_PTR
  465. else:
  466. query_string_ptr = 0
  467. if len(self.cs_addrs) > 0:
  468. cs_addrs_ptr = DUMMY_PTR
  469. else:
  470. cs_addrs_ptr = 0
  471. if self.blob != None:
  472. blob_ptr = DUMMY_PTR
  473. else:
  474. blob_ptr = 0
  475. buf = struct.pack("<LLLLLLLLLLLLLLL",
  476. 60,
  477. svc_name_ptr,
  478. svc_cls_id_ptr,
  479. self.version,
  480. comment_ptr,
  481. self.namespace,
  482. ns_provider_id_ptr,
  483. context_ptr,
  484. self.num_protocols,
  485. protocols_ptr,
  486. query_string_ptr,
  487. len(self.cs_addrs),
  488. cs_addrs_ptr,
  489. self.output_flags,
  490. blob_ptr)
  491. s.write_field(buf)
  492. s.write_string(self.service_instance_name)
  493. s.write_guid(self.service_class_id)
  494. s.write_string(self.comment)
  495. s.write_guid(self.ns_provider_id)
  496. s.write_string(self.context)
  497. s.write_dword(0) # FIXME: WSAQUERYSET.dwNumberOfProtocols
  498. s.write_string(self.query_string)
  499. s.write_dword(len(self.cs_addrs))
  500. buf = ""
  501. addrs = []
  502. for addr in self.cs_addrs:
  503. data, local_data, remote_data = addr.serialize()
  504. buf += data
  505. addrs.append(local_data)
  506. addrs.append(remote_data)
  507. s.write_field(buf)
  508. for addr in addrs:
  509. s.write_field(addr)
  510. if self.blob != None:
  511. blob_data = self.blob.serialize()
  512. s.write_dword(8)
  513. s.write_dword(len(blob_data))
  514. s.write_dword(DUMMY_PTR)
  515. s.write_field(blob_data)
  516. else:
  517. s.write_dword(0)
  518. return s.get_data()
  519. def __str__(self):
  520. addrs = ""
  521. for addr in self.cs_addrs:
  522. addrs += "\n %s" % str(addr)
  523. body_templ = """<QuerySet>
  524. <ServiceInstanceName>%s</ServiceInstanceName>
  525. <ServiceClassId>%s</ServiceClassId>
  526. <Version>0x%08x</Version>
  527. <Comment>%s</Comment>
  528. <NameSpace>%s</NameSpace>
  529. <NSProviderId>%s</NSProviderId>
  530. <Context>%s</Context>
  531. <Protocols/>
  532. <QueryString>%s</QueryString>
  533. <CsAddrs>%s</CsAddrs>
  534. <OutputFlags>0x%08x</OutputFlags>
  535. <Blob/>
  536. </QuerySet>"""
  537. return body_templ % (self.service_instance_name, self.service_class_id,
  538. self.version, self.comment, self.namespace,
  539. self.ns_provider_id, self.context, self.query_string,
  540. addrs, self.output_flags)
  541. class Hostent:
  542. def __init__(self, family=socket.AF_INET):
  543. self.h_name = "";
  544. self.h_aliases = []
  545. self.h_addrtype = family
  546. if self.h_addrtype == socket.AF_INET:
  547. self.h_length = 4
  548. elif self.h_addrtype == socket.AF_INET6:
  549. self.h_length = 16
  550. else:
  551. raise NotImplementedError("Unhandled family %d" % family)
  552. self.h_addr_list = []
  553. def serialize(self):
  554. # Base index: after the structure itself.
  555. pos = 16
  556. # Encode h_aliases.
  557. h_aliases_index = pos
  558. h_aliases_length = len(self.h_aliases) + 1
  559. h_aliases_bin_list = ""
  560. h_aliases_bin_data = ""
  561. pos += 4 * h_aliases_length
  562. for alias in self.h_aliases:
  563. h_aliases_bin_list += struct.pack("<L", pos)
  564. alias_bin = alias.encode("ascii") + "\x00"
  565. pos += len(alias_bin)
  566. h_aliases_bin_data += alias_bin
  567. h_aliases_bin_list += struct.pack("<L", 0)
  568. # Encode h_addr_list.
  569. h_addr_list_index = pos
  570. h_addr_list_length = len(self.h_addr_list) + 1
  571. h_addr_list_bin_list = ""
  572. h_addr_list_bin_data = ""
  573. pos += 4 * h_addr_list_length
  574. for addr in self.h_addr_list:
  575. h_addr_list_bin_list += struct.pack("<L", pos)
  576. addr_bin = socket.inet_pton(self.h_addrtype, addr)
  577. pos += len(addr_bin)
  578. h_addr_list_bin_data += addr_bin
  579. h_addr_list_bin_list += struct.pack("<L", 0)
  580. # Encode h_name.
  581. h_name_index = pos
  582. h_name_bin = self.h_name.encode("ascii") + "\x00"
  583. pos += len(h_name_bin)
  584. # Put everything together.
  585. s = struct.pack("<L", h_name_index)
  586. s += struct.pack("<L", h_aliases_index)
  587. s += struct.pack("<H", self.h_addrtype)
  588. s += struct.pack("<H", self.h_length)
  589. s += struct.pack("<L", h_addr_list_index)
  590. s += h_aliases_bin_list
  591. s += h_aliases_bin_data
  592. s += h_addr_list_bin_list
  593. s += h_addr_list_bin_data
  594. s += h_name_bin
  595. return s
  596. class CSAddrInfo:
  597. def __init__(self):
  598. self.local_addr = None
  599. self.remote_addr = None
  600. self.socket_type = -1
  601. self.protocol = -1
  602. def unserialize(self, data, local_data, remote_data):
  603. self.socket_type, self.protocol = struct.unpack("<LL", data[16:24])
  604. self.local_addr = self._unserialize_sockaddr(local_data)
  605. self.remote_addr = self._unserialize_sockaddr(remote_data)
  606. def serialize(self):
  607. local_data = self._serialize_sockaddr(self.local_addr)
  608. remote_data = self._serialize_sockaddr(self.remote_addr)
  609. if self.local_addr != None:
  610. local_addr_ptr = DUMMY_PTR
  611. else:
  612. local_addr_ptr = 0
  613. if self.remote_addr != None:
  614. remote_addr_ptr = DUMMY_PTR
  615. else:
  616. remote_addr_ptr = 0
  617. return (struct.pack("<LLLLLL", local_addr_ptr, len(local_data),
  618. remote_addr_ptr, len(remote_data),
  619. self.socket_type, self.protocol),
  620. local_data, remote_data)
  621. def _unserialize_sockaddr(self, data):
  622. family = struct.unpack("<H", data[0:2])[0]
  623. if family == socket.AF_INET:
  624. port = struct.unpack(">H", data[2:4])[0]
  625. return (family, socket.inet_ntoa(data[4:8]), port)
  626. else:
  627. raise NotImplementedError("Unhandled family %d" % family)
  628. def _serialize_sockaddr(self, addr):
  629. if addr == None:
  630. return None
  631. family, ascii_addr, port = addr
  632. s = struct.pack("<H", family)
  633. s += struct.pack(">H", port)
  634. if family == socket.AF_INET:
  635. s += socket.inet_aton(ascii_addr)
  636. s += "\x00\x00\x00\x00\x00\x00\x00\x00"
  637. elif family == socket.AF_INET6:
  638. s += socket.inet_pton(family, ascii_addr)
  639. s += "\x00\x00\x00\x00\x00\x00\x00\x00"
  640. else:
  641. raise NotImplementedError("Unhandled family %d" % family)
  642. return s
  643. def __str__(self):
  644. return "<CSAddrInfo><LocalAddress>%s</LocalAddress><RemoteAddress>%s</RemoteAddress><SocketType>%d</SocketType><Protocol>%d</Protocol></CSAddrInfo>" % \
  645. (self.local_addr, self.remote_addr, self.socket_type, self.protocol)