Skip to content

Commit

Permalink
Added automatic reopen of underlying device in case of libsml read 0. (
Browse files Browse the repository at this point in the history
…#370)

* Added automatic reopen of underlying device in case of libsml read 0.

As a workaround for #362 added an automatic reopen if
sml_transport_read returns 0 bytes.
Issue: #362

* Fix GTEST_LIBS_DIR for gmock.

Don't really know why this has changed. Might be that
gmock changed it.

* Added reopen as well to read to prevent use of invalid fd.

If reopen fails the fd might be invalid and the next read call
does a write or pass an invalid fd to sml_transport_read.
Now reopen gets triggered again and if it fails a sleep of 1s
is done to prevent busy loopings.
  • Loading branch information
mbehr1 committed Jan 6, 2019
1 parent 48cd577 commit d60752b
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 7 deletions.
4 changes: 2 additions & 2 deletions gmock/CMakeLists.txt
Expand Up @@ -19,6 +19,6 @@ set(GTEST_INCLUDE_DIRS ${source_dir}/googletest/include PARENT_SCOPE)

# Specify MainTest's link libraries
ExternalProject_Get_Property(googlemock binary_dir)
set(GTEST_LIBS_DIR ${binary_dir}/googlemock/gtest PARENT_SCOPE)
set(GMOCK_LIBS_DIR ${binary_dir}/googlemock PARENT_SCOPE)
set(GTEST_LIBS_DIR ${binary_dir}/lib PARENT_SCOPE)
set(GMOCK_LIBS_DIR ${binary_dir}/lib PARENT_SCOPE)

14 changes: 10 additions & 4 deletions include/protocols/MeterSML.hpp
Expand Up @@ -8,7 +8,7 @@
* @author Steffen Vogel <info@steffenvogel.de>
* @author Juri Glass
* @author Mathias Runge
* @author Nadim El Sayed
* @author Nadim El Sayed
*/
/*
* This file is part of volkzaehler.org
Expand All @@ -26,7 +26,7 @@
* You should have received a copy of the GNU General Public License
* along with volkszaehler.org. If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef _SML_H_
#define _SML_H_

Expand Down Expand Up @@ -54,20 +54,26 @@ class MeterSML : public vz::protocol::Protocol {

const char *host() const { return _host.c_str(); }
const char *device() const { return _device.c_str(); }

protected:
std::string _host;
std::string _device;
speed_t _baudrate;
parity_type_t _parity;
std::string _pull;
bool _use_local_time;

int _fd; /* file descriptor of port */
struct termios _old_tio; /* required to reset port */

const int BUFFER_LEN;

/**
* @brief reopen the underlying device. We do this to workaround issue #362
* @return true if reopen was successful. False otherwise.
* */
bool reopen();

/**
* Parses SML list entry and stores it in reading pointed by rd
*
Expand Down
32 changes: 31 additions & 1 deletion src/protocols/MeterSML.cpp
Expand Up @@ -166,6 +166,7 @@ MeterSML::MeterSML(std::list<Option> options)

MeterSML::MeterSML(const MeterSML &proto)
: Protocol(proto)
,_fd(ERR)
, BUFFER_LEN(SML_BUFFER_LEN)
{
}
Expand All @@ -182,7 +183,10 @@ int MeterSML::open() {
char *addr = strdup(host());
const char *node = strsep(&addr, ":");
const char *service = strsep(&addr, ":");
if (node == NULL && service == NULL) return -1;
if (node == NULL && service == NULL) {
free(addr);
return -1;
}
_fd = _openSocket(node, service);
free(addr);
}
Expand All @@ -199,6 +203,16 @@ int MeterSML::close() {
return ::close(_fd);
}

bool MeterSML::reopen() {
print(log_warning, "reopen called. current fd=%d", name().c_str(), _fd);
if (_fd != ERR) {
(void)close(); // we ignore errors on close
}
(void)open();
print(log_info, "after reopen fd=%d", name().c_str(), _fd);
return _fd != ERR;
}

ssize_t MeterSML::read(std::vector<Reading> &rds, size_t n) {

unsigned char buffer[SML_BUFFER_LEN];
Expand All @@ -208,6 +222,14 @@ ssize_t MeterSML::read(std::vector<Reading> &rds, size_t n) {
sml_get_list_response *body;
sml_list *entry;

if (_fd < 0) {
if (!reopen()) {
// sleep a little bit to prevent busy looping
sleep(1);
return 0;
}
}

if (_pull.size()) {
int wlen = write(_fd,_pull.c_str(),_pull.size());
print(log_debug,"sending pullsequenz send (len:%d is:%d).", name().c_str(), _pull.size(), wlen);
Expand All @@ -216,6 +238,14 @@ ssize_t MeterSML::read(std::vector<Reading> &rds, size_t n) {
/* wait until we receive a new datagram from the meter (blocking read) */
bytes = sml_transport_read(_fd, buffer, SML_BUFFER_LEN);

if (0 == bytes) {
// try to reopen. see issue #362
if (reopen()) {
bytes = sml_transport_read(_fd, buffer, SML_BUFFER_LEN);
print(log_info, "sml_transport_read returned len=%d after reopen", name().c_str(), bytes);
}
}

if (bytes < 16) {
print(log_error, "short message from sml_transport_read len=%d", name().c_str(), bytes);
return(0);
Expand Down

0 comments on commit d60752b

Please sign in to comment.