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.
41 #include "util/instance.hpp"
47 #include <sys/socket.h>
48 #include <sys/types.h>
49 #include <netinet/in.h>
52 namespace datadifferential
{
55 Instance::Instance(const std::string
& hostname_arg
, const std::string
& service_arg
) :
57 _service(service_arg
),
58 _sockfd(INVALID_SOCKET
),
67 Instance::Instance(const std::string
& hostname_arg
, const in_port_t port_arg
) :
69 _sockfd(INVALID_SOCKET
),
77 snprintf(tmp
, sizeof(tmp
), "%u", static_cast<unsigned int>(port_arg
));
85 for (Operation::vector::iterator iter
= _operations
.begin(); iter
!= _operations
.end(); ++iter
)
96 while (not _operations
.empty())
98 Operation::vector::value_type operation
= _operations
.back();
107 memset(&ai
, 0, sizeof(struct addrinfo
));
108 ai
.ai_socktype
= SOCK_STREAM
;
109 ai
.ai_protocol
= IPPROTO_TCP
;
111 int ret
= getaddrinfo(_host
.c_str(), _service
.c_str(), &ai
, &_addrinfo
);
114 std::stringstream message
;
115 message
<< "Failed to connect on " << _host
.c_str() << ":" << _service
.c_str() << " with " << gai_strerror(ret
);
116 _last_error
= message
.str();
120 _addrinfo_next
= _addrinfo
;
124 case NEXT_CONNECT_ADDRINFO
:
125 if (_addrinfo_next
->ai_next
== NULL
)
127 std::stringstream message
;
128 message
<< "Error connecting to " << _host
.c_str() << "." << std::endl
;
129 _last_error
= message
.str();
132 _addrinfo_next
= _addrinfo_next
->ai_next
;
138 _sockfd
= socket(_addrinfo_next
->ai_family
,
139 _addrinfo_next
->ai_socktype
,
140 _addrinfo_next
->ai_protocol
);
141 if (_sockfd
== INVALID_SOCKET
)
147 if (connect(_sockfd
, _addrinfo_next
->ai_addr
, _addrinfo_next
->ai_addrlen
) < 0)
164 state
= NEXT_CONNECT_ADDRINFO
;
175 // Add logic for poll() for nonblocking.
182 size_t packet_length
= operation
->size();
183 const char *packet
= operation
->ptr();
187 ssize_t write_size
= send(_sockfd
, packet
, packet_length
, 0);
194 std::cerr
<< "Failed during send(" << strerror(errno
) << ")" << std::endl
;
199 packet_length
-= static_cast<size_t>(write_size
);
200 packet
+= static_cast<size_t>(write_size
);
207 if (operation
->has_response())
215 read_length
= recv(_sockfd
, buffer
, sizeof(buffer
), 0);
222 std::cerr
<< "Error occured while reading data from " << _host
.c_str() << std::endl
;
227 operation
->push(buffer
, static_cast<size_t>(read_length
));
228 total_read
+= static_cast<size_t>(read_length
);
229 } while (more_to_read());
230 } // end has_response
236 std::string response
;
237 bool success
= operation
->response(response
);
240 if (not _finish_fn
->call(success
, response
))
242 // Error was sent from _finish_fn
247 if (operation
->reconnect())
250 _operations
.pop_back();
261 bool Instance::more_to_read() const
267 if (poll(&fds
, 1, 5) < 1) // Default timeout is 5
275 void Instance::close_socket()
277 if (_sockfd
== INVALID_SOCKET
)
280 /* in case of death shutdown to avoid blocking at close() */
281 if (shutdown(_sockfd
, SHUT_RDWR
) == SOCKET_ERROR
&& get_socket_errno() != ENOTCONN
)
285 else if (closesocket(_sockfd
) == SOCKET_ERROR
)
290 _sockfd
= INVALID_SOCKET
;
293 void Instance::free_addrinfo()
298 freeaddrinfo(_addrinfo
);
300 _addrinfo_next
= NULL
;
303 } /* namespace util */
304 } /* namespace datadifferential */