1 #include "scd_socket.h"
3 #include <sys/socket.h>
4 #include <netinet/tcp.h> // for TCP_NODELAY
9 #include "scd_logging.h"
10 #include "scd_exception.h"
12 scd_socket::scd_socket()
15 _is_connecting = false;
16 _is_connected = false;
19 scd_socket::~scd_socket() {}
21 bool scd_socket::is_valid() const
23 return (_socket != -1);
26 bool scd_socket::create()
28 // check if socket already created before
35 _socket = socket(PF_INET, SOCK_STREAM, 0);
41 _is_connecting = false;
42 _is_connected = false;
48 void scd_socket::close()
56 _is_connecting = false;
57 _is_connected = false;
60 bool scd_socket::bind(const std::string &loc_name, const uint16_t loc_port)
69 // prepare the local address
71 if ( !_get_sockaddr(loc_addr, loc_name, loc_port) )
76 // set socket reusable (to recreate listener without timeout)
78 ret = setsockopt( _socket, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) );
81 throw scd_exception("setsockopt()", errno);
84 ret = ::bind( _socket, reinterpret_cast<struct sockaddr*>(&loc_addr),
92 scd_error("must be root to bind to desired port");
95 scd_error("unable to bind as the address is already in use");
98 throw scd_exception("bind()", errno);
108 bool scd_socket::bind(const uint16_t loc_port)
110 return bind("", loc_port);
114 bool scd_socket::listen()
123 ret = ::listen(_socket, SCD_MAXCONN);
127 throw scd_exception("listen()", errno);
133 bool scd_socket::accept(scd_socket &new_sock)
142 ret = ::accept(_socket, NULL, NULL);
155 throw scd_exception("accept()", errno);
161 new_sock._is_connected = true;
162 new_sock._socket = ret;
163 new_sock._set_blocking(false);
165 new_sock._set_nodelay();
174 bool scd_socket::connect(const std::string &rem_name, const uint16_t rem_port)
178 if ( !is_valid() || _is_connecting || _is_connected )
181 sockaddr_in rem_addr;
182 if ( !_get_sockaddr(rem_addr, rem_name, rem_port) )
185 ret = ::connect(_socket, reinterpret_cast<const sockaddr*>(&rem_addr),
193 _is_connecting = true;
201 case EALREADY: // should be prevented by _is_connecting
203 throw scd_exception("connect()", errno);
209 _is_connected = true;
210 _is_connecting = false;
217 bool scd_socket::is_connecting()
219 if ( !is_valid() || !_is_connecting || _is_connected )
227 bool scd_socket::is_connected()
229 if ( !is_valid() || _is_connecting || !_is_connected)
237 bool scd_socket::connected_event()
244 scd_warn("write event occured on an invalid socket");
247 else if ( !_is_connecting )
249 scd_warn("checking connected event while not connecting");
253 // get possible errors from connection attempt
255 socklen_t err_size = sizeof(err);
256 ret = getsockopt(_socket, SOL_SOCKET, SO_ERROR, &err, &err_size);
260 throw scd_exception("getsockopt()", errno);
267 // connection established
268 _is_connecting = false;
269 _is_connected = true;
280 // connection attempt failed
281 _is_connecting = false;
285 // should not be possible as we received a completion event
286 throw scd_exception("checking connected event while still connecting");
288 case EALREADY: // should be prevented by _is_connecting
290 throw scd_exception("connect()", errno);
295 } //connected_event()
298 size_t scd_socket::send(const void* buf, size_t len)
302 if ( !is_valid() || len == 0 || !_is_connected )
305 ret = ::send(_socket, buf, len, MSG_NOSIGNAL);
319 throw scd_exception("send()", errno);
329 size_t scd_socket::recv(void* buf, size_t len)
333 if ( !is_valid() || len == 0 || !_is_connected)
336 ret = ::recv(_socket, buf, len, MSG_NOSIGNAL);
350 throw scd_exception("recv()", errno);
365 bool scd_socket::_get_sockaddr(sockaddr_in &addr, const std::string &name,
366 const uint16_t port) const
369 memset( &addr, 0, sizeof(addr) );
372 addr.sin_family = AF_INET;
373 addr.sin_port = htons( port );
376 // bind to all local addresses
377 addr.sin_addr.s_addr = INADDR_ANY;
381 // bint to specified address only
385 he = gethostbyname2(&name[0], AF_INET);
389 // copy address (network order)
390 addr.sin_addr.s_addr =
391 reinterpret_cast<struct in_addr*>(he->h_addr_list[0])->s_addr;
399 bool scd_socket::_set_blocking(const bool mode)
406 int opts = fcntl( _socket, F_GETFL );
410 throw scd_exception("fcntl()", errno);
414 opts = ( opts | O_NONBLOCK );
416 opts = ( opts & ~O_NONBLOCK );
418 fcntl( _socket, F_SETFL,opts );
425 bool scd_socket::_set_nodelay()
430 // disable Nagle algorithm
432 int ret = setsockopt( _socket, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on) );
435 throw scd_exception("setsockopt()", errno);