Socket::Socket() : descriptor_(0), addr_family_(AF_INET), type_(SOCK_STREAM), protocol_(0), close_on_delete_(true), is_alive_(false) { // Create a UDT socket descriptor_ = UDT::socket(addr_family_, type_, protocol_); // Catch a possible error if (descriptor_ == UDT::INVALID_SOCK) { translateUDTError(); return; } PYUDT_LOG_TRACE("Created UDT socket " << descriptor_); // Set default socket options bool blocking_send = false; bool blocking_recv = true; if (UDT::ERROR == UDT::setsockopt(descriptor_, 0, UDT_SNDSYN, &blocking_send, sizeof(blocking_send)) || UDT::ERROR == UDT::setsockopt(descriptor_, 0, UDT_RCVSYN, &blocking_recv, sizeof(blocking_recv)) ) { translateUDTError(); return; } PYUDT_LOG_TRACE("Set default options for UDT socket " << descriptor_); }
Socket::Socket(UDTSOCKET descriptor, bool close_on_delete) : descriptor_(descriptor), addr_family_(0), type_(0), protocol_(0), close_on_delete_(close_on_delete), is_alive_(true) { PYUDT_LOG_TRACE("Created Socket object from existing socket " << descriptor_); PYUDT_LOG_TRACE("Setting options for UDT socket " << descriptor_); // TODO: find a way to get the address family, type and protocol from an // existing UDT socket. addr_family_ = AF_INET; type_ = SOCK_STREAM; // Set default socket options bool blocking_send = false; bool blocking_recv = true; if (UDT::ERROR == UDT::setsockopt(descriptor_, 0, UDT_SNDSYN, &blocking_send, sizeof(blocking_send)) || UDT::ERROR == UDT::setsockopt(descriptor_, 0, UDT_RCVSYN, &blocking_recv, sizeof(blocking_recv)) ) { translateUDTError(); return; } PYUDT_LOG_TRACE("Default options set for UDT socket " << descriptor_); }
boost::tuple<Socket_ptr, boost::tuple<const char*,uint16_t> > Socket::accept() throw() { PYUDT_LOG_TRACE("Accepting connection to socket " << descriptor_ << "..."); // Parameters of the incoming connection sockaddr_in client_addr; int client_addrlen; UDTSOCKET client_descriptor; // Retrieve an incoming connection Py_BEGIN_ALLOW_THREADS; client_descriptor = UDT::accept(descriptor_, (sockaddr*)&client_addr, &client_addrlen); Py_END_ALLOW_THREADS; if (client_descriptor == UDT::ERROR) { translateUDTError(); return boost::tuple<Socket_ptr, boost::tuple<const char*,uint16_t> > (Socket_ptr(), boost::tuple<const char*,uint16_t>("", 0)); } Socket_ptr client = make_shared<Socket>(client_descriptor); client->descriptor_ = client_descriptor; client->addr_family_ = addr_family_; client->type_ = type_; client->protocol_ = protocol_; client->is_alive_ = true; char client_host[NI_MAXHOST]; char client_srvc[NI_MAXSERV]; memset(client_host, '\0', sizeof(client_host)); memset(client_srvc, '\0', sizeof(client_srvc)); // Get the client hostname if (getnameinfo((sockaddr*) &client_addr, client_addrlen, client_host, sizeof(client_host) , client_srvc, sizeof(client_srvc) , NI_NUMERICHOST | NI_NUMERICSERV)) { PYUDT_LOG_ERROR("Failed to get the client host info"); } PYUDT_LOG_TRACE("Accepted connection to socket " << descriptor_ << " from address " << client_host); return boost::tuple<Socket_ptr, boost::tuple<const char*, uint16_t> > (make_shared<Socket>(client->getDescriptor()), boost::tuple<const char*, uint16_t> (client_host, client_addr.sin_port)); }
Epoll::~Epoll() { PYUDT_LOG_TRACE("Releasing epoll " << id_ << "..."); // Release the epoll if (UDT::epoll_release(id_) < 0) { PYUDT_LOG_ERROR("Could not release epoll " << id_); translateUDTError(); return; } PYUDT_LOG_TRACE("Released epoll " << id_); }
void Epoll::garbage_collect() throw() { std::map<UDTSOCKET, Socket*>::iterator iter; UDTSTATUS status; for (iter = objmap_.begin(); iter != objmap_.end(); ++iter) { status = UDT::getsockstate(iter->first); if ( status == BROKEN || status == CLOSED || status == NONEXIST) { // Remove the UDT socket from the epoll UDT::epoll_remove_usock(id_, iter->first); // Destroy the socket delete iter->second; // Remove the socket from the map objmap_.erase(iter); } } PYUDT_LOG_TRACE("Garbage collection done for epoll " << id_); }
py::str Socket::recv(int buf_len) const throw() { int res; char* buf = (char*) malloc (buf_len * sizeof(char)); // Initialize the buffer to \0 memset(buf, '\0', buf_len); // FIXME: useful python macros? Py_BEGIN_ALLOW_THREADS; res = UDT::recv(descriptor_, buf, buf_len, 0); Py_END_ALLOW_THREADS; if (res == UDT::ERROR) { free(buf); PYUDT_LOG_ERROR("Could not receive data from socket " << descriptor_); translateUDTError(); // None return py::str(); } py::str py_buf = buf; free(buf); PYUDT_LOG_TRACE("Received " << buf_len << " byte(s) from socket " << descriptor_ << " that are stored in " << static_cast<void *>(&buf)); return py_buf; }
void Socket::send(const char* buf, int buf_len) const throw() { if (buf == nullptr) { throw Exception("Null buffer provided during Socket::send", ""); } int res; // FIXME: useful python macros? Py_BEGIN_ALLOW_THREADS; res = UDT::send(descriptor_, buf, buf_len, 0); Py_END_ALLOW_THREADS; if (res == UDT::ERROR) { PYUDT_LOG_ERROR("Could not send data through socket " << descriptor_); translateUDTError(); return; } PYUDT_LOG_TRACE("Sent " << buf_len << " byte(s) through socket " << descriptor_ << " that were stored in " << static_cast<void *>(&buf)); }
void Socket::close() { int res; if (is_alive_) { res = UDT::close(descriptor_); // FIXME: currently ignore invalid socket errors // This happens when the socket destructor is called after the epoll // destructor. if (res == UDT::ERROR && UDT::getlasterror().getErrorCode() != CUDTException::EINVSOCK) { translateUDTError(); return; } else { PYUDT_LOG_TRACE("Closed UDT socket " << descriptor_); } is_alive_ = false; } }
void Socket::recv(char* buf, int buf_len) const throw() { if (buf == nullptr) { throw Exception("Null buffer provided during Socket::recv", ""); } int res; // Initialize the buffer to \0 memset(buf, '\0', buf_len); // FIXME: useful python macros? Py_BEGIN_ALLOW_THREADS; res = UDT::recv(descriptor_, buf, buf_len, 0); Py_END_ALLOW_THREADS; if (res == UDT::ERROR) { PYUDT_LOG_ERROR("Could not receive data from socket " << descriptor_); translateUDTError(); return; } PYUDT_LOG_TRACE("Received " << buf_len << " byte(s) from socket " << descriptor_ << " that are stored in " << static_cast<void *>(&buf)); }
Epoll::Epoll() { PYUDT_LOG_TRACE("Creating an epoll..."); // Create the epoll id_ = UDT::epoll_create(); // Catch a possible error if (id_ < 0) { PYUDT_LOG_ERROR("Could not create an epoll"); translateUDTError(); return; } PYUDT_LOG_TRACE("Created epoll " << id_); }
Socket::~Socket() { // TODO: make sure that the socket is no longer referenced in an epoll // Close socket on destruction if (close_on_delete_) close(); PYUDT_LOG_TRACE("Destroyed UDT socket " << descriptor_); }
void Socket::listen(unsigned int backlog) throw() { if (UDT::ERROR == UDT::listen(descriptor_, backlog)) { translateUDTError(); return; } PYUDT_LOG_TRACE("Socket " << descriptor_ << " set to listen state. Maximum number of pending " << "connections = " << backlog); }
void Socket::bind_to_udp(UDPSOCKET udp_socket) throw() { if (UDT::ERROR == UDT::bind2(descriptor_, udp_socket)) { translateUDTError(); return; } is_alive_ = true; PYUDT_LOG_TRACE("Bound UDT socket " << descriptor_ << " to UDP socket " << udp_socket); }
void Socket::send(py::object py_buf) const throw() { // pointer to buffer char* buf = nullptr; // true buffer length int buf_len = 0; // passed in length size int pref_len = 0; // TODO: find a way to use Boost.Python instead if (!PyArg_ParseTuple(py_buf.ptr(), "s#ii", &buf, &buf_len, &pref_len)) { Exception e("Wrong arguments: Socket::send((char*)buf, (int)buf_len)", ""); translateException(e); throw e; } else { if ((pref_len - buf_len) > buf_len) { Exception e("Buffer length must not double real buffer length", ""); translateException(e); throw e; return; } } if (buf == nullptr) { Exception e("Null buffer provided during Socket::send", ""); translateException(e); throw e; } int res; // FIXME: useful python macros? Py_BEGIN_ALLOW_THREADS; res = UDT::send(descriptor_, buf, buf_len, 0); Py_END_ALLOW_THREADS; if (res == UDT::ERROR) { PYUDT_LOG_ERROR("Could not send data through socket " << descriptor_); translateUDTError(); return; } PYUDT_LOG_TRACE("Sent " << buf_len << " byte(s) through socket " << descriptor_ << " that were stored in " << static_cast<void *>(&buf)); }
void Socket::connect(const char* ip, uint16_t port) throw() { sockaddr_in addr = build_sockaddr_in(ip, port); if (UDT::ERROR == UDT::connect(descriptor_, (sockaddr*) &addr, sizeof(addr))) { translateUDTError(); return; } is_alive_ = true; PYUDT_LOG_TRACE("Connect socket " << descriptor_ << " to address " << ip << ":" << port); }
void Epoll::add_ssock(py::object py_socket, py::object py_flags) throw() { // File descriptor of a system socket SYSSOCKET socket; int flags; try { // Extract the flags flags = py::extract<int>(py_flags); // First, try to extract a file descriptor py::extract<SYSSOCKET> get_syssocket(py_socket); if (get_syssocket.check()) socket = get_syssocket(); else { // Second, try to treat this as a Python TCP socket try { socket = py::call_method<SYSSOCKET>(py_socket.ptr(), "fileno"); } catch (...) { Exception e("Wrong arguments: Epoll::add_ssock((SYSSOCKET)s, "\ "(int)flags)", ""); translateException(e); throw e; } } if (UDT::ERROR == UDT::epoll_add_ssock(id_, socket, &flags)) { PYUDT_LOG_ERROR("Could not add system socket " << socket << " to epoll " << id_); translateUDTError(); return; } } catch (py::error_already_set& err) { std::cerr << parse_python_exception() << std::endl; throw err; } PYUDT_LOG_TRACE("Added system socket " << socket << " to epoll " << id_); }
void Epoll::add_usock(py::object py_socket, py::object py_flags) throw() { Socket* socket; int flags; try { try { socket = py::extract<Socket*>(py_socket); flags = py::extract<int>(py_flags); } catch (...) { Exception e("Wrong arguments: Epoll::add_usock((Socket)s, (int)flags)", ""); translateException(e); throw e; } objmap_[socket->getDescriptor()] = socket; if (UDT::ERROR == UDT::epoll_add_usock(id_, socket->getDescriptor(), &flags)) { PYUDT_LOG_ERROR("Could not add UDT socket " << socket->getDescriptor() << " to epoll " << id_); translateUDTError(); return; } } catch (py::error_already_set& err) { std::cerr << parse_python_exception() << std::endl; throw err; } PYUDT_LOG_TRACE("Added UDT socket " << socket->getDescriptor() << " to epoll " << id_ << " with flag " << flags); }
void Epoll::remove_ssock(py::object py_socket) throw() { SYSSOCKET socket; try { py::extract<SYSSOCKET> get_syssocket(py_socket); if (get_syssocket.check()) socket = get_syssocket(); else { try { socket = py::call_method<SYSSOCKET>(py_socket.ptr(), "fileno"); } catch (...) { Exception e("Wrong arguments: Epoll::remove_ssock((SYSSOCKET)s)", ""); translateException(e); throw e; } } if (UDT::ERROR == UDT::epoll_remove_ssock(id_, socket)) { PYUDT_LOG_ERROR("Could not remove system socket " << socket << " from epoll " << id_); translateUDTError(); return; } } catch (py::error_already_set& err) { std::cerr << parse_python_exception() << std::endl; throw err; } PYUDT_LOG_TRACE("Removed system socket " << socket << " from epoll " << id_); }
void Epoll::add_ssock(py::object py_socket, py::object py_flags) throw() { // file descriptor of a system socket SYSSOCKET socket; int flags; try { try { socket = py::extract<SYSSOCKET>(py_socket); flags = py::extract<int>(py_flags); } catch (...) { Exception e("Wrong arguments: Epoll::add_ssock((SYSSOCKET)s, (int)flags)", ""); translateException(e); throw e; } if (UDT::ERROR == UDT::epoll_add_ssock(id_, socket, &flags)) { PYUDT_LOG_ERROR("Could not add system socket " << socket << " to epoll " << id_); translateUDTError(); return; } } catch (py::error_already_set& err) { std::cerr << parse_python_exception() << std::endl; throw err; } PYUDT_LOG_TRACE("Added system socket " << socket << " to epoll " << id_); }
void Epoll::remove_usock(py::object py_socket) throw() { Socket* socket; try { try { socket = py::extract<Socket*>(py_socket); } catch (...) { Exception e("Wrong arguments: Epoll::remove_usock((Socket)s)", ""); translateException(e); throw e; } objmap_.erase(socket->getDescriptor()); if (UDT::ERROR == UDT::epoll_remove_usock(id_, socket->getDescriptor())) { PYUDT_LOG_ERROR("Could not remove UDT socket " << socket->getDescriptor() << " from epoll " << id_); translateUDTError(); return; } } catch (py::error_already_set& err) { std::cerr << parse_python_exception() << std::endl; throw err; } PYUDT_LOG_TRACE("Removed UDT socket " << socket->getDescriptor() << " from epoll " << id_); }
int Epoll::wait(int64_t ms_timeout, bool do_uread, bool do_uwrite, bool do_sread, bool do_swrite) throw () { int res = UDT::epoll_wait(id_, (do_uread)? &read_udt_:nullptr, (do_uwrite)? &write_udt_:nullptr, ms_timeout, (do_sread)? &read_sys_:nullptr, (do_swrite)? &write_sys_:nullptr); if (res == UDT::ERROR) { if (UDT::getlasterror().getErrorCode() == CUDTException::ETIMEOUT) res = 0; else translateUDTError(); } PYUDT_LOG_TRACE("Number of UDT/system sockets ready for IO in epoll " << id_ << ": " << res); return res; }