IBR-DTNSuite
0.8
|
00001 /* 00002 * tcpclient.cpp 00003 * 00004 * Created on: 29.07.2009 00005 * Author: morgenro 00006 */ 00007 00008 #include "ibrcommon/config.h" 00009 #include "ibrcommon/net/tcpclient.h" 00010 #include <sys/types.h> 00011 #include <sys/socket.h> 00012 #include <sys/un.h> 00013 #include <netdb.h> 00014 #include <unistd.h> 00015 #include <stdio.h> 00016 #include <stdlib.h> 00017 #include <string.h> 00018 00019 #include <streambuf> 00020 #include <netinet/in.h> 00021 #include <arpa/inet.h> 00022 #include <sstream> 00023 00024 namespace ibrcommon 00025 { 00026 tcpclient::tcpclient() 00027 { 00028 } 00029 00030 tcpclient::tcpclient(const ibrcommon::File &s) 00031 { 00032 open(s); 00033 } 00034 00035 void tcpclient::open(const ibrcommon::File &s) 00036 { 00037 int len = 0; 00038 struct sockaddr_un saun; 00039 00040 /* 00041 * Get a socket to work with. This socket will 00042 * be in the UNIX domain, and will be a 00043 * stream socket. 00044 */ 00045 if ((_socket = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { 00046 throw SocketException("Could not create a socket."); 00047 } 00048 00049 /* 00050 * Create the address we will be connecting to. 00051 */ 00052 saun.sun_family = AF_UNIX; 00053 strcpy(saun.sun_path, s.getPath().c_str()); 00054 00055 /* 00056 * Try to connect to the address. For this to 00057 * succeed, the server must already have bound 00058 * this address, and must have issued a listen() 00059 * request. 00060 * 00061 * The third argument indicates the "length" of 00062 * the structure, not just the length of the 00063 * socket name. 00064 */ 00065 len = sizeof(saun.sun_family) + strlen(saun.sun_path); 00066 00067 if (connect(_socket, (struct sockaddr *)&saun, len) < 0) { 00068 throw SocketException("Could not connect to the named socket."); 00069 } 00070 } 00071 00072 tcpclient::tcpclient(const string &address, const int port, size_t timeout) 00073 { 00074 open(address, port, timeout); 00075 } 00076 00077 void tcpclient::open(const string &address, const int port, size_t timeout) 00078 { 00079 struct addrinfo hints; 00080 struct addrinfo *walk; 00081 memset(&hints, 0, sizeof(struct addrinfo)); 00082 hints.ai_family = PF_UNSPEC; 00083 hints.ai_socktype = SOCK_STREAM; 00084 00085 struct addrinfo *res; 00086 int ret; 00087 00088 std::stringstream ss; ss << port; std::string port_string = ss.str(); 00089 00090 if ((ret = getaddrinfo(address.c_str(), port_string.c_str(), &hints, &res)) != 0) 00091 { 00092 throw SocketException("getaddrinfo(): " + std::string(gai_strerror(ret))); 00093 } 00094 00095 if (res == NULL) 00096 { 00097 throw SocketException("Could not connect to the server."); 00098 } 00099 00100 try { 00101 for (walk = res; walk != NULL; walk = walk->ai_next) { 00102 _socket = socket(walk->ai_family, walk->ai_socktype, walk->ai_protocol); 00103 if (_socket < 0){ 00104 /* Hier kann eine Fehlermeldung hin, z.B. mit warn() */ 00105 00106 if (walk->ai_next == NULL) 00107 { 00108 throw SocketException("Could not create a socket."); 00109 } 00110 continue; 00111 } 00112 00113 if (timeout == 0) 00114 { 00115 if (connect(_socket, walk->ai_addr, walk->ai_addrlen) != 0) { 00116 ::close(_socket); 00117 _socket = -1; 00118 /* Hier kann eine Fehlermeldung hin, z.B. mit warn() */ 00119 if (walk->ai_next == NULL) 00120 { 00121 throw SocketException("Could not connect to the server."); 00122 } 00123 continue; 00124 } 00125 } 00126 else 00127 { 00128 // timeout is requested, set socket to non-blocking 00129 vsocket::set_non_blocking(_socket); 00130 00131 // now connect to the host (this returns immediately 00132 ::connect(_socket, walk->ai_addr, walk->ai_addrlen); 00133 00134 try { 00135 bool read = false; 00136 bool write = true; 00137 bool error = false; 00138 00139 // now wait until we could write on this socket 00140 tcpstream::select(_interrupt_pipe_read[1], read, write, error, timeout); 00141 00142 // set the socket to blocking again 00143 vsocket::set_non_blocking(_socket, false); 00144 00145 // check if the attempt was successful 00146 int err = 0; 00147 socklen_t err_len = sizeof(err_len); 00148 ::getsockopt(_socket, SOL_SOCKET, SO_ERROR, &err, &err_len); 00149 00150 if (err != 0) 00151 { 00152 throw SocketException("Could not connect to the server."); 00153 } 00154 } catch (const select_exception &ex) { 00155 throw SocketException("Could not connect to the server."); 00156 } 00157 } 00158 break; 00159 } 00160 00161 freeaddrinfo(res); 00162 } catch (ibrcommon::Exception&) { 00163 freeaddrinfo(res); 00164 throw; 00165 } 00166 } 00167 00168 tcpclient::~tcpclient() 00169 { 00170 } 00171 }