/*************************************************************************** * Copyright (C) 2006 by Gerd v. Egidy * * gve@intra2net.com * * * * This library is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License version * * 2.1 as published by the Free Software Foundation. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "socket_client.hxx" #include "t2n_exception.hxx" using namespace std; namespace libt2n { socket_client_connection::socket_client_connection(int _port, const std::string& _server, long long _connect_timeout_usec, int _max_retries) : client_connection(), socket_handler(0,tcp_s) { max_retries=_max_retries; connect_timeout_usec=_connect_timeout_usec; server=_server; port=_port; tcp_connect(max_retries); } socket_client_connection::socket_client_connection(const std::string& _path, long long _connect_timeout_usec, int _max_retries) : client_connection(), socket_handler(0,unix_s) { max_retries=_max_retries; connect_timeout_usec=_connect_timeout_usec; path=_path; unix_connect(max_retries); } void socket_client_connection::tcp_connect(int max_retries) { struct sockaddr_in sock_addr; sock_addr.sin_family = AF_INET; sock_addr.sin_port = htons(port); // find the target ip if (inet_aton(server.c_str(),&sock_addr.sin_addr)==0) { struct hostent *server_hent; server_hent=gethostbyname(server.c_str()); if (server_hent == NULL) throw t2n_connect_error(string("can't find server ")+server); memcpy(&sock_addr.sin_addr,server_hent->h_addr_list[0],sizeof(sock_addr.sin_addr)); } sock = socket(PF_INET, SOCK_STREAM, 0); if (!sock) throw t2n_connect_error(string("socket() error: ")+strerror(errno)); try { connect_with_timeout((struct sockaddr *) &sock_addr,sizeof(sock_addr)); } catch (t2n_connect_error &e) { // recurse if retries left if (max_retries > 0) tcp_connect(max_retries-1); } do_callbacks(new_connection); } void socket_client_connection::unix_connect(int max_retries) { struct sockaddr_un unix_addr; unix_addr.sun_family = AF_UNIX; strcpy (unix_addr.sun_path, path.c_str()); sock = socket(PF_UNIX, SOCK_STREAM, 0); if (!sock) throw t2n_connect_error(string("socket() error: ")+strerror(errno)); try { connect_with_timeout((struct sockaddr *) &unix_addr, sizeof(unix_addr)); } catch (t2n_connect_error &e) { // recurse if retries left if (max_retries > 0) tcp_connect(max_retries-1); } do_callbacks(new_connection); } void socket_client_connection::connect_with_timeout(struct sockaddr *sock_addr,unsigned int sockaddr_size) { set_socket_options(sock); int ret=::connect(sock,sock_addr, sockaddr_size); if (ret < 0) { if (errno==EINPROGRESS) { /* set timeout */ struct timeval tval; struct timeval *timeout_ptr; if (connect_timeout_usec == -1) timeout_ptr = NULL; else { timeout_ptr = &tval; // convert timeout from long long usec to int sec + int usec tval.tv_sec = connect_timeout_usec / 1000000; tval.tv_usec = connect_timeout_usec % 1000000; } fd_set connect_socket_set; FD_ZERO(&connect_socket_set); FD_SET(sock,&connect_socket_set); int ret; while ((ret=select(FD_SETSIZE, NULL, &connect_socket_set, NULL, timeout_ptr)) && ret < 0 && errno==EINTR); if (ret < 0) throw t2n_connect_error(string("connect() error (select): ")+strerror(errno)); socklen_t sopt=sizeof(int); int valopt; ret=getsockopt(sock, SOL_SOCKET, SO_ERROR, (void*)(&valopt), &sopt); if (ret < 0 || valopt) throw t2n_connect_error(string("connect() error (getsockopt): ")+strerror(errno)); } else throw t2n_connect_error(string("connect() error: ")+strerror(errno)); } } void socket_client_connection::close() { if (!client_connection::is_closed()) { socket_handler::close(); client_connection::close(); } } }