PDUUnit.cpp 4.11 KB
Newer Older
1
2
3
4
5
6
7
8
9
/*
 * PDUUnit.cpp
 *
 *  Created on: 26.02.2018
 *      Author: Micha Mueller
 */

#include "PDUUnit.h"
#include "timestamp.h"
10
11
12
13

#include <iostream>
#include <sstream>

14
#include <boost/foreach.hpp>
15
16
#include <boost/property_tree/xml_parser.hpp>

17
18
19
20
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/bio.h>

21
PDUUnit::PDUUnit() {
22
	_ttl = 1000;
23
	_lastRefresh = 0;
24
	_host = "";
25
	_strand = NULL;
26
27
28
29
30
31
}

PDUUnit::~PDUUnit() {
	// TODO Auto-generated destructor stub
}

32
uint64_t PDUUnit::readValue(const xmlPathVector_t& xmlPath) {
33
	uint64_t now = getTimestamp();
34
	if (now >= _lastRefresh + MS_TO_NS(_ttl)) {
35
36
		refresh();
#ifdef DEBUG
Micha Mueller's avatar
Micha Mueller committed
37
		LOG(debug) << "PDUUnit " << _host << " refreshed XML-file";
38
#endif
39
	}
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59

	std::string reading;
	boost::property_tree::ptree node = _ptree;
	for (size_t i = 0; i < xmlPath.size(); i++) {
		const std::string& path = std::get<0>(xmlPath[i]);
		const std::string& child = std::get<1>(xmlPath[i]);
		const attributesVector_t& attVec = std::get<2>(xmlPath[i]);

		unsigned matchCount;
		if (child != "") {
			BOOST_FOREACH(boost::property_tree::ptree::value_type &v, node.get_child(path)) {
				if (v.first == child) {
					matchCount = 0;
					for (size_t j = 0; j < attVec.size(); j++) {
						std::string attributeVal = v.second.get_child("<xmlattr>." + attVec[j].first).data();

						if (attributeVal != attVec[j].second) { //attribute values don't match
							break;
						} else {
							matchCount++;
60
61
						}
					}
62
63
64
65
66
					if (matchCount == attVec.size()) { //all attributes matched
						reading = v.second.data();
						node = v.second;
						break;
					}
67
68
				}
			}
69
70
71
		} else {	//child == ""
			reading = node.get(path, "");
			break;	//last (part of the) path
72
73
		}
	}
74
75
76

	if (reading == "") {
#ifdef DEBUG
77
		LOG(debug) << "PDU: Value not found!";
78
79
80
81
#endif
		return 0;
	}
#ifdef DEBUG
82
	LOG(debug) << "Read: " << reading;
83
84
#endif
	return stoul(reading);
85
86
}

Micha Mueller's avatar
Micha Mueller committed
87
void PDUUnit::initializeStrand(boost::asio::io_service& io) {
88
89
90
	if (!_strand) {
		_strand = new boost::asio::io_service::strand(io);
	}
91
92
}

93
void PDUUnit::refresh() {
94
95
	SSL_library_init();
	SSL_load_error_strings();
96
	ERR_load_BIO_strings();
97
98
99
100
101
102
103
104
	OpenSSL_add_all_algorithms();

	SSL_CTX*	ctx;
	BIO*		bio;

	ctx = SSL_CTX_new(SSLv23_method());

	if (!ctx) {
105
		LOG(error) << "OpenSSL: Could not create context: " << ERR_reason_error_string(ERR_get_error());
106
107
108
		return;
	}

109
110
	/*
	if (!SSL_CTX_load_verify_locations(ctx, "/home/micha/LRZ/dcdbOwnFork/deps/openssl-1.0.2l/certs/demo/ca-cert.pem", NULL)) {
111
		LOG(error) << "OpenSSL: Could not load certificate: " << ERR_reason_error_string(ERR_get_error());
112
113
114
115
116
		SSL_CTX_free(ctx);
		return;
	}
	*/

117
118
	bio = BIO_new_ssl_connect(ctx);

119
	BIO_set_conn_hostname(bio, _host.c_str());
120
121
122

	if(BIO_do_connect(bio) <= 0)
	{
123
		LOG(error) << "OpenSSL: Could not connect: " << ERR_reason_error_string(ERR_get_error());
124
125
126
127
128
	    BIO_free_all(bio);
	    SSL_CTX_free(ctx);
	    return;
	}

129
130
131
132
133
	size_t len = _request.length();
	const char* reqBuf = _request.c_str();	//request

	char resBuf[2048];	//response
	memset(resBuf, 0, 2048);
134
135
136
137
138

	// do not bother too long if a write/read failed. Sensor intervals are usually small, just try again when next sensor wants to read.
	// Current sensor has to use old value though.

	// send request
139
	if (BIO_write(bio, reqBuf, len) <= 0) {
140
		LOG(error) << "OpenSSL: Could not send request: " << ERR_reason_error_string(ERR_get_error());
141
142
143
		BIO_free_all(bio);
		SSL_CTX_free(ctx);
		return;
144
	}
145
146

	// read reply
147
148
149
150
151
152
153
154
155
156
157
158
	std::string response;
	while ((len = BIO_read(bio, resBuf, sizeof(resBuf))) > 0) {
                resBuf[len] = 0;
                response.append(resBuf);
        }

	if (len < 0) {
                std::cerr << "OpenSSL: Could not read response: " << ERR_reason_error_string(ERR_get_error()) << std::endl;
                BIO_free_all(bio);
                SSL_CTX_free(ctx);
                return;
        }
159
160
161
162

	BIO_free_all(bio);
	SSL_CTX_free(ctx);

163
164
	std::string xml = response.substr(response.find("<"));
	std::istringstream treeStream(xml);
165
166
167
168
169
170
	try {
		boost::property_tree::read_xml(treeStream, _ptree);
	} catch (const std::exception& e) {
		LOG(error) << "PDU: Got malformed XML repsonse from " << _host;
		return;
	}
171
	_lastRefresh = getTimestamp();
172
	return;
173
174
}