Commit f9a1f7440777556e1ee6106ff0e1172aef3d4ed7

Authored by Jojo-1000
Committed by Moritz Wirger
1 parent bd30ad58

Use system_error instead of runtime_error where error codes exist.

hueplusplus/LinHttpHandler.cpp
1 /** 1 /**
2 - \file LinHttpHandler.cpp  
3 - Copyright Notice\n  
4 - Copyright (C) 2017 Jan Rogall - developer\n  
5 - Copyright (C) 2017 Moritz Wirger - developer\n  
6 -  
7 - This program is free software; you can redistribute it and/or modify  
8 - it under the terms of the GNU General Public License as published by  
9 - the Free Software Foundation; either version 3 of the License, or  
10 - (at your option) any later version.  
11 - This program is distributed in the hope that it will be useful,  
12 - but WITHOUT ANY WARRANTY; without even the implied warranty of  
13 - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the  
14 - 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 Street, Fifth Floor, Boston, MA 02110-1301 USA 2 + \file LinHttpHandler.cpp
  3 + Copyright Notice\n
  4 + Copyright (C) 2017 Jan Rogall - developer\n
  5 + Copyright (C) 2017 Moritz Wirger - developer\n
  6 +
  7 + This program is free software; you can redistribute it and/or modify
  8 + it under the terms of the GNU General Public License as published by
  9 + the Free Software Foundation; either version 3 of the License, or
  10 + (at your option) any later version.
  11 + This program is distributed in the hope that it will be useful,
  12 + but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14 + 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 Street, Fifth Floor, Boston, MA 02110-1301 USA
18 **/ 18 **/
19 19
20 #include "include/LinHttpHandler.h" 20 #include "include/LinHttpHandler.h"
@@ -31,173 +31,185 @@ @@ -31,173 +31,185 @@
31 #include <stdio.h> // printf, sprintf 31 #include <stdio.h> // printf, sprintf
32 #include <stdlib.h> // exit 32 #include <stdlib.h> // exit
33 #include <string.h> // functions for C style null-terminated strings 33 #include <string.h> // functions for C style null-terminated strings
  34 +#include <system_error>
34 #include <unistd.h> // read, write, close 35 #include <unistd.h> // read, write, close
35 36
36 class SocketCloser { 37 class SocketCloser {
37 - public: SocketCloser(int sockFd) :s(sockFd) {}  
38 - ~SocketCloser() { close(s); }  
39 - private: int s; 38 +public:
  39 + SocketCloser(int sockFd) : s(sockFd) {}
  40 + ~SocketCloser() { close(s); }
  41 +private:
  42 + int s;
40 }; 43 };
41 44
42 std::string LinHttpHandler::send(const std::string & msg, const std::string & adr, int port) const 45 std::string LinHttpHandler::send(const std::string & msg, const std::string & adr, int port) const
43 { 46 {
44 - // create socket  
45 - int socketFD = socket(AF_INET, SOCK_STREAM, 0);  
46 -  
47 - SocketCloser closeMySocket(socketFD);  
48 - if (socketFD < 0)  
49 - {  
50 - std::cerr << "linHttpHandler: Failed to open socket: " << std::strerror(errno) << "\n";  
51 - throw(std::runtime_error("linHttpHandler: Failed to open socket"));  
52 - }  
53 -  
54 - // lookup ip address  
55 - hostent *server;  
56 - server = gethostbyname(adr.c_str());  
57 - if (server == NULL)  
58 - {  
59 - std::cerr << "linHttpHandler: Failed to find host with address " << adr << ": " << std::strerror(errno) << "\n";  
60 - throw(std::runtime_error("linHttpHandler: Failed to find host"));  
61 - }  
62 -  
63 - // fill in the structure  
64 - sockaddr_in server_addr;  
65 - memset(&server_addr, 0, sizeof(server_addr));  
66 - server_addr.sin_family = AF_INET;  
67 - server_addr.sin_port = htons(port);  
68 - memcpy(&server_addr.sin_addr.s_addr, server->h_addr, server->h_length);  
69 -  
70 - // connect the socket  
71 - if (connect(socketFD, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)  
72 - {  
73 - std::cerr << "linHttpHandler: Failed to connect socket: " << std::strerror(errno) << "\n";  
74 - throw(std::runtime_error("linHttpHandler: Failed to connect socket"));  
75 - }  
76 -  
77 - // send the request  
78 - size_t total = msg.length();  
79 - ssize_t sent = 0;  
80 - do  
81 - {  
82 - ssize_t bytes = write(socketFD, msg.c_str() + sent, total - sent);  
83 - if (bytes < 0)  
84 - {  
85 - std::cerr << "linHttpHandler: Failed to write message to socket: " << std::strerror(errno) << "\n";  
86 - throw(std::runtime_error("linHttpHandler: Failed to write message to socket"));  
87 - }  
88 - if (bytes == 0)  
89 - {  
90 - break;  
91 - }  
92 - if (bytes)  
93 - {  
94 - sent += bytes;  
95 - }  
96 - } while (sent < total);  
97 -  
98 - // receive the response  
99 - std::string response;  
100 - total = sizeof(response) - 1;  
101 - int received = 0;  
102 - char buffer[128] = {};  
103 - do  
104 - {  
105 - ssize_t bytes = read(socketFD, buffer, 127);  
106 - if (bytes < 0)  
107 - {  
108 - std::cerr << "linHttpHandler: Failed to read response from socket: " << std::strerror(errno) << std::endl;  
109 - throw(std::runtime_error("linHttpHandler: Failed to read response from socket"));  
110 - }  
111 - if (bytes == 0)  
112 - {  
113 - break;  
114 - }  
115 - if (bytes)  
116 - {  
117 - received += bytes;  
118 - response.append(buffer, bytes);  
119 - }  
120 - } while (true);  
121 -  
122 - if (received == total)  
123 - {  
124 - std::cerr << "LinHttpHandler: Failed to store complete response from socket\n";  
125 - throw(std::runtime_error("LinHttpHandler: Failed to store complete response from socket"));  
126 - }  
127 -  
128 - return response; 47 + // create socket
  48 + int socketFD = socket(AF_INET, SOCK_STREAM, 0);
  49 +
  50 + SocketCloser closeMySocket(socketFD);
  51 + if (socketFD < 0)
  52 + {
  53 + int errCode = errno;
  54 + std::cerr << "LinHttpHandler: Failed to open socket: " << std::strerror(errCode) << "\n";
  55 + throw(std::system_error(errCode, std::generic_category(), "LinHttpHandler: Failed to open socket"));
  56 + }
  57 +
  58 + // lookup ip address
  59 + hostent *server;
  60 + server = gethostbyname(adr.c_str());
  61 + if (server == NULL)
  62 + {
  63 + int errCode = errno;
  64 + std::cerr << "LinHttpHandler: Failed to find host with address " << adr << ": " << std::strerror(errCode) << "\n";
  65 + throw(std::system_error(errCode, std::generic_category(), "LinHttpHandler: gethostbyname"));
  66 + }
  67 +
  68 + // fill in the structure
  69 + sockaddr_in server_addr;
  70 + memset(&server_addr, 0, sizeof(server_addr));
  71 + server_addr.sin_family = AF_INET;
  72 + server_addr.sin_port = htons(port);
  73 + memcpy(&server_addr.sin_addr.s_addr, server->h_addr, server->h_length);
  74 +
  75 + // connect the socket
  76 + if (connect(socketFD, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
  77 + {
  78 + int errCode = errno;
  79 + std::cerr << "LinHttpHandler: Failed to connect socket: " << std::strerror(errCode) << "\n";
  80 + throw(std::system_error(errCode, std::generic_category(), "LinHttpHandler: Failed to connect socket"));
  81 + }
  82 +
  83 + // send the request
  84 + size_t total = msg.length();
  85 + ssize_t sent = 0;
  86 + do
  87 + {
  88 + ssize_t bytes = write(socketFD, msg.c_str() + sent, total - sent);
  89 + if (bytes < 0)
  90 + {
  91 + int errCode = errno;
  92 + std::cerr << "LinHttpHandler: Failed to write message to socket: " << std::strerror(errCode) << "\n";
  93 + throw(std::system_error(errCode, std::generic_category(), "LinHttpHandler: Failed to write message to socket"));
  94 + }
  95 + if (bytes == 0)
  96 + {
  97 + break;
  98 + }
  99 + if (bytes)
  100 + {
  101 + sent += bytes;
  102 + }
  103 + } while (sent < total);
  104 +
  105 + // receive the response
  106 + std::string response;
  107 + total = sizeof(response) - 1;
  108 + int received = 0;
  109 + char buffer[128] = {};
  110 + do
  111 + {
  112 + ssize_t bytes = read(socketFD, buffer, 127);
  113 + if (bytes < 0)
  114 + {
  115 + int errCode = errno;
  116 + std::cerr << "LinHttpHandler: Failed to read response from socket: " << std::strerror(errCode) << std::endl;
  117 + throw(std::system_error(errCode, std::generic_category(), "LinHttpHandler: Failed to read response from socket"));
  118 + }
  119 + if (bytes == 0)
  120 + {
  121 + break;
  122 + }
  123 + if (bytes)
  124 + {
  125 + received += bytes;
  126 + response.append(buffer, bytes);
  127 + }
  128 + } while (true);
  129 +
  130 + if (received == total)
  131 + {
  132 + std::cerr << "LinHttpHandler: Failed to store complete response from socket\n";
  133 + throw(std::runtime_error("LinHttpHandler: Failed to store complete response from socket"));
  134 + }
  135 +
  136 + return response;
129 } 137 }
130 138
131 std::vector<std::string> LinHttpHandler::sendMulticast(const std::string & msg, const std::string & adr, int port, int timeout) const 139 std::vector<std::string> LinHttpHandler::sendMulticast(const std::string & msg, const std::string & adr, int port, int timeout) const
132 { 140 {
133 - hostent *server; // host information  
134 - sockaddr_in server_addr; // server address  
135 -  
136 - //fill in the server's address and data  
137 - memset((char*)&server_addr, 0, sizeof(server_addr));  
138 - server_addr.sin_family = AF_INET;  
139 - server_addr.sin_port = htons(port);  
140 -  
141 - // look up the address of the server given its name  
142 - server = gethostbyname(adr.c_str());  
143 - if (!server)  
144 - {  
145 - std::cerr << "linHttpHandler: sendMulticast: Failed to obtain address of " << msg << ": " << std::strerror(errno) << "\n";  
146 - throw(std::runtime_error("linHttpHandler: sendMulticast: Failed to obtain address of host"));  
147 - }  
148 -  
149 - // put the host's address into the server address structure  
150 - memcpy( (void *)&server_addr.sin_addr, server->h_addr_list[0], server->h_length );  
151 -  
152 - // create the socket  
153 - int socketFD = socket(AF_INET, SOCK_DGRAM, 0);  
154 - SocketCloser closeMySendSocket(socketFD);  
155 - if (socketFD < 0)  
156 - {  
157 - std::cerr << "linHttpHandler: sendMulticast: Failed to open socket: " << std::strerror(errno) << "\n";  
158 - throw(std::runtime_error("linHttpHandler: sendMulticast: Failed to open socket"));  
159 - }  
160 -  
161 - // send a message to the server  
162 - if (sendto(socketFD, msg.c_str(), strlen(msg.c_str()), 0, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)  
163 - {  
164 - std::cerr << "linHttpHandler: sendMulticast: Failed to send message: " << std::strerror(errno) << "\n";  
165 - throw(std::runtime_error("linHttpHandler: sendMulticast: Failed to send message"));  
166 - }  
167 -  
168 - std::string response;  
169 - char buffer[2048] = {}; // receive buffer  
170 - ssize_t bytesReceived = 0;  
171 -  
172 - std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();  
173 - while (std::chrono::steady_clock::now() - start < std::chrono::seconds(timeout))  
174 - {  
175 - bytesReceived = recv(socketFD, &buffer, 2048, MSG_DONTWAIT);  
176 - if (bytesReceived < 0)  
177 - {  
178 - if (errno != EAGAIN && errno != EWOULDBLOCK)  
179 - {  
180 - std::cerr << "linHttpHandler: sendMulticast: Failed to read response from socket: " << std::strerror(errno) << "\n";  
181 - throw(std::runtime_error("linHttpHandler: sendMulticast: Failed to read response from socket"));  
182 - }  
183 - continue;  
184 - }  
185 - if (bytesReceived)  
186 - {  
187 - response.append(buffer, bytesReceived);  
188 - }  
189 - }  
190 -  
191 - // construct return vector  
192 - std::vector<std::string> returnString;  
193 - size_t pos = response.find("\r\n\r\n");  
194 - size_t prevpos = 0;  
195 - while (pos != std::string::npos)  
196 - {  
197 - returnString.push_back(response.substr(prevpos, pos-prevpos));  
198 - pos += 4;  
199 - prevpos = pos;  
200 - pos = response.find("\r\n\r\n", pos);  
201 - }  
202 - return returnString; 141 + hostent *server; // host information
  142 + sockaddr_in server_addr; // server address
  143 +
  144 + //fill in the server's address and data
  145 + memset((char*)&server_addr, 0, sizeof(server_addr));
  146 + server_addr.sin_family = AF_INET;
  147 + server_addr.sin_port = htons(port);
  148 +
  149 + // look up the address of the server given its name
  150 + server = gethostbyname(adr.c_str());
  151 + if (!server)
  152 + {
  153 + int errCode = errno;
  154 + std::cerr << "LinHttpHandler: sendMulticast: Failed to obtain address of " << msg << ": " << std::strerror(errCode) << "\n";
  155 + throw(std::system_error(errCode, std::generic_category(), "LinHttpHandler: sendMulticast: Failed to obtain address of host"));
  156 + }
  157 +
  158 + // put the host's address into the server address structure
  159 + memcpy((void *)&server_addr.sin_addr, server->h_addr_list[0], server->h_length);
  160 +
  161 + // create the socket
  162 + int socketFD = socket(AF_INET, SOCK_DGRAM, 0);
  163 + SocketCloser closeMySendSocket(socketFD);
  164 + if (socketFD < 0)
  165 + {
  166 + int errCode = errno;
  167 + std::cerr << "LinHttpHandler: sendMulticast: Failed to open socket: " << std::strerror(errCode) << "\n";
  168 + throw(std::system_error(errCode, std::generic_category(), "LinHttpHandler: sendMulticast: Failed to open socket"));
  169 + }
  170 +
  171 + // send a message to the server
  172 + if (sendto(socketFD, msg.c_str(), strlen(msg.c_str()), 0, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
  173 + {
  174 + int errCode = errno;
  175 + std::cerr << "LinHttpHandler: sendMulticast: Failed to send message: " << std::strerror(errCode) << "\n";
  176 + throw(std::system_error(errCode, std::generic_category(), "LinHttpHandler: sendMulticast: Failed to send message"));
  177 + }
  178 +
  179 + std::string response;
  180 + char buffer[2048] = {}; // receive buffer
  181 + ssize_t bytesReceived = 0;
  182 +
  183 + std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
  184 + while (std::chrono::steady_clock::now() - start < std::chrono::seconds(timeout))
  185 + {
  186 + bytesReceived = recv(socketFD, &buffer, 2048, MSG_DONTWAIT);
  187 + if (bytesReceived < 0)
  188 + {
  189 + int errCode = errno;
  190 + if (errCode != EAGAIN && errCode != EWOULDBLOCK)
  191 + {
  192 + std::cerr << "LinHttpHandler: sendMulticast: Failed to read response from socket: " << std::strerror(errCode) << "\n";
  193 + throw(std::system_error(errCode, std::generic_category(), "LinHttpHandler: sendMulticast: Failed to read response from socket"));
  194 + }
  195 + continue;
  196 + }
  197 + if (bytesReceived)
  198 + {
  199 + response.append(buffer, bytesReceived);
  200 + }
  201 + }
  202 +
  203 + // construct return vector
  204 + std::vector<std::string> returnString;
  205 + size_t pos = response.find("\r\n\r\n");
  206 + size_t prevpos = 0;
  207 + while (pos != std::string::npos)
  208 + {
  209 + returnString.push_back(response.substr(prevpos, pos - prevpos));
  210 + pos += 4;
  211 + prevpos = pos;
  212 + pos = response.find("\r\n\r\n", pos);
  213 + }
  214 + return returnString;
203 } 215 }
hueplusplus/WinHttpHandler.cpp
@@ -23,239 +23,273 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA @@ -23,239 +23,273 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 #include <iostream> 23 #include <iostream>
24 #include <memory> 24 #include <memory>
25 #include <stdio.h> 25 #include <stdio.h>
  26 +#include <system_error>
26 #include <ws2tcpip.h> 27 #include <ws2tcpip.h>
27 28
28 #pragma comment(lib, "Ws2_32.lib") 29 #pragma comment(lib, "Ws2_32.lib")
29 30
  31 +namespace
  32 +{
  33 + class AddrInfoFreer
  34 + {
  35 + public:
  36 + explicit AddrInfoFreer(addrinfo* p) : p(p)
  37 + {}
  38 + ~AddrInfoFreer()
  39 + {
  40 + freeaddrinfo(p);
  41 + }
  42 + private:
  43 + addrinfo * p;
  44 + };
  45 + class SocketCloser
  46 + {
  47 + public:
  48 + explicit SocketCloser(SOCKET s) : s(s)
  49 + {}
  50 + ~SocketCloser()
  51 + {
  52 + closesocket(s);
  53 + }
  54 + private:
  55 + SOCKET s;
  56 + };
  57 +}
  58 +
30 WinHttpHandler::WinHttpHandler() 59 WinHttpHandler::WinHttpHandler()
31 { 60 {
32 - // Initialize Winsock  
33 - int return_code = WSAStartup(MAKEWORD(2, 2), &wsaData);  
34 - if (return_code != 0)  
35 - {  
36 - std::cerr << "WinHttpHandler: Failed to open socket: " << return_code << std::endl;  
37 - throw(std::runtime_error("WinHttpHandler: Failed to open socket"));  
38 - } 61 + // Initialize Winsock
  62 + int return_code = WSAStartup(MAKEWORD(2, 2), &wsaData);
  63 + if (return_code != 0)
  64 + {
  65 + std::cerr << "WinHttpHandler: Failed to open socket: " << return_code << std::endl;
  66 + throw(std::system_error(return_code, std::system_category(), "WinHttpHandler: Failed to open socket"));
  67 + }
39 } 68 }
40 69
41 WinHttpHandler::~WinHttpHandler() 70 WinHttpHandler::~WinHttpHandler()
42 { 71 {
43 - WSACleanup(); 72 + WSACleanup();
44 } 73 }
45 74
46 std::string WinHttpHandler::send(const std::string & msg, const std::string & adr, int port) const 75 std::string WinHttpHandler::send(const std::string & msg, const std::string & adr, int port) const
47 { 76 {
48 - struct addrinfo hints = {};  
49 - hints.ai_family = AF_INET;  
50 - hints.ai_socktype = SOCK_STREAM;  
51 - hints.ai_protocol = IPPROTO_TCP;  
52 -  
53 - // Resolve the server address and port  
54 - struct addrinfo *result = nullptr;  
55 - if (getaddrinfo(adr.c_str(), std::to_string(port).c_str(), &hints, &result) != 0)  
56 - {  
57 - std::cerr << "WinHttpHandler: getaddrinfo failed: " << WSAGetLastError() << std::endl;  
58 - throw(std::runtime_error("WinHttpHandler: getaddrinfo failed"));  
59 - }  
60 -  
61 - // Attempt to connect to the first address returned by  
62 - // the call to getaddrinfo  
63 - struct addrinfo *ptr = result;  
64 -  
65 - // Create a SOCKET for connecting to server  
66 - SOCKET connect_socket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);  
67 -  
68 - if (connect_socket == INVALID_SOCKET)  
69 - {  
70 - freeaddrinfo(result);  
71 - std::cerr << "WinHttpHandler: Error at socket(): " << WSAGetLastError() << std::endl;  
72 - throw(std::runtime_error("WinHttpHandler: Error at socket()"));  
73 - }  
74 -  
75 - // Connect to server.  
76 - if (connect(connect_socket, ptr->ai_addr, (int)ptr->ai_addrlen) == SOCKET_ERROR)  
77 - {  
78 - closesocket(connect_socket);  
79 - connect_socket = INVALID_SOCKET;  
80 - }  
81 -  
82 - // Should really try the next address returned by getaddrinfo  
83 - // if the connect call failed  
84 - // But for this simple example we just free the resources  
85 - // returned by getaddrinfo and print an error message  
86 -  
87 - freeaddrinfo(result);  
88 -  
89 - if (connect_socket == INVALID_SOCKET)  
90 - {  
91 - std::cerr << "WinHttpHandler: Unable to connect to server!" << std::endl;  
92 - throw(std::runtime_error("WinHttpHandler: Unable to connect to server!"));  
93 - }  
94 -  
95 - // Send an initial buffer  
96 - if (::send(connect_socket, msg.c_str(), msg.size(), 0) == SOCKET_ERROR)  
97 - {  
98 - closesocket(connect_socket);  
99 - std::cerr << "WinHttpHandler: send failed: " << WSAGetLastError() << std::endl;  
100 - throw(std::runtime_error("WinHttpHandler: send failed"));  
101 - }  
102 -  
103 - // shutdown the connection for sending since no more data will be sent  
104 - // the client can still use the ConnectSocket for receiving data  
105 - if (shutdown(connect_socket, SD_SEND) == SOCKET_ERROR)  
106 - {  
107 - closesocket(connect_socket);  
108 - std::cerr << "WinHttpHandler: shutdown failed: " << WSAGetLastError() << std::endl;  
109 - throw(std::runtime_error("WinHttpHandler: shutdown failed"));  
110 - }  
111 -  
112 - const int recvbuflen = 128;  
113 - char recvbuf[recvbuflen];  
114 -  
115 - // Receive data until the server closes the connection  
116 - std::string response;  
117 - int res;  
118 - do  
119 - {  
120 - res = recv(connect_socket, recvbuf, recvbuflen, 0);  
121 - if (res > 0)  
122 - {  
123 - //std::cout << "WinHttpHandler: Bytes received: " << res << std::endl;  
124 - response.append(recvbuf, res);  
125 - }  
126 - else if (res == 0)  
127 - {  
128 - //std::cout << "WinHttpHandler: Connection closed " << std::endl;  
129 - }  
130 - else  
131 - {  
132 - closesocket(connect_socket);  
133 - std::cerr << "WinHttpHandler: recv failed: " << WSAGetLastError() << std::endl;  
134 - throw(std::runtime_error("WinHttpHandler: recv failed"));  
135 - }  
136 - } while (res > 0);  
137 - closesocket(connect_socket);  
138 -  
139 - return response; 77 + struct addrinfo hints = {};
  78 + hints.ai_family = AF_INET;
  79 + hints.ai_socktype = SOCK_STREAM;
  80 + hints.ai_protocol = IPPROTO_TCP;
  81 +
  82 + // Resolve the server address and port
  83 + struct addrinfo *result = nullptr;
  84 + if (getaddrinfo(adr.c_str(), std::to_string(port).c_str(), &hints, &result) != 0)
  85 + {
  86 + int err = WSAGetLastError();
  87 + std::cerr << "WinHttpHandler: getaddrinfo failed: " << err << std::endl;
  88 + throw(std::system_error(err, std::system_category(), "WinHttpHandler: getaddrinfo failed"));
  89 + }
  90 + SOCKET connect_socket = INVALID_SOCKET;
  91 + {
  92 + AddrInfoFreer freeResult(result);
  93 +
  94 + // Attempt to connect to the first address returned by
  95 + // the call to getaddrinfo
  96 + struct addrinfo *ptr = result;
  97 +
  98 + // Create a SOCKET for connecting to server
  99 + connect_socket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
  100 +
  101 + if (connect_socket == INVALID_SOCKET)
  102 + {
  103 + int err = WSAGetLastError();
  104 + std::cerr << "WinHttpHandler: Error at socket(): " << err << std::endl;
  105 + throw(std::system_error(err, std::system_category(), "WinHttpHandler: Error at socket()"));
  106 + }
  107 +
  108 + // Connect to server.
  109 + if (connect(connect_socket, ptr->ai_addr, (int)ptr->ai_addrlen) == SOCKET_ERROR)
  110 + {
  111 + closesocket(connect_socket);
  112 + connect_socket = INVALID_SOCKET;
  113 + }
  114 +
  115 + // Should really try the next address returned by getaddrinfo
  116 + // if the connect call failed
  117 + // But for this simple example we just free the resources
  118 + // returned by getaddrinfo and print an error message
  119 + }
  120 +
  121 + if (connect_socket == INVALID_SOCKET)
  122 + {
  123 + std::cerr << "WinHttpHandler: Unable to connect to server!" << std::endl;
  124 + throw(std::runtime_error("WinHttpHandler: Unable to connect to server!"));
  125 + }
  126 + SocketCloser closeSocket(connect_socket);
  127 +
  128 + // Send an initial buffer
  129 + if (::send(connect_socket, msg.c_str(), msg.size(), 0) == SOCKET_ERROR)
  130 + {
  131 + int err = WSAGetLastError();
  132 + std::cerr << "WinHttpHandler: send failed: " << err << std::endl;
  133 + throw(std::system_error(err, std::system_category(), "WinHttpHandler: send failed"));
  134 + }
  135 +
  136 + // shutdown the connection for sending since no more data will be sent
  137 + // the client can still use the ConnectSocket for receiving data
  138 + if (shutdown(connect_socket, SD_SEND) == SOCKET_ERROR)
  139 + {
  140 + int err = WSAGetLastError();
  141 + std::cerr << "WinHttpHandler: shutdown failed: " << err << std::endl;
  142 + throw(std::system_error(err, std::system_category(), "WinHttpHandler: shutdown failed"));
  143 + }
  144 +
  145 + const int recvbuflen = 128;
  146 + char recvbuf[recvbuflen];
  147 +
  148 + // Receive data until the server closes the connection
  149 + std::string response;
  150 + int res;
  151 + do
  152 + {
  153 + res = recv(connect_socket, recvbuf, recvbuflen, 0);
  154 + if (res > 0)
  155 + {
  156 + //std::cout << "WinHttpHandler: Bytes received: " << res << std::endl;
  157 + response.append(recvbuf, res);
  158 + }
  159 + else if (res == 0)
  160 + {
  161 + //std::cout << "WinHttpHandler: Connection closed " << std::endl;
  162 + }
  163 + else
  164 + {
  165 + int err = WSAGetLastError();
  166 + std::cerr << "WinHttpHandler: recv failed: " << err << std::endl;
  167 + throw(std::system_error(err, std::system_category(), "WinHttpHandler: recv failed"));
  168 + }
  169 + } while (res > 0);
  170 +
  171 + return response;
140 } 172 }
141 173
142 std::vector<std::string> WinHttpHandler::sendMulticast(const std::string & msg, const std::string & adr, int port, int timeout) const 174 std::vector<std::string> WinHttpHandler::sendMulticast(const std::string & msg, const std::string & adr, int port, int timeout) const
143 { 175 {
144 - struct addrinfo hints = {};  
145 - hints.ai_family = AF_INET;  
146 - hints.ai_socktype = SOCK_DGRAM;  
147 - hints.ai_protocol = IPPROTO_TCP;  
148 -  
149 - // Resolve the server address and port  
150 - struct addrinfo *result = nullptr;  
151 - if (getaddrinfo(adr.c_str(), std::to_string(port).c_str(), &hints, &result) != 0)  
152 - {  
153 - std::cerr << "WinHttpHandler: sendMulticast: getaddrinfo failed: " << WSAGetLastError() << std::endl;  
154 - throw(std::runtime_error("WinHttpHandler: sendMulticast: getaddrinfo failed"));  
155 - }  
156 -  
157 - // Attempt to connect to the first address returned by  
158 - // the call to getaddrinfo  
159 - struct addrinfo *ptr = result;  
160 -  
161 - // Create a SOCKET for connecting to server  
162 - SOCKET connect_socket;  
163 - if ((connect_socket = socket(ptr->ai_family, ptr->ai_socktype, 0)) == INVALID_SOCKET)  
164 - {  
165 - freeaddrinfo(result);  
166 - std::cerr << "WinHttpHandler: sendMulticast: Error at socket(): " << WSAGetLastError() << std::endl;  
167 - throw(std::runtime_error("WinHttpHandler: sendMulticast: Error at socket()"));  
168 - }  
169 -  
170 - // Fill out source socket's address information.  
171 - SOCKADDR_IN source_sin;  
172 - source_sin.sin_family = AF_INET;  
173 - source_sin.sin_port = htons(0);  
174 - source_sin.sin_addr.s_addr = htonl(INADDR_ANY);  
175 -  
176 - // Associate the source socket's address with the socket, Sock.  
177 - if (bind(connect_socket, (struct sockaddr FAR *) &source_sin, sizeof(source_sin)) == SOCKET_ERROR)  
178 - {  
179 - closesocket(connect_socket);  
180 - std::cerr << "WinHttpHandler: sendMulticast: Binding socket failed: " << WSAGetLastError() << std::endl;  
181 - throw(std::runtime_error("WinHttpHandler: sendMulticast: Binding socket failed"));  
182 - }  
183 -  
184 - u_long sock_mode = 1;  
185 - ioctlsocket(connect_socket, FIONBIO, &sock_mode);  
186 -  
187 - BOOL bOptVal = TRUE;  
188 - setsockopt(connect_socket, SOL_SOCKET, SO_BROADCAST, (char *)&bOptVal, sizeof(bOptVal));  
189 -  
190 - // Set the Time-to-Live of the multicast.  
191 - int iOptVal = 1; // for same subnet, but might be increased to 16  
192 - if (setsockopt(connect_socket, IPPROTO_IP, IP_MULTICAST_TTL, (char FAR *)&iOptVal, sizeof(int)) == SOCKET_ERROR)  
193 - {  
194 - closesocket(connect_socket);  
195 - std::cerr << "WinHttpHandler: sendMulticast: setsockopt failed: " << WSAGetLastError() << std::endl;  
196 - throw(std::runtime_error("WinHttpHandler: sendMulticast: setsockopt failed"));  
197 - }  
198 -  
199 - // Fill out the desination socket's address information.  
200 - SOCKADDR_IN dest_sin;  
201 - dest_sin.sin_family = AF_INET;  
202 - dest_sin.sin_port = htons(port);  
203 - dest_sin.sin_addr.s_addr = inet_addr((const char*)ptr->ai_addr);  
204 -  
205 - // Send a message to the multicasting address.  
206 - if (sendto(connect_socket, msg.c_str(), msg.size(), 0, (struct sockaddr FAR *) &dest_sin, sizeof(dest_sin)) == SOCKET_ERROR)  
207 - {  
208 - closesocket(connect_socket);  
209 - std::cerr << "WinHttpHandler: sendMulticast: sendto failed: " << WSAGetLastError() << std::endl;  
210 - throw(std::runtime_error("WinHttpHandler: sendMulticast: sendto failed"));  
211 - }  
212 -  
213 - // shutdown the connection for sending since no more data will be sent  
214 - // the client can still use the ConnectSocket for receiving data  
215 - if (shutdown(connect_socket, SD_SEND) == SOCKET_ERROR)  
216 - {  
217 - closesocket(connect_socket);  
218 - std::cerr << "WinHttpHandler: sendMulticast: shutdown failed: " << WSAGetLastError() << std::endl;  
219 - throw(std::runtime_error("WinHttpHandler: sendMulticast: shutdown failed"));  
220 - }  
221 -  
222 - std::string response;  
223 - const int recvbuflen = 2048;  
224 - char recvbuf[recvbuflen] = {};  
225 - int res;  
226 - std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();  
227 - while (std::chrono::steady_clock::now() - start < std::chrono::seconds(timeout))  
228 - {  
229 - res = recv(connect_socket, recvbuf, recvbuflen, 0);  
230 - if (res > 0)  
231 - {  
232 - //std::cout << "WinHttpHandler: sendMulticast: Bytes received: " << res << std::endl;  
233 - response.append(recvbuf, res);  
234 - }  
235 - else if (res == 0)  
236 - {  
237 - //std::cout << "WinHttpHandler: sendMulticast: Connection closed " << std::endl;  
238 - }  
239 - else  
240 - {  
241 - // No exception here due to non blocking socket  
242 - //std::cerr << "sendMulticast: recv failed: " << WSAGetLastError() << std::endl;  
243 - //throw(std::runtime_error("recv failed"));  
244 - }  
245 - }  
246 - closesocket(connect_socket); // Is this needed?  
247 -  
248 - // construct return vector  
249 - std::vector<std::string> returnString;  
250 - size_t pos = response.find("\r\n\r\n");  
251 - size_t prevpos = 0;  
252 - while (pos != std::string::npos)  
253 - {  
254 - returnString.push_back(response.substr(prevpos, pos - prevpos));  
255 - pos += 4;  
256 - prevpos = pos;  
257 - pos = response.find("\r\n\r\n", pos);  
258 - }  
259 -  
260 - return returnString; 176 + struct addrinfo hints = {};
  177 + hints.ai_family = AF_INET;
  178 + hints.ai_socktype = SOCK_DGRAM;
  179 + hints.ai_protocol = IPPROTO_TCP;
  180 +
  181 + // Resolve the server address and port
  182 + struct addrinfo *result = nullptr;
  183 + if (getaddrinfo(adr.c_str(), std::to_string(port).c_str(), &hints, &result) != 0)
  184 + {
  185 + int err = WSAGetLastError();
  186 + std::cerr << "WinHttpHandler: sendMulticast: getaddrinfo failed: " << err << std::endl;
  187 + throw(std::system_error(err, std::system_category(), "WinHttpHandler: sendMulticast: getaddrinfo failed"));
  188 + }
  189 + AddrInfoFreer freeResult(result);
  190 +
  191 + // Attempt to connect to the first address returned by
  192 + // the call to getaddrinfo
  193 + struct addrinfo *ptr = result;
  194 +
  195 + // Create a SOCKET for connecting to server
  196 + SOCKET connect_socket = socket(ptr->ai_family, ptr->ai_socktype, 0);
  197 + if (connect_socket == INVALID_SOCKET)
  198 + {
  199 + int err = WSAGetLastError();
  200 + std::cerr << "WinHttpHandler: sendMulticast: Error at socket(): " << err << std::endl;
  201 + throw(std::system_error(err, std::system_category(), "WinHttpHandler: sendMulticast: Error at socket()"));
  202 + }
  203 + SocketCloser closeSocket(connect_socket);
  204 +
  205 + // Fill out source socket's address information.
  206 + SOCKADDR_IN source_sin;
  207 + source_sin.sin_family = AF_INET;
  208 + source_sin.sin_port = htons(0);
  209 + source_sin.sin_addr.s_addr = htonl(INADDR_ANY);
  210 +
  211 + // Associate the source socket's address with the socket, Sock.
  212 + if (bind(connect_socket, (struct sockaddr FAR *) &source_sin, sizeof(source_sin)) == SOCKET_ERROR)
  213 + {
  214 + int err = WSAGetLastError();
  215 + std::cerr << "WinHttpHandler: sendMulticast: Binding socket failed: " << err << std::endl;
  216 + throw(std::system_error(err, std::system_category(), "WinHttpHandler: sendMulticast: Binding socket failed"));
  217 + }
  218 +
  219 + u_long sock_mode = 1;
  220 + ioctlsocket(connect_socket, FIONBIO, &sock_mode);
  221 +
  222 + BOOL bOptVal = TRUE;
  223 + setsockopt(connect_socket, SOL_SOCKET, SO_BROADCAST, (char *)&bOptVal, sizeof(bOptVal));
  224 +
  225 + // Set the Time-to-Live of the multicast.
  226 + int iOptVal = 1; // for same subnet, but might be increased to 16
  227 + if (setsockopt(connect_socket, IPPROTO_IP, IP_MULTICAST_TTL, (char FAR *)&iOptVal, sizeof(int)) == SOCKET_ERROR)
  228 + {
  229 + int err = WSAGetLastError();
  230 + std::cerr << "WinHttpHandler: sendMulticast: setsockopt failed: " << err << std::endl;
  231 + throw(std::system_error(err, std::system_category(), "WinHttpHandler: sendMulticast: setsockopt failed"));
  232 + }
  233 +
  234 + // Fill out the desination socket's address information.
  235 + SOCKADDR_IN dest_sin;
  236 + dest_sin.sin_family = AF_INET;
  237 + dest_sin.sin_port = htons(port);
  238 + dest_sin.sin_addr.s_addr = inet_addr((const char*)ptr->ai_addr);
  239 +
  240 + // Send a message to the multicasting address.
  241 + if (sendto(connect_socket, msg.c_str(), msg.size(), 0, (struct sockaddr FAR *) &dest_sin, sizeof(dest_sin)) == SOCKET_ERROR)
  242 + {
  243 + int err = WSAGetLastError();
  244 + std::cerr << "WinHttpHandler: sendMulticast: sendto failed: " << WSAGetLastError() << std::endl;
  245 + throw(std::system_error(err, std::system_category(), "WinHttpHandler: sendMulticast: sendto failed"));
  246 + }
  247 +
  248 + // shutdown the connection for sending since no more data will be sent
  249 + // the client can still use the ConnectSocket for receiving data
  250 + if (shutdown(connect_socket, SD_SEND) == SOCKET_ERROR)
  251 + {
  252 + int err = WSAGetLastError();
  253 + std::cerr << "WinHttpHandler: sendMulticast: shutdown failed: " << err << std::endl;
  254 + throw(std::system_error(err, std::system_category(), "WinHttpHandler: sendMulticast: shutdown failed"));
  255 + }
  256 +
  257 + std::string response;
  258 + const int recvbuflen = 2048;
  259 + char recvbuf[recvbuflen] = {};
  260 + int res;
  261 + std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
  262 + while (std::chrono::steady_clock::now() - start < std::chrono::seconds(timeout))
  263 + {
  264 + res = recv(connect_socket, recvbuf, recvbuflen, 0);
  265 + if (res > 0)
  266 + {
  267 + //std::cout << "WinHttpHandler: sendMulticast: Bytes received: " << res << std::endl;
  268 + response.append(recvbuf, res);
  269 + }
  270 + else if (res == 0)
  271 + {
  272 + //std::cout << "WinHttpHandler: sendMulticast: Connection closed " << std::endl;
  273 + }
  274 + else
  275 + {
  276 + // No exception here due to non blocking socket
  277 + //std::cerr << "sendMulticast: recv failed: " << WSAGetLastError() << std::endl;
  278 + //throw(std::runtime_error("recv failed"));
  279 + }
  280 + }
  281 +
  282 + // construct return vector
  283 + std::vector<std::string> returnString;
  284 + size_t pos = response.find("\r\n\r\n");
  285 + size_t prevpos = 0;
  286 + while (pos != std::string::npos)
  287 + {
  288 + returnString.push_back(response.substr(prevpos, pos - prevpos));
  289 + pos += 4;
  290 + prevpos = pos;
  291 + pos = response.find("\r\n\r\n", pos);
  292 + }
  293 +
  294 + return returnString;
261 } 295 }