blob: 90a93f30ec9284cb446955b7143b020351f0f0ac [file] [log] [blame]
Mark Slee89e2bb82007-03-01 00:20:36 +00001# Copyright (c) 2006- Facebook
2# Distributed under the Thrift Software License
3#
4# See accompanying file LICENSE or visit the Thrift site at:
5# http://developers.facebook.com/thrift/
6
Mark Sleecde2b612006-09-03 21:13:07 +00007from TTransport import *
David Reisse29995e2008-07-31 20:15:17 +00008import os
9import errno
Mark Sleecde2b612006-09-03 21:13:07 +000010import socket
11
David Reisse29995e2008-07-31 20:15:17 +000012class TSocketBase(TTransportBase):
13 def _resolveAddr(self):
14 if self._unix_socket is not None:
15 return [(socket.AF_UNIX, socket.SOCK_STREAM, None, None, self._unix_socket)]
16 else:
17 return socket.getaddrinfo(self.host, self.port, socket.AF_UNSPEC, socket.SOCK_STREAM, 0, socket.AI_PASSIVE | socket.AI_ADDRCONFIG)
Mark Sleecde2b612006-09-03 21:13:07 +000018
David Reisse29995e2008-07-31 20:15:17 +000019 def close(self):
20 if self.handle:
21 self.handle.close()
22 self.handle = None
23
24class TSocket(TSocketBase):
Mark Sleecde2b612006-09-03 21:13:07 +000025 """Socket implementation of TTransport base."""
26
David Reissc16a8f62007-12-14 23:46:47 +000027 def __init__(self, host='localhost', port=9090, unix_socket=None):
28 """Initialize a TSocket
29
30 @param host(str) The host to connect to.
31 @param port(int) The (TCP) port to connect to.
32 @param unix_socket(str) The filename of a unix socket to connect to.
33 (host and port will be ignored.)
34 """
35
Mark Sleecde2b612006-09-03 21:13:07 +000036 self.host = host
Aditya Agarwal9bae5e72007-02-07 02:36:56 +000037 self.port = port
Mark Sleecde2b612006-09-03 21:13:07 +000038 self.handle = None
David Reissc16a8f62007-12-14 23:46:47 +000039 self._unix_socket = unix_socket
40 self._timeout = None
David Reiss0c90f6f2008-02-06 22:18:40 +000041
Mark Slee4f0fed62006-10-02 17:50:08 +000042 def setHandle(self, h):
Mark Sleec9676562006-09-05 17:34:52 +000043 self.handle = h
44
Mark Sleecde2b612006-09-03 21:13:07 +000045 def isOpen(self):
Aditya Agarwalf954f972007-02-06 01:26:12 +000046 return self.handle != None
47
48 def setTimeout(self, ms):
David Reissc16a8f62007-12-14 23:46:47 +000049 if ms is None:
50 self._timeout = None
James Wange168d5e2007-07-24 23:59:51 +000051 else:
David Reissc16a8f62007-12-14 23:46:47 +000052 self._timeout = ms/1000.0
David Reiss0c90f6f2008-02-06 22:18:40 +000053
David Reissc16a8f62007-12-14 23:46:47 +000054 if (self.handle != None):
55 self.handle.settimeout(self._timeout)
Mark Sleecde2b612006-09-03 21:13:07 +000056
57 def open(self):
Mark Slee92195ae2007-02-21 05:16:30 +000058 try:
David Reissc16a8f62007-12-14 23:46:47 +000059 res0 = self._resolveAddr()
Mark Slee22974602007-07-06 22:20:19 +000060 for res in res0:
61 self.handle = socket.socket(res[0], res[1])
David Reissc16a8f62007-12-14 23:46:47 +000062 self.handle.settimeout(self._timeout)
Mark Slee22974602007-07-06 22:20:19 +000063 try:
64 self.handle.connect(res[4])
65 except socket.error, e:
66 if res is not res0[-1]:
67 continue
68 else:
69 raise e
70 break
Mark Slee92195ae2007-02-21 05:16:30 +000071 except socket.error, e:
David Reisse29995e2008-07-31 20:15:17 +000072 if self._unix_socket:
73 message = 'Could not connect to socket %s' % self._unix_socket
74 else:
75 message = 'Could not connect to %s:%d' % (self.host, self.port)
76 raise TTransportException(TTransportException.NOT_OPEN, message)
Mark Sleecde2b612006-09-03 21:13:07 +000077
Mark Sleecde2b612006-09-03 21:13:07 +000078 def read(self, sz):
79 buff = self.handle.recv(sz)
Mark Sleec9676562006-09-05 17:34:52 +000080 if len(buff) == 0:
Mark Slee4f0fed62006-10-02 17:50:08 +000081 raise TTransportException('TSocket read 0 bytes')
Mark Sleecde2b612006-09-03 21:13:07 +000082 return buff
83
84 def write(self, buff):
Mark Sleec9676562006-09-05 17:34:52 +000085 sent = 0
86 have = len(buff)
87 while sent < have:
88 plus = self.handle.send(buff)
89 if plus == 0:
Mark Slee92195ae2007-02-21 05:16:30 +000090 raise TTransportException('TSocket sent 0 bytes')
Mark Sleec9676562006-09-05 17:34:52 +000091 sent += plus
92 buff = buff[plus:]
Mark Sleecde2b612006-09-03 21:13:07 +000093
94 def flush(self):
95 pass
Mark Sleec9676562006-09-05 17:34:52 +000096
David Reissd73255d2009-03-24 22:51:02 +000097class TServerSocket(TSocketBase, TServerTransportBase):
Mark Sleec9676562006-09-05 17:34:52 +000098 """Socket implementation of TServerTransport base."""
99
David Reisse29995e2008-07-31 20:15:17 +0000100 def __init__(self, port=9090, unix_socket=None):
101 self.host = None
Mark Sleec9676562006-09-05 17:34:52 +0000102 self.port = port
David Reisse29995e2008-07-31 20:15:17 +0000103 self._unix_socket = unix_socket
Mark Sleec9676562006-09-05 17:34:52 +0000104 self.handle = None
Mark Slee256bdc42007-11-27 08:42:19 +0000105
Mark Sleec9676562006-09-05 17:34:52 +0000106 def listen(self):
David Reisse29995e2008-07-31 20:15:17 +0000107 res0 = self._resolveAddr()
Mark Slee22974602007-07-06 22:20:19 +0000108 for res in res0:
109 if res[0] is socket.AF_INET6 or res is res0[-1]:
110 break
111
David Reisse29995e2008-07-31 20:15:17 +0000112 # We need remove the old unix socket if the file exists and
113 # nobody is listening on it.
114 if self._unix_socket:
115 tmp = socket.socket(res[0], res[1])
116 try:
117 tmp.connect(res[4])
118 except socket.error, err:
119 eno, message = err.args
120 if eno == errno.ECONNREFUSED:
121 os.unlink(res[4])
122
Mark Slee22974602007-07-06 22:20:19 +0000123 self.handle = socket.socket(res[0], res[1])
Mark Slee4f0fed62006-10-02 17:50:08 +0000124 self.handle.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
125 if hasattr(self.handle, 'set_timeout'):
126 self.handle.set_timeout(None)
Mark Slee22974602007-07-06 22:20:19 +0000127 self.handle.bind(res[4])
Mark Sleec9676562006-09-05 17:34:52 +0000128 self.handle.listen(128)
129
130 def accept(self):
David Reisse29995e2008-07-31 20:15:17 +0000131 client, addr = self.handle.accept()
Mark Sleec9676562006-09-05 17:34:52 +0000132 result = TSocket()
Mark Slee4f0fed62006-10-02 17:50:08 +0000133 result.setHandle(client)
Mark Sleec9676562006-09-05 17:34:52 +0000134 return result