IBR-DTNSuite 0.6

ibrcommon/ibrcommon/net/tcpclient.cpp

Go to the documentation of this file.
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 }