Commit 9e554815917bfd7671363baec1d88950498b45ea
Committed by
Moritz Wirger
1 parent
f0b19d95
Add crude windows compatability,
- Rename HttpHandler to linHttpHandler - Add new winHttpHandler for windows - Export duplicate functions from win/lin-HttpHandler into IHttpHandler
Showing
6 changed files
with
512 additions
and
298 deletions
hueplusplus/include/HttpHandler.h deleted
| 1 | -/** | |
| 2 | - \file HttpHandler.h | |
| 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 | -**/ | |
| 19 | - | |
| 20 | -#ifndef _HTTPHANDLER_H | |
| 21 | -#define _HTTPHANDLER_H | |
| 22 | - | |
| 23 | -#include <string> | |
| 24 | -#include <vector> | |
| 25 | - | |
| 26 | -#include "IHttpHandler.h" | |
| 27 | - | |
| 28 | -#include "json/json.h" | |
| 29 | -#include "IHttpHandler.h" | |
| 30 | - | |
| 31 | -//! Class to handle http requests and multicast requests | |
| 32 | -class HttpHandler : public IHttpHandler | |
| 33 | -{ | |
| 34 | -public: | |
| 35 | - //! \brief Function that sends a given message to the specified host and returns the response. | |
| 36 | - //! | |
| 37 | - //! \param msg String that contains the message that is sent to the specified address | |
| 38 | - //! \param adr String that contains an ip or hostname in dotted decimal notation like "192.168.2.1" | |
| 39 | - //! \param port Optional integer that specifies the port to which the request is sent to. Default is 80 | |
| 40 | - //! \return String containing the response of the host | |
| 41 | - std::string send(const std::string &msg, const std::string &adr, int port=80) const; | |
| 42 | - | |
| 43 | - //! \brief Function that sends a given message to the specified host and returns the body of the response. | |
| 44 | - //! | |
| 45 | - //! Note if no body is found a runtime error is thrown! | |
| 46 | - //! \param msg String that contains the message that is sent to the specified address | |
| 47 | - //! \param adr String that contains an ip or hostname in dotted decimal notation like "192.168.2.1" | |
| 48 | - //! \param port Optional integer that specifies the port to which the request is sent. Default is 80 | |
| 49 | - //! \return String containing the body of the response of the host | |
| 50 | - std::string sendGetHTTPBody(const std::string &msg, const std::string &adr, int port = 80) const; | |
| 51 | - | |
| 52 | - //! \brief Function that sends a multicast request with the specified message. | |
| 53 | - //! | |
| 54 | - //! \param msg String that contains the request that is sent to the specified address | |
| 55 | - //! \param adr Optional String that contains an ip or hostname in dotted decimal notation, default is "239.255.255.250" | |
| 56 | - //! \param port Optional integer that specifies the port to which the request is sent. Default is 1900 | |
| 57 | - //! \param timeout Optional Integer that specifies the timeout of the request in seconds. Default is 5 | |
| 58 | - //! \return Vector containing strings of each answer received | |
| 59 | - std::vector<std::string> sendMulticast(const std::string &msg, const std::string &adr = "239.255.255.250", int port = 1900, int timeout = 5) const; | |
| 60 | - | |
| 61 | - //! \brief Function that sends a HTTP request with the given method to the specified host and returns the body of the response. | |
| 62 | - //! | |
| 63 | - //! Note body can also be left empty! | |
| 64 | - //! \param method String that contains the HTTP method type e.g. GET, HEAD, POST, PUT, DELETE, ... | |
| 65 | - //! \param uri String that contains the uniform resource identifier | |
| 66 | - //! \param content_type String that contains the type(MIME) of the body data e.g. "text/html", "application/json", ... | |
| 67 | - //! \param body String that contains the data of the request | |
| 68 | - //! \param adr String that contains an ip or hostname in dotted decimal notation like "192.168.2.1" | |
| 69 | - //! \param port Optional integer that specifies the port to which the request is sent to. Default is 80 | |
| 70 | - //! \return String containing the body of the response of the host | |
| 71 | - std::string sendHTTPRequest(std::string method, std::string uri, std::string content_type, std::string body, const std::string &adr, int port=80) const; | |
| 72 | - | |
| 73 | - //! \brief Function that sends a HTTP GET request to the specified host and returns the body of the response. | |
| 74 | - //! | |
| 75 | - //! Note body can also be left empty! | |
| 76 | - //! \param uri String that contains the uniform resource identifier | |
| 77 | - //! \param content_type String that contains the type(MIME) of the body data e.g. "text/html", "application/json", ... | |
| 78 | - //! \param body String that contains the data of the request | |
| 79 | - //! \param adr String that contains an ip or hostname in dotted decimal notation like "192.168.2.1" | |
| 80 | - //! \param port Optional integer that specifies the port to which the request is sent to. Default is 80 | |
| 81 | - //! \return String containing the body of the response of the host | |
| 82 | - std::string GETString(std::string uri, std::string content_type, std::string body, const std::string &adr, int port=80) const; | |
| 83 | - | |
| 84 | - //! \brief Function that sends a HTTP POST request to the specified host and returns the body of the response. | |
| 85 | - //! | |
| 86 | - //! Note body can also be left empty! | |
| 87 | - //! \param uri String that contains the uniform resource identifier | |
| 88 | - //! \param content_type String that contains the type(MIME) of the body data e.g. "text/html", "application/json", ... | |
| 89 | - //! \param body String that contains the data of the request | |
| 90 | - //! \param adr String that contains an ip or hostname in dotted decimal notation like "192.168.2.1" | |
| 91 | - //! \param port Optional integer that specifies the port to which the request is sent to. Default is 80 | |
| 92 | - //! \return String containing the body of the response of the host | |
| 93 | - std::string POSTString(std::string uri, std::string content_type, std::string body, const std::string &adr, int port=80) const; | |
| 94 | - | |
| 95 | - //! \brief Function that sends a HTTP PUT request to the specified host and returns the body of the response. | |
| 96 | - //! | |
| 97 | - //! Note body can also be left empty! | |
| 98 | - //! \param uri String that contains the uniform resource identifier | |
| 99 | - //! \param content_type String that contains the type(MIME) of the body data e.g. "text/html", "application/json", ... | |
| 100 | - //! \param body String that contains the data of the request | |
| 101 | - //! \param adr String that contains an ip or hostname in dotted decimal notation like "192.168.2.1" | |
| 102 | - //! \param port Optional integer that specifies the port to which the request is sent to. Default is 80 | |
| 103 | - //! \return String containing the body of the response of the host | |
| 104 | - std::string PUTString(std::string uri, std::string content_type, std::string body, const std::string &adr, int port=80) const; | |
| 105 | - | |
| 106 | - //! \brief Function that sends a HTTP DELETE request to the specified host and returns the body of the response. | |
| 107 | - //! | |
| 108 | - //! Note body can also be left empty! | |
| 109 | - //! \param uri String that contains the uniform resource identifier | |
| 110 | - //! \param content_type String that contains the type(MIME) of the body data e.g. "text/html", "application/json", ... | |
| 111 | - //! \param body String that contains the data of the request | |
| 112 | - //! \param adr String that contains an ip or hostname in dotted decimal notation like "192.168.2.1" | |
| 113 | - //! \param port Optional integer that specifies the port to which the request is sent to. Default is 80 | |
| 114 | - //! \return String containing the body of the response of the host | |
| 115 | - std::string DELETEString(std::string uri, std::string content_type, std::string body, const std::string &adr, int port=80) const; | |
| 116 | - | |
| 117 | - //! \brief Function that sends a HTTP GET request to the specified host and returns the body of the response. | |
| 118 | - //! | |
| 119 | - //! Note body can also be left empty! | |
| 120 | - //! \param uri String that contains the uniform resource identifier | |
| 121 | - //! \param body Json::Value that contains the data of the request | |
| 122 | - //! \param adr String that contains an ip or hostname in dotted decimal notation like "192.168.2.1" | |
| 123 | - //! \param port Optional integer that specifies the port to which the request is sent to. Default is 80 | |
| 124 | - //! \return Json::Value containing the parsed body of the response of the host | |
| 125 | - Json::Value GETJson(std::string uri, const Json::Value& body, const std::string &adr, int port=80) const; | |
| 126 | - | |
| 127 | - //! \brief Function that sends a HTTP POST request to the specified host and returns the body of the response. | |
| 128 | - //! | |
| 129 | - //! Note body can also be left empty! | |
| 130 | - //! \param uri String that contains the uniform resource identifier | |
| 131 | - //! \param body Json::Value that contains the data of the request | |
| 132 | - //! \param adr String that contains an ip or hostname in dotted decimal notation like "192.168.2.1" | |
| 133 | - //! \param port Optional integer that specifies the port to which the request is sent to. Default is 80 | |
| 134 | - //! \return Json::Value containing the parsed body of the response of the host | |
| 135 | - Json::Value POSTJson(std::string uri, const Json::Value& body, const std::string &adr, int port=80) const; | |
| 136 | - | |
| 137 | - //! \brief Function that sends a HTTP PUT request to the specified host and returns the body of the response. | |
| 138 | - //! | |
| 139 | - //! Note body can also be left empty! | |
| 140 | - //! \param uri String that contains the uniform resource identifier | |
| 141 | - //! \param body Json::Value that contains the data of the request | |
| 142 | - //! \param adr String that contains an ip or hostname in dotted decimal notation like "192.168.2.1" | |
| 143 | - //! \param port Optional integer that specifies the port to which the request is sent to. Default is 80 | |
| 144 | - //! \return Json::Value containing the parsed body of the response of the host | |
| 145 | - Json::Value PUTJson(std::string uri, const Json::Value& body, const std::string &adr, int port=80) const; | |
| 146 | - | |
| 147 | - //! \brief Function that sends a HTTP DELETE request to the specified host and returns the body of the response. | |
| 148 | - //! | |
| 149 | - //! Note body can also be left empty! | |
| 150 | - //! \param uri String that contains the uniform resource identifier | |
| 151 | - //! \param body Json::Value that contains the data of the request | |
| 152 | - //! \param adr String that contains an ip or hostname in dotted decimal notation like "192.168.2.1" | |
| 153 | - //! \param port Optional integer that specifies the port to which the request is sent to. Default is 80 | |
| 154 | - //! \return Json::Value containing the parsed body of the response of the host | |
| 155 | - Json::Value DELETEJson(std::string uri, const Json::Value& body, const std::string &adr, int port=80) const; | |
| 156 | -}; | |
| 157 | - | |
| 158 | -#endif |
hueplusplus/include/IHttpHandler.h
| ... | ... | @@ -20,6 +20,8 @@ |
| 20 | 20 | #ifndef _IHTTPHANDLER_H |
| 21 | 21 | #define _IHTTPHANDLER_H |
| 22 | 22 | |
| 23 | +#include <iostream> | |
| 24 | +#include <memory> | |
| 23 | 25 | #include <string> |
| 24 | 26 | #include <vector> |
| 25 | 27 | |
| ... | ... | @@ -48,7 +50,18 @@ public: |
| 48 | 50 | //! \param adr String that contains an ip or hostname in dotted decimal notation like "192.168.2.1" |
| 49 | 51 | //! \param port Optional integer that specifies the port to which the request should be sent. Default is 80 |
| 50 | 52 | //! \return String containing the body of the response of the host |
| 51 | - virtual std::string sendGetHTTPBody(const std::string &msg, const std::string &adr, int port = 80) const = 0; | |
| 53 | + virtual std::string sendGetHTTPBody(const std::string &msg, const std::string &adr, int port = 80) const | |
| 54 | + { | |
| 55 | + std::string response = send(msg, adr, port); | |
| 56 | + size_t start = response.find("\r\n\r\n"); | |
| 57 | + if (start == std::string::npos) | |
| 58 | + { | |
| 59 | + std::cerr << "Failed to find body in response\n"; | |
| 60 | + throw(std::runtime_error("Failed to find body in response")); | |
| 61 | + } | |
| 62 | + response.erase(0, start + 4); | |
| 63 | + return response; | |
| 64 | + }; | |
| 52 | 65 | |
| 53 | 66 | //! \brief Virtual function that should send a multicast request with a specified message. |
| 54 | 67 | //! |
| ... | ... | @@ -69,7 +82,31 @@ public: |
| 69 | 82 | //! \param adr String that contains an ip or hostname in dotted decimal notation like "192.168.2.1" |
| 70 | 83 | //! \param port Optional integer that specifies the port to which the request is sent to. Default is 80 |
| 71 | 84 | //! \return String containing the body of the response of the host |
| 72 | - virtual std::string sendHTTPRequest(std::string method, std::string uri, std::string content_type, std::string body, const std::string &adr, int port=80) const = 0; | |
| 85 | + virtual std::string sendHTTPRequest(std::string method, std::string uri, std::string content_type, std::string body, const std::string &adr, int port=80) const | |
| 86 | + { | |
| 87 | + std::string request; | |
| 88 | + // Protocol reference: https://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html | |
| 89 | + // Request-Line | |
| 90 | + request.append(method); // Method | |
| 91 | + request.append(" "); // Separation | |
| 92 | + request.append(uri); // Request-URI | |
| 93 | + request.append(" "); // Separation | |
| 94 | + request.append("HTTP/1.0"); // HTTP-Version | |
| 95 | + request.append("\r\n"); // Ending | |
| 96 | + // Entities | |
| 97 | + request.append("Content-Type:"); // entity-header | |
| 98 | + request.append(" "); // Separation | |
| 99 | + request.append(content_type); // media-type | |
| 100 | + request.append("\r\n"); // Entity ending | |
| 101 | + request.append("Content-Length:"); // entity-header | |
| 102 | + request.append(" "); // Separation | |
| 103 | + request.append(std::to_string(body.size())); // length | |
| 104 | + request.append("\r\n\r\n"); // Entity ending & Request-Line ending | |
| 105 | + request.append(body); // message-body | |
| 106 | + request.append("\r\n\r\n"); // Ending | |
| 107 | + | |
| 108 | + return sendGetHTTPBody(request.c_str(), adr, port); | |
| 109 | + }; | |
| 73 | 110 | |
| 74 | 111 | //! \brief Virtual function that should send a HTTP GET request to the specified host and return the body of the response. |
| 75 | 112 | //! |
| ... | ... | @@ -80,7 +117,10 @@ public: |
| 80 | 117 | //! \param adr String that contains an ip or hostname in dotted decimal notation like "192.168.2.1" |
| 81 | 118 | //! \param port Optional integer that specifies the port to which the request is sent to. Default is 80 |
| 82 | 119 | //! \return String containing the body of the response of the host |
| 83 | - virtual std::string GETString(std::string uri, std::string content_type, std::string body, const std::string &adr, int port=80) const = 0; | |
| 120 | + virtual std::string GETString(std::string uri, std::string content_type, std::string body, const std::string &adr, int port=80) const | |
| 121 | + { | |
| 122 | + return sendHTTPRequest("GET", uri, content_type, body, adr, port); | |
| 123 | + }; | |
| 84 | 124 | |
| 85 | 125 | //! \brief Virtual function that should send a HTTP POST request to the specified host and returns the body of the response. |
| 86 | 126 | //! |
| ... | ... | @@ -91,7 +131,10 @@ public: |
| 91 | 131 | //! \param adr String that contains an ip or hostname in dotted decimal notation like "192.168.2.1" |
| 92 | 132 | //! \param port Optional integer that specifies the port to which the request is sent to. Default is 80 |
| 93 | 133 | //! \return String containing the body of the response of the host |
| 94 | - virtual std::string POSTString(std::string uri, std::string content_type, std::string body, const std::string &adr, int port=80) const = 0; | |
| 134 | + virtual std::string POSTString(std::string uri, std::string content_type, std::string body, const std::string &adr, int port=80) const | |
| 135 | + { | |
| 136 | + return sendHTTPRequest("POST", uri, content_type, body, adr, port); | |
| 137 | + }; | |
| 95 | 138 | |
| 96 | 139 | //! \brief Virtual function that should send a HTTP PUT request to the specified host and return the body of the response. |
| 97 | 140 | //! |
| ... | ... | @@ -102,7 +145,10 @@ public: |
| 102 | 145 | //! \param adr String that contains an ip or hostname in dotted decimal notation like "192.168.2.1" |
| 103 | 146 | //! \param port Optional integer that specifies the port to which the request is sent to. Default is 80 |
| 104 | 147 | //! \return String containing the body of the response of the host |
| 105 | - virtual std::string PUTString(std::string uri, std::string content_type, std::string body, const std::string &adr, int port=80) const = 0; | |
| 148 | + virtual std::string PUTString(std::string uri, std::string content_type, std::string body, const std::string &adr, int port=80) const | |
| 149 | + { | |
| 150 | + return sendHTTPRequest("PUT", uri, content_type, body, adr, port); | |
| 151 | + }; | |
| 106 | 152 | |
| 107 | 153 | //! \brief Virtual function that should send a HTTP DELETE request to the specified host and return the body of the response. |
| 108 | 154 | //! |
| ... | ... | @@ -113,7 +159,10 @@ public: |
| 113 | 159 | //! \param adr String that contains an ip or hostname in dotted decimal notation like "192.168.2.1" |
| 114 | 160 | //! \param port Optional integer that specifies the port to which the request is sent to. Default is 80 |
| 115 | 161 | //! \return String containing the body of the response of the host |
| 116 | - virtual std::string DELETEString(std::string uri, std::string content_type, std::string body, const std::string &adr, int port=80) const = 0; | |
| 162 | + virtual std::string DELETEString(std::string uri, std::string content_type, std::string body, const std::string &adr, int port=80) const | |
| 163 | + { | |
| 164 | + return sendHTTPRequest("DELETE", uri, content_type, body, adr, port); | |
| 165 | + }; | |
| 117 | 166 | |
| 118 | 167 | //! \brief Virtual function that should send a HTTP GET request to the specified host and return the body of the response. |
| 119 | 168 | //! |
| ... | ... | @@ -123,7 +172,22 @@ public: |
| 123 | 172 | //! \param adr String that contains an ip or hostname in dotted decimal notation like "192.168.2.1" |
| 124 | 173 | //! \param port Optional integer that specifies the port to which the request is sent to. Default is 80 |
| 125 | 174 | //! \return Json::Value containing the parsed body of the response of the host |
| 126 | - virtual Json::Value GETJson(std::string uri, const Json::Value& body, const std::string &adr, int port=80) const = 0; | |
| 175 | + virtual Json::Value GETJson(std::string uri, const Json::Value& body, const std::string &adr, int port=80) const | |
| 176 | + { | |
| 177 | + std::string response = GETString(uri, "application/json", body.toStyledString(), adr, port); | |
| 178 | + | |
| 179 | + std::string error; | |
| 180 | + Json::Value result; | |
| 181 | + Json::CharReaderBuilder builder; | |
| 182 | + builder["collectComments"] = false; | |
| 183 | + std::unique_ptr<Json::CharReader> reader = std::unique_ptr<Json::CharReader>(builder.newCharReader()); | |
| 184 | + if (!reader->parse(response.c_str(), response.c_str() + response.length(), &result, &error)) | |
| 185 | + { | |
| 186 | + std::cout << "Error while parsing JSON in function GETJson() of linHttpHandler: " << error << std::endl; | |
| 187 | + throw(std::runtime_error("Error while parsing JSON in function GETJson() of linHttpHandler")); | |
| 188 | + } | |
| 189 | + return result; | |
| 190 | + }; | |
| 127 | 191 | |
| 128 | 192 | //! \brief Virtual function that should send a HTTP POST request to the specified host and return the body of the response. |
| 129 | 193 | //! |
| ... | ... | @@ -133,7 +197,22 @@ public: |
| 133 | 197 | //! \param adr String that contains an ip or hostname in dotted decimal notation like "192.168.2.1" |
| 134 | 198 | //! \param port Optional integer that specifies the port to which the request is sent to. Default is 80 |
| 135 | 199 | //! \return Json::Value containing the parsed body of the response of the host |
| 136 | - virtual Json::Value POSTJson(std::string uri, const Json::Value& body, const std::string &adr, int port=80) const = 0; | |
| 200 | + virtual Json::Value POSTJson(std::string uri, const Json::Value& body, const std::string &adr, int port=80) const | |
| 201 | + { | |
| 202 | + std::string response = POSTString(uri, "application/json", body.toStyledString(), adr, port); | |
| 203 | + | |
| 204 | + std::string error; | |
| 205 | + Json::Value result; | |
| 206 | + Json::CharReaderBuilder builder; | |
| 207 | + builder["collectComments"] = false; | |
| 208 | + std::unique_ptr<Json::CharReader> reader = std::unique_ptr<Json::CharReader>(builder.newCharReader()); | |
| 209 | + if (!reader->parse(response.c_str(), response.c_str() + response.length(), &result, &error)) | |
| 210 | + { | |
| 211 | + std::cout << "Error while parsing JSON in function POSTJson() of linHttpHandler: " << error << std::endl; | |
| 212 | + throw(std::runtime_error("Error while parsing JSON in function POSTJson() of linHttpHandler")); | |
| 213 | + } | |
| 214 | + return result; | |
| 215 | + } | |
| 137 | 216 | |
| 138 | 217 | //! \brief Virtual function that should send a HTTP PUT request to the specified host and return the body of the response. |
| 139 | 218 | //! |
| ... | ... | @@ -143,7 +222,22 @@ public: |
| 143 | 222 | //! \param adr String that contains an ip or hostname in dotted decimal notation like "192.168.2.1" |
| 144 | 223 | //! \param port Optional integer that specifies the port to which the request is sent to. Default is 80 |
| 145 | 224 | //! \return Json::Value containing the parsed body of the response of the host |
| 146 | - virtual Json::Value PUTJson(std::string uri, const Json::Value& body, const std::string &adr, int port=80) const = 0; | |
| 225 | + virtual Json::Value PUTJson(std::string uri, const Json::Value& body, const std::string &adr, int port=80) const | |
| 226 | + { | |
| 227 | + std::string response = PUTString(uri, "application/json", body.toStyledString(), adr, port); | |
| 228 | + | |
| 229 | + std::string error; | |
| 230 | + Json::Value result; | |
| 231 | + Json::CharReaderBuilder builder; | |
| 232 | + builder["collectComments"] = false; | |
| 233 | + std::unique_ptr<Json::CharReader> reader = std::unique_ptr<Json::CharReader>(builder.newCharReader()); | |
| 234 | + if (!reader->parse(response.c_str(), response.c_str() + response.length(), &result, &error)) | |
| 235 | + { | |
| 236 | + std::cout << "Error while parsing JSON in function PUTJson() of linHttpHandler: " << error << std::endl; | |
| 237 | + throw(std::runtime_error("Error while parsing JSON in function PUTJson() of linHttpHandler")); | |
| 238 | + } | |
| 239 | + return result; | |
| 240 | + }; | |
| 147 | 241 | |
| 148 | 242 | //! \brief Virtual function that should send a HTTP DELETE request to the specified host and return the body of the response. |
| 149 | 243 | //! |
| ... | ... | @@ -153,7 +247,22 @@ public: |
| 153 | 247 | //! \param adr String that contains an ip or hostname in dotted decimal notation like "192.168.2.1" |
| 154 | 248 | //! \param port Optional integer that specifies the port to which the request is sent to. Default is 80 |
| 155 | 249 | //! \return Json::Value containing the parsed body of the response of the host |
| 156 | - virtual Json::Value DELETEJson(std::string uri, const Json::Value& body, const std::string &adr, int port=80) const = 0; | |
| 250 | + virtual Json::Value DELETEJson(std::string uri, const Json::Value& body, const std::string &adr, int port=80) const | |
| 251 | + { | |
| 252 | + std::string response = DELETEString(uri, "application/json", body.toStyledString(), adr, port); | |
| 253 | + | |
| 254 | + std::string error; | |
| 255 | + Json::Value result; | |
| 256 | + Json::CharReaderBuilder builder; | |
| 257 | + builder["collectComments"] = false; | |
| 258 | + std::unique_ptr<Json::CharReader> reader = std::unique_ptr<Json::CharReader>(builder.newCharReader()); | |
| 259 | + if (!reader->parse(response.c_str(), response.c_str() + response.length(), &result, &error)) | |
| 260 | + { | |
| 261 | + std::cout << "Error while parsing JSON in function PUTJson() of linHttpHandler: " << error << std::endl; | |
| 262 | + throw(std::runtime_error("Error while parsing JSON in function PUTJson() of linHttpHandler")); | |
| 263 | + } | |
| 264 | + return result; | |
| 265 | + }; | |
| 157 | 266 | }; |
| 158 | 267 | |
| 159 | 268 | #endif | ... | ... |
hueplusplus/include/linHttpHandler.h
0 โ 100644
| 1 | +/** | |
| 2 | + \file linHttpHandler.h | |
| 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 | +**/ | |
| 19 | + | |
| 20 | +#ifndef _LINHTTPHANDLER_H | |
| 21 | +#define _LINHTTPHANDLER_H | |
| 22 | + | |
| 23 | +#include <string> | |
| 24 | +#include <vector> | |
| 25 | + | |
| 26 | +#include "IHttpHandler.h" | |
| 27 | + | |
| 28 | +#include "json/json.h" | |
| 29 | + | |
| 30 | +//! Class to handle http requests and multicast requests on linux systems | |
| 31 | +class linHttpHandler : public IHttpHandler | |
| 32 | +{ | |
| 33 | +public: | |
| 34 | + //! \brief Function that sends a given message to the specified host and returns the response. | |
| 35 | + //! | |
| 36 | + //! \param msg String that contains the message that is sent to the specified address | |
| 37 | + //! \param adr String that contains an ip or hostname in dotted decimal notation like "192.168.2.1" | |
| 38 | + //! \param port Optional integer that specifies the port to which the request is sent to. Default is 80 | |
| 39 | + //! \return String containing the response of the host | |
| 40 | + std::string send(const std::string &msg, const std::string &adr, int port=80) const; | |
| 41 | + | |
| 42 | + //! \brief Function that sends a multicast request with the specified message. | |
| 43 | + //! | |
| 44 | + //! \param msg String that contains the request that is sent to the specified address | |
| 45 | + //! \param adr Optional String that contains an ip or hostname in dotted decimal notation, default is "239.255.255.250" | |
| 46 | + //! \param port Optional integer that specifies the port to which the request is sent. Default is 1900 | |
| 47 | + //! \param timeout Optional Integer that specifies the timeout of the request in seconds. Default is 5 | |
| 48 | + //! \return Vector containing strings of each answer received | |
| 49 | + std::vector<std::string> sendMulticast(const std::string &msg, const std::string &adr = "239.255.255.250", int port = 1900, int timeout = 5) const; | |
| 50 | +}; | |
| 51 | + | |
| 52 | +#endif | ... | ... |
hueplusplus/include/winHttpHandler.h
0 โ 100644
| 1 | +/** | |
| 2 | +\file winHttpHandler.h | |
| 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 | +**/ | |
| 19 | + | |
| 20 | +#ifndef _WINHTTPHANDLER_H | |
| 21 | +#define _WINHTTPHANDLER_H | |
| 22 | + | |
| 23 | +#include <string> | |
| 24 | +#include <vector> | |
| 25 | +#include <winsock2.h> | |
| 26 | + | |
| 27 | +#include "IHttpHandler.h" | |
| 28 | + | |
| 29 | +#include "json/json.h" | |
| 30 | + | |
| 31 | +//! Class to handle http requests and multicast requests on windows systems | |
| 32 | +class winHttpHandler : public IHttpHandler | |
| 33 | +{ | |
| 34 | +public: | |
| 35 | + //! \brief Ctor needed for initializing wsaData | |
| 36 | + winHttpHandler(); | |
| 37 | + | |
| 38 | + //! \brief Dtor needed for wsaData cleanup | |
| 39 | + ~winHttpHandler(); | |
| 40 | + | |
| 41 | + //! \brief Function that sends a given message to the specified host and returns the response. | |
| 42 | + //! | |
| 43 | + //! \param msg String that contains the message that is sent to the specified address | |
| 44 | + //! \param adr String that contains an ip or hostname in dotted decimal notation like "192.168.2.1" | |
| 45 | + //! \param port Optional integer that specifies the port to which the request is sent to. Default is 80 | |
| 46 | + //! \return String containing the response of the host | |
| 47 | + std::string send(const std::string &msg, const std::string &adr, int port = 80) const; | |
| 48 | + | |
| 49 | + //! \brief Function that sends a multicast request with the specified message. | |
| 50 | + //! | |
| 51 | + //! \param msg String that contains the request that is sent to the specified address | |
| 52 | + //! \param adr Optional String that contains an ip or hostname in dotted decimal notation, default is "239.255.255.250" | |
| 53 | + //! \param port Optional integer that specifies the port to which the request is sent. Default is 1900 | |
| 54 | + //! \param timeout Optional Integer that specifies the timeout of the request in seconds. Default is 5 | |
| 55 | + //! \return Vector containing strings of each answer received | |
| 56 | + std::vector<std::string> sendMulticast(const std::string &msg, const std::string &adr = "239.255.255.250", int port = 1900, int timeout = 5) const; | |
| 57 | + | |
| 58 | +private: | |
| 59 | + WSADATA wsaData; | |
| 60 | +}; | |
| 61 | + | |
| 62 | +#endif | ... | ... |
hueplusplus/HttpHandler.cpp renamed to hueplusplus/linHttpHandler.cpp
100755 โ 100644
| 1 | 1 | /** |
| 2 | - \file HttpHandler.cpp | |
| 2 | + \file linHttpHandler.cpp | |
| 3 | 3 | Copyright Notice\n |
| 4 | 4 | Copyright (C) 2017 Jan Rogall - developer\n |
| 5 | 5 | Copyright (C) 2017 Moritz Wirger - developer\n |
| ... | ... | @@ -17,7 +17,9 @@ |
| 17 | 17 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
| 18 | 18 | **/ |
| 19 | 19 | |
| 20 | -#include "include/HttpHandler.h" | |
| 20 | +#include "include/linHttpHandler.h" | |
| 21 | + | |
| 22 | +#ifndef _MSC_VER | |
| 21 | 23 | |
| 22 | 24 | #include <chrono> |
| 23 | 25 | #include <netinet/in.h> // struct sockaddr_in, struct sockaddr |
| ... | ... | @@ -38,7 +40,7 @@ class SocketCloser { |
| 38 | 40 | private: int s; |
| 39 | 41 | }; |
| 40 | 42 | |
| 41 | -std::string HttpHandler::send(const std::string & msg, const std::string & adr, int port) const | |
| 43 | +std::string linHttpHandler::send(const std::string & msg, const std::string & adr, int port) const | |
| 42 | 44 | { |
| 43 | 45 | // create socket |
| 44 | 46 | int socketFD = socket(AF_INET, SOCK_STREAM, 0); |
| ... | ... | @@ -127,20 +129,7 @@ std::string HttpHandler::send(const std::string & msg, const std::string & adr, |
| 127 | 129 | return response; |
| 128 | 130 | } |
| 129 | 131 | |
| 130 | -std::string HttpHandler::sendGetHTTPBody(const std::string & msg, const std::string & adr, int port) const | |
| 131 | -{ | |
| 132 | - std::string response = send(msg, adr, port); | |
| 133 | - size_t start = response.find("\r\n\r\n"); | |
| 134 | - if (start == std::string::npos) | |
| 135 | - { | |
| 136 | - std::cerr << "Failed to find body in response\n"; | |
| 137 | - throw(std::runtime_error("Failed to find body in response")); | |
| 138 | - } | |
| 139 | - response.erase(0, start + 4); | |
| 140 | - return response; | |
| 141 | -} | |
| 142 | - | |
| 143 | -std::vector<std::string> HttpHandler::sendMulticast(const std::string & msg, const std::string & adr, int port, int timeout) const | |
| 132 | +std::vector<std::string> linHttpHandler::sendMulticast(const std::string & msg, const std::string & adr, int port, int timeout) const | |
| 144 | 133 | { |
| 145 | 134 | hostent *server; // host information |
| 146 | 135 | sockaddr_in server_addr; // server address |
| ... | ... | @@ -219,116 +208,4 @@ std::vector<std::string> HttpHandler::sendMulticast(const std::string & msg, con |
| 219 | 208 | return returnString; |
| 220 | 209 | } |
| 221 | 210 | |
| 222 | -std::string HttpHandler::sendHTTPRequest(std::string method, std::string uri, std::string content_type, std::string body, const std::string &adr, int port) const | |
| 223 | -{ | |
| 224 | - std::string request; | |
| 225 | - // Protocol reference: https://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html | |
| 226 | - // Request-Line | |
| 227 | - request.append(method); // Method | |
| 228 | - request.append(" "); // Separation | |
| 229 | - request.append(uri); // Request-URI | |
| 230 | - request.append(" "); // Separation | |
| 231 | - request.append("HTTP/1.0"); // HTTP-Version | |
| 232 | - request.append("\r\n"); // Ending | |
| 233 | - // Entities | |
| 234 | - request.append("Content-Type:"); // entity-header | |
| 235 | - request.append(" "); // Separation | |
| 236 | - request.append(content_type); // media-type | |
| 237 | - request.append("\r\n"); // Entity ending | |
| 238 | - request.append("Content-Length:"); // entity-header | |
| 239 | - request.append(" "); // Separation | |
| 240 | - request.append(std::to_string(body.size())); // length | |
| 241 | - request.append("\r\n\r\n"); // Entity ending & Request-Line ending | |
| 242 | - request.append(body); // message-body | |
| 243 | - request.append("\r\n\r\n"); // Ending | |
| 244 | - | |
| 245 | - return sendGetHTTPBody(request.c_str(), adr, port); | |
| 246 | -} | |
| 247 | - | |
| 248 | -std::string HttpHandler::GETString(std::string uri, std::string content_type, std::string body, const std::string &adr, int port) const | |
| 249 | -{ | |
| 250 | - return sendHTTPRequest("GET", uri, content_type, body, adr, port); | |
| 251 | -} | |
| 252 | - | |
| 253 | -std::string HttpHandler::POSTString(std::string uri, std::string content_type, std::string body, const std::string &adr, int port) const | |
| 254 | -{ | |
| 255 | - return sendHTTPRequest("POST", uri, content_type, body, adr, port); | |
| 256 | -} | |
| 257 | - | |
| 258 | -std::string HttpHandler::PUTString(std::string uri, std::string content_type, std::string body, const std::string &adr, int port) const | |
| 259 | -{ | |
| 260 | - return sendHTTPRequest("PUT", uri, content_type, body, adr, port); | |
| 261 | -} | |
| 262 | - | |
| 263 | -std::string HttpHandler::DELETEString(std::string uri, std::string content_type, std::string body, const std::string &adr, int port) const | |
| 264 | -{ | |
| 265 | - return sendHTTPRequest("DELETE", uri, content_type, body, adr, port); | |
| 266 | -} | |
| 267 | - | |
| 268 | -Json::Value HttpHandler::GETJson(std::string uri, const Json::Value& body, const std::string &adr, int port) const | |
| 269 | -{ | |
| 270 | - std::string response = GETString(uri, "application/json", body.toStyledString(), adr, port); | |
| 271 | - | |
| 272 | - std::string error; | |
| 273 | - Json::Value result; | |
| 274 | - Json::CharReaderBuilder builder; | |
| 275 | - builder["collectComments"] = false; | |
| 276 | - std::unique_ptr<Json::CharReader> reader = std::unique_ptr<Json::CharReader>(builder.newCharReader()); | |
| 277 | - if (!reader->parse(response.c_str(), response.c_str() + response.length(), &result, &error)) | |
| 278 | - { | |
| 279 | - std::cout << "Error while parsing JSON in function GETJson() of HttpHandler: " << error << std::endl; | |
| 280 | - throw(std::runtime_error("Error while parsing JSON in function GETJson() of HttpHandler")); | |
| 281 | - } | |
| 282 | - return result; | |
| 283 | -} | |
| 284 | - | |
| 285 | -Json::Value HttpHandler::POSTJson(std::string uri, const Json::Value& body, const std::string &adr, int port) const | |
| 286 | -{ | |
| 287 | - std::string response = POSTString(uri, "application/json", body.toStyledString(), adr, port); | |
| 288 | - | |
| 289 | - std::string error; | |
| 290 | - Json::Value result; | |
| 291 | - Json::CharReaderBuilder builder; | |
| 292 | - builder["collectComments"] = false; | |
| 293 | - std::unique_ptr<Json::CharReader> reader = std::unique_ptr<Json::CharReader>(builder.newCharReader()); | |
| 294 | - if (!reader->parse(response.c_str(), response.c_str() + response.length(), &result, &error)) | |
| 295 | - { | |
| 296 | - std::cout << "Error while parsing JSON in function POSTJson() of HttpHandler: " << error << std::endl; | |
| 297 | - throw(std::runtime_error("Error while parsing JSON in function POSTJson() of HttpHandler")); | |
| 298 | - } | |
| 299 | - return result; | |
| 300 | -} | |
| 301 | - | |
| 302 | -Json::Value HttpHandler::PUTJson(std::string uri, const Json::Value& body, const std::string &adr, int port) const | |
| 303 | -{ | |
| 304 | - std::string response = PUTString(uri, "application/json", body.toStyledString(), adr, port); | |
| 305 | - | |
| 306 | - std::string error; | |
| 307 | - Json::Value result; | |
| 308 | - Json::CharReaderBuilder builder; | |
| 309 | - builder["collectComments"] = false; | |
| 310 | - std::unique_ptr<Json::CharReader> reader = std::unique_ptr<Json::CharReader>(builder.newCharReader()); | |
| 311 | - if (!reader->parse(response.c_str(), response.c_str() + response.length(), &result, &error)) | |
| 312 | - { | |
| 313 | - std::cout << "Error while parsing JSON in function PUTJson() of HttpHandler: " << error << std::endl; | |
| 314 | - throw(std::runtime_error("Error while parsing JSON in function PUTJson() of HttpHandler")); | |
| 315 | - } | |
| 316 | - return result; | |
| 317 | -} | |
| 318 | - | |
| 319 | -Json::Value HttpHandler::DELETEJson(std::string uri, const Json::Value& body, const std::string &adr, int port) const | |
| 320 | -{ | |
| 321 | - std::string response = DELETEString(uri, "application/json", body.toStyledString(), adr, port); | |
| 322 | - | |
| 323 | - std::string error; | |
| 324 | - Json::Value result; | |
| 325 | - Json::CharReaderBuilder builder; | |
| 326 | - builder["collectComments"] = false; | |
| 327 | - std::unique_ptr<Json::CharReader> reader = std::unique_ptr<Json::CharReader>(builder.newCharReader()); | |
| 328 | - if (!reader->parse(response.c_str(), response.c_str() + response.length(), &result, &error)) | |
| 329 | - { | |
| 330 | - std::cout << "Error while parsing JSON in function PUTJson() of HttpHandler: " << error << std::endl; | |
| 331 | - throw(std::runtime_error("Error while parsing JSON in function PUTJson() of HttpHandler")); | |
| 332 | - } | |
| 333 | - return result; | |
| 334 | -} | |
| 211 | +#endif | ... | ... |
hueplusplus/winHttpHandler.cpp
0 โ 100644
| 1 | +/** | |
| 2 | +\file winHttpHandler.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 | +**/ | |
| 19 | + | |
| 20 | +#include "include/winHttpHandler.h" | |
| 21 | + | |
| 22 | +#ifdef _MSC_VER | |
| 23 | + | |
| 24 | +#include <chrono> | |
| 25 | +#include <iostream> | |
| 26 | +#include <memory> | |
| 27 | +#include <stdio.h> | |
| 28 | +#include <ws2tcpip.h> | |
| 29 | + | |
| 30 | +#pragma comment(lib, "Ws2_32.lib") | |
| 31 | + | |
| 32 | +winHttpHandler::winHttpHandler() | |
| 33 | +{ | |
| 34 | + // Initialize Winsock | |
| 35 | + if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) | |
| 36 | + { | |
| 37 | + std::cerr << "Failed to open socket: " << WSAGetLastError() << std::endl; | |
| 38 | + throw(std::runtime_error("Failed to open socket")); | |
| 39 | + } | |
| 40 | +} | |
| 41 | + | |
| 42 | +winHttpHandler::~winHttpHandler() | |
| 43 | +{ | |
| 44 | + WSACleanup(); | |
| 45 | +} | |
| 46 | + | |
| 47 | +std::string winHttpHandler::send(const std::string & msg, const std::string & adr, int port) const | |
| 48 | +{ | |
| 49 | + struct addrinfo *result = nullptr, *ptr = nullptr, hints; | |
| 50 | + | |
| 51 | + ZeroMemory(&hints, sizeof(hints)); | |
| 52 | + hints.ai_family = AF_INET; | |
| 53 | + hints.ai_socktype = SOCK_STREAM; | |
| 54 | + hints.ai_protocol = IPPROTO_TCP; | |
| 55 | + | |
| 56 | + // Resolve the server address and port | |
| 57 | + int res = getaddrinfo(adr.c_str(), std::to_string(port).c_str(), &hints, &result); | |
| 58 | + if (res != 0) | |
| 59 | + { | |
| 60 | + std::cerr << "getaddrinfo failed: " << res << std::endl; | |
| 61 | + throw(std::runtime_error("getaddrinfo failed")); | |
| 62 | + } | |
| 63 | + | |
| 64 | + SOCKET connect_socket = INVALID_SOCKET; | |
| 65 | + | |
| 66 | + | |
| 67 | + // Attempt to connect to the first address returned by | |
| 68 | + // the call to getaddrinfo | |
| 69 | + ptr = result; | |
| 70 | + | |
| 71 | + // Create a SOCKET for connecting to server | |
| 72 | + connect_socket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol); | |
| 73 | + | |
| 74 | + if (connect_socket == INVALID_SOCKET) | |
| 75 | + { | |
| 76 | + freeaddrinfo(result); | |
| 77 | + std::cerr << "Error at socket(): " << WSAGetLastError() << std::endl; | |
| 78 | + throw(std::runtime_error("Error at socket()")); | |
| 79 | + } | |
| 80 | + | |
| 81 | + // Connect to server. | |
| 82 | + res = connect(connect_socket, ptr->ai_addr, (int)ptr->ai_addrlen); | |
| 83 | + if (res == SOCKET_ERROR) | |
| 84 | + { | |
| 85 | + closesocket(connect_socket); | |
| 86 | + connect_socket = INVALID_SOCKET; | |
| 87 | + } | |
| 88 | + | |
| 89 | + // Should really try the next address returned by getaddrinfo | |
| 90 | + // if the connect call failed | |
| 91 | + // But for this simple example we just free the resources | |
| 92 | + // returned by getaddrinfo and print an error message | |
| 93 | + | |
| 94 | + freeaddrinfo(result); | |
| 95 | + | |
| 96 | + if (connect_socket == INVALID_SOCKET) | |
| 97 | + { | |
| 98 | + std::cerr << "Unable to connect to server!" << std::endl; | |
| 99 | + throw(std::runtime_error("Unable to connect to server!")); | |
| 100 | + } | |
| 101 | + | |
| 102 | + // Send an initial buffer | |
| 103 | + res = ::send(connect_socket, msg.c_str(), msg.size(), 0); | |
| 104 | + if (res == SOCKET_ERROR) | |
| 105 | + { | |
| 106 | + std::cerr << "send failed: " << WSAGetLastError() << std::endl; | |
| 107 | + throw(std::runtime_error("send failed")); | |
| 108 | + } | |
| 109 | + | |
| 110 | + // shutdown the connection for sending since no more data will be sent | |
| 111 | + // the client can still use the ConnectSocket for receiving data | |
| 112 | + res = shutdown(connect_socket, SD_SEND); | |
| 113 | + if (res == SOCKET_ERROR) | |
| 114 | + { | |
| 115 | + closesocket(connect_socket); | |
| 116 | + std::cerr << "shutdown failed: " << WSAGetLastError() << std::endl; | |
| 117 | + throw(std::runtime_error("shutdown failed")); | |
| 118 | + } | |
| 119 | + | |
| 120 | + const int recvbuflen = 128; | |
| 121 | + char recvbuf[recvbuflen]; | |
| 122 | + | |
| 123 | + // Receive data until the server closes the connection | |
| 124 | + std::string response; | |
| 125 | + int received = 0; | |
| 126 | + do | |
| 127 | + { | |
| 128 | + res = recv(connect_socket, recvbuf, recvbuflen, 0); | |
| 129 | + if (res > 0) | |
| 130 | + { | |
| 131 | + std::cout << "Bytes received: " << res << std::endl; | |
| 132 | + response.append(recvbuf, res); | |
| 133 | + } | |
| 134 | + else if (res == 0) | |
| 135 | + { | |
| 136 | + std::cout << "Connection closed " << std::endl; | |
| 137 | + } | |
| 138 | + else | |
| 139 | + { | |
| 140 | + std::cerr << "recv failed: " << WSAGetLastError() << std::endl; | |
| 141 | + throw(std::runtime_error("recv failed")); | |
| 142 | + } | |
| 143 | + } while (res > 0); | |
| 144 | + | |
| 145 | + return response; | |
| 146 | +} | |
| 147 | + | |
| 148 | +std::vector<std::string> winHttpHandler::sendMulticast(const std::string & msg, const std::string & adr, int port, int timeout) const | |
| 149 | +{ | |
| 150 | + struct addrinfo *result = nullptr, *ptr = nullptr, hints; | |
| 151 | + SOCKADDR_IN source_sin, dest_sin; | |
| 152 | + | |
| 153 | + ZeroMemory(&hints, sizeof(hints)); | |
| 154 | + hints.ai_family = AF_INET; | |
| 155 | + hints.ai_socktype = SOCK_DGRAM; | |
| 156 | + hints.ai_protocol = IPPROTO_TCP; | |
| 157 | + | |
| 158 | + // Resolve the server address and port | |
| 159 | + int res = getaddrinfo(adr.c_str(), std::to_string(port).c_str(), &hints, &result); | |
| 160 | + if (res != 0) | |
| 161 | + { | |
| 162 | + std::cerr << "sendMulticast: getaddrinfo failed: " << res << std::endl; | |
| 163 | + throw(std::runtime_error("getaddrinfo failed")); | |
| 164 | + } | |
| 165 | + | |
| 166 | + SOCKET connect_socket = INVALID_SOCKET; | |
| 167 | + | |
| 168 | + | |
| 169 | + // Attempt to connect to the first address returned by | |
| 170 | + // the call to getaddrinfo | |
| 171 | + ptr = result; | |
| 172 | + | |
| 173 | + // Create a SOCKET for connecting to server | |
| 174 | + if ((connect_socket = socket(ptr->ai_family, ptr->ai_socktype, 0)) == INVALID_SOCKET) | |
| 175 | + { | |
| 176 | + freeaddrinfo(result); | |
| 177 | + std::cerr << "sendMulticast: Error at socket(): " << WSAGetLastError() << std::endl; | |
| 178 | + throw(std::runtime_error("Error at socket()")); | |
| 179 | + } | |
| 180 | + | |
| 181 | + // Fill out source socket's address information. | |
| 182 | + source_sin.sin_family = AF_INET; | |
| 183 | + source_sin.sin_port = htons(0); | |
| 184 | + source_sin.sin_addr.s_addr = htonl(INADDR_ANY); | |
| 185 | + | |
| 186 | + // Associate the source socket's address with the socket, Sock. | |
| 187 | + if (bind(connect_socket, (struct sockaddr FAR *) &source_sin, sizeof(source_sin)) == SOCKET_ERROR) | |
| 188 | + { | |
| 189 | + closesocket(connect_socket); | |
| 190 | + std::cerr << "sendMulticast: Binding socket failed: " << WSAGetLastError() << std::endl; | |
| 191 | + throw(std::runtime_error("Binding socket failed")); | |
| 192 | + } | |
| 193 | + | |
| 194 | + u_long sock_mode = 1; | |
| 195 | + ioctlsocket(connect_socket, FIONBIO, &sock_mode); | |
| 196 | + | |
| 197 | + BOOL bOptVal = TRUE; | |
| 198 | + setsockopt(connect_socket, SOL_SOCKET, SO_BROADCAST, (char *)&bOptVal, sizeof(bOptVal)); | |
| 199 | + | |
| 200 | + // Set the Time-to-Live of the multicast. | |
| 201 | + int iOptVal = 64; | |
| 202 | + if (setsockopt(connect_socket, IPPROTO_IP, IP_MULTICAST_TTL, (char FAR *)&iOptVal, sizeof(int)) == SOCKET_ERROR) | |
| 203 | + { | |
| 204 | + closesocket(connect_socket); | |
| 205 | + std::cerr << "sendMulticast: setsockopt failed: " << WSAGetLastError() << std::endl; | |
| 206 | + throw(std::runtime_error("setsockopt failed")); | |
| 207 | + } | |
| 208 | + | |
| 209 | + // Fill out the desination socket's address information. | |
| 210 | + dest_sin.sin_family = AF_INET; | |
| 211 | + dest_sin.sin_port = htons(port); | |
| 212 | + dest_sin.sin_addr.s_addr = inet_addr((const char*)ptr->ai_addr); | |
| 213 | + | |
| 214 | + // Send a message to the multicasting address. | |
| 215 | + if (sendto(connect_socket, msg.c_str(), msg.size(), 0, (struct sockaddr FAR *) &dest_sin, sizeof(dest_sin)) == SOCKET_ERROR) | |
| 216 | + { | |
| 217 | + std::cerr << "sendMulticast: sendto failed: " << WSAGetLastError() << std::endl; | |
| 218 | + closesocket(connect_socket); | |
| 219 | + throw(std::runtime_error("sendto failed")); | |
| 220 | + } | |
| 221 | + | |
| 222 | + // shutdown the connection for sending since no more data will be sent | |
| 223 | + // the client can still use the ConnectSocket for receiving data | |
| 224 | + res = shutdown(connect_socket, SD_SEND); | |
| 225 | + if (res == SOCKET_ERROR) | |
| 226 | + { | |
| 227 | + closesocket(connect_socket); | |
| 228 | + std::cerr << "sendMulticast: shutdown failed: " << WSAGetLastError() << std::endl; | |
| 229 | + throw(std::runtime_error("shutdown failed")); | |
| 230 | + } | |
| 231 | + | |
| 232 | + std::string response; | |
| 233 | + const int recvbuflen = 2048; | |
| 234 | + char recvbuf[recvbuflen] = {}; | |
| 235 | + std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now(); | |
| 236 | + while (std::chrono::steady_clock::now() - start < std::chrono::seconds(timeout)) | |
| 237 | + { | |
| 238 | + res = recv(connect_socket, recvbuf, recvbuflen, 0); | |
| 239 | + if (res > 0) | |
| 240 | + { | |
| 241 | + std::cout << "sendMulticast: Bytes received: " << res << std::endl; | |
| 242 | + response.append(recvbuf, res); | |
| 243 | + } | |
| 244 | + else if (res == 0) | |
| 245 | + { | |
| 246 | + std::cout << "sendMulticast: Connection closed " << std::endl; | |
| 247 | + } | |
| 248 | + else | |
| 249 | + { | |
| 250 | + // No exception here due to non blocking socket | |
| 251 | + //std::cerr << "sendMulticast: recv failed: " << WSAGetLastError() << std::endl; | |
| 252 | + //throw(std::runtime_error("recv failed")); | |
| 253 | + } | |
| 254 | + } | |
| 255 | + closesocket(connect_socket); // Is this needed? | |
| 256 | + | |
| 257 | + // construct return vector | |
| 258 | + std::vector<std::string> returnString; | |
| 259 | + size_t pos = response.find("\r\n\r\n"); | |
| 260 | + size_t prevpos = 0; | |
| 261 | + while (pos != std::string::npos) | |
| 262 | + { | |
| 263 | + returnString.push_back(response.substr(prevpos, pos - prevpos)); | |
| 264 | + pos += 4; | |
| 265 | + prevpos = pos; | |
| 266 | + pos = response.find("\r\n\r\n", pos); | |
| 267 | + } | |
| 268 | + | |
| 269 | + return returnString; | |
| 270 | +} | |
| 271 | + | |
| 272 | +#endif | ... | ... |