d83781914cc60151380c009fedaa246b351e060e
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 "mem_config.h"
39 #include <libtest/common.h>
45 #include <sys/types.h>
46 #include <sys/socket.h>
53 SimpleClient::SimpleClient(const std::string
& hostname_
, in_port_t port_
) :
56 sock_fd(INVALID_SOCKET
),
61 bool SimpleClient::ready(int event_
)
65 fds
[0].events
= event_
;
68 int ready_fds
= poll(fds
, 1, 5000);
72 _error
= strerror(errno
);
75 else if (ready_fds
== 1)
77 if (fds
[0].revents
& (POLLERR
| POLLHUP
| POLLNVAL
))
80 socklen_t len
= sizeof (err
);
81 // We replace errno with err if getsockopt() passes, but err has been
83 if (getsockopt(fds
[0].fd
, SOL_SOCKET
, SO_ERROR
, &err
, &len
) == 0)
85 // We check the value to see what happened wth the socket.
88 _error
= "getsockopt() returned no error but poll() indicated one existed";
93 _error
= strerror(errno
);
98 if (fds
[0].revents
& event_
)
104 fatal_assert(ready_fds
== 0);
110 struct addrinfo
* SimpleClient::lookup()
112 struct addrinfo
*ai
= NULL
;
113 struct addrinfo hints
;
114 memset(&hints
, 0, sizeof(struct addrinfo
));
115 hints
.ai_socktype
= SOCK_STREAM
;
116 hints
.ai_protocol
= IPPROTO_TCP
;
118 char service
[NI_MAXSERV
];
119 (void)snprintf(service
, NI_MAXSERV
, "%d", _port
);
121 int getaddrinfo_error
;
122 if ((getaddrinfo_error
= getaddrinfo(_hostname
.c_str(), service
, &hints
, &ai
)) != 0)
124 if (getaddrinfo_error
!= EAI_SYSTEM
)
126 _error
= gai_strerror(getaddrinfo_error
);
131 _error
= strerror(getaddrinfo_error
);
139 SimpleClient::~SimpleClient()
144 void SimpleClient::close_socket()
147 sock_fd
= INVALID_SOCKET
;
150 bool SimpleClient::instance_connect()
156 struct addrinfo
* address_info_next
= ai
;
158 while (address_info_next
and sock_fd
== INVALID_SOCKET
)
160 if ((sock_fd
= socket(address_info_next
->ai_family
, address_info_next
->ai_socktype
, address_info_next
->ai_protocol
)) != SOCKET_ERROR
)
162 if (connect(sock_fd
, address_info_next
->ai_addr
, address_info_next
->ai_addrlen
) == SOCKET_ERROR
)
165 _error
= strerror(errno
);
170 fatal_message(strerror(errno
));
172 address_info_next
= address_info_next
->ai_next
;
178 if (sock_fd
== INVALID_SOCKET
)
180 fatal_assert(_error
.size());
183 return bool(sock_fd
!= INVALID_SOCKET
);
189 bool SimpleClient::is_valid()
192 if (sock_fd
== INVALID_SOCKET
)
194 return instance_connect();
200 bool SimpleClient::message(const std::string
& arg
)
207 const char* ptr
= arg
.c_str();
208 size_t len
= arg
.size();
212 ssize_t nw
= send(sock_fd
, ptr
+ offset
, len
- offset
, MSG_NOSIGNAL
);
217 _error
= strerror(errno
);
225 } while (offset
< ssize_t(len
));
231 fatal_assert(_error
.size());
236 bool SimpleClient::send_message(const std::string
& arg
)
238 if (message(arg
) == true)
240 return message("\r\n");
246 bool SimpleClient::send_message(const std::string
& message_
, std::string
& response_
)
249 if (send_message(message_
))
251 return response(response_
);
257 bool SimpleClient::response(std::string
& response_
)
270 ssize_t nr
= recv(sock_fd
, buffer
, 1, MSG_NOSIGNAL
);
275 _error
= strerror(errno
);
281 fatal_assert(nr
== 1);
282 if (buffer
[0] == '\n')
286 response_
.append(buffer
);
290 return response_
.size();
294 fatal_assert(_error
.size());
298 } // namespace libtest