socket_client_pos.cpp
Go to the documentation of this file.
00001 
00009 /*****************************************************************************
00010 ** Cross platform
00011 *****************************************************************************/
00012 
00013 #include <ecl/config/ecl.hpp>
00014 #ifndef ECL_IS_APPLE
00015 #ifdef ECL_IS_POSIX
00016 
00017 /*****************************************************************************
00018 ** Includes
00019 *****************************************************************************/
00020 
00021 #include <unistd.h>
00022 #include <iostream>
00023 #include <netdb.h> // gethostbyname
00024 #include <ecl/exceptions/standard_exception.hpp>
00025 #include "../../include/ecl/devices/detail/socket_error_handler_pos.hpp"
00026 #include "../../include/ecl/devices/detail/socket_exception_handler_pos.hpp"
00027 #include "../../include/ecl/devices/socket_connection_status.hpp"
00028 #include "../../include/ecl/devices/socket_client_pos.hpp"
00029 
00030 /*****************************************************************************
00031 ** Namespaces
00032 *****************************************************************************/
00033 
00034 namespace ecl {
00035 
00036 /*****************************************************************************
00037 ** Using
00038 *****************************************************************************/
00039 
00040 using std::string;
00041 
00042 /*****************************************************************************
00043 ** Implementation
00044 *****************************************************************************/
00045 
00046 SocketClient::SocketClient(const std::string &host_name, const unsigned int &port_number) ecl_throw_decl(StandardException) :
00047                 hostname(host_name),
00048                 port(port_number),
00049                 is_open(false),
00050                 error_handler(NoError)
00051 {
00052     ecl_try {
00053         open(host_name, port_number);
00054     } ecl_catch ( StandardException &e ) {
00055         ecl_throw(StandardException(LOC,e));
00056     }
00057 }
00058 
00059 void SocketClient::close() {
00060          is_open = false;
00061          ::close(socket_fd); // should have error handling here
00062 }
00063 
00064 bool SocketClient::open( const std::string &host_name, const unsigned int& port_number ) ecl_throw_decl(StandardException) {
00065 
00066         if ( this->open() ) { this->close(); }
00067         hostname = host_name;
00068     port = port_number;
00069 
00070         /*********************
00071          * Open
00072         **********************
00073      * PF_INET (IP4), PF_LOCAL (LOCALHOST)
00074      * SOCK_STREAM (TCPIP), SOCK_DGRAM (UDP), SOCK_RAW
00075      * Last argument is generally always 0 (sub-type)
00076      */
00077     // maybe hostname == localhost or 127.0.0.1 -> use PF_LOCAL?
00078     socket_fd = socket(AF_INET, SOCK_STREAM, 0);
00079 //    socket_fd = socket(PF_INET, SOCK_STREAM, 0);
00080     if ( socket_fd == -1 ) {
00081         ecl_throw(devices::socket_exception(LOC));
00082         error_handler = devices::socket_error();
00083         return false;
00084     }
00085     /*********************
00086         ** Hostname
00087         **********************/
00088     struct hostent *host_entry;
00089     /******************************************
00090      * struct hostent {
00091      *   char  *h_name;            //official name of host
00092      *   char **h_aliases;         // array of aliases (terminated by NULL)
00093      *   int    h_addrtype;        // host address type
00094      *   int    h_length;          // length of address
00095      *   char **h_addr_list;       // array of addresses (terminated by NULL)
00096      * }
00097      ******************************************/
00098     host_entry = gethostbyname(hostname.c_str());
00099     if ( host_entry == NULL ) { // gethostbyname doesn't seem to be checking hostname validity???
00100         ::close(socket_fd);
00101         ecl_throw(devices::gethostbyname_exception(LOC,hostname));
00102         error_handler = devices::gethostbyname_error();
00103         return false;
00104     }
00105 
00106     /*********************
00107         ** Socket Details
00108         **********************/
00109     struct sockaddr_in destination;
00110     destination.sin_family = AF_INET;    // host byte order
00111     destination.sin_addr = *((struct in_addr *)host_entry->h_addr);
00112     destination.sin_port = htons(port);  // short host byte order to network byte order
00113     memset(destination.sin_zero, '\0', sizeof destination.sin_zero);
00114 
00115     /*********************
00116         ** Connect
00117         **********************/
00118     int connect_result = connect( socket_fd, (struct sockaddr *) &destination, sizeof(destination) );
00119     if ( connect_result == -1 ) {
00120         is_open = false;
00121         ::close(socket_fd);
00122         ecl_throw(devices::connection_exception(LOC));
00123         error_handler = devices::connection_error();
00124         return false;
00125     }
00126     is_open = true;
00127     error_handler = NoError;
00128     return true;
00129 }
00130 
00131 /*****************************************************************************
00132 ** Implementation [SocketClient][Source]
00133 *****************************************************************************/
00134 
00135 long SocketClient::read(char &c) ecl_assert_throw_decl(StandardException) {
00136     return read(&c,1);
00137 }
00138 
00139 long SocketClient::read(char *s, const unsigned long &n) ecl_assert_throw_decl(StandardException) {
00140 
00141     if ( !open() ) {
00142         return ConnectionDisconnected;
00143     }
00144 
00145     /*********************
00146      * Check Status
00147      *********************/
00148 //    SocketStatus status = pollStatus(POLLIN); // Times out according to timeout_ms if it can't read in the specified time.
00149 //    std::cout << "Polling Status " << status << std::endl;
00150 //    if ( status != SocketReadReady ) { return status; } // else it is ok to write.
00151 
00152     int bytes_read = ::recv(socket_fd, s, n, 0); // Consider using MSG_WAITALL
00153 
00154     /*********************
00155         ** Error Handling
00156         **********************/
00157     if ( bytes_read == 0 ) {
00158         // Server has dropped
00159         close();
00160         return ConnectionHungUp;
00161     }
00162     if ( bytes_read < 0 ) {
00163         if ( errno == ECONNRESET ) {
00164                 close();
00165                 return ConnectionHungUp;
00166         } else {
00167                         ecl_debug_throw( devices::receive_exception(LOC) );
00168                         error_handler = devices::receive_error();
00169                         return ConnectionProblem;
00170         }
00171     }
00172     error_handler = NoError;
00173     return bytes_read;
00174 }
00175 
00176 long SocketClient::peek(char *s, const unsigned long &n) ecl_assert_throw_decl(StandardException) {
00177 
00178     if ( !open() ) { return ConnectionDisconnected; }
00179 
00180         int bytes_read = ::recv(socket_fd, s, n, MSG_PEEK);
00181     if ( bytes_read < 0 ) {
00182         ecl_debug_throw( devices::receive_exception(LOC) );
00183         error_handler = devices::receive_error();
00184         return ConnectionProblem;
00185     }
00186     error_handler = NoError;
00187     return bytes_read;
00188 };
00189 
00190 long SocketClient::remaining() {
00191 
00192     if ( !open() ) { return ConnectionDisconnected; }
00193 
00194     unsigned long bytes;
00195     int result = ioctl(socket_fd, FIONREAD, &bytes);
00196     if ( result == -1 ) {
00197         ecl_debug_throw( devices::ioctl_exception(LOC) );
00198         error_handler =  devices::ioctl_error();
00199     }
00200     error_handler = NoError;
00201     return bytes;
00202 };
00203 
00204 /*****************************************************************************
00205 ** Implementation [SocketClient][Sink]
00206 *****************************************************************************/
00207 
00208 long SocketClient::write(const char &c) ecl_assert_throw_decl(StandardException) {
00209 
00210         return write(&c, 1);
00211 }
00212 
00213 long SocketClient::write(const char *s, unsigned long n) ecl_assert_throw_decl(StandardException) {
00214 
00215         if ( !open() ) { return ConnectionDisconnected; }
00216 
00217     /*********************
00218      * Write
00219      *********************/
00220     int bytes_written = ::send(socket_fd,s,n,MSG_NOSIGNAL);
00221 
00222     if ( bytes_written < 0 ) {
00223         switch(errno) {
00224             case ( EPIPE ) : {
00225                 close();
00226                 return ConnectionHungUp;
00227             }
00228             default : {
00229                     ecl_debug_throw( devices::send_exception(LOC) );
00230                     error_handler = devices::send_error();
00231                     return ConnectionProblem;
00232             }
00233         }
00234     }
00235     return bytes_written;
00236 }
00237 
00238 } // namespace ecl
00239 
00240 #endif /* ECL_IS_POSIX */
00241 #endif  /* !ECL_IS_APPLE */


ecl_devices
Author(s): Daniel Stonier
autogenerated on Thu Jun 6 2019 21:18:03