1 /* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3 * Data Differential YATL (i.e. libtest) library
5 * Copyright (C) 2012 Data Differential, http://datadifferential.com/
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
14 * * Redistributions in binary form must reproduce the above
15 * copyright notice, this list of conditions and the following disclaimer
16 * in the documentation and/or other materials provided with the
19 * * The names of its contributors may not be used to endorse or
20 * promote products derived from this software without specific prior
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 #include "libtest/yatlcon.h"
38 #include <libtest/common.h>
40 #include <sys/types.h>
41 #include <sys/socket.h>
48 SimpleClient::SimpleClient(const std::string
& hostname_
, in_port_t port_
) :
52 sock_fd(INVALID_SOCKET
),
57 bool SimpleClient::ready(int event_
)
61 fds
[0].events
= event_
;
65 if (_is_connected
== false)
67 timeout
= timeout
* 30;
70 int ready_fds
= poll(fds
, 1, timeout
);
74 _error
= strerror(errno
);
77 else if (ready_fds
== 1)
79 if (fds
[0].revents
& (POLLERR
| POLLHUP
| POLLNVAL
))
82 socklen_t len
= sizeof (err
);
83 // We replace errno with err if getsockopt() passes, but err has been
85 if (getsockopt(fds
[0].fd
, SOL_SOCKET
, SO_ERROR
, &err
, &len
) == 0)
87 // We check the value to see what happened wth the socket.
90 _error
= "getsockopt() returned no error but poll() indicated one existed";
95 _error
= strerror(errno
);
101 if (fds
[0].revents
& event_
)
107 fatal_assert(ready_fds
== 0);
113 struct addrinfo
* SimpleClient::lookup()
115 struct addrinfo
*ai
= NULL
;
116 struct addrinfo hints
;
117 memset(&hints
, 0, sizeof(struct addrinfo
));
118 hints
.ai_socktype
= SOCK_STREAM
;
119 hints
.ai_protocol
= IPPROTO_TCP
;
121 libtest::vchar_t service
;
122 service
.resize(NI_MAXSERV
);
123 (void)snprintf(&service
[0], service
.size(), "%d", _port
);
125 int getaddrinfo_error
;
126 if ((getaddrinfo_error
= getaddrinfo(_hostname
.c_str(), &service
[0], &hints
, &ai
)) != 0)
128 if (getaddrinfo_error
!= EAI_SYSTEM
)
130 _error
= gai_strerror(getaddrinfo_error
);
135 _error
= strerror(getaddrinfo_error
);
143 SimpleClient::~SimpleClient()
148 void SimpleClient::close_socket()
150 if (sock_fd
!= INVALID_SOCKET
)
153 sock_fd
= INVALID_SOCKET
;
157 bool SimpleClient::instance_connect()
159 _is_connected
= false;
164 struct addrinfo
* address_info_next
= ai
;
166 while (address_info_next
and sock_fd
== INVALID_SOCKET
)
168 if ((sock_fd
= socket(address_info_next
->ai_family
, address_info_next
->ai_socktype
, address_info_next
->ai_protocol
)) != SOCKET_ERROR
)
170 if (connect(sock_fd
, address_info_next
->ai_addr
, address_info_next
->ai_addrlen
) == SOCKET_ERROR
)
173 _error
= strerror(errno
);
178 fatal_message(strerror(errno
));
180 address_info_next
= address_info_next
->ai_next
;
186 if (sock_fd
== INVALID_SOCKET
)
188 fatal_assert(_error
.size());
191 return bool(sock_fd
!= INVALID_SOCKET
);
197 bool SimpleClient::is_valid()
200 if (sock_fd
== INVALID_SOCKET
)
202 return instance_connect();
208 bool SimpleClient::message(const char* ptr
, const size_t len
)
217 ssize_t nw
= send(sock_fd
, ptr
+ offset
, len
- offset
, MSG_NOSIGNAL
);
222 _error
= strerror(errno
);
230 } while (offset
< ssize_t(len
));
236 fatal_assert(_error
.size());
241 bool SimpleClient::send_message(const std::string
& arg
)
243 if (message(arg
.c_str(), arg
.size()) == true)
245 return message("\r\n", 2);
251 bool SimpleClient::send_data(const libtest::vchar_t
& message_
, libtest::vchar_t
& response_
)
254 if (message(&message_
[0], message_
.size()))
256 return response(response_
);
262 bool SimpleClient::send_message(const std::string
& message_
, std::string
& response_
)
265 if (send_message(message_
))
267 return response(response_
);
273 bool SimpleClient::response(libtest::vchar_t
& response_
)
286 ssize_t nr
= recv(sock_fd
, buffer
, 1, MSG_NOSIGNAL
);
291 _error
= strerror(errno
);
302 response_
.reserve(response_
.size() + nr
+1);
303 fatal_assert(nr
== 1);
304 if (buffer
[0] == '\n')
308 response_
.insert(response_
.end(), buffer
, buffer
+nr
);
312 return response_
.size();
316 fatal_assert(_error
.size());
320 bool SimpleClient::response(std::string
& response_
)
333 ssize_t nr
= recv(sock_fd
, buffer
, 1, MSG_NOSIGNAL
);
338 _error
= strerror(errno
);
349 fatal_assert(nr
== 1);
350 if (buffer
[0] == '\n')
354 response_
.append(buffer
);
358 return response_
.size();
362 fatal_assert(_error
.size());
366 } // namespace libtest