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>
50 #ifndef HAVE_MSG_NOSIGNAL
51 # define MSG_NOSIGNAL 0
56 SimpleClient::SimpleClient(const std::string
& hostname_
, in_port_t port_
) :
59 sock_fd(INVALID_SOCKET
),
64 bool SimpleClient::ready(int event_
)
68 fds
[0].events
= event_
;
71 int ready_fds
= poll(fds
, 1, 5000);
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
);
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 char service
[NI_MAXSERV
];
122 (void)snprintf(service
, NI_MAXSERV
, "%d", _port
);
124 int getaddrinfo_error
;
125 if ((getaddrinfo_error
= getaddrinfo(_hostname
.c_str(), service
, &hints
, &ai
)) != 0)
127 if (getaddrinfo_error
!= EAI_SYSTEM
)
129 _error
= gai_strerror(getaddrinfo_error
);
134 _error
= strerror(getaddrinfo_error
);
142 SimpleClient::~SimpleClient()
147 void SimpleClient::close_socket()
150 sock_fd
= INVALID_SOCKET
;
153 bool SimpleClient::instance_connect()
159 struct addrinfo
* address_info_next
= ai
;
161 while (address_info_next
and sock_fd
== INVALID_SOCKET
)
163 if ((sock_fd
= socket(address_info_next
->ai_family
, address_info_next
->ai_socktype
, address_info_next
->ai_protocol
)) != SOCKET_ERROR
)
165 if (connect(sock_fd
, address_info_next
->ai_addr
, address_info_next
->ai_addrlen
) == SOCKET_ERROR
)
168 _error
= strerror(errno
);
173 fatal_message(strerror(errno
));
175 address_info_next
= address_info_next
->ai_next
;
181 if (sock_fd
== INVALID_SOCKET
)
183 fatal_assert(_error
.size());
186 return bool(sock_fd
!= INVALID_SOCKET
);
192 bool SimpleClient::is_valid()
195 if (sock_fd
== INVALID_SOCKET
)
197 return instance_connect();
203 bool SimpleClient::message(const std::string
& arg
)
210 const char* ptr
= arg
.c_str();
211 size_t len
= arg
.size();
215 ssize_t nw
= send(sock_fd
, ptr
+ offset
, len
- offset
, MSG_NOSIGNAL
);
220 _error
= strerror(errno
);
228 } while (offset
< ssize_t(len
));
234 fatal_assert(_error
.size());
239 bool SimpleClient::send_message(const std::string
& arg
)
241 if (message(arg
) == true)
243 return message("\r\n");
249 bool SimpleClient::send_message(const std::string
& message_
, std::string
& response_
)
252 if (send_message(message_
))
254 return response(response_
);
260 bool SimpleClient::response(std::string
& response_
)
273 ssize_t nr
= recv(sock_fd
, buffer
, 1, MSG_NOSIGNAL
);
278 _error
= strerror(errno
);
284 fatal_assert(nr
== 1);
285 if (buffer
[0] == '\n')
289 response_
.append(buffer
);
293 return response_
.size();
297 fatal_assert(_error
.size());
301 } // namespace libtest