|
IBR-DTNSuite 0.6
|
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 memset(&hints, 0, sizeof(struct addrinfo)); 00081 hints.ai_family = PF_UNSPEC; 00082 hints.ai_socktype = SOCK_STREAM; 00083 00084 struct addrinfo *res; 00085 int ret; 00086 00087 std::stringstream ss; ss << port; std::string port_string = ss.str(); 00088 00089 if ((ret = getaddrinfo(address.c_str(), port_string.c_str(), &hints, &res)) != 0) 00090 { 00091 throw SocketException("getaddrinfo(): " + std::string(gai_strerror(ret))); 00092 } 00093 00094 if (res == NULL) 00095 { 00096 throw SocketException("Could not connect to the server."); 00097 } 00098 00099 struct addrinfo *walk; 00100 for (walk = res; walk != NULL; walk = walk->ai_next) { 00101 _socket = socket(walk->ai_family, walk->ai_socktype, walk->ai_protocol); 00102 if (_socket < 0){ 00103 /* Hier kann eine Fehlermeldung hin, z.B. mit warn() */ 00104 00105 if (walk->ai_next == NULL) 00106 { 00107 throw SocketException("Could not create a socket."); 00108 } 00109 continue; 00110 } 00111 00112 if (timeout == 0) 00113 { 00114 if (connect(_socket, walk->ai_addr, walk->ai_addrlen) != 0) { 00115 ::close(_socket); 00116 _socket = -1; 00117 /* Hier kann eine Fehlermeldung hin, z.B. mit warn() */ 00118 if (walk->ai_next == NULL) 00119 { 00120 throw SocketException("Could not connect to the server."); 00121 } 00122 continue; 00123 } 00124 } 00125 else 00126 { 00127 // timeout is requested, set socket to non-blocking 00128 vsocket::set_non_blocking(_socket); 00129 00130 // now connect to the host (this returns immediately 00131 ::connect(_socket, walk->ai_addr, walk->ai_addrlen); 00132 00133 try { 00134 bool read = false; 00135 bool write = true; 00136 bool error = false; 00137 00138 // now wait until we could write on this socket 00139 tcpstream::select(_interrupt_pipe_read[1], read, write, error, timeout); 00140 00141 // set the socket to blocking again 00142 vsocket::set_non_blocking(_socket, false); 00143 00144 // check if the attempt was successful 00145 int err = 0; 00146 socklen_t err_len = sizeof(err_len); 00147 ::getsockopt(_socket, SOL_SOCKET, SO_ERROR, &err, &err_len); 00148 00149 if (err != 0) 00150 { 00151 throw SocketException("Could not connect to the server."); 00152 } 00153 } catch (const select_exception &ex) { 00154 throw SocketException("Could not connect to the server."); 00155 } 00156 } 00157 break; 00158 } 00159 00160 freeaddrinfo(res); 00161 } 00162 00163 tcpclient::~tcpclient() 00164 { 00165 } 00166 }