1 /******************************************************************************
3 * Copyright (C) 2012-2016 Icinga Development Team (https://www.icinga.org/) *
5 * This program is free software; you can redistribute it and/or *
6 * modify it under the terms of the GNU General Public License *
7 * as published by the Free Software Foundation; either version 2 *
8 * of the License, or (at your option) any later version. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the Free Software Foundation *
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
18 ******************************************************************************/
20 #include "base/tcpsocket.hpp"
21 #include "base/logger.hpp"
22 #include "base/utility.hpp"
23 #include "base/exception.hpp"
24 #include <boost/exception/errinfo_api_function.hpp>
25 #include <boost/exception/errinfo_errno.hpp>
28 using namespace icinga;
31 * Creates a socket and binds it to the specified service.
33 * @param service The service.
34 * @param family The address family for the socket.
36 void TcpSocket::Bind(const String& service, int family)
38 Bind(String(), service, family);
42 * Creates a socket and binds it to the specified node and service.
44 * @param node The node.
45 * @param service The service.
46 * @param family The address family for the socket.
48 void TcpSocket::Bind(const String& node, const String& service, int family)
55 memset(&hints, 0, sizeof(hints));
56 hints.ai_family = family;
57 hints.ai_socktype = SOCK_STREAM;
58 hints.ai_protocol = IPPROTO_TCP;
59 hints.ai_flags = AI_PASSIVE;
61 int rc = getaddrinfo(node.IsEmpty() ? NULL : node.CStr(),
62 service.CStr(), &hints, &result);
65 Log(LogCritical, "TcpSocket")
66 << "getaddrinfo() failed with error code " << rc << ", \"" << gai_strerror(rc) << "\"";
68 BOOST_THROW_EXCEPTION(socket_error()
69 << boost::errinfo_api_function("getaddrinfo")
70 << errinfo_getaddrinfo_error(rc));
73 int fd = INVALID_SOCKET;
75 for (addrinfo *info = result; info != NULL; info = info->ai_next) {
76 fd = socket(info->ai_family, info->ai_socktype, info->ai_protocol);
78 if (fd == INVALID_SOCKET) {
80 error = WSAGetLastError();
89 const int optFalse = 0;
90 setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, reinterpret_cast<const char *>(&optFalse), sizeof(optFalse));
93 const int optTrue = 1;
94 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<const char *>(&optTrue), sizeof(optTrue));
97 int rc = bind(fd, info->ai_addr, info->ai_addrlen);
101 error = WSAGetLastError();
117 freeaddrinfo(result);
119 if (GetFD() == INVALID_SOCKET) {
120 Log(LogCritical, "TcpSocket")
121 << "Invalid socket: " << Utility::FormatErrorNumber(error);
124 BOOST_THROW_EXCEPTION(socket_error()
125 << boost::errinfo_api_function(func)
126 << boost::errinfo_errno(error));
128 BOOST_THROW_EXCEPTION(socket_error()
129 << boost::errinfo_api_function(func)
130 << errinfo_win32_error(error));
136 * Creates a socket and connects to the specified node and service.
138 * @param node The node.
139 * @param service The service.
141 void TcpSocket::Connect(const String& node, const String& service)
148 memset(&hints, 0, sizeof(hints));
149 hints.ai_family = AF_UNSPEC;
150 hints.ai_socktype = SOCK_STREAM;
151 hints.ai_protocol = IPPROTO_TCP;
153 int rc = getaddrinfo(node.CStr(), service.CStr(), &hints, &result);
156 Log(LogCritical, "TcpSocket")
157 << "getaddrinfo() failed with error code " << rc << ", \"" << gai_strerror(rc) << "\"";
159 BOOST_THROW_EXCEPTION(socket_error()
160 << boost::errinfo_api_function("getaddrinfo")
161 << errinfo_getaddrinfo_error(rc));
164 int fd = INVALID_SOCKET;
166 for (addrinfo *info = result; info != NULL; info = info->ai_next) {
167 fd = socket(info->ai_family, info->ai_socktype, info->ai_protocol);
169 if (fd == INVALID_SOCKET) {
171 error = WSAGetLastError();
180 rc = connect(fd, info->ai_addr, info->ai_addrlen);
184 error = WSAGetLastError();
200 freeaddrinfo(result);
202 if (GetFD() == INVALID_SOCKET) {
203 Log(LogCritical, "TcpSocket")
204 << "Invalid socket: " << Utility::FormatErrorNumber(error);
207 BOOST_THROW_EXCEPTION(socket_error()
208 << boost::errinfo_api_function(func)
209 << boost::errinfo_errno(error));
211 BOOST_THROW_EXCEPTION(socket_error()
212 << boost::errinfo_api_function(func)
213 << errinfo_win32_error(error));