├── .gitignore ├── LICENSE.txt ├── TODO.mkd ├── app └── recvfile.py ├── automated_tests.cfg ├── automated_tests.py ├── setup.py ├── test_client.py ├── test_server.py ├── test_udt.py ├── udt.py ├── udt_py.cxx └── udt_py.h /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.swp 3 | build 4 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011, Pykara Ltd 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, 8 | this list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of the Pykara Ltd nor the names of its contributors may 15 | be used to endorse or promote products derived from this software without 16 | specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /TODO.mkd: -------------------------------------------------------------------------------- 1 | * Bugs 2 | * one test in test\_udt.py fails 3 | * `Ctrl-C` can't terminate test_server 4 | 5 | * Features 6 | * [UDT::sendfile](http://udt.sourceforge.net/udt4/doc/sendfile.htm) 7 | * [UDT::recvfile](http://udt.sourceforge.net/udt4/doc/recvfile.htm) 8 | -------------------------------------------------------------------------------- /app/recvfile.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # vim:fileencoding=utf-8 3 | 4 | import sys 5 | import udt 6 | import struct 7 | import socket 8 | 9 | try: 10 | fn = sys.argv[3].encode() 11 | server = sys.argv[1] 12 | port = int(sys.argv[2]) 13 | except (IndexError, ValueError): 14 | sys.exit('usage: ') 15 | 16 | # udt.startup() 17 | s = udt.socket(socket.AF_INET, socket.SOCK_STREAM, socket.AI_PASSIVE) 18 | s.connect((server, port)) 19 | 20 | l = struct.pack('I', len(fn)) 21 | s.send(l, 0) 22 | s.send(fn, 0) 23 | a = s.recv(8, 0) 24 | print(a) 25 | l = struct.unpack('q', a)[0] 26 | print('Size:', l) 27 | if l < 0: 28 | sys.exit('File not found') 29 | 30 | left = l 31 | with open(fn, 'wb') as f: 32 | while left > 0: 33 | data = s.recv(l, 0) 34 | f.write(data) 35 | left -= len(data) 36 | -------------------------------------------------------------------------------- /automated_tests.cfg: -------------------------------------------------------------------------------- 1 | { 2 | "tests" : [ 3 | { 4 | "module" : "automated_tests", 5 | "class" : "ConnectionTest", 6 | "args" : [], 7 | "kwargs" : {}, 8 | "agents" : { 9 | "server" : { 10 | "host" : "localhost", 11 | "port" : 8888, 12 | "module" : "automated_tests", 13 | "class" : "StreamServer", 14 | "args" : [] 15 | }, 16 | "client" : { 17 | "host" : "localhost", 18 | "port" : 8888, 19 | "module" : "automated_tests", 20 | "class" : "StreamClient", 21 | "args" : [] 22 | } 23 | } 24 | } 25 | ], 26 | "plugins" : [ 27 | { 28 | "module": "dspyte.report.text", 29 | "args" : [], 30 | "kwargs": {} 31 | } 32 | ], 33 | "paths" : { 34 | "remote" : [], 35 | "local" : [] 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /automated_tests.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import socket 4 | import os 5 | import time 6 | import threading 7 | import rpyc 8 | 9 | import dspyte.core 10 | 11 | class Pinger(threading.Thread): 12 | def run(self): 13 | for i in range(60): 14 | print("xxxxxx", i, time.time()) 15 | time.sleep(1) 16 | 17 | class ConnectionTest(dspyte.core.Main): 18 | """ 19 | Basic connection test 20 | """ 21 | name = 'ConnectionTest' 22 | def __call__(self, agents, *args, **kwargs): 23 | server = agents['server'] 24 | client = agents['client'] 25 | server.agent.listen() 26 | #p = Pinger() 27 | #p.start() 28 | client.agent.connect() 29 | server.agent.accept() 30 | client.agent.send_data() 31 | server.agent.recv_data() 32 | 33 | class StreamServer(dspyte.core.Agent): 34 | port = 7778 35 | name = 'server' 36 | def listen(self): 37 | import udt 38 | self.s = udt.socket(socket.AF_INET, socket.SOCK_STREAM, 0) 39 | self.send_msg('binding') 40 | self.s.bind(('localhost', self.port)) 41 | self.send_msg("bound to port: %s" % self.port) 42 | self.s.listen(10) 43 | 44 | def accept(self): 45 | import udt 46 | self.client, addr = self.s.accept() 47 | self.send_msg('accepted client!') 48 | 49 | def recv_data(self): 50 | self.send_msg("got %s" % self.client.recv(1024, 0)) 51 | 52 | class StreamClient(dspyte.core.Agent): 53 | name = 'client' 54 | def connect(self): 55 | import udt 56 | import ctypes 57 | self.s = udt.socket(socket.AF_INET, socket.SOCK_STREAM, 0) 58 | print(self.s.connect(("localhost", StreamServer.port))) 59 | self.send_msg("connection ok!") 60 | 61 | def send_data(self): 62 | self.s.send("Hello World!", 100) 63 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from distutils.core import setup, Extension 2 | 3 | from os.path import join 4 | 5 | module = Extension( 6 | '_udt', 7 | sources = ['udt_py.cxx'], 8 | include_dirs = [".", "../udt4/src"], 9 | libraries = ['udt'], 10 | library_dirs = ['../udt4/src'], 11 | extra_link_args = ['-Wl,-R../udt4/src/'], 12 | ) 13 | 14 | setup ( 15 | name = 'udt_py', 16 | version = '1.0', 17 | description = 'Python bindings for UDT', 18 | py_modules = ['udt'], 19 | ext_modules = [module] 20 | ) 21 | -------------------------------------------------------------------------------- /test_client.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import udt 4 | import socket 5 | import time 6 | 7 | s = udt.socket(socket.AF_INET, socket.SOCK_STREAM, 0) 8 | s.connect(("localhost", 5555)) 9 | 10 | print("Sending...") 11 | s.send(b"Hello", 0) 12 | buf = s.recv(1024, 0) 13 | print(repr(buf)) 14 | -------------------------------------------------------------------------------- /test_server.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import udt 4 | import socket 5 | import time 6 | import threading 7 | 8 | class Pinger(threading.Thread): 9 | def run(self): 10 | for i in range(300): 11 | print("ping ...", i) 12 | time.sleep(1) 13 | 14 | p = Pinger() 15 | p.start() 16 | 17 | s = udt.socket(socket.AF_INET, socket.SOCK_STREAM, 0) 18 | epoll = udt.epoll() 19 | s.bind(("127.0.0.1", 5555)) 20 | s.listen(10) 21 | 22 | 23 | while True: 24 | client, addr = s.accept() 25 | print("accept", client, addr) 26 | epoll.add_usock(client.fileno(), udt.UDT_EPOLL_IN) 27 | print('wait..') 28 | print(epoll.epoll_wait(-1)) 29 | print('got data..') 30 | client.send(b"Hello World" * 10, -1) 31 | client.close() 32 | -------------------------------------------------------------------------------- /test_udt.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import sys 4 | import socket 5 | import unittest 6 | 7 | import udt 8 | import _udt 9 | 10 | class TestSocket(unittest.TestCase): 11 | def create_socket(self): 12 | return udt.socket(socket.AF_INET, socket.SOCK_STREAM, 0) 13 | 14 | def create_int_socket(self): 15 | return _udt.socket(socket.AF_INET, socket.SOCK_STREAM, 0) 16 | 17 | def test_init(self): 18 | s = self.create_socket() 19 | self.assertEquals(s.family, socket.AF_INET) 20 | self.assertEquals(s.type, socket.SOCK_STREAM) 21 | self.assertEquals(s.proto, 0) 22 | 23 | def test_not_enough_args_init(self): 24 | self.assertRaises(TypeError, udt.socket, ()) 25 | 26 | def test_close(self): 27 | s = self.create_socket() 28 | # perhaps this should fail since it was never open? 29 | s.close() 30 | 31 | def test_double_close(self): 32 | s = self.create_socket() 33 | s.close() 34 | self.assertRaises(RuntimeError, s.close, ()) 35 | 36 | def test_connect_bad_args(self): 37 | addr = ("192.168.0.1", 2222) 38 | s = self.create_int_socket() 39 | # 0 args 40 | self.assertRaises(TypeError, s.connect, ()) 41 | # 1 arg 42 | self.assertRaises(TypeError, s.connect, "localhost", 22, ) 43 | # string port 44 | self.assertRaises(TypeError, s.connect, ("localhost", "22")) 45 | 46 | def test_connect_no_listen(self): 47 | s = self.create_socket() 48 | self.assertRaises(RuntimeError, s.connect, ("127.0.0.1", 2344)) 49 | self.assertRaises(RuntimeError, s.connect, ("localhost", 2344)) 50 | 51 | def test_bind_ok(self): 52 | s = self.create_socket() 53 | s.bind(("127.0.0.1", 3333)) 54 | 55 | def test_startup(self): 56 | udt.startup() 57 | 58 | def test_cleanup(self): 59 | udt.cleanup() 60 | 61 | def test_socket_fileno(self): 62 | s = self.create_socket() 63 | self.assertTrue(isinstance(s.fileno(), int)) 64 | 65 | def test_getset_sockopt_mss(self): 66 | s = self.create_socket() 67 | val = s.getsockopt(0, udt.UDT_MSS) 68 | self.assertEquals(val, 1500) 69 | 70 | s.setsockopt(0, udt.UDT_MSS, 1800) 71 | val = s.getsockopt(0, udt.UDT_MSS) 72 | self.assertEquals(val, 1800) 73 | 74 | def test_getset_sockopt_sndsyn(self): 75 | s = self.create_socket() 76 | val = s.getsockopt(0, udt.UDT_SNDSYN) 77 | self.assertEquals(val, True) 78 | 79 | s.setsockopt(0, udt.UDT_SNDSYN, False) 80 | val = s.getsockopt(0, udt.UDT_SNDSYN) 81 | self.assertEquals(val, False) 82 | 83 | def test_getset_sockopt_rcvsyn(self): 84 | s = self.create_socket() 85 | val = s.getsockopt(0, udt.UDT_RCVSYN) 86 | self.assertEquals(val, True) 87 | 88 | def test_getset_sockopt_fc(self): 89 | s = self.create_socket() 90 | val = s.getsockopt(0, udt.UDT_FC) 91 | self.assertEquals(val, 25600) 92 | 93 | s.setsockopt(0, udt.UDT_FC, 10000) 94 | val = s.getsockopt(0, udt.UDT_FC) 95 | self.assertEquals(val, 10000) 96 | 97 | def test_getset_sockopt_sndbuf(self): 98 | s = self.create_socket() 99 | val = s.getsockopt(0, udt.UDT_SNDBUF) 100 | self.assertEquals(val, 12058624) 101 | 102 | s.setsockopt(0, udt.UDT_SNDBUF, 198720) 103 | val = s.getsockopt(0, udt.UDT_SNDBUF) 104 | self.assertEquals(val, 198720) 105 | 106 | def test_getsockopt_rcvbuf(self): 107 | s = self.create_socket() 108 | val = s.getsockopt(0, udt.UDT_RCVBUF) 109 | self.assertEquals(val, 12058624) 110 | 111 | s.setsockopt(0, udt.UDT_RCVBUF, 198720) 112 | val = s.getsockopt(0, udt.UDT_RCVBUF) 113 | self.assertEquals(val, 198720) 114 | 115 | def test_getsockopt_udp_sndbuf(self): 116 | s = self.create_socket() 117 | val = s.getsockopt(0, udt.UDP_SNDBUF) 118 | 119 | s.setsockopt(0, udt.UDP_SNDBUF, 10000) 120 | val = s.getsockopt(0, udt.UDP_SNDBUF) 121 | self.assertEquals(val, 10000) 122 | 123 | def test_getsockopt_udp_rcvbuf(self): 124 | s = self.create_socket() 125 | val = s.getsockopt(0, udt.UDP_RCVBUF) 126 | 127 | def test_getsockopt_snd_timeout(self): 128 | s = self.create_socket() 129 | val = s.getsockopt(0, udt.UDT_SNDTIMEO) 130 | self.assertEquals(val, -1) 131 | 132 | def test_getsockopt_rcv_timeout(self): 133 | s = self.create_socket() 134 | val = s.getsockopt(0, udt.UDT_RCVTIMEO) 135 | self.assertEquals(val, -1) 136 | 137 | def test_getsockopt_reuseaddr(self): 138 | s = self.create_socket() 139 | val = s.getsockopt(0, udt.UDT_REUSEADDR) 140 | self.assertEquals(val, True) 141 | 142 | def test_getsockopt_linger(self): 143 | s = self.create_socket() 144 | val = s.getsockopt(0, udt.UDT_LINGER) 145 | self.assertEquals(val, (1, 180)) 146 | 147 | def test_getsockopt_max_bw(self): 148 | s = self.create_socket() 149 | val = s.getsockopt(0, udt.UDT_MAXBW) 150 | self.assertEquals(val, -1) 151 | 152 | def test_create_epoll(self): 153 | epoll = udt.epoll() 154 | self.assertTrue(epoll.eid) 155 | 156 | def test_epoll_release(self): 157 | epoll = udt.epoll() 158 | epoll.release() 159 | 160 | def test_epoll_double_release(self): 161 | epoll = udt.epoll() 162 | epoll.release() 163 | self.assertRaises(RuntimeError, epoll.release) 164 | 165 | def test_epoll_add_usock(self): 166 | epoll = udt.epoll() 167 | s = self.create_socket() 168 | self.assertEquals(0, epoll.add_usock(s.fileno(), udt.UDT_EPOLL_IN)) 169 | 170 | def test_epoll_add_ssock(self): 171 | epoll = udt.epoll() 172 | s1, s2 = socket.socketpair() 173 | epoll.add_ssock(s1.fileno(), udt.UDT_EPOLL_IN) 174 | 175 | def test_epoll_remove_usock(self): 176 | epoll = udt.epoll() 177 | s = self.create_socket() 178 | epoll.add_usock(s.fileno(), udt.UDT_EPOLL_IN) 179 | epoll.remove_usock(s.fileno(), udt.UDT_EPOLL_IN) 180 | 181 | def test_epoll_remove_bad_usock(self): 182 | epoll = udt.epoll() 183 | s = self.create_socket() 184 | fileno = s.fileno() 185 | s.close() 186 | self.assertRaises(RuntimeError, epoll.remove_usock, fileno, udt.UDT_EPOLL_IN) 187 | 188 | # FIXME - broken functionality in UDT ? 189 | def _test_epoll_remove_ssock(self): 190 | epoll = udt.epoll() 191 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 192 | s.connect(('127.0.0.1', 22)) 193 | self.assertEquals( 194 | epoll.add_ssock(s.fileno(), udt.UDT_EPOLL_IN), 195 | 0 196 | ) 197 | epoll.remove_ssock(s.fileno(), udt.UDT_EPOLL_IN) 198 | 199 | def test_epoll_wait(self): 200 | s = self.create_socket() 201 | epoll = udt.epoll() 202 | epoll.add_usock(s.fileno(), udt.UDT_EPOLL_IN) 203 | print(epoll.epoll_wait(0)) 204 | print(epoll.epoll_wait(1)) 205 | 206 | unittest.main() 207 | 208 | -------------------------------------------------------------------------------- /udt.py: -------------------------------------------------------------------------------- 1 | # use socket library for portability 2 | import socket as socketlib 3 | from _udt import * 4 | import _udt 5 | 6 | class socket(_udt.socket): 7 | def connect(self, addr): 8 | conn_addr = self._get_addr(addr) 9 | return _udt.socket.connect(self, conn_addr) 10 | 11 | def bind(self, addr): 12 | bind_addr = self._get_addr(addr) 13 | return _udt.socket.bind(self, bind_addr) 14 | 15 | def _get_addr(self, addr): 16 | host, port = addr 17 | family, socktype, proto, name, addr = socketlib.getaddrinfo( 18 | host, 19 | port, 20 | self.family, 21 | 0, 22 | 0, 23 | 0 24 | )[0] 25 | return addr 26 | 27 | class epoll(_udt.epoll): 28 | def __init__(self): 29 | _udt.epoll.__init__(self) 30 | self._released = False 31 | 32 | def release(self): 33 | if not self._released: 34 | _udt.epoll.release(self) 35 | 36 | def add_usock(self, s, events): 37 | # according to the docs, adding flags is not supported 38 | rv = _udt.epoll.add_usock(self, s, events) 39 | return rv 40 | 41 | def add_ssock(self, s, events): 42 | rv = _udt.epoll.add_ssock(self, s, events) 43 | return rv 44 | 45 | def remove_usock(self, s, events): 46 | rv = _udt.epoll.remove_usock(self, s, events) 47 | return rv 48 | 49 | def remove_ssock(self, s, events): 50 | rv = _udt.epoll.remove_ssock(self, s, events) 51 | return rv 52 | -------------------------------------------------------------------------------- /udt_py.cxx: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "udt_py.h" 8 | 9 | PyObject* pyudt_socket_accept(PyObject *self, PyObject *args, PyObject *kwargs); 10 | 11 | static PyObject* pyudt_epoll_add_usock(PyObject *self, PyObject *args, PyObject *kwargs); 12 | static PyObject* pyudt_epoll_remove_usock(PyObject *self, PyObject *args, PyObject *kwargs); 13 | 14 | static PyObject* pyudt_epoll_add_ssock(PyObject *self, PyObject *args, PyObject *kwargs); 15 | static PyObject* pyudt_epoll_remove_ssock(PyObject *self, PyObject *args, PyObject *kwargs); 16 | 17 | static PyObject* pyudt_epoll_wait(PyObject *self, PyObject *args, PyObject *kwargs); 18 | 19 | #define PY_TRY_CXX \ 20 | try \ 21 | { 22 | 23 | #define PY_CATCH_CXX(ret_val) \ 24 | } \ 25 | catch(py_udt_error& e) \ 26 | { \ 27 | try \ 28 | { \ 29 | UDT::ERRORINFO& udt_err = UDT::getlasterror(); \ 30 | PyErr_SetString(PyExc_RuntimeError, udt_err.getErrorMessage()); \ 31 | UDT::getlasterror().clear(); \ 32 | return ret_val; \ 33 | } \ 34 | catch(...)\ 35 | {\ 36 | PyErr_SetString(PyExc_RuntimeError, "UDT error"); \ 37 | UDT::getlasterror().clear(); \ 38 | return ret_val; \ 39 | }\ 40 | } \ 41 | catch(std::exception& e) \ 42 | { \ 43 | PyErr_SetString(PyExc_RuntimeError, e.what()); \ 44 | return ret_val; \ 45 | } \ 46 | catch(...) \ 47 | {\ 48 | PyErr_SetString(PyExc_RuntimeError, "C++ error"); \ 49 | return ret_val; \ 50 | } 51 | 52 | 53 | AutoDecref::AutoDecref(PyObject *ptr) 54 | { 55 | this->ptr = ptr; 56 | } 57 | 58 | AutoDecref::~AutoDecref() 59 | { 60 | if(this->ptr != NULL) 61 | { 62 | Py_DECREF(ptr); 63 | } 64 | } 65 | 66 | void AutoDecref::ok() 67 | { 68 | this->ptr = NULL; 69 | } 70 | 71 | AutoGILCallOut::AutoGILCallOut() 72 | { 73 | state = PyEval_SaveThread(); 74 | } 75 | 76 | AutoGILCallOut::~AutoGILCallOut() 77 | { 78 | PyEval_RestoreThread(state); 79 | } 80 | 81 | AutoGILCallBack::AutoGILCallBack() 82 | { 83 | state = PyGILState_Ensure(); 84 | } 85 | 86 | AutoGILCallBack::~AutoGILCallBack() 87 | { 88 | PyGILState_Release(state); 89 | } 90 | 91 | PyObject* pyudt_cleanup(PyObject *self, PyObject *args, PyObject *kwargs) 92 | { 93 | PY_TRY_CXX 94 | 95 | if(!PyArg_ParseTuple(args, "")) 96 | { 97 | return NULL; 98 | } 99 | 100 | if (UDT::cleanup() == UDT::ERROR) 101 | { 102 | throw py_udt_error(); 103 | } 104 | 105 | Py_RETURN_NONE; 106 | 107 | PY_CATCH_CXX(NULL) 108 | } 109 | 110 | PyObject* pyudt_startup(PyObject *self, PyObject *args, PyObject *kwargs) 111 | { 112 | PY_TRY_CXX 113 | 114 | if(!PyArg_ParseTuple(args, "")) 115 | { 116 | return NULL; 117 | } 118 | 119 | if (UDT::startup() == UDT::ERROR) 120 | { 121 | throw py_udt_error(); 122 | } 123 | 124 | Py_RETURN_NONE; 125 | 126 | PY_CATCH_CXX(NULL) 127 | } 128 | 129 | RecvBuffer::RecvBuffer(unsigned int len) 130 | { 131 | head = new char[len + 1]; 132 | buf_len = 0; 133 | max_buf_len = len; 134 | head[max_buf_len] = '\0'; 135 | } 136 | 137 | RecvBuffer::~RecvBuffer() 138 | { 139 | delete[] head; 140 | } 141 | 142 | char *RecvBuffer::get_head() 143 | { 144 | return head; 145 | } 146 | 147 | unsigned int RecvBuffer::get_max_len() 148 | { 149 | return max_buf_len; 150 | } 151 | 152 | unsigned int RecvBuffer::get_buf_len() 153 | { 154 | return buf_len; 155 | } 156 | 157 | unsigned int RecvBuffer::set_buf_len(unsigned int new_len) 158 | { 159 | /* FIXME - overflow check required */ 160 | buf_len = new_len; 161 | head[buf_len] = '\0'; 162 | return buf_len; 163 | } 164 | 165 | int pyudt_epoll_init(PyObject *self, PyObject *args, PyObject *kwargs) 166 | { 167 | PY_TRY_CXX 168 | 169 | if(!PyArg_ParseTuple(args, "")) 170 | { 171 | return -1; 172 | } 173 | 174 | pyudt_epoll_object* py_epoll = ((pyudt_epoll_object*)self); 175 | py_epoll->eid = UDT::epoll_create(); 176 | 177 | if(py_epoll->eid < 0) 178 | { 179 | throw py_udt_error(); 180 | } 181 | return 0; 182 | PY_CATCH_CXX(-1) 183 | } 184 | 185 | PyObject* pyudt_epoll_release(PyObject *self, PyObject *args, PyObject *kwargs) 186 | { 187 | PY_TRY_CXX 188 | 189 | if(!PyArg_ParseTuple(args, "")) 190 | { 191 | return NULL; 192 | } 193 | 194 | if(UDT::epoll_release(((pyudt_epoll_object*)self)->eid)) 195 | { 196 | throw py_udt_error(); 197 | } 198 | Py_RETURN_NONE; 199 | PY_CATCH_CXX(NULL) 200 | } 201 | 202 | static PyObject* pyudt_epoll_get_eid(PyObject *py_epoll) 203 | { 204 | return Py_BuildValue("i", ((pyudt_epoll_object*)py_epoll)->eid); 205 | } 206 | 207 | static PyGetSetDef pyudt_epoll_getset[] = { 208 | { 209 | (char*)"eid", 210 | (getter)pyudt_epoll_get_eid, 211 | NULL, 212 | (char*)"get epoll id", 213 | NULL 214 | }, 215 | {NULL} /* Sentinel */ 216 | }; 217 | 218 | static PyMethodDef pyudt_epoll_methods[] = { 219 | { 220 | "release", 221 | (PyCFunction)pyudt_epoll_release, 222 | METH_VARARGS, 223 | "epoll release" 224 | }, 225 | { 226 | "add_usock", 227 | (PyCFunction)pyudt_epoll_add_usock, 228 | METH_VARARGS, 229 | "add udt socket to epoll" 230 | }, 231 | { 232 | "add_ssock", 233 | (PyCFunction)pyudt_epoll_add_ssock, 234 | METH_VARARGS, 235 | "add system socket to epoll" 236 | }, 237 | { 238 | "remove_usock", 239 | (PyCFunction)pyudt_epoll_remove_usock, 240 | METH_VARARGS, 241 | "remove udt socket from epoll" 242 | }, 243 | { 244 | "remove_ssock", 245 | (PyCFunction)pyudt_epoll_remove_ssock, 246 | METH_VARARGS, 247 | "remove system socket from epoll" 248 | }, 249 | { 250 | "epoll_wait", 251 | (PyCFunction)pyudt_epoll_wait, 252 | METH_VARARGS, 253 | "wait on a epoll events" 254 | }, 255 | {NULL} /* Sentinel */ 256 | }; 257 | 258 | static PyTypeObject pyudt_epoll_type = { 259 | PyObject_HEAD_INIT(NULL) 260 | "_udt.socket", /* tp_name */ 261 | sizeof(pyudt_socket_object), /* tp_basicsize */ 262 | 0, /* tp_itemsize */ 263 | 0, /* tp_dealloc */ 264 | 0, /* tp_print */ 265 | 0, /* tp_getattr */ 266 | 0, /* tp_setattr */ 267 | 0, /* tp_reserved */ 268 | 0, /* tp_repr */ 269 | 0, /* tp_as_number */ 270 | 0, /* tp_as_sequence */ 271 | 0, /* tp_as_mapping */ 272 | 0, /* tp_hash */ 273 | 0, /* tp_call */ 274 | 0, /* tp_str */ 275 | 0, /* tp_getattro */ 276 | 0, /* tp_setattro */ 277 | 0, /* tp_as_buffer*/ 278 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,/* tp_flags */ 279 | "UDT epoll", /* tp_doc */ 280 | 0, /* tp_traverse */ 281 | 0, /* tp_clear */ 282 | 0, /* tp_richcompare */ 283 | 0, /* tp_weaklistoffset */ 284 | 0, /* tp_iter */ 285 | 0, /* tp_iternext */ 286 | pyudt_epoll_methods, /* tp_methods */ 287 | 0, /* tp_members */ 288 | pyudt_epoll_getset, /* tp_getset */ 289 | 0, /* tp_base */ 290 | 0, /* tp_dict */ 291 | 0, /* tp_descr_get */ 292 | 0, /* tp_descr_set */ 293 | 0, /* tp_dictoffset */ 294 | (initproc)pyudt_epoll_init, /* tp_init */ 295 | 0, /* tp_alloc */ 296 | 0, /* tp_new */ 297 | 298 | }; 299 | 300 | 301 | static PyObject* pyudt_socket_get_family(PyObject *py_socket) 302 | { 303 | return Py_BuildValue("i", ((pyudt_socket_object*)py_socket)->family); 304 | } 305 | 306 | static PyObject* pyudt_socket_get_type(PyObject *py_socket) 307 | { 308 | return Py_BuildValue("i", ((pyudt_socket_object*)py_socket)->type); 309 | } 310 | 311 | static PyObject* pyudt_socket_get_proto(PyObject *py_socket) 312 | { 313 | return Py_BuildValue("i", ((pyudt_socket_object*)py_socket)->proto); 314 | } 315 | PyObject* pyudt_socket_connect(PyObject *self, PyObject *args, PyObject *kwargs) 316 | { 317 | PY_TRY_CXX 318 | char *address; 319 | int port = 0; 320 | 321 | sockaddr_in serv_addr; 322 | 323 | pyudt_socket_object* py_socket = ((pyudt_socket_object*)self); 324 | if(!PyArg_ParseTuple(args, "(si)", &address, &port)) 325 | { 326 | return NULL; 327 | } 328 | 329 | serv_addr.sin_family = py_socket->family; 330 | serv_addr.sin_port = htons(port); 331 | int res = inet_pton(py_socket->family, address, &serv_addr.sin_addr); 332 | 333 | if(res == 0) 334 | { 335 | PyErr_SetString(PyExc_ValueError, "bad address"); 336 | return NULL; 337 | } 338 | else if(res == -1 && errno == EAFNOSUPPORT) 339 | { 340 | PyErr_SetString(PyExc_ValueError, "address family not supported"); 341 | return NULL; 342 | } 343 | 344 | memset(&(serv_addr.sin_zero), '\0', 8); 345 | 346 | if (UDT::ERROR == UDT::connect( 347 | py_socket->cc_socket, 348 | (sockaddr*)&serv_addr, sizeof(serv_addr))) 349 | { 350 | throw py_udt_error(); 351 | } 352 | Py_RETURN_NONE; 353 | 354 | PY_CATCH_CXX(NULL) 355 | } 356 | 357 | 358 | PyObject* pyudt_socket_bind(PyObject *self, PyObject *args, PyObject *kwargs) 359 | { 360 | PY_TRY_CXX 361 | char *address; 362 | int port; 363 | 364 | sockaddr_in serv_addr; 365 | 366 | pyudt_socket_object* py_socket = ((pyudt_socket_object*)self); 367 | if(!PyArg_ParseTuple(args, "(si)", &address, &port)) 368 | { 369 | return NULL; 370 | } 371 | 372 | int res = inet_pton(py_socket->family, address, &serv_addr.sin_addr); 373 | 374 | serv_addr.sin_family = py_socket->family; 375 | serv_addr.sin_port = htons(port); 376 | 377 | if(res == 0) 378 | { 379 | PyErr_SetString(PyExc_ValueError, "bad address"); 380 | return NULL; 381 | } 382 | else if(res == -1 && errno == EAFNOSUPPORT) 383 | { 384 | PyErr_SetString(PyExc_ValueError, "address family not supported"); 385 | return NULL; 386 | } 387 | 388 | memset(&(serv_addr.sin_zero), '\0', 8); 389 | 390 | if (UDT::ERROR == UDT::bind( 391 | py_socket->cc_socket, 392 | (sockaddr*)&serv_addr, sizeof(serv_addr))) 393 | { 394 | throw py_udt_error(); 395 | } 396 | Py_RETURN_NONE; 397 | 398 | PY_CATCH_CXX(NULL) 399 | } 400 | 401 | PyObject* pyudt_socket_close(PyObject *self, PyObject *args, PyObject *kwargs) 402 | { 403 | PY_TRY_CXX 404 | 405 | if(UDT::close(((pyudt_socket_object*)self)->cc_socket)) 406 | { 407 | throw py_udt_error(); 408 | } 409 | Py_RETURN_NONE; 410 | PY_CATCH_CXX(NULL) 411 | } 412 | 413 | PyObject* pyudt_socket_listen(PyObject *self, PyObject *args, PyObject *kwargs) 414 | { 415 | PY_TRY_CXX 416 | int backlog; 417 | if(!PyArg_ParseTuple(args, "i", &backlog)) 418 | { 419 | return NULL; 420 | } 421 | 422 | if(UDT::listen(((pyudt_socket_object*)self)->cc_socket, backlog)) 423 | { 424 | throw py_udt_error(); 425 | } 426 | Py_RETURN_NONE; 427 | 428 | PY_CATCH_CXX(NULL) 429 | } 430 | 431 | int pyudt_socket_init(PyObject *self, PyObject *args, PyObject *kwargs) 432 | { 433 | PY_TRY_CXX 434 | 435 | int family; 436 | int type; 437 | int proto; 438 | 439 | if(!PyArg_ParseTuple(args, "iii", &family, &type, &proto)) 440 | { 441 | return -1; 442 | } 443 | 444 | if(family != AF_INET) 445 | { 446 | PyErr_SetString(PyExc_ValueError, "UDT only supports AF_INET addresses"); 447 | return -1; 448 | } 449 | 450 | UDTSOCKET cc_socket = UDT::socket(family, type, proto); 451 | if(cc_socket == -1) 452 | { 453 | PyErr_SetString(PyExc_RuntimeError, "socket creation returned -1"); 454 | return -1; 455 | } 456 | 457 | pyudt_socket_object* py_socket = ((pyudt_socket_object*)self); 458 | py_socket->cc_socket = cc_socket; 459 | py_socket->family = family; 460 | py_socket->type = type; 461 | py_socket->proto = proto; 462 | 463 | return 0; 464 | PY_CATCH_CXX(-1) 465 | } 466 | 467 | PyObject* pyudt_socket_send(PyObject *self, PyObject *args, PyObject *kwargs) 468 | { 469 | PY_TRY_CXX 470 | 471 | char* buf; 472 | int buf_len; 473 | int flags; 474 | int send_len = 0; 475 | 476 | pyudt_socket_object* py_socket = ((pyudt_socket_object*)self); 477 | 478 | if(!PyArg_ParseTuple(args, "y#i", &buf, &buf_len, &flags)) 479 | { 480 | return NULL; 481 | } 482 | 483 | { 484 | AutoGILCallOut g; 485 | send_len = UDT::send(py_socket->cc_socket, buf, buf_len, flags); 486 | } 487 | 488 | if(send_len == UDT::ERROR) 489 | { 490 | throw py_udt_error(); 491 | } 492 | return Py_BuildValue("i", send_len); 493 | 494 | PY_CATCH_CXX(NULL) 495 | } 496 | 497 | 498 | PyObject* pyudt_socket_sendmsg(PyObject *self, PyObject *args, PyObject *kwargs) 499 | { 500 | PY_TRY_CXX 501 | 502 | char* buf; 503 | int buf_len; 504 | int ttl; 505 | int send_len = 0; 506 | int in_order = 0; 507 | 508 | pyudt_socket_object* py_socket = ((pyudt_socket_object*)self); 509 | 510 | if(!PyArg_ParseTuple(args, "y#ii", &buf, &buf_len, &ttl, &in_order)) 511 | { 512 | return NULL; 513 | } 514 | 515 | send_len = UDT::sendmsg(py_socket->cc_socket, buf, buf_len, ttl, in_order); 516 | 517 | if(send_len == UDT::ERROR) 518 | { 519 | throw py_udt_error(); 520 | } 521 | return Py_BuildValue("i", send_len); 522 | 523 | PY_CATCH_CXX(NULL) 524 | } 525 | 526 | PyObject* pyudt_socket_recv(PyObject *self, PyObject *args, PyObject *kwargs) 527 | { 528 | PY_TRY_CXX 529 | 530 | int len; 531 | int flags; 532 | int recv_len = 0; 533 | 534 | pyudt_socket_object* py_socket = ((pyudt_socket_object*)self); 535 | 536 | if(!PyArg_ParseTuple(args, "ii", &len, &flags)) 537 | { 538 | return NULL; 539 | } 540 | 541 | RecvBuffer recv_buf(len); 542 | recv_len = UDT::recv(py_socket->cc_socket, recv_buf.get_head(), len, flags); 543 | 544 | if(recv_len == UDT::ERROR) 545 | { 546 | throw py_udt_error(); 547 | } 548 | 549 | recv_buf.set_buf_len(recv_len); 550 | return Py_BuildValue("y#", recv_buf.get_head(), recv_len); 551 | 552 | PY_CATCH_CXX(NULL) 553 | } 554 | 555 | PyObject* pyudt_socket_recvmsg(PyObject *self, PyObject *args, PyObject *kwargs) 556 | { 557 | PY_TRY_CXX 558 | 559 | int len; 560 | int recv_len = 0; 561 | 562 | pyudt_socket_object* py_socket = ((pyudt_socket_object*)self); 563 | 564 | if(!PyArg_ParseTuple(args, "i", &len)) 565 | { 566 | return NULL; 567 | } 568 | 569 | RecvBuffer recv_buf(len); 570 | recv_len = UDT::recvmsg(py_socket->cc_socket, recv_buf.get_head(), len); 571 | 572 | if(recv_len == UDT::ERROR) 573 | { 574 | throw py_udt_error(); 575 | } 576 | 577 | recv_buf.set_buf_len(recv_len); 578 | return Py_BuildValue("y#", recv_buf.get_head(), recv_len); 579 | 580 | PY_CATCH_CXX(NULL) 581 | } 582 | 583 | PyObject* pyudt_socket_perfmon(PyObject *self, PyObject *args, PyObject *kwargs) 584 | { 585 | PY_TRY_CXX 586 | int clear = 0; 587 | pyudt_socket_object* py_socket = ((pyudt_socket_object*)self); 588 | 589 | if(!PyArg_ParseTuple(args, "i", &clear)) 590 | { 591 | return NULL; 592 | } 593 | 594 | UDT::TRACEINFO info; 595 | if(UDT::perfmon(py_socket->cc_socket, &info, clear) == UDT::ERROR) 596 | { 597 | throw py_udt_error(); 598 | } 599 | /* Slow */ 600 | return Py_BuildValue( 601 | "{sLsLsLsisisisisisisisLsLsisisisisisisisdsdsdsisisisdsdsisi}", 602 | /* Aggregate Values */ 603 | "msTimeStamp", 604 | info.msTimeStamp, 605 | "pktSentTotal", 606 | info.pktSentTotal, 607 | "pktRecvTotal", 608 | info.pktRecvTotal, 609 | "pktSndLossTotal", 610 | info.pktSndLossTotal, 611 | "pktRcvLossTotal", 612 | info.pktRcvLossTotal, 613 | "pktRetransTotal", 614 | info.pktRetransTotal, 615 | "pktSentACKTotal", 616 | info.pktSentACKTotal, 617 | "pktRecvACKTotal", 618 | info.pktRecvACKTotal, 619 | "pktSentNAKTotal", 620 | info.pktSentNAKTotal, 621 | "pktRecvNAKTotal", 622 | info.pktRecvNAKTotal, 623 | /* Local Values */ 624 | "pktSent", 625 | info.pktSent, 626 | "pktRecv", 627 | info.pktRecv, 628 | "pktSndLoss", 629 | info.pktSndLoss, 630 | "pktRcvLoss", 631 | info.pktRcvLoss, 632 | "pktRetrans", 633 | info.pktRetrans, 634 | "pktSentACK", 635 | info.pktSentACK, 636 | "pktRecvACK", 637 | info.pktRecvACK, 638 | "pktSentNAK", 639 | info.pktSentNAK, 640 | "pktRecvNAK", 641 | info.pktRecvNAK, 642 | "mbpsSendRate", 643 | info.mbpsSendRate, 644 | "mbpsRecvRate", 645 | info.mbpsRecvRate, 646 | /* Instant Values */ 647 | "usPktSndPeriod", 648 | info.usPktSndPeriod, 649 | "pktFlowWindow", 650 | info.pktFlowWindow, 651 | "pktCongestionWindow", 652 | info.pktCongestionWindow, 653 | "pktFlightSize", 654 | info.pktFlightSize, 655 | "msRTT", 656 | info.msRTT, 657 | "mbpsBandwidth", 658 | info.mbpsBandwidth, 659 | "byteAvailSndBuf", 660 | info.byteAvailSndBuf, 661 | "byteAvailRcvBuf", 662 | info.byteAvailRcvBuf 663 | ); 664 | 665 | PY_CATCH_CXX(NULL) 666 | } 667 | 668 | /* 669 | It looks like UDT::getsockopt doesn't check the buffer length. 670 | The big switch makes it easier to call from Python and prevents segfaults. 671 | */ 672 | PyObject* pyudt_socket_getsockopt(PyObject *self, PyObject *args, PyObject *kwargs) 673 | { 674 | PY_TRY_CXX 675 | int level = 0; 676 | int opt_name = 0; 677 | int opt_len = 0; 678 | 679 | if(!PyArg_ParseTuple(args, "ii", &level, &opt_name)) 680 | { 681 | return NULL; 682 | } 683 | 684 | pyudt_socket_object* py_socket = ((pyudt_socket_object*)self); 685 | 686 | UDT::SOCKOPT switch_opt = (UDT::SOCKOPT)opt_name; 687 | switch(switch_opt) 688 | { 689 | case UDT_MSS: 690 | case UDT_FC: 691 | case UDT_SNDBUF: 692 | case UDT_RCVBUF: 693 | case UDP_SNDBUF: 694 | case UDP_RCVBUF: 695 | case UDT_SNDTIMEO: 696 | case UDT_RCVTIMEO: 697 | { 698 | int opt_val = 0; 699 | if (UDT::getsockopt( 700 | py_socket->cc_socket, 701 | level, switch_opt, &opt_val, &opt_len) == UDT::ERROR) 702 | { 703 | throw py_udt_error(); 704 | } 705 | return Py_BuildValue("i", opt_val); 706 | break; 707 | } 708 | case UDT_SNDSYN: 709 | case UDT_RCVSYN: 710 | case UDT_RENDEZVOUS: 711 | case UDT_REUSEADDR: 712 | { 713 | bool opt_val = true; 714 | if (UDT::getsockopt(py_socket->cc_socket, 715 | level, switch_opt, &opt_val, &opt_len) == UDT::ERROR) 716 | { 717 | throw py_udt_error(); 718 | } 719 | if(opt_val) 720 | { 721 | Py_RETURN_TRUE; 722 | } 723 | else 724 | { 725 | Py_RETURN_FALSE; 726 | } 727 | break; 728 | } 729 | case UDT_CC: 730 | { 731 | PyErr_SetString(PyExc_NotImplementedError, "UTC_CC not implemented yet"); 732 | return NULL; 733 | break; 734 | } 735 | case UDT_LINGER: 736 | { 737 | linger opt_val; 738 | opt_val.l_onoff = 0; 739 | opt_val.l_linger = 0; 740 | 741 | opt_len = sizeof(linger); 742 | if (UDT::getsockopt(py_socket->cc_socket, 743 | level, switch_opt, &opt_val, &opt_len) == UDT::ERROR) 744 | { 745 | throw py_udt_error(); 746 | } 747 | return Py_BuildValue("(ii)", opt_val.l_onoff, opt_val.l_linger); 748 | break; 749 | } 750 | case UDT_MAXBW: 751 | { 752 | int64_t opt_val; 753 | if (UDT::getsockopt(py_socket->cc_socket, 754 | level, switch_opt, &opt_val, &opt_len) == UDT::ERROR) 755 | { 756 | throw py_udt_error(); 757 | } 758 | return Py_BuildValue("l", opt_val); 759 | break; 760 | } 761 | default: 762 | { 763 | PyErr_SetString(PyExc_ValueError, "unknown socket option"); 764 | return NULL; 765 | } 766 | } 767 | PY_CATCH_CXX(NULL) 768 | } 769 | 770 | PyObject* pyudt_socket_setsockopt(PyObject *self, PyObject *args, PyObject *kwargs) 771 | { 772 | PY_TRY_CXX 773 | int level = 0; 774 | int opt_name = 0; 775 | PyObject *opt_obj = NULL; 776 | 777 | if(!PyArg_ParseTuple(args, "iiO", &level, &opt_name, &opt_obj)) 778 | { 779 | return NULL; 780 | } 781 | 782 | pyudt_socket_object* py_socket = ((pyudt_socket_object*)self); 783 | 784 | UDT::SOCKOPT switch_opt = (UDT::SOCKOPT)opt_name; 785 | switch(switch_opt) 786 | { 787 | case UDT_MSS: 788 | case UDT_FC: 789 | case UDT_SNDBUF: 790 | case UDT_RCVBUF: 791 | case UDP_SNDBUF: 792 | case UDP_RCVBUF: 793 | case UDT_SNDTIMEO: 794 | case UDT_RCVTIMEO: 795 | { 796 | int opt_val = 0; 797 | if(!PyArg_ParseTuple(args, "iii", &level, &opt_name, &opt_val)) 798 | { 799 | return NULL; 800 | } 801 | if (UDT::setsockopt( 802 | py_socket->cc_socket, 803 | level, switch_opt, &opt_val, sizeof(int)) == UDT::ERROR) 804 | { 805 | throw py_udt_error(); 806 | } 807 | Py_RETURN_NONE; 808 | break; 809 | } 810 | case UDT_SNDSYN: 811 | case UDT_RCVSYN: 812 | case UDT_RENDEZVOUS: 813 | case UDT_REUSEADDR: 814 | { 815 | bool opt_val = true; 816 | if(opt_obj == Py_True) 817 | { 818 | opt_val = true; 819 | } 820 | else if(opt_obj == Py_False) 821 | { 822 | opt_val = false; 823 | } 824 | else 825 | { 826 | PyErr_SetString(PyExc_TypeError, "option must be boolean"); 827 | return NULL; 828 | } 829 | 830 | 831 | if (UDT::setsockopt(py_socket->cc_socket, 832 | level, switch_opt, &opt_val, sizeof(bool)) == UDT::ERROR) 833 | { 834 | throw py_udt_error(); 835 | } 836 | Py_RETURN_NONE; 837 | break; 838 | } 839 | case UDT_CC: 840 | { 841 | PyErr_SetString(PyExc_NotImplementedError, "UTC_CC not implemented yet"); 842 | return NULL; 843 | break; 844 | } 845 | case UDT_LINGER: 846 | { 847 | linger opt_val; 848 | int opt_onoff; 849 | int opt_linger; 850 | 851 | if(!PyArg_ParseTuple(args, "ii(ii)", &level, &opt_name, &opt_onoff, &opt_linger)) 852 | { 853 | return NULL; 854 | } 855 | 856 | opt_val.l_onoff = opt_onoff; 857 | opt_val.l_linger = opt_linger; 858 | 859 | if (UDT::setsockopt(py_socket->cc_socket, 860 | level, switch_opt, &opt_val, sizeof(linger)) == UDT::ERROR) 861 | { 862 | throw py_udt_error(); 863 | } 864 | Py_RETURN_NONE; 865 | break; 866 | } 867 | case UDT_MAXBW: 868 | { 869 | int64_t opt_val; 870 | if(!PyArg_ParseTuple(args, "iil", &level, &opt_name, &opt_val)) 871 | { 872 | return NULL; 873 | } 874 | 875 | if (UDT::setsockopt(py_socket->cc_socket, 876 | level, switch_opt, &opt_val, sizeof(int64_t)) == UDT::ERROR) 877 | { 878 | throw py_udt_error(); 879 | } 880 | return Py_BuildValue("l", opt_val); 881 | break; 882 | } 883 | default: 884 | { 885 | PyErr_SetString(PyExc_ValueError, "unknown socket option"); 886 | return NULL; 887 | } 888 | } 889 | PY_CATCH_CXX(NULL) 890 | } 891 | 892 | 893 | PyObject* pyudt_socket_fileno(PyObject *self, PyObject *args, PyObject *kwargs) 894 | { 895 | PY_TRY_CXX 896 | 897 | pyudt_socket_object* py_socket = ((pyudt_socket_object*)self); 898 | 899 | if(!PyArg_ParseTuple(args, "")) 900 | { 901 | return NULL; 902 | } 903 | return Py_BuildValue("l", py_socket->cc_socket); 904 | 905 | PY_CATCH_CXX(NULL) 906 | } 907 | 908 | static PyMethodDef pyudt_socket_methods[] = { 909 | { 910 | "accept", 911 | (PyCFunction)pyudt_socket_accept, 912 | METH_VARARGS, 913 | "socket accept" 914 | }, 915 | { 916 | "connect", 917 | (PyCFunction)pyudt_socket_connect, 918 | METH_VARARGS, 919 | "socket connect" 920 | }, 921 | { 922 | "close", 923 | (PyCFunction)pyudt_socket_close, 924 | METH_VARARGS, 925 | "close the socket" 926 | }, 927 | { 928 | "bind", 929 | (PyCFunction)pyudt_socket_bind, 930 | METH_VARARGS, 931 | "socket bind" 932 | }, 933 | { 934 | "listen", 935 | (PyCFunction)pyudt_socket_listen, 936 | METH_VARARGS, 937 | "listen with backlog" 938 | }, 939 | { 940 | "send", 941 | (PyCFunction)pyudt_socket_send, 942 | METH_VARARGS, 943 | "send data" 944 | }, 945 | { 946 | "sendmsg", 947 | (PyCFunction)pyudt_socket_sendmsg, 948 | METH_VARARGS, 949 | "send msg" 950 | }, 951 | { 952 | "recv", 953 | (PyCFunction)pyudt_socket_recv, 954 | METH_VARARGS, 955 | "recv data" 956 | }, 957 | { 958 | "recvmsg", 959 | (PyCFunction)pyudt_socket_recvmsg, 960 | METH_VARARGS, 961 | "recv msg" 962 | }, 963 | { 964 | "perfmon", 965 | (PyCFunction)pyudt_socket_perfmon, 966 | METH_VARARGS, 967 | "get perfmon stats" 968 | }, 969 | { 970 | "getsockopt", 971 | (PyCFunction)pyudt_socket_getsockopt, 972 | METH_VARARGS, 973 | "get socket options" 974 | }, 975 | { 976 | "setsockopt", 977 | (PyCFunction)pyudt_socket_setsockopt, 978 | METH_VARARGS, 979 | "set socket options" 980 | }, 981 | { 982 | "fileno", 983 | (PyCFunction)pyudt_socket_fileno, 984 | METH_VARARGS, 985 | "get socket file descriptor" 986 | }, 987 | {NULL} /* Sentinel */ 988 | }; 989 | 990 | static PyGetSetDef pyudt_socket_getset[] = { 991 | { 992 | (char*)"family", 993 | (getter)pyudt_socket_get_family, 994 | NULL, 995 | (char*)"address family", 996 | NULL 997 | }, 998 | { 999 | (char*)"type", 1000 | (getter)pyudt_socket_get_type, 1001 | NULL, 1002 | (char*)"address type", 1003 | NULL 1004 | }, 1005 | { 1006 | (char*)"proto", 1007 | (getter)pyudt_socket_get_proto, 1008 | NULL, 1009 | (char*)"address protocol", 1010 | NULL 1011 | }, 1012 | {NULL} /* Sentinel */ 1013 | }; 1014 | 1015 | 1016 | static PyMethodDef pyudt_methods[] = { 1017 | { 1018 | (char*)"startup", 1019 | (PyCFunction)pyudt_startup, 1020 | METH_VARARGS, 1021 | (char*)"startup-up UDT library", 1022 | }, 1023 | { 1024 | (char*)"cleanup", 1025 | (PyCFunction)pyudt_cleanup, 1026 | METH_VARARGS, 1027 | (char*)"clean-up UDT library", 1028 | }, 1029 | {NULL, NULL, 0, NULL} 1030 | }; 1031 | 1032 | static PyModuleDef udtmodule = { 1033 | PyModuleDef_HEAD_INIT, 1034 | "_udt", 1035 | "UDT: UDP-based Data Transfer Library", 1036 | -1, 1037 | pyudt_methods, 1038 | NULL, NULL, NULL, NULL 1039 | }; 1040 | 1041 | 1042 | static PyTypeObject pyudt_socket_type = { 1043 | PyObject_HEAD_INIT(NULL) 1044 | "_udt.socket", /* tp_name */ 1045 | sizeof(pyudt_socket_object), /* tp_basicsize */ 1046 | 0, /* tp_itemsize */ 1047 | 0, /* tp_dealloc */ 1048 | 0, /* tp_print */ 1049 | 0, /* tp_getattr */ 1050 | 0, /* tp_setattr */ 1051 | 0, /* tp_compare */ 1052 | 0, /* tp_repr */ 1053 | 0, /* tp_as_number */ 1054 | 0, /* tp_as_sequence */ 1055 | 0, /* tp_as_mapping */ 1056 | 0, /* tp_hash */ 1057 | 0, /* tp_call */ 1058 | 0, /* tp_str */ 1059 | 0, /* tp_getattro */ 1060 | 0, /* tp_setattro */ 1061 | 0, /* tp_as_buffer*/ 1062 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,/* tp_flags */ 1063 | "UDT socket", /* tp_doc */ 1064 | 0, /* tp_traverse */ 1065 | 0, /* tp_clear */ 1066 | 0, /* tp_richcompare */ 1067 | 0, /* tp_weaklistoffset */ 1068 | 0, /* tp_iter */ 1069 | 0, /* tp_iternext */ 1070 | pyudt_socket_methods, /* tp_methods */ 1071 | 0, /* tp_members */ 1072 | pyudt_socket_getset, /* tp_getset */ 1073 | 0, /* tp_base */ 1074 | 0, /* tp_dict */ 1075 | 0, /* tp_descr_get */ 1076 | 0, /* tp_descr_set */ 1077 | 0, /* tp_dictoffset */ 1078 | (initproc)pyudt_socket_init, /* tp_init */ 1079 | 0, /* tp_alloc */ 1080 | 0, /* tp_new */ 1081 | 1082 | }; 1083 | 1084 | PyObject* pyudt_socket_accept(PyObject *self, PyObject *args, PyObject *kwargs) 1085 | { 1086 | PY_TRY_CXX 1087 | // char *address; 1088 | // int port; 1089 | int namelen; 1090 | 1091 | sockaddr_in client_addr; 1092 | 1093 | pyudt_socket_object* py_socket = ((pyudt_socket_object*)self); 1094 | 1095 | if(!PyArg_ParseTuple(args, "")) 1096 | { 1097 | return NULL; 1098 | } 1099 | 1100 | UDTSOCKET cc_client = 0; 1101 | { 1102 | AutoGILCallOut g; 1103 | cc_client = UDT::accept( 1104 | py_socket->cc_socket, 1105 | (sockaddr*)&client_addr, 1106 | &namelen 1107 | ); 1108 | } 1109 | 1110 | if (cc_client == UDT::ERROR) 1111 | { 1112 | throw py_udt_error(); 1113 | } 1114 | 1115 | pyudt_socket_object* py_client = (pyudt_socket_object*)PyObject_New( 1116 | pyudt_socket_object, 1117 | &pyudt_socket_type 1118 | ); 1119 | 1120 | AutoDecref dec((PyObject*)py_client); 1121 | 1122 | py_client->cc_socket = cc_client; 1123 | py_client->family = client_addr.sin_family; 1124 | py_client->type = py_socket->type; // FIXME 1125 | py_client->proto = py_socket->proto; // FIXME 1126 | 1127 | PyObject *ret = Py_BuildValue( 1128 | "N(si)", 1129 | py_client, 1130 | inet_ntoa(client_addr.sin_addr), 1131 | client_addr.sin_port 1132 | ); 1133 | 1134 | if(ret == NULL) 1135 | { 1136 | return NULL; 1137 | } 1138 | dec.ok(); 1139 | return ret; 1140 | 1141 | 1142 | PY_CATCH_CXX(NULL) 1143 | } 1144 | 1145 | /* FIXME - should accept None. */ 1146 | static PyObject* pyudt_epoll_add_usock(PyObject *self, PyObject *args, PyObject *kwargs) 1147 | { 1148 | PY_TRY_CXX 1149 | int eid = ((pyudt_epoll_object*)self)->eid; 1150 | int events = 0; 1151 | int fileno = 0; 1152 | 1153 | if(!PyArg_ParseTuple(args, "ii", &fileno, &events)) 1154 | { 1155 | return NULL; 1156 | } 1157 | 1158 | int rv = UDT::epoll_add_usock(eid, fileno, &events); 1159 | 1160 | if(rv < 0) 1161 | { 1162 | throw py_udt_error(); 1163 | } 1164 | return Py_BuildValue("i", rv); 1165 | PY_CATCH_CXX(NULL) 1166 | } 1167 | 1168 | 1169 | /* FIXME - should accept None. */ 1170 | static PyObject* pyudt_epoll_add_ssock(PyObject *self, PyObject *args, PyObject *kwargs) 1171 | { 1172 | PY_TRY_CXX 1173 | int eid = ((pyudt_epoll_object*)self)->eid; 1174 | int events = 0; 1175 | int fileno = 0; 1176 | 1177 | if(!PyArg_ParseTuple(args, "ii", &fileno, &events)) 1178 | { 1179 | return NULL; 1180 | } 1181 | 1182 | int rv = UDT::epoll_add_ssock(eid, fileno, &events); 1183 | 1184 | if(rv < 0) 1185 | { 1186 | throw py_udt_error(); 1187 | } 1188 | return Py_BuildValue("i", rv); 1189 | PY_CATCH_CXX(NULL) 1190 | } 1191 | 1192 | /* FIXME - should accept None. */ 1193 | static PyObject* pyudt_epoll_remove_usock(PyObject *self, PyObject *args, PyObject *kwargs) 1194 | { 1195 | PY_TRY_CXX 1196 | int eid = ((pyudt_epoll_object*)self)->eid; 1197 | int events = 0; 1198 | int fileno = 0; 1199 | 1200 | if(!PyArg_ParseTuple(args, "ii", &fileno, &events)) 1201 | { 1202 | return NULL; 1203 | } 1204 | 1205 | int rv = UDT::epoll_remove_usock(eid, fileno); 1206 | 1207 | if(rv < 0) 1208 | { 1209 | throw py_udt_error(); 1210 | } 1211 | return Py_BuildValue("i", rv); 1212 | PY_CATCH_CXX(NULL) 1213 | } 1214 | 1215 | 1216 | /* FIXME - should accept None. */ 1217 | static PyObject* pyudt_epoll_remove_ssock(PyObject *self, PyObject *args, PyObject *kwargs) 1218 | { 1219 | PY_TRY_CXX 1220 | int eid = ((pyudt_epoll_object*)self)->eid; 1221 | int events = 0; 1222 | int fileno = 0; 1223 | 1224 | if(!PyArg_ParseTuple(args, "ii", &fileno, &events)) 1225 | { 1226 | return NULL; 1227 | } 1228 | 1229 | int rv = UDT::epoll_remove_ssock(eid, fileno); 1230 | 1231 | if(rv < 0) 1232 | { 1233 | throw py_udt_error(); 1234 | } 1235 | return Py_BuildValue("i", rv); 1236 | PY_CATCH_CXX(NULL) 1237 | } 1238 | 1239 | static PyObject* pyudt_epoll_wait(PyObject *self, PyObject *args, PyObject *kwargs) 1240 | { 1241 | PY_TRY_CXX 1242 | 1243 | PyObject *r_usock_set = NULL; 1244 | PyObject *w_usock_set = NULL; 1245 | 1246 | PyObject *r_ssock_set = NULL; 1247 | PyObject *w_ssock_set = NULL; 1248 | 1249 | int64_t timeout = 0; 1250 | 1251 | int eid = ((pyudt_epoll_object*)self)->eid; 1252 | 1253 | if(!PyArg_ParseTuple(args, "i", &timeout)) 1254 | { 1255 | return NULL; 1256 | } 1257 | 1258 | r_usock_set = PySet_New(0); 1259 | if(!r_usock_set) return NULL; 1260 | AutoDecref dec1(r_usock_set); 1261 | 1262 | w_usock_set = PySet_New(0); 1263 | if(!w_usock_set) return NULL; 1264 | AutoDecref dec2(w_usock_set); 1265 | 1266 | r_ssock_set = PySet_New(0); 1267 | if(!r_ssock_set) return NULL; 1268 | AutoDecref dec3(r_ssock_set); 1269 | 1270 | w_ssock_set = PySet_New(0); 1271 | if(!w_ssock_set) return NULL; 1272 | AutoDecref dec4(w_ssock_set); 1273 | 1274 | std::set r_usock_out; 1275 | std::set w_usock_out; 1276 | 1277 | std::set r_ssock_out; 1278 | std::set w_ssock_out; 1279 | 1280 | { 1281 | AutoGILCallOut g; 1282 | if(UDT::epoll_wait(eid, &r_usock_out, &w_usock_out, timeout) < 0) 1283 | { 1284 | throw py_udt_error(); 1285 | } 1286 | } 1287 | 1288 | std::set::const_iterator usock_iter; 1289 | for(usock_iter = r_usock_out.begin(); usock_iter != r_usock_out.end(); ++usock_iter) 1290 | { 1291 | 1292 | PyObject *i = PyLong_FromLong(*usock_iter); 1293 | 1294 | if(!i) 1295 | { 1296 | return NULL; 1297 | } 1298 | 1299 | if(PySet_Add(r_usock_set, i) == -1) 1300 | { 1301 | return NULL; 1302 | } 1303 | } 1304 | 1305 | for(usock_iter = w_usock_out.begin(); usock_iter != w_usock_out.end(); ++usock_iter) 1306 | { 1307 | 1308 | PyObject *i = PyLong_FromLong(*usock_iter); 1309 | 1310 | if(!i) 1311 | { 1312 | return NULL; 1313 | } 1314 | 1315 | if(PySet_Add(w_usock_set, i) == -1) 1316 | { 1317 | return NULL; 1318 | } 1319 | } 1320 | 1321 | std::set::const_iterator ssock_iter; 1322 | for(ssock_iter = r_ssock_out.begin(); ssock_iter != r_ssock_out.end(); ++ssock_iter) 1323 | { 1324 | 1325 | PyObject *i = PyLong_FromLong(*ssock_iter); 1326 | 1327 | if(!i) 1328 | { 1329 | return NULL; 1330 | } 1331 | 1332 | if(PySet_Add(r_ssock_set, i) == -1) 1333 | { 1334 | return NULL; 1335 | } 1336 | } 1337 | 1338 | for(ssock_iter = w_ssock_out.begin(); ssock_iter != w_ssock_out.end(); ++ssock_iter) 1339 | { 1340 | 1341 | PyObject *i = PyLong_FromLong(*ssock_iter); 1342 | 1343 | if(!i) 1344 | { 1345 | return NULL; 1346 | } 1347 | 1348 | if(PySet_Add(w_ssock_set, i) == -1) 1349 | { 1350 | return NULL; 1351 | } 1352 | } 1353 | 1354 | PyObject *ret = Py_BuildValue( 1355 | "NNNN", 1356 | r_usock_set, 1357 | w_usock_set, 1358 | r_ssock_set, 1359 | w_ssock_set 1360 | ); 1361 | 1362 | dec1.ok(); 1363 | dec2.ok(); 1364 | dec3.ok(); 1365 | dec4.ok(); 1366 | 1367 | return ret; 1368 | 1369 | PY_CATCH_CXX(NULL) 1370 | } 1371 | 1372 | PyMODINIT_FUNC 1373 | PyInit__udt(void) 1374 | { 1375 | PyObject *module; 1376 | 1377 | pyudt_socket_type.tp_new = PyType_GenericNew; 1378 | if (PyType_Ready(&pyudt_socket_type) < 0) 1379 | return NULL; 1380 | 1381 | pyudt_epoll_type.tp_new = PyType_GenericNew; 1382 | if (PyType_Ready(&pyudt_epoll_type) < 0) 1383 | return NULL; 1384 | 1385 | module = PyModule_Create(&udtmodule); 1386 | if (module == NULL) 1387 | { 1388 | return NULL; 1389 | } 1390 | 1391 | Py_INCREF(&pyudt_socket_type); 1392 | Py_INCREF(&pyudt_epoll_type); 1393 | PyModule_AddObject(module, "socket", (PyObject *)&pyudt_socket_type); 1394 | PyModule_AddObject(module, "epoll", (PyObject *)&pyudt_epoll_type); 1395 | 1396 | if(PyModule_AddIntConstant(module, "UDT_MSS", UDT_MSS) == -1 ) {return NULL;} 1397 | if(PyModule_AddIntConstant(module, "UDT_SNDSYN", UDT_SNDSYN) == -1 ) {return NULL;} 1398 | if(PyModule_AddIntConstant(module, "UDT_RCVSYN", UDT_RCVSYN) == -1 ) {return NULL;} 1399 | if(PyModule_AddIntConstant(module, "UDT_CC", UDT_CC) == -1 ) {return NULL;} 1400 | if(PyModule_AddIntConstant(module, "UDT_FC", UDT_FC) == -1 ) {return NULL;} 1401 | if(PyModule_AddIntConstant(module, "UDT_SNDBUF", UDT_SNDBUF) == -1 ) {return NULL;} 1402 | if(PyModule_AddIntConstant(module, "UDT_RCVBUF", UDT_RCVBUF) == -1 ) {return NULL;} 1403 | if(PyModule_AddIntConstant(module, "UDT_LINGER", UDT_LINGER) == -1 ) {return NULL;} 1404 | if(PyModule_AddIntConstant(module, "UDP_SNDBUF", UDP_SNDBUF) == -1 ) {return NULL;} 1405 | if(PyModule_AddIntConstant(module, "UDP_RCVBUF", UDP_RCVBUF) == -1 ) {return NULL;} 1406 | if(PyModule_AddIntConstant(module, "UDT_MAXMSG", UDT_MAXMSG) == -1 ) {return NULL;} 1407 | if(PyModule_AddIntConstant(module, "UDT_MSGTTL", UDT_MSGTTL) == -1 ) {return NULL;} 1408 | if(PyModule_AddIntConstant(module, "UDT_RENDEZVOUS", UDT_RENDEZVOUS) == -1 ) {return NULL;} 1409 | if(PyModule_AddIntConstant(module, "UDT_SNDTIMEO", UDT_SNDTIMEO) == -1 ) {return NULL;} 1410 | if(PyModule_AddIntConstant(module, "UDT_RCVTIMEO", UDT_RCVTIMEO) == -1 ) {return NULL;} 1411 | if(PyModule_AddIntConstant(module, "UDT_REUSEADDR", UDT_REUSEADDR) == -1 ) {return NULL;} 1412 | if(PyModule_AddIntConstant(module, "UDT_MAXBW", UDT_MAXBW) == -1 ) {return NULL;} 1413 | if(PyModule_AddIntConstant(module, "UDT_EPOLL_IN", UDT_EPOLL_IN) == -1 ) {return NULL;} 1414 | if(PyModule_AddIntConstant(module, "UDT_EPOLL_OUT", UDT_EPOLL_OUT) == -1 ) {return NULL;} 1415 | if(PyModule_AddIntConstant(module, "UDT_EPOLL_ERR", UDT_EPOLL_ERR) == -1 ) {return NULL;} 1416 | 1417 | return module; 1418 | } 1419 | -------------------------------------------------------------------------------- /udt_py.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | typedef struct py_udt_error : std::exception {} py_udt_error; 6 | typedef struct cc_general_error : std::exception {} cc_general_error; 7 | 8 | /* 9 | FIXME - Need to implement GIL handling 10 | */ 11 | class AutoGILCallOut 12 | { 13 | public: 14 | AutoGILCallOut(); 15 | ~AutoGILCallOut(); 16 | 17 | private: 18 | PyThreadState *state; 19 | }; 20 | 21 | class AutoGILCallBack 22 | { 23 | public: 24 | AutoGILCallBack(); 25 | ~AutoGILCallBack(); 26 | 27 | private: 28 | PyGILState_STATE state; 29 | }; 30 | 31 | class AutoDecref 32 | { 33 | public: 34 | AutoDecref(PyObject *o); 35 | ~AutoDecref(); 36 | void ok(); 37 | 38 | private: 39 | PyObject *ptr; 40 | }; 41 | 42 | typedef struct 43 | { 44 | PyObject_HEAD; 45 | UDTSOCKET cc_socket; 46 | int family; 47 | int type; 48 | int proto; 49 | 50 | } pyudt_socket_object; 51 | 52 | typedef struct 53 | { 54 | PyObject_HEAD; 55 | int eid; 56 | } pyudt_epoll_object; 57 | 58 | class RecvBuffer 59 | { 60 | public: 61 | RecvBuffer(unsigned int size); 62 | ~RecvBuffer(); 63 | 64 | char *get_head(); 65 | unsigned int get_max_len(); 66 | unsigned int get_buf_len(); 67 | unsigned int set_buf_len(unsigned int len); 68 | 69 | private: 70 | char *head; 71 | unsigned int max_buf_len; 72 | unsigned int buf_len; 73 | 74 | 75 | }; 76 | --------------------------------------------------------------------------------