$search
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 */