1 /* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3 * DataDifferential Utility Library
5 * Copyright (C) 2011 Data Differential, http://datadifferential.com/
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
15 * * Redistributions in binary form must reproduce the above
16 * copyright notice, this list of conditions and the following disclaimer
17 * in the documentation and/or other materials provided with the
20 * * The names of its contributors may not be used to endorse or
21 * promote products derived from this software without specific prior
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
27 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
28 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 #include "mem_config.h"
41 #include "util/instance.hpp"
46 #include <netinet/in.h>
49 #include <sys/socket.h>
50 #include <sys/types.h>
56 #ifndef INVALID_SOCKET
57 # define INVALID_SOCKET -1
61 # define SOCKET_ERROR -1
64 #ifndef get_socket_errno
65 # define get_socket_errno() errno
69 # define closesocket(a) close(a)
73 namespace datadifferential
{
76 Instance::Instance(const std::string
& hostname_arg
, const std::string
& service_arg
) :
78 _service(service_arg
),
79 _sockfd(INVALID_SOCKET
),
88 Instance::Instance(const std::string
& hostname_arg
, const in_port_t port_arg
) :
90 _sockfd(INVALID_SOCKET
),
98 snprintf(tmp
, sizeof(tmp
), "%u", static_cast<unsigned int>(port_arg
));
102 Instance::~Instance()
106 for (Operation::vector::iterator iter
= _operations
.begin(); iter
!= _operations
.end(); ++iter
)
117 while (not _operations
.empty())
119 Operation::vector::value_type operation
= _operations
.back();
128 memset(&ai
, 0, sizeof(struct addrinfo
));
129 ai
.ai_socktype
= SOCK_STREAM
;
130 ai
.ai_protocol
= IPPROTO_TCP
;
132 int ret
= getaddrinfo(_host
.c_str(), _service
.c_str(), &ai
, &_addrinfo
);
135 std::stringstream message
;
136 message
<< "Failed to connect on " << _host
.c_str() << ":" << _service
.c_str() << " with " << gai_strerror(ret
);
137 _last_error
= message
.str();
141 _addrinfo_next
= _addrinfo
;
145 case NEXT_CONNECT_ADDRINFO
:
146 if (_addrinfo_next
->ai_next
== NULL
)
148 std::stringstream message
;
149 message
<< "Error connecting to " << _host
.c_str() << "." << std::endl
;
150 _last_error
= message
.str();
153 _addrinfo_next
= _addrinfo_next
->ai_next
;
159 _sockfd
= socket(_addrinfo_next
->ai_family
,
160 _addrinfo_next
->ai_socktype
,
161 _addrinfo_next
->ai_protocol
);
162 if (_sockfd
== INVALID_SOCKET
)
168 if (connect(_sockfd
, _addrinfo_next
->ai_addr
, _addrinfo_next
->ai_addrlen
) < 0)
185 state
= NEXT_CONNECT_ADDRINFO
;
196 // Add logic for poll() for nonblocking.
203 size_t packet_length
= operation
->size();
204 const char *packet
= operation
->ptr();
208 ssize_t write_size
= send(_sockfd
, packet
, packet_length
, 0);
215 std::cerr
<< "Failed dureng send(" << strerror(errno
) << ")" << std::endl
;
220 packet_length
-= static_cast<size_t>(write_size
);
221 packet
+= static_cast<size_t>(write_size
);
228 if (operation
->has_response())
235 read_length
= ::recv(_sockfd
, buffer
, sizeof(buffer
), 0);
243 _last_error
+= "Error occured while reading data from ";
248 else if (read_length
== 0)
251 _last_error
+= "Socket was shutdown while reading from ";
257 operation
->push(buffer
, static_cast<size_t>(read_length
));
259 } while (more_to_read());
260 } // end has_response
266 std::string response
;
267 bool success
= operation
->response(response
);
270 if (not _finish_fn
->call(success
, response
))
272 // Error was sent from _finish_fn
277 if (operation
->reconnect())
280 _operations
.pop_back();
291 bool Instance::more_to_read() const
297 if (poll(&fds
, 1, 5) < 1) // Default timeout is 5
305 void Instance::close_socket()
307 if (_sockfd
== INVALID_SOCKET
)
312 /* in case of death shutdown to avoid blocking at close() */
313 if (shutdown(_sockfd
, SHUT_RDWR
) == SOCKET_ERROR
&& get_socket_errno() != ENOTCONN
)
317 else if (closesocket(_sockfd
) == SOCKET_ERROR
)
322 _sockfd
= INVALID_SOCKET
;
325 void Instance::free_addrinfo()
327 if (_addrinfo
== NULL
)
332 freeaddrinfo(_addrinfo
);
334 _addrinfo_next
= NULL
;
337 } /* namespace util */
338 } /* namespace datadifferential */