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


ecl_devices
Author(s): Daniel Stonier (d.stonier@gmail.com)
autogenerated on Thu Jan 2 2014 11:12:50