diff --git a/DPlusAuthenticator.cpp b/DPlusAuthenticator.cpp index 98b03b4..c36bc86 100644 --- a/DPlusAuthenticator.cpp +++ b/DPlusAuthenticator.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2010-2015 by Jonathan Naylor G4KLX - * Copyright (C) 2018 by Thomas A. Early N7TAE + * Copyright (C) 2018-2019 by Thomas A. Early N7TAE * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -29,9 +29,6 @@ #include #include "DPlusAuthenticator.h" -//#include "DStarDefines.h" -//#include "Utils.h" -//#include "Defs.h" CDPlusAuthenticator::CDPlusAuthenticator(const std::string &loginCallsign, const std::string &address) : m_loginCallsign(loginCallsign), @@ -49,48 +46,16 @@ CDPlusAuthenticator::~CDPlusAuthenticator() bool CDPlusAuthenticator::Process(std::map &gwy_map, const bool reflectors, const bool repeaters) // return true if everything went okay { - struct addrinfo hints, *infoptr; - memset(&hints, 0, sizeof(struct addrinfo)); - hints.ai_family = AF_INET; // AF_INET means IPv4 only addresses - hints.ai_socktype = SOCK_STREAM; - - int result = EAI_AGAIN; - int count = 0; - while (EAI_AGAIN==result && 20>count++) { // we'll wait up to 60 seconds for this to work - result = getaddrinfo(m_address.c_str(), NULL, &hints, &infoptr); - if (EAI_AGAIN == result) { - fprintf(stdout, "getaddrinfo not ready: please wait...\n"); - std::this_thread::sleep_for(std::chrono::seconds(3)); - } - } + int result = client.open(m_address, AF_UNSPEC, "20001"); if (result) { - fprintf(stderr, "DPlus Authroization failed: %s\n", gai_strerror(result)); - return false; + fprintf(stderr, "DPlus Authorization failed: %s\n", gai_strerror(result)); + return true; } - - struct addrinfo *p; - char host[256]; - - bool success = false; - - for (p = infoptr; p != NULL && !success; p = p->ai_next) { - getnameinfo(p->ai_addr, p->ai_addrlen, host, sizeof(host), NULL, 0, NI_NUMERICHOST); - printf("Trying %s from %s\n", host, m_address.c_str()); - success = authenticate(m_loginCallsign, std::string(host), gwy_map, reflectors, repeaters); - } - - freeaddrinfo(infoptr); - return success; + return authenticate(m_loginCallsign, gwy_map, reflectors, repeaters); } -bool CDPlusAuthenticator::authenticate(const std::string &callsign, const std::string &hostname, std::map &gwy_map, const bool reflectors, const bool repeaters) +bool CDPlusAuthenticator::authenticate(const std::string &callsign, std::map &gwy_map, const bool reflectors, const bool repeaters) { - CTCPReaderWriterClient socket(hostname, 20001U); - - bool ret = socket.open(); - if (!ret) - return false; - unsigned char* buffer = new unsigned char[4096U]; ::memset(buffer, ' ', 56U); @@ -104,28 +69,30 @@ bool CDPlusAuthenticator::authenticate(const std::string &callsign, const std::s ::memcpy(buffer+28, "W7IB2", 5); ::memcpy(buffer+40, "DHS0257", 7); - ret = socket.write(buffer, 56U); - if (!ret) { - socket.close(); + int ret = client.write(buffer, 56U); + if (ret <= 0) { + fprintf(stderr, "ERROR: could not write opening phrase\n"); + client.close(); delete[] buffer; - return false; + return true; } - ret = read(socket, buffer, 2U); + ret = client.read(buffer, 2U); + size_t sofar = gwy_map.size(); - while (ret) { + while (ret == 2) { unsigned int len = (buffer[1U] & 0x0FU) * 256U + buffer[0U]; // Ensure that we get exactly len - 2U bytes from the TCP stream - ret = read(socket, buffer + 2U, len - 2U); - if (!ret) { - fprintf(stderr, "Short read from %s:20001", hostname.c_str()); - return false; + ret = client.read(buffer + 2U, len - 2U); + if (ret <= 0) { + fprintf(stderr, "Short read\n"); + return true; } if ((buffer[1U] & 0xC0U) != 0xC0U || buffer[2U] != 0x01U) { - fprintf(stderr, "Invalid packet received from %s:20001", hostname.c_str()); - return false; + fprintf(stderr, "Invalid packet received from 20001\n"); + return true; } for (unsigned int i = 8U; (i + 25U) < len; i += 26U) { @@ -148,16 +115,16 @@ bool CDPlusAuthenticator::authenticate(const std::string &callsign, const std::s } } - ret = read(socket, buffer, 2U); + ret = client.read(buffer, 2U); } - printf("Authorized DPlus with %s using callsign %s\n", hostname.c_str(), callsign.c_str()); - printf("Added %d DPlus gateways\n", (int)gwy_map.size()); - socket.close(); + printf("Probably authorized DPlus with %s using callsign %s\n", m_address.c_str(), callsign.c_str()); + printf("Added %lu DPlus gateways\n", gwy_map.size() - sofar); + client.close(); delete[] buffer; - return true; + return false; } void CDPlusAuthenticator::Trim(std::string &s) @@ -171,18 +138,3 @@ void CDPlusAuthenticator::Trim(std::string &s) rit = s.rbegin(); } } - -bool CDPlusAuthenticator::read(CTCPReaderWriterClient &socket, unsigned char *buffer, unsigned int len) const -{ - unsigned int offset = 0U; - - do { - int n = socket.read(buffer + offset, len - offset, 10U); - if (n < 0) - return false; - - offset += n; - } while ((len - offset) > 0U); - - return true; -} diff --git a/DPlusAuthenticator.h b/DPlusAuthenticator.h index c9e712a..7b949fc 100644 --- a/DPlusAuthenticator.h +++ b/DPlusAuthenticator.h @@ -1,7 +1,7 @@ #pragma once /* * Copyright (C) 2010-2013 by Jonathan Naylor G4KLX - * Copyright (C) 2018 by Thomas A. Early N7TAE + * Copyright (C) 2018-2019 by Thomas A. Early N7TAE * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -33,8 +33,8 @@ public: private: std::string m_loginCallsign; std::string m_address; + CTCPReaderWriterClient client; void Trim(std::string &s); - bool authenticate(const std::string &callsign, const std::string &hostname, std::map &gwy_map, const bool reflectors, const bool repeaters); - bool read(CTCPReaderWriterClient &socket, unsigned char *buffer, unsigned int len) const; + bool authenticate(const std::string &callsign, std::map &gwy_map, const bool reflectors, const bool repeaters); }; diff --git a/QnetLink.cpp b/QnetLink.cpp index c074d84..2c9d453 100644 --- a/QnetLink.cpp +++ b/QnetLink.cpp @@ -315,9 +315,9 @@ bool CQnetLink::load_gwys(const std::string &filename) if (dplus_authorize && !dplus_priority) { CDPlusAuthenticator auth(login_call, std::string("auth.dstargateway.org")); if (auth.Process(gwy_list, dplus_reflectors, dplus_repeaters)) - fprintf(stdout, "DPlus Authorization complete.\n"); + fprintf(stdout, "DPlus Authorization failed.\n"); else - fprintf(stderr, "DPlus Authorization failed!\n"); + fprintf(stderr, "DPlus Authorization complete!\n"); } char inbuf[1024]; @@ -411,9 +411,9 @@ bool CQnetLink::load_gwys(const std::string &filename) if (dplus_authorize && dplus_priority) { CDPlusAuthenticator auth(login_call, std::string("auth.dstargateway.org")); if (auth.Process(gwy_list, dplus_reflectors, dplus_repeaters)) - fprintf(stdout, "DPlus Authorization complete.\n"); + fprintf(stdout, "DPlus Authorization failed.\n"); else - fprintf(stderr, "DPlus Authorization failed!\n"); + fprintf(stderr, "DPlus Authorization completed!\n"); } for (auto it=gwy_list.begin(); it!=gwy_list.end(); it++) diff --git a/TCPReaderWriterClient.cpp b/TCPReaderWriterClient.cpp index c26c365..c30ed45 100644 --- a/TCPReaderWriterClient.cpp +++ b/TCPReaderWriterClient.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2010-2013 by Jonathan Naylor G4KLX + * Copyright (C) 2019 by Thomas A. Early N7TAE * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,37 +18,21 @@ */ #include "TCPReaderWriterClient.h" -//#include "UDPReaderWriter.h" #include #include #include #include -CTCPReaderWriterClient::CTCPReaderWriterClient(const std::string &address, unsigned int port, const std::string &localAddress) : +CTCPReaderWriterClient::CTCPReaderWriterClient(const std::string &address, int family, const std::string &port) : m_address(address), +m_family(family), m_port(port), -m_localAddress(localAddress), m_fd(-1) { - assert(address.size()); - assert(port > 0U); } -CTCPReaderWriterClient::CTCPReaderWriterClient(int fd) : -m_address(), -m_port(0U), -m_localAddress(), -m_fd(fd) -{ - assert(fd >= 0); -} - -CTCPReaderWriterClient::CTCPReaderWriterClient() : -m_address(), -m_port(0U), -m_localAddress(), -m_fd(-1) +CTCPReaderWriterClient::CTCPReaderWriterClient() : m_fd(-1) { } @@ -55,104 +40,87 @@ CTCPReaderWriterClient::~CTCPReaderWriterClient() { } -bool CTCPReaderWriterClient::open(const std::string& address, unsigned int port, const std::string& localAddress) +bool CTCPReaderWriterClient::open(const std::string &address, int family, const std::string &port) { - m_address = address; - m_port = port; - m_localAddress = localAddress; + m_address = address; + m_family = family; + m_port = port; return open(); } bool CTCPReaderWriterClient::open() { - if (m_fd != -1) + if (m_fd != -1) { + fprintf(stderr, "ERROR: port for '%s' is already open!\n", m_address.c_str()); return true; - - if (0 == m_address.size() || m_port == 0U) - return false; - - m_fd = ::socket(PF_INET, SOCK_STREAM, 0); - if (m_fd < 0) { - fprintf(stderr, "Cannot create the TCP client socket, err=%d\n", errno); - return false; } - if (m_localAddress.size()) { - sockaddr_in addr; - ::memset(&addr, 0x00, sizeof(struct sockaddr_in)); - addr.sin_family = AF_INET; - addr.sin_port = 0U; - addr.sin_addr.s_addr = ::inet_addr(m_localAddress.c_str()); - if (addr.sin_addr.s_addr == INADDR_NONE) { - fprintf(stderr, "The address is invalid - %s\n", m_localAddress.c_str()); - close(); - return false; - } - - if (::bind(m_fd, (sockaddr*)&addr, sizeof(sockaddr_in)) == -1) { - fprintf(stderr, "Cannot bind the TCP client address, err=%d\n", errno); - close(); - return false; - } + if (0 == m_address.size() || 0 == m_port.size() || 0 == std::stoul(m_port)) { + fprintf(stderr, "ERROR: '%s:%s' is malformed!\n", m_address.c_str(), m_port.c_str()); + return true; } - struct sockaddr_in addr; - ::memset(&addr, 0x00, sizeof(struct sockaddr_in)); - addr.sin_family = AF_INET; - addr.sin_port = htons(m_port); - addr.sin_addr = lookup(m_address); + if (AF_INET!=m_family || AF_INET6!=m_family || AF_UNSPEC!=m_family) { + fprintf(stderr, "ERROR: family must be AF_INET, AF_INET6 or AF_UNSPEC\n"); + return true; + } - if (addr.sin_addr.s_addr == INADDR_NONE) { - close(); - return false; + struct addrinfo hints; + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + //hints.ai_flags = AI_PASSIVE; + hints.ai_protocol = IPPROTO_TCP; + + struct addrinfo *res; + int s = EAI_AGAIN; + int count = 0; + while (EAI_AGAIN==s and count++<20) { + // connecting to a server, so we can wait until it's ready + s = getaddrinfo(m_address.c_str(), m_port.c_str(), &hints, &res); + std::this_thread::sleep_for(std::chrono::seconds(3)); + } + if (s != 0) { + fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s)); + return true; } - if (::connect(m_fd, (sockaddr*)&addr, sizeof(struct sockaddr_in)) == -1) { - fprintf(stderr, "Cannot connect the TCP client socket, err=%d\n", errno); - close(); - return false; + struct addrinfo *rp; + for (rp = res; rp != NULL; rp = rp->ai_next) { + m_fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + if (m_fd == -1) + continue; + + if (connect(m_fd, rp->ai_addr, rp->ai_addrlen)) { + close(); + continue; + } else { + char buf[INET6_ADDRSTRLEN]; + if (inet_ntop(rp->ai_family, rp->ai_addr, buf, INET6_ADDRSTRLEN)) + fprintf(stderr, "Successfully connected %s to %s:%s\n", m_address.c_str(), buf, m_port.c_str()); + break; + } } + freeaddrinfo(res); - int noDelay = 1; - if (::setsockopt(m_fd, IPPROTO_TCP, TCP_NODELAY, (char *)&noDelay, sizeof(noDelay)) == -1) { - fprintf(stderr, "Cannot set the TCP client socket option, err=%d\n", errno); - close(); - return false; + if (rp == NULL) { + fprintf(stderr, "Could not connect to any system returned by %s\n", m_address.c_str()); + m_fd = -1; + return true; } - return true; + return false; } -int CTCPReaderWriterClient::read(unsigned char* buffer, unsigned int length, unsigned int secs, unsigned int msecs) +int CTCPReaderWriterClient::read(unsigned char* buffer, unsigned int length) { assert(buffer != NULL); assert(length > 0U); assert(m_fd != -1); - // Check that the recv() won't block - fd_set readFds; - FD_ZERO(&readFds); - FD_SET(m_fd, &readFds); - - // Return after timeout - timeval tv; - tv.tv_sec = secs; - tv.tv_usec = msecs * 1000; - - int ret = ::select(m_fd + 1, &readFds, NULL, NULL, &tv); - if (ret < 0) { - fprintf(stderr, "Error returned from TCP client select, err=%d\n", errno); - return -1; - } - - if (!FD_ISSET(m_fd, &readFds)) - return 0; - - ssize_t len = ::recv(m_fd, (char*)buffer, length, 0); - if (len == 0) { - return -2; - } else if (len < 0) { + ssize_t len = recv(m_fd, buffer, length, 0); + if (len < 0) { fprintf(stderr, "Error returned from recv, err=%d\n", errno); return -1; } @@ -160,7 +128,7 @@ int CTCPReaderWriterClient::read(unsigned char* buffer, unsigned int length, uns return len; } -int CTCPReaderWriterClient::readLine(std::string& line, unsigned int secs) +int CTCPReaderWriterClient::readLine(std::string& line) { //maybe there is a better way to do this like reading blocks, pushing them for later calls //Nevermind, we'll read one char at a time for the time being. @@ -171,7 +139,7 @@ int CTCPReaderWriterClient::readLine(std::string& line, unsigned int secs) do { - resultCode = read(&c, 1, secs); + resultCode = read(&c, 1); if(resultCode == 1){ line += c; len++; @@ -202,7 +170,6 @@ bool CTCPReaderWriterClient::writeLine(const std::string& line) if(lineCopy.size() > 0 && lineCopy.at(lineCopy.size() - 1) != '\n') lineCopy.append("\n"); - //stupidly write one char after the other size_t len = lineCopy.size(); bool result = true; for(size_t i = 0; i < len && result; i++){ @@ -220,24 +187,3 @@ void CTCPReaderWriterClient::close() m_fd = -1; } } - -in_addr CTCPReaderWriterClient::lookup(const std::string &hostname) -{ - in_addr addr; - in_addr_t address = ::inet_addr(hostname.c_str()); - if (address != in_addr_t(-1)) { - addr.s_addr = address; - return addr; - } - - struct hostent* hp = ::gethostbyname(hostname.c_str()); - if (hp != NULL) { - ::memcpy(&addr, hp->h_addr_list[0], sizeof(struct in_addr)); - return addr; - } - - fprintf(stderr, "Cannot find address for host %s", hostname.c_str()); - - addr.s_addr = INADDR_NONE; - return addr; -} diff --git a/TCPReaderWriterClient.h b/TCPReaderWriterClient.h index 3470010..c603549 100644 --- a/TCPReaderWriterClient.h +++ b/TCPReaderWriterClient.h @@ -3,6 +3,7 @@ /* end of inma once */ /* * Copyright (C) 2010,2011,2012,2013 by Jonathan Naylor G4KLX + * Copyright (C) 2019 by Thomas A. Early N7TAE * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -29,28 +30,29 @@ #include #include #include +#include +#include class CTCPReaderWriterClient { public: - CTCPReaderWriterClient(const std::string &address, unsigned int port, const std::string &localAddress = std::string("")); - CTCPReaderWriterClient(int fd); + CTCPReaderWriterClient(const std::string &address, int family, const std::string &port); CTCPReaderWriterClient(); ~CTCPReaderWriterClient(); - bool open(const std::string &address, unsigned int port, const std::string &localAddress = std::string("")); + bool open(const std::string &address, int family, const std::string &port); bool open(); - int read(unsigned char *buffer, unsigned int length, unsigned int secs, unsigned int msecs = 0U); - int readLine(std::string &line, unsigned int secs); + int read(unsigned char *buffer, unsigned int length); + int readLine(std::string &line); bool write(const unsigned char* buffer, unsigned int length); bool writeLine(const std::string &line); - in_addr lookup(const std::string &hostname); + int GetFD() { return m_fd; } void close(); private: std::string m_address; - unsigned short m_port; - std::string m_localAddress; + int m_family; + std::string m_port; int m_fd; }; diff --git a/aprs.cpp b/aprs.cpp index cc47504..46353c9 100644 --- a/aprs.cpp +++ b/aprs.cpp @@ -123,7 +123,7 @@ void CAPRS::ProcessText(unsigned short streamID, unsigned char seq, unsigned cha (errno == ENETUNREACH) || (errno == EHOSTDOWN) || (errno == ENOTCONN)) { - printf("CAPRS::ProcessText(): APRS_HOST closed connection,error=%d\n",errno); + printf("CAPRS::ProcessText(): APRS_HOST closed connection, error=%d\n",errno); close(aprs_sock); aprs_sock = -1; } else /* if it is WOULDBLOCK, we will not go into a loop here */