socket_client_pos.cpp
Go to the documentation of this file.
1 
9 /*****************************************************************************
10 ** Cross platform
11 *****************************************************************************/
12 
13 #include <ecl/config/ecl.hpp>
14 #ifndef ECL_IS_APPLE
15 #ifdef ECL_IS_POSIX
16 
17 /*****************************************************************************
18 ** Includes
19 *****************************************************************************/
20 
21 #include <unistd.h>
22 #include <iostream>
23 #include <netdb.h> // gethostbyname
25 #include "../../include/ecl/devices/detail/socket_error_handler_pos.hpp"
26 #include "../../include/ecl/devices/detail/socket_exception_handler_pos.hpp"
27 #include "../../include/ecl/devices/socket_connection_status.hpp"
28 #include "../../include/ecl/devices/socket_client_pos.hpp"
29 
30 /*****************************************************************************
31 ** Namespaces
32 *****************************************************************************/
33 
34 namespace ecl {
35 
36 /*****************************************************************************
37 ** Using
38 *****************************************************************************/
39 
40 using std::string;
41 
42 /*****************************************************************************
43 ** Implementation
44 *****************************************************************************/
45 
46 SocketClient::SocketClient(const std::string &host_name, const unsigned int &port_number) :
47  hostname(host_name),
48  port(port_number),
49  is_open(false),
50  error_handler(NoError)
51 {
52  ecl_try {
53  open(host_name, port_number);
54  } ecl_catch ( StandardException &e ) {
55  ecl_throw(StandardException(LOC,e));
56  }
57 }
58 
59 void SocketClient::close() {
60  is_open = false;
61  ::close(socket_fd); // should have error handling here
62 }
63 
64 bool SocketClient::open( const std::string &host_name, const unsigned int& port_number ) {
65 
66  if ( this->open() ) { this->close(); }
67  hostname = host_name;
68  port = port_number;
69 
70  /*********************
71  * Open
72  **********************
73  * PF_INET (IP4), PF_LOCAL (LOCALHOST)
74  * SOCK_STREAM (TCPIP), SOCK_DGRAM (UDP), SOCK_RAW
75  * Last argument is generally always 0 (sub-type)
76  */
77  // maybe hostname == localhost or 127.0.0.1 -> use PF_LOCAL?
78  socket_fd = socket(AF_INET, SOCK_STREAM, 0);
79 // socket_fd = socket(PF_INET, SOCK_STREAM, 0);
80  if ( socket_fd == -1 ) {
81  ecl_throw(devices::socket_exception(LOC));
82  error_handler = devices::socket_error();
83  return false;
84  }
85  /*********************
86  ** Hostname
87  **********************/
88  struct hostent *host_entry;
89  /******************************************
90  * struct hostent {
91  * char *h_name; //official name of host
92  * char **h_aliases; // array of aliases (terminated by NULL)
93  * int h_addrtype; // host address type
94  * int h_length; // length of address
95  * char **h_addr_list; // array of addresses (terminated by NULL)
96  * }
97  ******************************************/
98  host_entry = gethostbyname(hostname.c_str());
99  if ( host_entry == NULL ) { // gethostbyname doesn't seem to be checking hostname validity???
100  ::close(socket_fd);
101  ecl_throw(devices::gethostbyname_exception(LOC,hostname));
102  error_handler = devices::gethostbyname_error();
103  return false;
104  }
105 
106  /*********************
107  ** Socket Details
108  **********************/
109  struct sockaddr_in destination;
110  destination.sin_family = AF_INET; // host byte order
111  destination.sin_addr = *((struct in_addr *)host_entry->h_addr);
112  destination.sin_port = htons(port); // short host byte order to network byte order
113  memset(destination.sin_zero, '\0', sizeof destination.sin_zero);
114 
115  /*********************
116  ** Connect
117  **********************/
118  int connect_result = connect( socket_fd, (struct sockaddr *) &destination, sizeof(destination) );
119  if ( connect_result == -1 ) {
120  is_open = false;
121  ::close(socket_fd);
122  ecl_throw(devices::connection_exception(LOC));
123  error_handler = devices::connection_error();
124  return false;
125  }
126  is_open = true;
127  error_handler = NoError;
128  return true;
129 }
130 
131 /*****************************************************************************
132 ** Implementation [SocketClient][Source]
133 *****************************************************************************/
134 
135 long SocketClient::read(char &c) {
136  return read(&c,1);
137 }
138 
139 long SocketClient::read(char *s, const unsigned long &n) {
140 
141  if ( !open() ) {
142  return ConnectionDisconnected;
143  }
144 
145  /*********************
146  * Check Status
147  *********************/
148 // SocketStatus status = pollStatus(POLLIN); // Times out according to timeout_ms if it can't read in the specified time.
149 // std::cout << "Polling Status " << status << std::endl;
150 // if ( status != SocketReadReady ) { return status; } // else it is ok to write.
151 
152  int bytes_read = ::recv(socket_fd, s, n, 0); // Consider using MSG_WAITALL
153 
154  /*********************
155  ** Error Handling
156  **********************/
157  if ( bytes_read == 0 ) {
158  // Server has dropped
159  close();
160  return ConnectionHungUp;
161  }
162  if ( bytes_read < 0 ) {
163  if ( errno == ECONNRESET ) {
164  close();
165  return ConnectionHungUp;
166  } else {
167  ecl_debug_throw( devices::receive_exception(LOC) );
168  error_handler = devices::receive_error();
169  return ConnectionProblem;
170  }
171  }
172  error_handler = NoError;
173  return bytes_read;
174 }
175 
176 long SocketClient::peek(char *s, const unsigned long &n) {
177 
178  if ( !open() ) { return ConnectionDisconnected; }
179 
180  int bytes_read = ::recv(socket_fd, s, n, MSG_PEEK);
181  if ( bytes_read < 0 ) {
182  ecl_debug_throw( devices::receive_exception(LOC) );
183  error_handler = devices::receive_error();
184  return ConnectionProblem;
185  }
186  error_handler = NoError;
187  return bytes_read;
188 };
189 
190 long SocketClient::remaining() {
191 
192  if ( !open() ) { return ConnectionDisconnected; }
193 
194  unsigned long bytes;
195  int result = ioctl(socket_fd, FIONREAD, &bytes);
196  if ( result == -1 ) {
197  ecl_debug_throw( devices::ioctl_exception(LOC) );
198  error_handler = devices::ioctl_error();
199  }
200  error_handler = NoError;
201  return bytes;
202 };
203 
204 /*****************************************************************************
205 ** Implementation [SocketClient][Sink]
206 *****************************************************************************/
207 
208 long SocketClient::write(const char &c) {
209 
210  return write(&c, 1);
211 }
212 
213 long SocketClient::write(const char *s, unsigned long n) {
214 
215  if ( !open() ) { return ConnectionDisconnected; }
216 
217  /*********************
218  * Write
219  *********************/
220  int bytes_written = ::send(socket_fd,s,n,MSG_NOSIGNAL);
221 
222  if ( bytes_written < 0 ) {
223  switch(errno) {
224  case ( EPIPE ) : {
225  close();
226  return ConnectionHungUp;
227  }
228  default : {
229  ecl_debug_throw( devices::send_exception(LOC) );
230  error_handler = devices::send_error();
231  return ConnectionProblem;
232  }
233  }
234  }
235  return bytes_written;
236 }
237 
238 } // namespace ecl
239 
240 #endif /* ECL_IS_POSIX */
241 #endif /* !ECL_IS_APPLE */
ecl::ConnectionHungUp
@ ConnectionHungUp
Used to signify when a server/client detects that the other end has 'hung up'.
Definition: socket_connection_status.hpp:49
ecl_try
#define ecl_try
ecl::ConnectionProblem
@ ConnectionProblem
Was some error in the last operation..
Definition: socket_connection_status.hpp:47
ecl::NoError
NoError
standard_exception.hpp
ecl_catch
#define ecl_catch(exception)
ecl_throw
#define ecl_throw(exception)
ecl
Embedded control libraries.
ecl::ConnectionDisconnected
@ ConnectionDisconnected
Used to state when a server/client detects that there is no other connection at the other end.
Definition: socket_connection_status.hpp:48
ecl_debug_throw
#define ecl_debug_throw(exception)


ecl_devices
Author(s): Daniel Stonier
autogenerated on Wed Mar 2 2022 00:16:45