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>
46 #include <sys/socket.h>
49 #include <sys/types.h>
58 #include <libtest/signal.h>
61 # define SOCK_CLOEXEC 0
65 # define SOCK_NONBLOCK 0
72 #ifndef __INTEL_COMPILER
73 #pragma GCC diagnostic ignored "-Wold-style-cast"
76 using namespace libtest
;
79 typedef std::vector
< std::pair
< int, in_port_t
> > socket_port_t
;
87 void release(in_port_t _arg
)
89 for (socket_port_t::iterator iter
= _pair
.begin();
93 if ((*iter
).second
== _arg
)
95 shutdown((*iter
).first
, SHUT_RDWR
);
103 for (socket_port_t::iterator iter
= _pair
.begin();
107 shutdown((*iter
).first
, SHUT_RDWR
);
108 close((*iter
).first
);
113 static socket_st all_socket_fd
;
115 static in_port_t global_port
= 0;
119 in_port_t
default_port()
121 if (global_port
== 0)
123 global_port
= get_free_port();
129 void release_port(in_port_t arg
)
131 all_socket_fd
.release(arg
);
134 in_port_t
get_free_port()
136 const in_port_t default_port
= in_port_t(-1);
143 ret_port
= default_port
;
145 if ((sd
= socket(AF_INET
, SOCK_STREAM
, 0)) != SOCKET_ERROR
)
148 if (setsockopt(sd
, SOL_SOCKET
, SO_REUSEADDR
, &optval
, sizeof(optval
)) != SOCKET_ERROR
)
150 struct sockaddr_in sin
;
152 sin
.sin_addr
.s_addr
= 0;
153 sin
.sin_addr
.s_addr
= INADDR_ANY
;
154 sin
.sin_family
= AF_INET
;
159 if ((bind_ret
= bind(sd
, (struct sockaddr
*)&sin
, sizeof(struct sockaddr_in
) )) != SOCKET_ERROR
)
161 socklen_t addrlen
= sizeof(sin
);
163 if (getsockname(sd
, (struct sockaddr
*)&sin
, &addrlen
) != -1)
165 ret_port
= sin
.sin_port
;
170 if (errno
!= EADDRINUSE
)
172 Error
<< strerror(errno
);
176 if (errno
== EADDRINUSE
)
178 libtest::dream(2, 0);
180 } while (bind_ret
== -1 and errno
== EADDRINUSE
);
182 all_socket_fd
._pair
.push_back(std::make_pair(sd
, ret_port
));
186 Error
<< strerror(errno
);
191 Error
<< strerror(errno
);
194 if (ret_port
== default_port
)
196 Error
<< "no ret_port set:" << strerror(errno
);
198 else if (ret_port
> 1024 and ret_port
!= all_socket_fd
.last_port
)
204 // We handle the case where if we max out retries, we still abort.
207 FATAL("No port could be found, exhausted retry");
212 FATAL("No port could be found");
215 if (ret_port
== default_port
)
217 FATAL("No port could be found");
220 if (ret_port
<= 1024)
222 FATAL("No port could be found, though some where available below or at 1024");
225 all_socket_fd
.last_port
= ret_port
;
226 release_port(ret_port
);
231 } // namespace libtest