SF patch 555085 (timeout socket implementation) by Michael Gilfix.
I've made considerable changes to Michael's code, specifically to use the select() system call directly and to store the timeout as a C double instead of a Python object; internally, -1.0 (or anything negative) represents the None from the API. I'm not 100% sure that all corner cases are covered correctly, so please keep an eye on this. Next I'm going to try it Windows before Tim complains. No way is this a bugfix candidate. :-)
This commit is contained in:
parent
c9a55776c8
commit
67f7a38849
131
Lib/socket.py
131
Lib/socket.py
|
@ -134,7 +134,8 @@ def getfqdn(name=''):
|
||||||
_socketmethods = (
|
_socketmethods = (
|
||||||
'bind', 'connect', 'connect_ex', 'fileno', 'listen',
|
'bind', 'connect', 'connect_ex', 'fileno', 'listen',
|
||||||
'getpeername', 'getsockname', 'getsockopt', 'setsockopt',
|
'getpeername', 'getsockname', 'getsockopt', 'setsockopt',
|
||||||
'recv', 'recvfrom', 'send', 'sendall', 'sendto', 'setblocking', 'shutdown')
|
'recv', 'recvfrom', 'send', 'sendall', 'sendto', 'setblocking',
|
||||||
|
'settimeout', 'gettimeout', 'shutdown')
|
||||||
|
|
||||||
class _socketobject:
|
class _socketobject:
|
||||||
|
|
||||||
|
@ -168,94 +169,108 @@ class _socketobject:
|
||||||
|
|
||||||
|
|
||||||
class _fileobject:
|
class _fileobject:
|
||||||
|
"""Implements a file object on top of a regular socket object."""
|
||||||
|
|
||||||
def __init__(self, sock, mode, bufsize):
|
def __init__(self, sock, mode='rb', bufsize=8192):
|
||||||
self._sock = sock
|
self._sock = sock
|
||||||
self._mode = mode
|
self._mode = mode
|
||||||
if bufsize < 0:
|
if bufsize <= 0:
|
||||||
bufsize = 512
|
bufsize = 512
|
||||||
self._rbufsize = max(1, bufsize)
|
self._rbufsize = bufsize
|
||||||
self._wbufsize = bufsize
|
self._wbufsize = bufsize
|
||||||
self._wbuf = self._rbuf = ""
|
self._rbuf = [ ]
|
||||||
|
self._wbuf = [ ]
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
try:
|
try:
|
||||||
if self._sock:
|
if self._sock:
|
||||||
self.flush()
|
self.flush()
|
||||||
finally:
|
finally:
|
||||||
self._sock = 0
|
self._sock = None
|
||||||
|
|
||||||
def __del__(self):
|
def __del__(self):
|
||||||
self.close()
|
self.close()
|
||||||
|
|
||||||
def flush(self):
|
def flush(self):
|
||||||
if self._wbuf:
|
if self._wbuf:
|
||||||
self._sock.sendall(self._wbuf)
|
buffer = ''.join(self._wbuf)
|
||||||
self._wbuf = ""
|
self._sock.sendall(buffer)
|
||||||
|
self._wbuf = [ ]
|
||||||
|
|
||||||
def fileno(self):
|
def fileno (self):
|
||||||
return self._sock.fileno()
|
return self._sock.fileno()
|
||||||
|
|
||||||
def write(self, data):
|
def write(self, data):
|
||||||
self._wbuf = self._wbuf + data
|
self._wbuf.append (data)
|
||||||
|
# A _wbufsize of 1 means we're doing unbuffered IO.
|
||||||
|
# Flush accordingly.
|
||||||
if self._wbufsize == 1:
|
if self._wbufsize == 1:
|
||||||
if '\n' in data:
|
if '\n' in data:
|
||||||
self.flush()
|
self.flush ()
|
||||||
else:
|
elif self.__get_wbuf_len() >= self._wbufsize:
|
||||||
if len(self._wbuf) >= self._wbufsize:
|
self.flush()
|
||||||
self.flush()
|
|
||||||
|
|
||||||
def writelines(self, list):
|
def writelines(self, list):
|
||||||
filter(self._sock.sendall, list)
|
filter(self._sock.sendall, list)
|
||||||
self.flush()
|
self.flush()
|
||||||
|
|
||||||
def read(self, n=-1):
|
def __get_wbuf_len (self):
|
||||||
if n >= 0:
|
buf_len = 0
|
||||||
k = len(self._rbuf)
|
for i in [len(x) for x in self._wbuf]:
|
||||||
if n <= k:
|
buf_len += i
|
||||||
data = self._rbuf[:n]
|
return buf_len
|
||||||
self._rbuf = self._rbuf[n:]
|
|
||||||
return data
|
|
||||||
n = n - k
|
|
||||||
L = [self._rbuf]
|
|
||||||
self._rbuf = ""
|
|
||||||
while n > 0:
|
|
||||||
new = self._sock.recv(max(n, self._rbufsize))
|
|
||||||
if not new: break
|
|
||||||
k = len(new)
|
|
||||||
if k > n:
|
|
||||||
L.append(new[:n])
|
|
||||||
self._rbuf = new[n:]
|
|
||||||
break
|
|
||||||
L.append(new)
|
|
||||||
n = n - k
|
|
||||||
return "".join(L)
|
|
||||||
k = max(512, self._rbufsize)
|
|
||||||
L = [self._rbuf]
|
|
||||||
self._rbuf = ""
|
|
||||||
while 1:
|
|
||||||
new = self._sock.recv(k)
|
|
||||||
if not new: break
|
|
||||||
L.append(new)
|
|
||||||
k = min(k*2, 1024**2)
|
|
||||||
return "".join(L)
|
|
||||||
|
|
||||||
def readline(self, limit=-1):
|
def __get_rbuf_len(self):
|
||||||
data = ""
|
buf_len = 0
|
||||||
i = self._rbuf.find('\n')
|
for i in [len(x) for x in self._rbuf]:
|
||||||
while i < 0 and not (0 < limit <= len(self._rbuf)):
|
buf_len += i
|
||||||
new = self._sock.recv(self._rbufsize)
|
return buf_len
|
||||||
if not new: break
|
|
||||||
i = new.find('\n')
|
def read(self, size=-1):
|
||||||
if i >= 0: i = i + len(self._rbuf)
|
buf_len = self.__get_rbuf_len()
|
||||||
self._rbuf = self._rbuf + new
|
while size < 0 or buf_len < size:
|
||||||
if i < 0: i = len(self._rbuf)
|
recv_size = max(self._rbufsize, size - buf_len)
|
||||||
else: i = i+1
|
data = self._sock.recv(recv_size)
|
||||||
if 0 <= limit < len(self._rbuf): i = limit
|
if not data:
|
||||||
data, self._rbuf = self._rbuf[:i], self._rbuf[i:]
|
break
|
||||||
|
buf_len += len(data)
|
||||||
|
self._rbuf.append(data)
|
||||||
|
data = ''.join(self._rbuf)
|
||||||
|
# Clear the rbuf at the end so we're not affected by
|
||||||
|
# an exception during a recv
|
||||||
|
self._rbuf = [ ]
|
||||||
|
if buf_len > size and size >= 0:
|
||||||
|
self._rbuf.append(data[size:])
|
||||||
|
data = data[:size]
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def readlines(self, sizehint = 0):
|
def readline(self, size=-1):
|
||||||
|
index = -1
|
||||||
|
buf_len = self.__get_rbuf_len()
|
||||||
|
if len (self._rbuf):
|
||||||
|
index = min([x.find('\n') for x in self._rbuf])
|
||||||
|
while index < 0 and (size < 0 or buf_len < size):
|
||||||
|
recv_size = max(self._rbufsize, size - buf_len)
|
||||||
|
data = self._sock.recv(recv_size)
|
||||||
|
if not data:
|
||||||
|
break
|
||||||
|
buf_len += len(data)
|
||||||
|
self._rbuf.append(data)
|
||||||
|
index = data.find('\n')
|
||||||
|
data = ''.join(self._rbuf)
|
||||||
|
self._rbuf = [ ]
|
||||||
|
index = data.find('\n')
|
||||||
|
if index >= 0:
|
||||||
|
index += 1
|
||||||
|
elif buf_len > size:
|
||||||
|
index = size
|
||||||
|
else:
|
||||||
|
index = buf_len
|
||||||
|
self._rbuf.append(data[index:])
|
||||||
|
data = data[:index]
|
||||||
|
return data
|
||||||
|
|
||||||
|
def readlines(self, sizehint=0):
|
||||||
total = 0
|
total = 0
|
||||||
list = []
|
list = []
|
||||||
while 1:
|
while 1:
|
||||||
|
|
|
@ -109,6 +109,7 @@ except socket.error:
|
||||||
canfork = hasattr(os, 'fork')
|
canfork = hasattr(os, 'fork')
|
||||||
try:
|
try:
|
||||||
PORT = 50007
|
PORT = 50007
|
||||||
|
msg = 'socket test\n'
|
||||||
if not canfork or os.fork():
|
if not canfork or os.fork():
|
||||||
# parent is server
|
# parent is server
|
||||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
@ -133,13 +134,52 @@ try:
|
||||||
f = conn.makefile()
|
f = conn.makefile()
|
||||||
if verbose:
|
if verbose:
|
||||||
print 'file obj:', f
|
print 'file obj:', f
|
||||||
|
data = conn.recv(1024)
|
||||||
|
if verbose:
|
||||||
|
print 'received:', data
|
||||||
|
conn.sendall(data)
|
||||||
|
|
||||||
|
# Perform a few tests on the windows file object
|
||||||
|
if verbose:
|
||||||
|
print "Staring _fileobject tests..."
|
||||||
|
f = socket._fileobject (conn, 'rb', 8192)
|
||||||
|
first_seg = f.read(7)
|
||||||
|
second_seg = f.read(5)
|
||||||
|
if not first_seg == 'socket ' or not second_seg == 'test\n':
|
||||||
|
print "Error performing read with the python _fileobject class"
|
||||||
|
os._exit (1)
|
||||||
|
elif verbose:
|
||||||
|
print "_fileobject buffered read works"
|
||||||
|
f.write (data)
|
||||||
|
f.flush ()
|
||||||
|
|
||||||
|
buf = ''
|
||||||
while 1:
|
while 1:
|
||||||
data = conn.recv(1024)
|
char = f.read(1)
|
||||||
if not data:
|
if not char:
|
||||||
|
print "Error performing unbuffered read with the python ", \
|
||||||
|
"_fileobject class"
|
||||||
|
os._exit (1)
|
||||||
|
buf += char
|
||||||
|
if buf == msg:
|
||||||
|
if verbose:
|
||||||
|
print "__fileobject unbuffered read works"
|
||||||
break
|
break
|
||||||
if verbose:
|
if verbose:
|
||||||
print 'received:', data
|
# If we got this far, write() must work as well
|
||||||
conn.sendall(data)
|
print "__fileobject write works"
|
||||||
|
f.write(buf)
|
||||||
|
f.flush()
|
||||||
|
|
||||||
|
line = f.readline()
|
||||||
|
if not line == msg:
|
||||||
|
print "Error perferming readline with the python _fileobject class"
|
||||||
|
os._exit (1)
|
||||||
|
f.write(line)
|
||||||
|
f.flush()
|
||||||
|
if verbose:
|
||||||
|
print "__fileobject readline works"
|
||||||
|
|
||||||
conn.close()
|
conn.close()
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
|
@ -149,11 +189,18 @@ try:
|
||||||
if verbose:
|
if verbose:
|
||||||
print 'child connecting'
|
print 'child connecting'
|
||||||
s.connect(("127.0.0.1", PORT))
|
s.connect(("127.0.0.1", PORT))
|
||||||
msg = 'socket test'
|
|
||||||
s.send(msg)
|
iteration = 0
|
||||||
data = s.recv(1024)
|
while 1:
|
||||||
if msg != data:
|
s.send(msg)
|
||||||
print 'parent/client mismatch'
|
data = s.recv(12)
|
||||||
|
if not data:
|
||||||
|
break
|
||||||
|
if msg != data:
|
||||||
|
print "parent/client mismatch. Failed in %s iteration. Received: [%s]" \
|
||||||
|
%(iteration, data)
|
||||||
|
time.sleep (1)
|
||||||
|
iteration += 1
|
||||||
s.close()
|
s.close()
|
||||||
finally:
|
finally:
|
||||||
os._exit(1)
|
os._exit(1)
|
||||||
|
|
|
@ -0,0 +1,136 @@
|
||||||
|
#!/home/bernie/src/python23/dist/src/python
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
import time
|
||||||
|
import socket
|
||||||
|
|
||||||
|
class creationTestCase(unittest.TestCase):
|
||||||
|
"""Test Case for socket.gettimeout() and socket.settimeout()"""
|
||||||
|
def setUp(self):
|
||||||
|
self.__s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
self.__s.close()
|
||||||
|
|
||||||
|
def testObjectCreation(self):
|
||||||
|
"Test Socket creation"
|
||||||
|
self.assertEqual(self.__s.gettimeout(), None,
|
||||||
|
"Timeout socket not default to disable (None)")
|
||||||
|
|
||||||
|
def testFloatReturnValue(self):
|
||||||
|
"Test return value of getter/setter"
|
||||||
|
self.__s.settimeout(7.345)
|
||||||
|
self.assertEqual(self.__s.gettimeout(), 7.345,
|
||||||
|
"settimeout() and gettimeout() return different result")
|
||||||
|
|
||||||
|
self.__s.settimeout(3)
|
||||||
|
self.assertEqual(self.__s.gettimeout(), 3,
|
||||||
|
"settimeout() and gettimeout() return different result")
|
||||||
|
|
||||||
|
def testReturnType(self):
|
||||||
|
"Test return type of getter/setter"
|
||||||
|
self.__s.settimeout(1)
|
||||||
|
self.assertEqual(type(self.__s.gettimeout()), type(1.0),
|
||||||
|
"return type of gettimeout() is not FloatType")
|
||||||
|
|
||||||
|
self.__s.settimeout(3.9)
|
||||||
|
self.assertEqual(type(self.__s.gettimeout()), type(1.0),
|
||||||
|
"return type of gettimeout() is not FloatType")
|
||||||
|
|
||||||
|
|
||||||
|
class timeoutTestCase(unittest.TestCase):
|
||||||
|
"""Test Case for socket.socket() timeout functions"""
|
||||||
|
def setUp(self):
|
||||||
|
self.__s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
self.__addr_remote = ('www.google.com', 80)
|
||||||
|
self.__addr_local = ('127.0.0.1', 25339)
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
self.__s.close()
|
||||||
|
|
||||||
|
def testConnectTimeout(self):
|
||||||
|
"Test connect() timeout"
|
||||||
|
_timeout = 0.02
|
||||||
|
self.__s.settimeout(_timeout)
|
||||||
|
|
||||||
|
_t1 = time.time()
|
||||||
|
self.failUnlessRaises(socket.error, self.__s.connect,
|
||||||
|
self.__addr_remote)
|
||||||
|
_t2 = time.time()
|
||||||
|
|
||||||
|
_delta = abs(_t1 - _t2)
|
||||||
|
self.assert_(_delta < _timeout + 0.5,
|
||||||
|
"timeout (%f) is 0.5 seconds more than required (%f)"
|
||||||
|
%(_delta, _timeout))
|
||||||
|
|
||||||
|
def testRecvTimeout(self):
|
||||||
|
"Test recv() timeout"
|
||||||
|
_timeout = 0.02
|
||||||
|
self.__s.connect(self.__addr_remote)
|
||||||
|
self.__s.settimeout(_timeout)
|
||||||
|
|
||||||
|
_t1 = time.time()
|
||||||
|
self.failUnlessRaises(socket.error, self.__s.recv, 1024)
|
||||||
|
_t2 = time.time()
|
||||||
|
|
||||||
|
_delta = abs(_t1 - _t2)
|
||||||
|
self.assert_(_delta < _timeout + 0.5,
|
||||||
|
"timeout (%f) is 0.5 seconds more than required (%f)"
|
||||||
|
%(_delta, _timeout))
|
||||||
|
|
||||||
|
def testAcceptTimeout(self):
|
||||||
|
"Test accept() timeout()"
|
||||||
|
_timeout = 2
|
||||||
|
self.__s.settimeout(_timeout)
|
||||||
|
self.__s.bind(self.__addr_local)
|
||||||
|
self.__s.listen(5)
|
||||||
|
|
||||||
|
_t1 = time.time()
|
||||||
|
self.failUnlessRaises(socket.error, self.__s.accept)
|
||||||
|
_t2 = time.time()
|
||||||
|
|
||||||
|
_delta = abs(_t1 - _t2)
|
||||||
|
self.assert_(_delta < _timeout + 0.5,
|
||||||
|
"timeout (%f) is 0.5 seconds more than required (%f)"
|
||||||
|
%(_delta, _timeout))
|
||||||
|
|
||||||
|
def testRecvfromTimeout(self):
|
||||||
|
"Test recvfrom() timeout()"
|
||||||
|
_timeout = 2
|
||||||
|
self.__s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||||
|
self.__s.settimeout(_timeout)
|
||||||
|
self.__s.bind(self.__addr_local)
|
||||||
|
|
||||||
|
_t1 = time.time()
|
||||||
|
self.failUnlessRaises(socket.error, self.__s.recvfrom, 8192)
|
||||||
|
_t2 = time.time()
|
||||||
|
|
||||||
|
_delta = abs(_t1 - _t2)
|
||||||
|
self.assert_(_delta < _timeout + 0.5,
|
||||||
|
"timeout (%f) is 0.5 seconds more than required (%f)"
|
||||||
|
%(_delta, _timeout))
|
||||||
|
|
||||||
|
def testSend(self):
|
||||||
|
"Test send() timeout"
|
||||||
|
# couldn't figure out how to test it
|
||||||
|
pass
|
||||||
|
|
||||||
|
def testSendto(self):
|
||||||
|
"Test sendto() timeout"
|
||||||
|
# couldn't figure out how to test it
|
||||||
|
pass
|
||||||
|
|
||||||
|
def testSendall(self):
|
||||||
|
"Test sendall() timeout"
|
||||||
|
# couldn't figure out how to test it
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def suite():
|
||||||
|
suite = unittest.TestSuite()
|
||||||
|
|
||||||
|
return suite
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
|
@ -66,6 +66,8 @@ Socket methods:
|
||||||
- s.sendall(string [,flags]) # tries to send everything in a loop
|
- s.sendall(string [,flags]) # tries to send everything in a loop
|
||||||
- s.sendto(string, [flags,] sockaddr) --> nbytes
|
- s.sendto(string, [flags,] sockaddr) --> nbytes
|
||||||
- s.setblocking(0 | 1) --> None
|
- s.setblocking(0 | 1) --> None
|
||||||
|
- s.settimeout(None | float) -> None # Argument in seconds
|
||||||
|
- s.gettimeout() -> None or float seconds
|
||||||
- s.setsockopt(level, optname, value) --> None
|
- s.setsockopt(level, optname, value) --> None
|
||||||
- s.shutdown(how) --> None
|
- s.shutdown(how) --> None
|
||||||
- repr(s) --> "<socket object, fd=%d, family=%d, type=%d, protocol=%d>"
|
- repr(s) --> "<socket object, fd=%d, family=%d, type=%d, protocol=%d>"
|
||||||
|
@ -421,6 +423,107 @@ PyGAI_Err(int error)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* For timeout errors */
|
||||||
|
static PyObject *
|
||||||
|
timeout_err(void)
|
||||||
|
{
|
||||||
|
PyObject *v;
|
||||||
|
|
||||||
|
#ifdef MS_WINDOWS
|
||||||
|
v = Py_BuildValue("(is)", WSAETIMEDOUT, "Socket operation timed out");
|
||||||
|
#else
|
||||||
|
v = Py_BuildValue("(is)", ETIMEDOUT, "Socket operation timed out");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (v != NULL) {
|
||||||
|
PyErr_SetObject(PySocket_Error, v);
|
||||||
|
Py_DECREF(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Function to perfrom the setting of socket blocking mode
|
||||||
|
* internally. block = (1 | 0).
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
internal_setblocking(PySocketSockObject *s, int block)
|
||||||
|
{
|
||||||
|
#ifndef RISCOS
|
||||||
|
#ifndef MS_WINDOWS
|
||||||
|
int delay_flag;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
|
#ifdef __BEOS__
|
||||||
|
block = !block;
|
||||||
|
setsockopt( s->sock_fd, SOL_SOCKET, SO_NONBLOCK,
|
||||||
|
(void *)(&block), sizeof(int));
|
||||||
|
#else
|
||||||
|
#ifndef RISCOS
|
||||||
|
#ifndef MS_WINDOWS
|
||||||
|
#if defined(PYOS_OS2) && !defined(PYCC_GCC)
|
||||||
|
block = !block;
|
||||||
|
ioctl(s->sock_fd, FIONBIO, (caddr_t)&block, sizeof(block));
|
||||||
|
#else /* !PYOS_OS2 */
|
||||||
|
delay_flag = fcntl(s->sock_fd, F_GETFL, 0);
|
||||||
|
if (block)
|
||||||
|
delay_flag &= (~O_NDELAY);
|
||||||
|
else
|
||||||
|
delay_flag |= O_NDELAY;
|
||||||
|
fcntl(s->sock_fd, F_SETFL, delay_flag);
|
||||||
|
#endif /* !PYOS_OS2 */
|
||||||
|
#else /* MS_WINDOWS */
|
||||||
|
block = !block;
|
||||||
|
ioctlsocket(s->sock_fd, FIONBIO, (u_long*)&block);
|
||||||
|
#endif /* MS_WINDOWS */
|
||||||
|
#endif /* __BEOS__ */
|
||||||
|
#endif /* RISCOS */
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
|
|
||||||
|
/* Since these don't return anything */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For access to the select module to poll the socket for timeout
|
||||||
|
* functionality. If reading is: 1 poll as read, 0, poll as write.
|
||||||
|
* Return value: -1 if error, 0 if not ready, >= 1 if ready.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
internal_select(PySocketSockObject *s, int reading)
|
||||||
|
{
|
||||||
|
fd_set fds;
|
||||||
|
struct timeval tv;
|
||||||
|
int count;
|
||||||
|
|
||||||
|
/* Construct the arguments to select */
|
||||||
|
tv.tv_sec = (int)s->sock_timeout;
|
||||||
|
tv.tv_usec = (int)(s->sock_timeout/1e6);
|
||||||
|
FD_ZERO(&fds);
|
||||||
|
FD_SET(s->sock_fd, &fds);
|
||||||
|
|
||||||
|
/* See if the socket is ready */
|
||||||
|
if (reading)
|
||||||
|
count = select(s->sock_fd, &fds, NULL, NULL, &tv);
|
||||||
|
else
|
||||||
|
count = select(s->sock_fd, NULL, &fds, NULL, &tv);
|
||||||
|
|
||||||
|
/* Check for errors */
|
||||||
|
if (count < 0) {
|
||||||
|
s->errorhandler();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the error if the timeout has elapsed, i.e, we were not
|
||||||
|
* polled.
|
||||||
|
*/
|
||||||
|
if (count == 0)
|
||||||
|
timeout_err();
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
/* Initialize a new socket object. */
|
/* Initialize a new socket object. */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -434,6 +537,9 @@ init_sockobject(PySocketSockObject *s,
|
||||||
s->sock_family = family;
|
s->sock_family = family;
|
||||||
s->sock_type = type;
|
s->sock_type = type;
|
||||||
s->sock_proto = proto;
|
s->sock_proto = proto;
|
||||||
|
s->sock_blocking = 1; /* Start in blocking mode */
|
||||||
|
s->sock_timeout = -1.0; /* Start without timeout */
|
||||||
|
|
||||||
s->errorhandler = &PySocket_Err;
|
s->errorhandler = &PySocket_Err;
|
||||||
#ifdef RISCOS
|
#ifdef RISCOS
|
||||||
if(taskwindow) {
|
if(taskwindow) {
|
||||||
|
@ -691,7 +797,7 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
|
||||||
struct sockaddr_un* addr;
|
struct sockaddr_un* addr;
|
||||||
char *path;
|
char *path;
|
||||||
int len;
|
int len;
|
||||||
addr = (struct sockaddr_un* )&(s->sock_addr).un;
|
addr = (struct sockaddr_un*)&(s->sock_addr).un;
|
||||||
if (!PyArg_Parse(args, "t#", &path, &len))
|
if (!PyArg_Parse(args, "t#", &path, &len))
|
||||||
return 0;
|
return 0;
|
||||||
if (len > sizeof addr->sun_path) {
|
if (len > sizeof addr->sun_path) {
|
||||||
|
@ -861,9 +967,47 @@ PySocketSock_accept(PySocketSockObject *s)
|
||||||
if (!getsockaddrlen(s, &addrlen))
|
if (!getsockaddrlen(s, &addrlen))
|
||||||
return NULL;
|
return NULL;
|
||||||
memset(addrbuf, 0, addrlen);
|
memset(addrbuf, 0, addrlen);
|
||||||
|
|
||||||
|
errno = 0; /* Reset indicator for use with timeout behavior */
|
||||||
|
|
||||||
Py_BEGIN_ALLOW_THREADS
|
Py_BEGIN_ALLOW_THREADS
|
||||||
newfd = accept(s->sock_fd, (struct sockaddr *) addrbuf, &addrlen);
|
newfd = accept(s->sock_fd, (struct sockaddr *) addrbuf, &addrlen);
|
||||||
Py_END_ALLOW_THREADS
|
Py_END_ALLOW_THREADS
|
||||||
|
|
||||||
|
if (s->sock_timeout >= 0.0) {
|
||||||
|
#ifdef MS_WINDOWS
|
||||||
|
if (newfd == INVALID_SOCKET)
|
||||||
|
if (!s->sock_blocking)
|
||||||
|
return s->errorhandler();
|
||||||
|
/* Check if we have a true failure
|
||||||
|
for a blocking socket */
|
||||||
|
if (errno != WSAEWOULDBLOCK)
|
||||||
|
return s->errorhandler();
|
||||||
|
#else
|
||||||
|
if (newfd < 0) {
|
||||||
|
if (!s->sock_blocking)
|
||||||
|
return s->errorhandler();
|
||||||
|
/* Check if we have a true failure
|
||||||
|
for a blocking socket */
|
||||||
|
if (errno != EAGAIN && errno != EWOULDBLOCK)
|
||||||
|
return s->errorhandler();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* try waiting the timeout period */
|
||||||
|
if (internal_select(s, 0) <= 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
|
newfd = accept(s->sock_fd,
|
||||||
|
(struct sockaddr *)addrbuf,
|
||||||
|
&addrlen);
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
|
}
|
||||||
|
|
||||||
|
/* At this point, we really have an error, whether using timeout
|
||||||
|
* behavior or regular socket behavior
|
||||||
|
*/
|
||||||
#ifdef MS_WINDOWS
|
#ifdef MS_WINDOWS
|
||||||
if (newfd == INVALID_SOCKET)
|
if (newfd == INVALID_SOCKET)
|
||||||
#else
|
#else
|
||||||
|
@ -877,18 +1021,19 @@ PySocketSock_accept(PySocketSockObject *s)
|
||||||
s->sock_family,
|
s->sock_family,
|
||||||
s->sock_type,
|
s->sock_type,
|
||||||
s->sock_proto);
|
s->sock_proto);
|
||||||
|
|
||||||
if (sock == NULL) {
|
if (sock == NULL) {
|
||||||
SOCKETCLOSE(newfd);
|
SOCKETCLOSE(newfd);
|
||||||
goto finally;
|
goto finally;
|
||||||
}
|
}
|
||||||
addr = makesockaddr(s->sock_fd, (struct sockaddr *)addrbuf,
|
addr = makesockaddr(s->sock_fd, (struct sockaddr *)addrbuf,
|
||||||
addrlen);
|
addrlen);
|
||||||
if (addr == NULL)
|
if (addr == NULL)
|
||||||
goto finally;
|
goto finally;
|
||||||
|
|
||||||
res = Py_BuildValue("OO", sock, addr);
|
res = Py_BuildValue("OO", sock, addr);
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
Py_XDECREF(sock);
|
Py_XDECREF(sock);
|
||||||
Py_XDECREF(addr);
|
Py_XDECREF(addr);
|
||||||
return res;
|
return res;
|
||||||
|
@ -901,47 +1046,24 @@ Wait for an incoming connection. Return a new socket representing the\n\
|
||||||
connection, and the address of the client. For IP sockets, the address\n\
|
connection, and the address of the client. For IP sockets, the address\n\
|
||||||
info is a pair (hostaddr, port).";
|
info is a pair (hostaddr, port).";
|
||||||
|
|
||||||
|
|
||||||
/* s.setblocking(1 | 0) method */
|
/* s.setblocking(1 | 0) method */
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
PySocketSock_setblocking(PySocketSockObject *s, PyObject *arg)
|
PySocketSock_setblocking(PySocketSockObject *s, PyObject *arg)
|
||||||
{
|
{
|
||||||
int block;
|
int block;
|
||||||
#ifndef RISCOS
|
|
||||||
#ifndef MS_WINDOWS
|
|
||||||
int delay_flag;
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
block = PyInt_AsLong(arg);
|
block = PyInt_AsLong(arg);
|
||||||
if (block == -1 && PyErr_Occurred())
|
if (block == -1 && PyErr_Occurred())
|
||||||
return NULL;
|
return NULL;
|
||||||
Py_BEGIN_ALLOW_THREADS
|
|
||||||
#ifdef __BEOS__
|
s->sock_blocking = block;
|
||||||
block = !block;
|
|
||||||
setsockopt( s->sock_fd, SOL_SOCKET, SO_NONBLOCK,
|
/* If we're not using timeouts, actually set the blocking to give
|
||||||
(void *)(&block), sizeof( int ) );
|
* old python behavior.
|
||||||
#else
|
*/
|
||||||
#ifndef RISCOS
|
if (s->sock_timeout < 0.0)
|
||||||
#ifndef MS_WINDOWS
|
internal_setblocking(s, block);
|
||||||
#if defined(PYOS_OS2) && !defined(PYCC_GCC)
|
|
||||||
block = !block;
|
|
||||||
ioctl(s->sock_fd, FIONBIO, (caddr_t)&block, sizeof(block));
|
|
||||||
#else /* !PYOS_OS2 */
|
|
||||||
delay_flag = fcntl (s->sock_fd, F_GETFL, 0);
|
|
||||||
if (block)
|
|
||||||
delay_flag &= (~O_NDELAY);
|
|
||||||
else
|
|
||||||
delay_flag |= O_NDELAY;
|
|
||||||
fcntl (s->sock_fd, F_SETFL, delay_flag);
|
|
||||||
#endif /* !PYOS_OS2 */
|
|
||||||
#else /* MS_WINDOWS */
|
|
||||||
block = !block;
|
|
||||||
ioctlsocket(s->sock_fd, FIONBIO, (u_long*)&block);
|
|
||||||
#endif /* MS_WINDOWS */
|
|
||||||
#endif /* __BEOS__ */
|
|
||||||
#endif /* RISCOS */
|
|
||||||
Py_END_ALLOW_THREADS
|
|
||||||
|
|
||||||
Py_INCREF(Py_None);
|
Py_INCREF(Py_None);
|
||||||
return Py_None;
|
return Py_None;
|
||||||
|
@ -953,6 +1075,81 @@ static char setblocking_doc[] =
|
||||||
Set the socket to blocking (flag is true) or non-blocking (false).\n\
|
Set the socket to blocking (flag is true) or non-blocking (false).\n\
|
||||||
This uses the FIONBIO ioctl with the O_NDELAY flag.";
|
This uses the FIONBIO ioctl with the O_NDELAY flag.";
|
||||||
|
|
||||||
|
/* s.settimeout (float | int | long) method.
|
||||||
|
* Causes an exception to be raised when the integer number of seconds
|
||||||
|
* has elapsed when performing a blocking socket operation.
|
||||||
|
*/
|
||||||
|
static PyObject *
|
||||||
|
PySocketSock_settimeout(PySocketSockObject *s, PyObject *arg)
|
||||||
|
{
|
||||||
|
double value;
|
||||||
|
|
||||||
|
if (arg == Py_None)
|
||||||
|
value = -1.0;
|
||||||
|
else {
|
||||||
|
value = PyFloat_AsDouble(arg);
|
||||||
|
if (value < 0.0) {
|
||||||
|
if (!PyErr_Occurred())
|
||||||
|
PyErr_SetString(PyExc_ValueError,
|
||||||
|
"Invalid timeout value");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s->sock_timeout = value;
|
||||||
|
|
||||||
|
/* The semantics of setting socket timeouts are:
|
||||||
|
* If you settimeout(!=None):
|
||||||
|
* The actual socket gets put in non-blocking mode and the select
|
||||||
|
* is used to control timeouts.
|
||||||
|
* Else if you settimeout(None) [then value is -1.0]:
|
||||||
|
* The old behavior is used AND automatically, the socket is set
|
||||||
|
* to blocking mode. That means that someone who was doing
|
||||||
|
* non-blocking stuff before, sets a timeout, and then unsets
|
||||||
|
* one, will have to call setblocking(0) again if he wants
|
||||||
|
* non-blocking stuff. This makes sense because timeout stuff is
|
||||||
|
* blocking by nature.
|
||||||
|
*/
|
||||||
|
if (value < 0.0)
|
||||||
|
internal_setblocking(s, 0);
|
||||||
|
else
|
||||||
|
internal_setblocking(s, 1);
|
||||||
|
|
||||||
|
s->sock_blocking = 1; /* Always negate setblocking() */
|
||||||
|
|
||||||
|
Py_INCREF(Py_None);
|
||||||
|
return Py_None;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char settimeout_doc[] =
|
||||||
|
"settimeout(seconds)\n\
|
||||||
|
\n\
|
||||||
|
Set a timeout on blocking socket operations. 'seconds' can be a floating,\n\
|
||||||
|
integer, or long number of seconds, or the None value. Socket operations\n\
|
||||||
|
will raise an exception if the timeout period has elapsed before the\n\
|
||||||
|
operation has completed. Setting a timeout of None disables timeouts\n\
|
||||||
|
on socket operations.";
|
||||||
|
|
||||||
|
/* s.gettimeout () method.
|
||||||
|
* Returns the timeout associated with a socket.
|
||||||
|
*/
|
||||||
|
static PyObject *
|
||||||
|
PySocketSock_gettimeout(PySocketSockObject *s)
|
||||||
|
{
|
||||||
|
if (s->sock_timeout < 0.0) {
|
||||||
|
Py_INCREF(Py_None);
|
||||||
|
return Py_None;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return PyFloat_FromDouble(s->sock_timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char gettimeout_doc[] =
|
||||||
|
"gettimeout()\n\
|
||||||
|
\n\
|
||||||
|
Returns the timeout in floating seconds associated with socket \n\
|
||||||
|
operations. A timeout of None indicates that timeouts on socket \n\
|
||||||
|
operations are disabled.";
|
||||||
|
|
||||||
#ifdef RISCOS
|
#ifdef RISCOS
|
||||||
/* s.sleeptaskw(1 | 0) method */
|
/* s.sleeptaskw(1 | 0) method */
|
||||||
|
@ -960,16 +1157,16 @@ This uses the FIONBIO ioctl with the O_NDELAY flag.";
|
||||||
static PyObject *
|
static PyObject *
|
||||||
PySocketSock_sleeptaskw(PySocketSockObject *s,PyObject *args)
|
PySocketSock_sleeptaskw(PySocketSockObject *s,PyObject *args)
|
||||||
{
|
{
|
||||||
int block;
|
int block;
|
||||||
int delay_flag;
|
int delay_flag;
|
||||||
if (!PyArg_Parse(args, "i", &block))
|
if (!PyArg_Parse(args, "i", &block))
|
||||||
return NULL;
|
return NULL;
|
||||||
Py_BEGIN_ALLOW_THREADS
|
Py_BEGIN_ALLOW_THREADS
|
||||||
socketioctl(s->sock_fd, 0x80046679, (u_long*)&block);
|
socketioctl(s->sock_fd, 0x80046679, (u_long*)&block);
|
||||||
Py_END_ALLOW_THREADS
|
Py_END_ALLOW_THREADS
|
||||||
|
|
||||||
Py_INCREF(Py_None);
|
Py_INCREF(Py_None);
|
||||||
return Py_None;
|
return Py_None;
|
||||||
}
|
}
|
||||||
static char sleeptaskw_doc[] =
|
static char sleeptaskw_doc[] =
|
||||||
"sleeptaskw(flag)\n\
|
"sleeptaskw(flag)\n\
|
||||||
|
@ -1142,11 +1339,50 @@ PySocketSock_connect(PySocketSockObject *s, PyObject *addro)
|
||||||
|
|
||||||
if (!getsockaddrarg(s, addro, &addr, &addrlen))
|
if (!getsockaddrarg(s, addro, &addr, &addrlen))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
errno = 0; /* Reset the err indicator for use with timeouts */
|
||||||
|
|
||||||
Py_BEGIN_ALLOW_THREADS
|
Py_BEGIN_ALLOW_THREADS
|
||||||
res = connect(s->sock_fd, addr, addrlen);
|
res = connect(s->sock_fd, addr, addrlen);
|
||||||
Py_END_ALLOW_THREADS
|
Py_END_ALLOW_THREADS
|
||||||
|
|
||||||
|
if (s->sock_timeout >= 0.0) {
|
||||||
|
if (res < 0) {
|
||||||
|
/* Return if we're already connected */
|
||||||
|
#ifdef MS_WINDOWS
|
||||||
|
if (errno == WSAEINVAL || errno == WSAEISCONN)
|
||||||
|
#else
|
||||||
|
if (errno == EISCONN)
|
||||||
|
#endif
|
||||||
|
goto connected;
|
||||||
|
|
||||||
|
/* Check if we have an error */
|
||||||
|
if (!s->sock_blocking)
|
||||||
|
return s->errorhandler ();
|
||||||
|
/* Check if we have a true failure for a blocking socket */
|
||||||
|
#ifdef MS_WINDOWS
|
||||||
|
if (errno != WSAEWOULDBLOCK)
|
||||||
|
#else
|
||||||
|
if (errno != EINPROGRESS && errno != EALREADY &&
|
||||||
|
errno != EWOULDBLOCK)
|
||||||
|
#endif
|
||||||
|
return s->errorhandler();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if we're ready for the connect via select */
|
||||||
|
if (internal_select(s, 1) <= 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Complete the connection now */
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
|
res = connect(s->sock_fd, addr, addrlen);
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
|
}
|
||||||
|
|
||||||
if (res < 0)
|
if (res < 0)
|
||||||
return s->errorhandler();
|
return s->errorhandler();
|
||||||
|
|
||||||
|
connected:
|
||||||
Py_INCREF(Py_None);
|
Py_INCREF(Py_None);
|
||||||
return Py_None;
|
return Py_None;
|
||||||
}
|
}
|
||||||
|
@ -1169,9 +1405,46 @@ PySocketSock_connect_ex(PySocketSockObject *s, PyObject *addro)
|
||||||
|
|
||||||
if (!getsockaddrarg(s, addro, &addr, &addrlen))
|
if (!getsockaddrarg(s, addro, &addr, &addrlen))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
errno = 0; /* Reset the err indicator for use with timeouts */
|
||||||
|
|
||||||
Py_BEGIN_ALLOW_THREADS
|
Py_BEGIN_ALLOW_THREADS
|
||||||
res = connect(s->sock_fd, addr, addrlen);
|
res = connect(s->sock_fd, addr, addrlen);
|
||||||
Py_END_ALLOW_THREADS
|
Py_END_ALLOW_THREADS
|
||||||
|
|
||||||
|
if (s->sock_timeout >= 0.0) {
|
||||||
|
if (res < 0) {
|
||||||
|
/* Return if we're already connected */
|
||||||
|
#ifdef MS_WINDOWS
|
||||||
|
if (errno == WSAEINVAL || errno == WSAEISCONN)
|
||||||
|
#else
|
||||||
|
if (errno == EISCONN)
|
||||||
|
#endif
|
||||||
|
goto conex_finally;
|
||||||
|
|
||||||
|
/* Check if we have an error */
|
||||||
|
if (!s->sock_blocking)
|
||||||
|
goto conex_finally;
|
||||||
|
/* Check if we have a true failure for a blocking socket */
|
||||||
|
#ifdef MS_WINDOWS
|
||||||
|
if (errno != WSAEWOULDBLOCK)
|
||||||
|
#else
|
||||||
|
if (errno != EINPROGRESS && errno != EALREADY &&
|
||||||
|
errno != EWOULDBLOCK)
|
||||||
|
#endif
|
||||||
|
goto conex_finally;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if we're ready for the connect via select */
|
||||||
|
if (internal_select(s, 1) <= 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Complete the connection now */
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
|
res = connect(s->sock_fd, addr, addrlen);
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
|
}
|
||||||
|
|
||||||
if (res != 0) {
|
if (res != 0) {
|
||||||
#ifdef MS_WINDOWS
|
#ifdef MS_WINDOWS
|
||||||
res = WSAGetLastError();
|
res = WSAGetLastError();
|
||||||
|
@ -1179,6 +1452,8 @@ PySocketSock_connect_ex(PySocketSockObject *s, PyObject *addro)
|
||||||
res = errno;
|
res = errno;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
conex_finally:
|
||||||
return PyInt_FromLong((long) res);
|
return PyInt_FromLong((long) res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1360,7 +1635,7 @@ PySocketSock_makefile(PySocketSockObject *s, PyObject *args)
|
||||||
}
|
}
|
||||||
#ifdef USE_GUSI2
|
#ifdef USE_GUSI2
|
||||||
/* Workaround for bug in Metrowerks MSL vs. GUSI I/O library */
|
/* Workaround for bug in Metrowerks MSL vs. GUSI I/O library */
|
||||||
if (strchr(mode, 'b') != NULL )
|
if (strchr(mode, 'b') != NULL)
|
||||||
bufsize = 0;
|
bufsize = 0;
|
||||||
#endif
|
#endif
|
||||||
f = PyFile_FromFile(fp, "<socket>", mode, fclose);
|
f = PyFile_FromFile(fp, "<socket>", mode, fclose);
|
||||||
|
@ -1385,19 +1660,31 @@ PySocketSock_recv(PySocketSockObject *s, PyObject *args)
|
||||||
{
|
{
|
||||||
int len, n, flags = 0;
|
int len, n, flags = 0;
|
||||||
PyObject *buf;
|
PyObject *buf;
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "i|i:recv", &len, &flags))
|
if (!PyArg_ParseTuple(args, "i|i:recv", &len, &flags))
|
||||||
return NULL;
|
return NULL;
|
||||||
if (len < 0) {
|
|
||||||
|
if (len < 0) {
|
||||||
PyErr_SetString(PyExc_ValueError,
|
PyErr_SetString(PyExc_ValueError,
|
||||||
"negative buffersize in connect");
|
"negative buffersize in connect");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
buf = PyString_FromStringAndSize((char *) 0, len);
|
buf = PyString_FromStringAndSize((char *) 0, len);
|
||||||
if (buf == NULL)
|
if (buf == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
if (s->sock_timeout >= 0.0) {
|
||||||
|
if (s->sock_blocking) {
|
||||||
|
if (internal_select(s, 0) <= 0)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Py_BEGIN_ALLOW_THREADS
|
Py_BEGIN_ALLOW_THREADS
|
||||||
n = recv(s->sock_fd, PyString_AS_STRING(buf), len, flags);
|
n = recv(s->sock_fd, PyString_AS_STRING(buf), len, flags);
|
||||||
Py_END_ALLOW_THREADS
|
Py_END_ALLOW_THREADS
|
||||||
|
|
||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
Py_DECREF(buf);
|
Py_DECREF(buf);
|
||||||
return s->errorhandler();
|
return s->errorhandler();
|
||||||
|
@ -1425,16 +1712,25 @@ PySocketSock_recvfrom(PySocketSockObject *s, PyObject *args)
|
||||||
PyObject *buf = NULL;
|
PyObject *buf = NULL;
|
||||||
PyObject *addr = NULL;
|
PyObject *addr = NULL;
|
||||||
PyObject *ret = NULL;
|
PyObject *ret = NULL;
|
||||||
|
|
||||||
int len, n, flags = 0;
|
int len, n, flags = 0;
|
||||||
socklen_t addrlen;
|
socklen_t addrlen;
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "i|i:recvfrom", &len, &flags))
|
if (!PyArg_ParseTuple(args, "i|i:recvfrom", &len, &flags))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (!getsockaddrlen(s, &addrlen))
|
if (!getsockaddrlen(s, &addrlen))
|
||||||
return NULL;
|
return NULL;
|
||||||
buf = PyString_FromStringAndSize((char *) 0, len);
|
buf = PyString_FromStringAndSize((char *) 0, len);
|
||||||
if (buf == NULL)
|
if (buf == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
if (s->sock_timeout >= 0.0) {
|
||||||
|
if (s->sock_blocking) {
|
||||||
|
if (internal_select(s, 0) <= 0)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Py_BEGIN_ALLOW_THREADS
|
Py_BEGIN_ALLOW_THREADS
|
||||||
memset(addrbuf, 0, addrlen);
|
memset(addrbuf, 0, addrlen);
|
||||||
n = recvfrom(s->sock_fd, PyString_AS_STRING(buf), len, flags,
|
n = recvfrom(s->sock_fd, PyString_AS_STRING(buf), len, flags,
|
||||||
|
@ -1449,18 +1745,22 @@ PySocketSock_recvfrom(PySocketSockObject *s, PyObject *args)
|
||||||
#endif
|
#endif
|
||||||
);
|
);
|
||||||
Py_END_ALLOW_THREADS
|
Py_END_ALLOW_THREADS
|
||||||
|
|
||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
Py_DECREF(buf);
|
Py_DECREF(buf);
|
||||||
return s->errorhandler();
|
return s->errorhandler();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (n != len && _PyString_Resize(&buf, n) < 0)
|
if (n != len && _PyString_Resize(&buf, n) < 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (!(addr = makesockaddr(s->sock_fd, (struct sockaddr *)addrbuf, addrlen)))
|
if (!(addr = makesockaddr(s->sock_fd, (struct sockaddr *)addrbuf,
|
||||||
|
addrlen)))
|
||||||
goto finally;
|
goto finally;
|
||||||
|
|
||||||
ret = Py_BuildValue("OO", buf, addr);
|
ret = Py_BuildValue("OO", buf, addr);
|
||||||
finally:
|
|
||||||
|
finally:
|
||||||
Py_XDECREF(addr);
|
Py_XDECREF(addr);
|
||||||
Py_XDECREF(buf);
|
Py_XDECREF(buf);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -1471,7 +1771,6 @@ static char recvfrom_doc[] =
|
||||||
\n\
|
\n\
|
||||||
Like recv(buffersize, flags) but also return the sender's address info.";
|
Like recv(buffersize, flags) but also return the sender's address info.";
|
||||||
|
|
||||||
|
|
||||||
/* s.send(data [,flags]) method */
|
/* s.send(data [,flags]) method */
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
|
@ -1479,11 +1778,21 @@ PySocketSock_send(PySocketSockObject *s, PyObject *args)
|
||||||
{
|
{
|
||||||
char *buf;
|
char *buf;
|
||||||
int len, n, flags = 0;
|
int len, n, flags = 0;
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "s#|i:send", &buf, &len, &flags))
|
if (!PyArg_ParseTuple(args, "s#|i:send", &buf, &len, &flags))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
if (s->sock_timeout >= 0.0) {
|
||||||
|
if (s->sock_blocking) {
|
||||||
|
if (internal_select(s, 1) <= 0)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Py_BEGIN_ALLOW_THREADS
|
Py_BEGIN_ALLOW_THREADS
|
||||||
n = send(s->sock_fd, buf, len, flags);
|
n = send(s->sock_fd, buf, len, flags);
|
||||||
Py_END_ALLOW_THREADS
|
Py_END_ALLOW_THREADS
|
||||||
|
|
||||||
if (n < 0)
|
if (n < 0)
|
||||||
return s->errorhandler();
|
return s->errorhandler();
|
||||||
return PyInt_FromLong((long)n);
|
return PyInt_FromLong((long)n);
|
||||||
|
@ -1504,8 +1813,17 @@ PySocketSock_sendall(PySocketSockObject *s, PyObject *args)
|
||||||
{
|
{
|
||||||
char *buf;
|
char *buf;
|
||||||
int len, n, flags = 0;
|
int len, n, flags = 0;
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "s#|i:sendall", &buf, &len, &flags))
|
if (!PyArg_ParseTuple(args, "s#|i:sendall", &buf, &len, &flags))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
if (s->sock_timeout >= 0.0) {
|
||||||
|
if (s->sock_blocking) {
|
||||||
|
if (internal_select(s, 1) < 0)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Py_BEGIN_ALLOW_THREADS
|
Py_BEGIN_ALLOW_THREADS
|
||||||
do {
|
do {
|
||||||
n = send(s->sock_fd, buf, len, flags);
|
n = send(s->sock_fd, buf, len, flags);
|
||||||
|
@ -1515,8 +1833,10 @@ PySocketSock_sendall(PySocketSockObject *s, PyObject *args)
|
||||||
len -= n;
|
len -= n;
|
||||||
} while (len > 0);
|
} while (len > 0);
|
||||||
Py_END_ALLOW_THREADS
|
Py_END_ALLOW_THREADS
|
||||||
|
|
||||||
if (n < 0)
|
if (n < 0)
|
||||||
return s->errorhandler();
|
return s->errorhandler();
|
||||||
|
|
||||||
Py_INCREF(Py_None);
|
Py_INCREF(Py_None);
|
||||||
return Py_None;
|
return Py_None;
|
||||||
}
|
}
|
||||||
|
@ -1539,6 +1859,7 @@ PySocketSock_sendto(PySocketSockObject *s, PyObject *args)
|
||||||
char *buf;
|
char *buf;
|
||||||
struct sockaddr *addr;
|
struct sockaddr *addr;
|
||||||
int addrlen, len, n, flags;
|
int addrlen, len, n, flags;
|
||||||
|
|
||||||
flags = 0;
|
flags = 0;
|
||||||
if (!PyArg_ParseTuple(args, "s#O:sendto", &buf, &len, &addro)) {
|
if (!PyArg_ParseTuple(args, "s#O:sendto", &buf, &len, &addro)) {
|
||||||
PyErr_Clear();
|
PyErr_Clear();
|
||||||
|
@ -1546,11 +1867,21 @@ PySocketSock_sendto(PySocketSockObject *s, PyObject *args)
|
||||||
&buf, &len, &flags, &addro))
|
&buf, &len, &flags, &addro))
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!getsockaddrarg(s, addro, &addr, &addrlen))
|
if (!getsockaddrarg(s, addro, &addr, &addrlen))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
if (s->sock_timeout >= 0.0) {
|
||||||
|
if (s->sock_blocking) {
|
||||||
|
if (internal_select(s, 1) <= 0)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Py_BEGIN_ALLOW_THREADS
|
Py_BEGIN_ALLOW_THREADS
|
||||||
n = sendto(s->sock_fd, buf, len, flags, addr, addrlen);
|
n = sendto(s->sock_fd, buf, len, flags, addr, addrlen);
|
||||||
Py_END_ALLOW_THREADS
|
Py_END_ALLOW_THREADS
|
||||||
|
|
||||||
if (n < 0)
|
if (n < 0)
|
||||||
return s->errorhandler();
|
return s->errorhandler();
|
||||||
return PyInt_FromLong((long)n);
|
return PyInt_FromLong((long)n);
|
||||||
|
@ -1635,6 +1966,10 @@ static PyMethodDef PySocketSock_methods[] = {
|
||||||
sendto_doc},
|
sendto_doc},
|
||||||
{"setblocking", (PyCFunction)PySocketSock_setblocking, METH_O,
|
{"setblocking", (PyCFunction)PySocketSock_setblocking, METH_O,
|
||||||
setblocking_doc},
|
setblocking_doc},
|
||||||
|
{"settimeout", (PyCFunction)PySocketSock_settimeout, METH_O,
|
||||||
|
settimeout_doc},
|
||||||
|
{"gettimeout", (PyCFunction)PySocketSock_gettimeout, METH_NOARGS,
|
||||||
|
gettimeout_doc},
|
||||||
{"setsockopt", (PyCFunction)PySocketSock_setsockopt, METH_VARARGS,
|
{"setsockopt", (PyCFunction)PySocketSock_setsockopt, METH_VARARGS,
|
||||||
setsockopt_doc},
|
setsockopt_doc},
|
||||||
{"shutdown", (PyCFunction)PySocketSock_shutdown, METH_O,
|
{"shutdown", (PyCFunction)PySocketSock_shutdown, METH_O,
|
||||||
|
@ -1692,6 +2027,7 @@ PySocketSock_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||||
new = type->tp_alloc(type, 0);
|
new = type->tp_alloc(type, 0);
|
||||||
if (new != NULL) {
|
if (new != NULL) {
|
||||||
((PySocketSockObject *)new)->sock_fd = -1;
|
((PySocketSockObject *)new)->sock_fd = -1;
|
||||||
|
((PySocketSockObject *)new)->sock_timeout = -1.0;
|
||||||
((PySocketSockObject *)new)->errorhandler = &PySocket_Err;
|
((PySocketSockObject *)new)->errorhandler = &PySocket_Err;
|
||||||
}
|
}
|
||||||
return new;
|
return new;
|
||||||
|
@ -1713,9 +2049,11 @@ PySocketSock_init(PyObject *self, PyObject *args, PyObject *kwds)
|
||||||
"|iii:socket", keywords,
|
"|iii:socket", keywords,
|
||||||
&family, &type, &proto))
|
&family, &type, &proto))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
Py_BEGIN_ALLOW_THREADS
|
Py_BEGIN_ALLOW_THREADS
|
||||||
fd = socket(family, type, proto);
|
fd = socket(family, type, proto);
|
||||||
Py_END_ALLOW_THREADS
|
Py_END_ALLOW_THREADS
|
||||||
|
|
||||||
#ifdef MS_WINDOWS
|
#ifdef MS_WINDOWS
|
||||||
if (fd == INVALID_SOCKET)
|
if (fd == INVALID_SOCKET)
|
||||||
#else
|
#else
|
||||||
|
@ -1731,7 +2069,9 @@ PySocketSock_init(PyObject *self, PyObject *args, PyObject *kwds)
|
||||||
#ifdef SIGPIPE
|
#ifdef SIGPIPE
|
||||||
(void) signal(SIGPIPE, SIG_IGN);
|
(void) signal(SIGPIPE, SIG_IGN);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1885,6 +2225,7 @@ gethost_common(struct hostent *h, struct sockaddr *addr, int alen, int af)
|
||||||
#endif
|
#endif
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (h->h_addrtype != af) {
|
if (h->h_addrtype != af) {
|
||||||
#ifdef HAVE_STRERROR
|
#ifdef HAVE_STRERROR
|
||||||
/* Let's get real error message to return */
|
/* Let's get real error message to return */
|
||||||
|
@ -1895,35 +2236,47 @@ gethost_common(struct hostent *h, struct sockaddr *addr, int alen, int af)
|
||||||
#endif
|
#endif
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (af) {
|
switch (af) {
|
||||||
|
|
||||||
case AF_INET:
|
case AF_INET:
|
||||||
if (alen < sizeof(struct sockaddr_in))
|
if (alen < sizeof(struct sockaddr_in))
|
||||||
return NULL;
|
return NULL;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#ifdef ENABLE_IPV6
|
#ifdef ENABLE_IPV6
|
||||||
case AF_INET6:
|
case AF_INET6:
|
||||||
if (alen < sizeof(struct sockaddr_in6))
|
if (alen < sizeof(struct sockaddr_in6))
|
||||||
return NULL;
|
return NULL;
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((name_list = PyList_New(0)) == NULL)
|
if ((name_list = PyList_New(0)) == NULL)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
if ((addr_list = PyList_New(0)) == NULL)
|
if ((addr_list = PyList_New(0)) == NULL)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
for (pch = h->h_aliases; *pch != NULL; pch++) {
|
for (pch = h->h_aliases; *pch != NULL; pch++) {
|
||||||
int status;
|
int status;
|
||||||
tmp = PyString_FromString(*pch);
|
tmp = PyString_FromString(*pch);
|
||||||
if (tmp == NULL)
|
if (tmp == NULL)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
status = PyList_Append(name_list, tmp);
|
status = PyList_Append(name_list, tmp);
|
||||||
Py_DECREF(tmp);
|
Py_DECREF(tmp);
|
||||||
|
|
||||||
if (status)
|
if (status)
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (pch = h->h_addr_list; *pch != NULL; pch++) {
|
for (pch = h->h_addr_list; *pch != NULL; pch++) {
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
switch (af) {
|
switch (af) {
|
||||||
|
|
||||||
case AF_INET:
|
case AF_INET:
|
||||||
{
|
{
|
||||||
struct sockaddr_in sin;
|
struct sockaddr_in sin;
|
||||||
|
@ -1934,10 +2287,12 @@ gethost_common(struct hostent *h, struct sockaddr *addr, int alen, int af)
|
||||||
#endif
|
#endif
|
||||||
memcpy(&sin.sin_addr, *pch, sizeof(sin.sin_addr));
|
memcpy(&sin.sin_addr, *pch, sizeof(sin.sin_addr));
|
||||||
tmp = makeipaddr((struct sockaddr *)&sin, sizeof(sin));
|
tmp = makeipaddr((struct sockaddr *)&sin, sizeof(sin));
|
||||||
|
|
||||||
if (pch == h->h_addr_list && alen >= sizeof(sin))
|
if (pch == h->h_addr_list && alen >= sizeof(sin))
|
||||||
memcpy((char *) addr, &sin, sizeof(sin));
|
memcpy((char *) addr, &sin, sizeof(sin));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ENABLE_IPV6
|
#ifdef ENABLE_IPV6
|
||||||
case AF_INET6:
|
case AF_INET6:
|
||||||
{
|
{
|
||||||
|
@ -1950,24 +2305,31 @@ gethost_common(struct hostent *h, struct sockaddr *addr, int alen, int af)
|
||||||
memcpy(&sin6.sin6_addr, *pch, sizeof(sin6.sin6_addr));
|
memcpy(&sin6.sin6_addr, *pch, sizeof(sin6.sin6_addr));
|
||||||
tmp = makeipaddr((struct sockaddr *)&sin6,
|
tmp = makeipaddr((struct sockaddr *)&sin6,
|
||||||
sizeof(sin6));
|
sizeof(sin6));
|
||||||
|
|
||||||
if (pch == h->h_addr_list && alen >= sizeof(sin6))
|
if (pch == h->h_addr_list && alen >= sizeof(sin6))
|
||||||
memcpy((char *) addr, &sin6, sizeof(sin6));
|
memcpy((char *) addr, &sin6, sizeof(sin6));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
default: /* can't happen */
|
default: /* can't happen */
|
||||||
PyErr_SetString(PySocket_Error,
|
PyErr_SetString(PySocket_Error,
|
||||||
"unsupported address family");
|
"unsupported address family");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tmp == NULL)
|
if (tmp == NULL)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
status = PyList_Append(addr_list, tmp);
|
status = PyList_Append(addr_list, tmp);
|
||||||
Py_DECREF(tmp);
|
Py_DECREF(tmp);
|
||||||
|
|
||||||
if (status)
|
if (status)
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
rtn_tuple = Py_BuildValue("sOO", h->h_name, name_list, addr_list);
|
rtn_tuple = Py_BuildValue("sOO", h->h_name, name_list, addr_list);
|
||||||
|
|
||||||
err:
|
err:
|
||||||
Py_XDECREF(name_list);
|
Py_XDECREF(name_list);
|
||||||
Py_XDECREF(addr_list);
|
Py_XDECREF(addr_list);
|
||||||
|
@ -2022,10 +2384,14 @@ PySocket_gethostbyname_ex(PyObject *self, PyObject *args)
|
||||||
h = gethostbyname(name);
|
h = gethostbyname(name);
|
||||||
#endif /* HAVE_GETHOSTBYNAME_R */
|
#endif /* HAVE_GETHOSTBYNAME_R */
|
||||||
Py_END_ALLOW_THREADS
|
Py_END_ALLOW_THREADS
|
||||||
/* Some C libraries would require addr.__ss_family instead of addr.ss_family.
|
/* Some C libraries would require addr.__ss_family instead of
|
||||||
Therefore, we cast the sockaddr_storage into sockaddr to access sa_family. */
|
* addr.ss_family.
|
||||||
|
* Therefore, we cast the sockaddr_storage into sockaddr to
|
||||||
|
* access sa_family.
|
||||||
|
*/
|
||||||
sa = (struct sockaddr*)&addr;
|
sa = (struct sockaddr*)&addr;
|
||||||
ret = gethost_common(h, (struct sockaddr *)&addr, sizeof(addr), sa->sa_family);
|
ret = gethost_common(h, (struct sockaddr *)&addr, sizeof(addr),
|
||||||
|
sa->sa_family);
|
||||||
#ifdef USE_GETHOSTBYNAME_LOCK
|
#ifdef USE_GETHOSTBYNAME_LOCK
|
||||||
PyThread_release_lock(gethostbyname_lock);
|
PyThread_release_lock(gethostbyname_lock);
|
||||||
#endif
|
#endif
|
||||||
|
@ -2170,7 +2536,7 @@ PySocket_getprotobyname(PyObject *self, PyObject *args)
|
||||||
struct protoent *sp;
|
struct protoent *sp;
|
||||||
#ifdef __BEOS__
|
#ifdef __BEOS__
|
||||||
/* Not available in BeOS yet. - [cjh] */
|
/* Not available in BeOS yet. - [cjh] */
|
||||||
PyErr_SetString( PySocket_Error, "getprotobyname not supported" );
|
PyErr_SetString(PySocket_Error, "getprotobyname not supported");
|
||||||
return NULL;
|
return NULL;
|
||||||
#else
|
#else
|
||||||
if (!PyArg_ParseTuple(args, "s:getprotobyname", &name))
|
if (!PyArg_ParseTuple(args, "s:getprotobyname", &name))
|
||||||
|
|
|
@ -83,6 +83,9 @@ typedef struct {
|
||||||
PyObject *(*errorhandler)(void); /* Error handler; checks
|
PyObject *(*errorhandler)(void); /* Error handler; checks
|
||||||
errno, returns NULL and
|
errno, returns NULL and
|
||||||
sets a Python exception */
|
sets a Python exception */
|
||||||
|
int sock_blocking; /* Flag indicated whether the
|
||||||
|
socket is in blocking mode */
|
||||||
|
double sock_timeout; /* Operation timeout value */
|
||||||
} PySocketSockObject;
|
} PySocketSockObject;
|
||||||
|
|
||||||
/* --- C API ----------------------------------------------------*/
|
/* --- C API ----------------------------------------------------*/
|
||||||
|
|
Loading…
Reference in New Issue