6caac9b1b505d6fe0c94e34bcdf744354615426f
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>
49 SimpleClient::SimpleClient(const std::string
& hostname_
, in_port_t port_
) :
53 sock_fd(INVALID_SOCKET
),
58 bool SimpleClient::ready(int event_
)
62 fds
[0].events
= event_
;
66 if (_is_connected
== false)
68 timeout
= timeout
* 30;
71 int ready_fds
= poll(fds
, 1, timeout
);
75 _error
= strerror(errno
);
78 else if (ready_fds
== 1)
80 if (fds
[0].revents
& (POLLERR
| POLLHUP
| POLLNVAL
))
83 socklen_t len
= sizeof (err
);
84 // We replace errno with err if getsockopt() passes, but err has been
86 if (getsockopt(fds
[0].fd
, SOL_SOCKET
, SO_ERROR
, &err
, &len
) == 0)
88 // We check the value to see what happened wth the socket.
91 _error
= "getsockopt() returned no error but poll() indicated one existed";
96 _error
= strerror(errno
);
102 if (fds
[0].revents
& event_
)
108 fatal_assert(ready_fds
== 0);
114 struct addrinfo
* SimpleClient::lookup()
116 struct addrinfo
*ai
= NULL
;
117 struct addrinfo hints
;
118 memset(&hints
, 0, sizeof(struct addrinfo
));
119 hints
.ai_socktype
= SOCK_STREAM
;
120 hints
.ai_protocol
= IPPROTO_TCP
;
122 libtest::vchar_t service
;
123 service
.resize(NI_MAXSERV
);
124 (void)snprintf(&service
[0], service
.size(), "%d", _port
);
126 int getaddrinfo_error
;
127 if ((getaddrinfo_error
= getaddrinfo(_hostname
.c_str(), &service
[0], &hints
, &ai
)) != 0)
129 if (getaddrinfo_error
!= EAI_SYSTEM
)
131 _error
= gai_strerror(getaddrinfo_error
);
136 _error
= strerror(getaddrinfo_error
);
144 SimpleClient::~SimpleClient()
149 void SimpleClient::close_socket()
151 if (sock_fd
!= INVALID_SOCKET
)
154 sock_fd
= INVALID_SOCKET
;
158 bool SimpleClient::instance_connect()
160 _is_connected
= false;
165 struct addrinfo
* address_info_next
= ai
;
167 while (address_info_next
and sock_fd
== INVALID_SOCKET
)
169 if ((sock_fd
= socket(address_info_next
->ai_family
, address_info_next
->ai_socktype
, address_info_next
->ai_protocol
)) != SOCKET_ERROR
)
171 if (connect(sock_fd
, address_info_next
->ai_addr
, address_info_next
->ai_addrlen
) == SOCKET_ERROR
)
174 _error
= strerror(errno
);
179 fatal_message(strerror(errno
));
181 address_info_next
= address_info_next
->ai_next
;
187 if (sock_fd
== INVALID_SOCKET
)
189 fatal_assert(_error
.size());
192 return bool(sock_fd
!= INVALID_SOCKET
);
198 bool SimpleClient::is_valid()
201 if (sock_fd
== INVALID_SOCKET
)
203 return instance_connect();
209 bool SimpleClient::message(const char* ptr
, const size_t len
)
218 ssize_t nw
= send(sock_fd
, ptr
+ offset
, len
- offset
, MSG_NOSIGNAL
);
223 _error
= strerror(errno
);
231 } while (offset
< ssize_t(len
));
237 fatal_assert(_error
.size());
242 bool SimpleClient::send_message(const std::string
& arg
)
244 if (message(arg
.c_str(), arg
.size()) == true)
246 return message("\r\n", 2);
252 bool SimpleClient::send_data(const libtest::vchar_t
& message_
, libtest::vchar_t
& response_
)
255 if (message(&message_
[0], message_
.size()))
257 return response(response_
);
263 bool SimpleClient::send_message(const std::string
& message_
, std::string
& response_
)
266 if (send_message(message_
))
268 return response(response_
);
274 bool SimpleClient::response(libtest::vchar_t
& response_
)
287 ssize_t nr
= recv(sock_fd
, buffer
, 1, MSG_NOSIGNAL
);
292 _error
= strerror(errno
);
303 response_
.reserve(response_
.size() + nr
+1);
304 fatal_assert(nr
== 1);
305 if (buffer
[0] == '\n')
309 response_
.insert(response_
.end(), buffer
, buffer
+nr
);
313 return response_
.size();
317 fatal_assert(_error
.size());
321 bool SimpleClient::response(std::string
& response_
)
334 ssize_t nr
= recv(sock_fd
, buffer
, 1, MSG_NOSIGNAL
);
339 _error
= strerror(errno
);
350 fatal_assert(nr
== 1);
351 if (buffer
[0] == '\n')
355 response_
.append(buffer
);
359 return response_
.size();
363 fatal_assert(_error
.size());
367 } // namespace libtest