intermediate 4.0 branch merge

This commit is contained in:
Matej Sekoranja
2014-10-13 22:32:37 +02:00
12 changed files with 671 additions and 7 deletions

View File

@@ -13,3 +13,8 @@ c17653ce8b54de97d9a1a89ff9fe8604a7901ceb 3.0.2
d720da04d44ae6ed4a9d548717f453a0fbaa9e56 3.0.4
90a0844d7098ae1b06429ae6f931e21f8af6d48f before_merge_changesAfter3_0_2
1d5059b8308b3960ddf750883fa0ed482ca11c34 3.1.0
4ef1b1dbbb6104c24960bff5c650f702e4b494dc 4.0.0
4ef1b1dbbb6104c24960bff5c650f702e4b494dc 4.0.0
ceca448e7c62c23388a0c866c905c7080633a875 4.0.0
ceca448e7c62c23388a0c866c905c7080633a875 4.0.0
cf6fc9696904fd1735523a70a4f59b5ad6a3f2d5 4.0.0

6
TODO
View File

@@ -4,8 +4,8 @@
// should be called without any lock hold
// TODO in Java as in C++ ? reportChannelStateChange();
- searching of channel with server address specified
- improve searching of channel with server address specified
- void transportUnresponsive() { not implemented (also in Java)
- complete authNZ
- improve RPCClient (as it is in Java)
- complete authNZ (callback on right change)
- request event on disconnect/destroy, etc.?

View File

@@ -542,3 +542,4 @@ testApp/utils/testAtomicBoolean.cpp
testApp/utils/testHexDump.cpp
testApp/utils/testInetAddressUtils.cpp
testApp/utils/transportRegistryTest.cpp
pvtoolsSrc/pvlist.cpp

View File

@@ -14,6 +14,10 @@ PROD_HOST += pvinfo
pvinfo_SRCS += pvinfo.cpp
pvinfo_LIBS += pvAccess pvData pvMB Com
PROD_HOST += pvlist
pvlist_SRCS += pvlist.cpp
pvlist_LIBS += pvAccess pvData pvMB Com
PROD_HOST += eget
eget_SRCS += eget.cpp
eget_LIBS += pvAccess pvData pvMB ca Com

522
pvtoolsSrc/pvlist.cpp Normal file
View File

@@ -0,0 +1,522 @@
#include <stdio.h>
#include <iostream>
#include <map>
#include <vector>
#include <string>
#include <istream>
#include <fstream>
#include <sstream>
#include <epicsStdlib.h>
#include <epicsGetopt.h>
#include <pv/logger.h>
#include <epicsExit.h>
#include <osiSock.h>
#include <pv/byteBuffer.h>
#include <pv/serializeHelper.h>
#include <pv/pvaConstants.h>
#include <pv/inetAddressUtil.h>
#include <pv/configuration.h>
#include <pv/remote.h>
using namespace std;
using namespace std::tr1;
using namespace epics::pvData;
using namespace epics::pvAccess;
/// Byte to hexchar mapping.
static const char lookup[] = {
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
/// Get hex representation of byte.
string toHex(int8* ba, size_t len) {
string sb;
for (size_t i = 0; i < len; i++)
{
int8 b = ba[i];
int upper = (b>>4)&0x0F;
sb += lookup[upper];
int lower = b&0x0F;
sb += lookup[lower];
}
return sb;
}
static string emptyString;
std::size_t readSize(ByteBuffer* buffer) {
int8 b = buffer->getByte();
if(b==-1)
return -1;
else if(b==-2) {
int32 s = buffer->getInt();
if(s<0) THROW_BASE_EXCEPTION("negative size");
return s;
}
else
return (std::size_t)(b<0 ? b+256 : b);
}
string deserializeString(ByteBuffer* buffer) {
std::size_t size = /*SerializeHelper::*/readSize(buffer);
if(size!=(size_t)-1) // TODO null strings check, to be removed in the future
{
// entire string is in buffer, simply create a string out of it (copy)
std::size_t pos = buffer->getPosition();
string str(buffer->getArray()+pos, size);
buffer->setPosition(pos+size);
return str;
}
else
return emptyString;
}
struct ServerEntry {
string guid;
string protocol;
vector<osiSockAddr> addresses;
int8 version;
};
typedef map<string, ServerEntry> ServerMap;
static ServerMap serverMap;
void processSearchResponse(osiSockAddr const & responseFrom, ByteBuffer & receiveBuffer)
{
// first byte is PVA_MAGIC
int8 magic = receiveBuffer.getByte();
if(magic != PVA_MAGIC)
return;
// second byte version
int8 version = receiveBuffer.getByte();
// only data for UDP
int8 flags = receiveBuffer.getByte();
if (flags < 0)
{
// 7-bit set
receiveBuffer.setEndianess(EPICS_ENDIAN_BIG);
}
else
{
receiveBuffer.setEndianess(EPICS_ENDIAN_LITTLE);
}
// command ID and paylaod
int8 command = receiveBuffer.getByte();
if (command != (int8)0x04)
return;
size_t payloadSize = receiveBuffer.getInt();
if (payloadSize < (12+4+16+2))
return;
GUID guid;
receiveBuffer.get(guid.value, 0, sizeof(guid.value));
/*int32 searchSequenceId = */receiveBuffer.getInt();
osiSockAddr serverAddress;
serverAddress.ia.sin_family = AF_INET;
// 128-bit IPv6 address
if (!decodeAsIPv6Address(&receiveBuffer, &serverAddress)) return;
// accept given address if explicitly specified by sender
if (serverAddress.ia.sin_addr.s_addr == INADDR_ANY)
serverAddress.ia.sin_addr = responseFrom.ia.sin_addr;
serverAddress.ia.sin_port = htons(receiveBuffer.getShort());
string protocol = /*SerializeHelper::*/deserializeString(&receiveBuffer);
/*bool found =*/ receiveBuffer.getByte(); // != 0;
string guidString = toHex((int8*)guid.value, sizeof(guid.value));
ServerMap::iterator iter = serverMap.find(guidString);
if (iter != serverMap.end())
{
bool found = false;
vector<osiSockAddr>& vec = iter->second.addresses;
for (vector<osiSockAddr>::const_iterator ai = vec.begin();
ai != vec.end();
ai++)
if (sockAddrAreIdentical(&(*ai), &serverAddress))
{
found = true;
break;
}
if (!found)
vec.push_back(serverAddress);
}
else
{
ServerEntry serverEntry;
serverEntry.guid = guidString;
serverEntry.protocol = protocol;
serverEntry.addresses.push_back(serverAddress);
serverEntry.version = version;
serverMap[guidString] = serverEntry;
}
return;
}
bool discoverServers(double timeOut)
{
osiSockAttach();
SOCKET socket = epicsSocketCreate(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (socket == INVALID_SOCKET)
{
char errStr[64];
epicsSocketConvertErrnoToString(errStr, sizeof(errStr));
fprintf(stderr, "Failed to create a socket: %s\n", errStr);
return false;
}
//
// read config
//
Configuration::shared_pointer configuration(new SystemConfigurationImpl());
string addressList = configuration->getPropertyAsString("EPICS_PVA_ADDR_LIST", "");
bool autoAddressList = configuration->getPropertyAsBoolean("EPICS_PVA_AUTO_ADDR_LIST", true);
int broadcastPort = configuration->getPropertyAsInteger("EPICS_PVA_BROADCAST_PORT", PVA_BROADCAST_PORT);
// quary broadcast addresses of all IFs
auto_ptr<InetAddrVector> broadcastAddresses(getBroadcastAddresses(socket, broadcastPort));
// set broadcast address list
if (!addressList.empty())
{
// if auto is true, add it to specified list
InetAddrVector* appendList = 0;
if (autoAddressList)
appendList = broadcastAddresses.get();
auto_ptr<InetAddrVector> list(getSocketAddressList(addressList, broadcastPort, appendList));
if (list.get() && list->size()) {
// delete old list and take ownership of a new one
broadcastAddresses = list;
}
}
for (size_t i = 0; broadcastAddresses.get() && i < broadcastAddresses->size(); i++)
LOG(logLevelDebug,
"Broadcast address #%d: %s.", i, inetAddressToString((*broadcastAddresses)[i]).c_str());
// ---
int optval = 1;
int status = ::setsockopt(socket, SOL_SOCKET, SO_BROADCAST, (char *)&optval, sizeof(optval));
if (status)
{
char errStr[64];
epicsSocketConvertErrnoToString(errStr, sizeof(errStr));
fprintf(stderr, "Error setting SO_BROADCAST: %s\n", errStr);
epicsSocketDestroy (socket);
return false;
}
osiSockAddr bindAddr;
bindAddr.ia.sin_family = AF_INET;
bindAddr.ia.sin_port = htons(0);
bindAddr.ia.sin_addr.s_addr = htonl(INADDR_ANY);
status = ::bind(socket, (sockaddr*)&(bindAddr.sa), sizeof(sockaddr));
if (status)
{
char errStr[64];
epicsSocketConvertErrnoToString(errStr, sizeof(errStr));
fprintf(stderr, "Failed to bind: %s\n", errStr);
epicsSocketDestroy(socket);
return false;
}
osiSockAddr responseAddress;
osiSocklen_t sockLen = sizeof(sockaddr);
// read the actual socket info
status = ::getsockname(socket, &responseAddress.sa, &sockLen);
if (status) {
char errStr[64];
epicsSocketConvertErrnoToString(errStr, sizeof(errStr));
fprintf(stderr, "Failed to get local socket address: %s.", errStr);
return false;
}
char buffer[1024];
ByteBuffer sendBuffer(buffer, sizeof(buffer)/sizeof(char));
sendBuffer.putByte(PVA_MAGIC);
sendBuffer.putByte(PVA_VERSION);
sendBuffer.putByte((EPICS_BYTE_ORDER == EPICS_ENDIAN_BIG) ? 0x80 : 0x00); // data + 7-bit endianess
sendBuffer.putByte((int8_t)3); // search
sendBuffer.putInt(4+1+3+16+2+1); // "zero" payload
sendBuffer.putInt(0); // sequenceId
sendBuffer.putByte((int8_t)0x81); // reply required // TODO unicast vs multicast; for now we mark ourselves as unicast
sendBuffer.putByte((int8_t)0); // reserved
sendBuffer.putShort((int16_t)0); // reserved
// NOTE: is it possible (very likely) that address is any local address ::ffff:0.0.0.0
encodeAsIPv6Address(&sendBuffer, &responseAddress);
sendBuffer.putShort((int16_t)ntohs(responseAddress.ia.sin_port));
sendBuffer.putByte((int8_t)0x00); // no restriction on protocol
sendBuffer.putShort((int16_t)0); // count
bool oneOK = false;
for (size_t i = 0; i < broadcastAddresses->size(); i++)
{
// send the packet
status = ::sendto(socket, sendBuffer.getArray(), sendBuffer.getPosition(), 0,
&((*broadcastAddresses)[i].sa), sizeof(sockaddr));
if (status < 0)
{
char errStr[64];
epicsSocketConvertErrnoToString(errStr, sizeof(errStr));
fprintf(stderr, "Send error: %s\n", errStr);
}
else
oneOK = true;
}
if (!oneOK)
return false;
// set timeout in case message is not sent
struct timeval timeout;
memset(&timeout, 0, sizeof(struct timeval));
timeout.tv_sec = 1;
timeout.tv_usec = 0;
status = ::setsockopt (socket, SOL_SOCKET, SO_RCVTIMEO,
(char*)&timeout, sizeof(timeout));
if (status)
{
char errStr[64];
epicsSocketConvertErrnoToString(errStr, sizeof(errStr));
fprintf(stderr, "Error setting SO_RCVTIMEO: %s\n", errStr);
return false;
}
char rxbuff[1024];
ByteBuffer receiveBuffer(rxbuff, sizeof(rxbuff)/sizeof(char));
osiSockAddr fromAddress;
osiSocklen_t addrStructSize = sizeof(sockaddr);
while (true)
{
receiveBuffer.clear();
// receive packet from socket
int bytesRead = ::recvfrom(socket, (char*)receiveBuffer.getArray(),
receiveBuffer.getRemaining(), 0,
(sockaddr*)&fromAddress, &addrStructSize);
if (bytesRead > 0)
{
receiveBuffer.setPosition(bytesRead);
receiveBuffer.flip();
processSearchResponse(fromAddress, receiveBuffer);
}
else if (status <= 0)
{
if (status == -1)
{
int socketError = SOCKERRNO;
// interrupted or timeout
if (socketError == SOCK_EINTR ||
socketError == EAGAIN || // no alias in libCom
// windows times out with this
//socketError == SOCK_ETIMEDOUT ||
socketError == SOCK_EWOULDBLOCK)
continue;
if (socketError == SOCK_ECONNREFUSED || // avoid spurious ECONNREFUSED in Linux
socketError == SOCK_ECONNRESET) // or ECONNRESET in Windows
continue;
char errStr[64];
epicsSocketConvertErrnoToString(errStr, sizeof(errStr));
fprintf(stderr, "Socket recv error: %s\n", errStr);
}
break;
}
}
for (ServerMap::const_iterator iter = serverMap.begin();
iter != serverMap.end();
iter++)
{
const ServerEntry& entry = iter->second;
cout << "GUID 0x" << entry.guid << ", version " << entry.version << ": "
<< entry.protocol << "@[";
size_t count = entry.addresses.size();
for (size_t i = 0; i < count; i++)
{
cout << inetAddressToString(entry.addresses[i]);
if (i < (count-1))
cout << ", ";
}
cout << ']' << endl;
}
// TODO shutdown sockets?
// TODO this resouce is not released on failure
epicsSocketDestroy(socket);
return true;
}
#define DEFAULT_TIMEOUT 3.0
void usage (void)
{
fprintf (stderr, "\nUsage: pvlist [options] <names>...\n\n"
" -h: Help: Print this message\n"
"options:\n"
" -w <sec>: Wait time, specifies timeout, default is %f second(s)\n"
" -q: Quiet mode, print only error messages\n"
" -d: Enable debug output\n"
" -F <ofs>: Use <ofs> as an alternate output field separator\n"
// " -f <input file>: Use <input file> as an input that provides a list input parameters(s) to be read, use '-' for stdin\n"
"\nexample: pvinfo ...\n\n"
, DEFAULT_TIMEOUT);
}
/*+**************************************************************************
*
* Function: main
*
* Description: pvlist main()
* Evaluate command line options, ...
*
* Arg(s) In: [options] [<server>]...
*
* Arg(s) Out: none
*
* Return(s): Standard return code (0=success, 1=error)
*
**************************************************************************-*/
int main (int argc, char *argv[])
{
int opt; /* getopt() current option */
bool debug = false;
bool quiet = false;
double timeOut = DEFAULT_TIMEOUT;
// char fieldSeparator = ' ';
/*
istream* inputStream = 0;
ifstream ifs;
bool fromStream = false;
*/
setvbuf(stdout,NULL,_IOLBF,BUFSIZ); /* Set stdout to line buffering */
while ((opt = getopt(argc, argv, ":hw:qdF:f:")) != -1) {
switch (opt) {
case 'h': /* Print usage */
usage();
return 0;
case 'w': /* Set PVA timeout value */
if(epicsScanDouble(optarg, &timeOut) != 1 || timeOut <= 0.0)
{
fprintf(stderr, "'%s' is not a valid timeout value "
"- ignored. ('pvlist -h' for help.)\n", optarg);
timeOut = DEFAULT_TIMEOUT;
}
break;
case 'q': /* Quiet mode */
quiet = true;
break;
case 'd': /* Debug log level */
debug = true;
break;
/*
case 'F': // Store this for output formatting
fieldSeparator = (char) *optarg;
break;
case 'f': // Use input stream as input
{
string fileName = optarg;
if (fileName == "-")
inputStream = &cin;
else
{
ifs.open(fileName.c_str(), ifstream::in);
if (!ifs)
{
fprintf(stderr,
"Failed to open file '%s'.\n",
fileName.c_str());
return 1;
}
else
inputStream = &ifs;
}
fromStream = true;
break;
}*/
case '?':
fprintf(stderr,
"Unrecognized option: '-%c'. ('pvlist -h' for help.)\n",
optopt);
return 1;
case ':':
fprintf(stderr,
"Option '-%c' requires an argument. ('pvlist -h' for help.)\n",
optopt);
return 1;
default :
usage();
return 1;
}
}
SET_LOG_LEVEL(debug ? logLevelDebug : logLevelError);
if (!quiet)
fprintf(stderr, "Searching...\n");
discoverServers(timeOut);
if (!quiet)
fprintf(stderr, "done.\n");
return 0;
}

View File

@@ -86,6 +86,12 @@ std::ostream& terse(std::ostream& o, PVField::shared_pointer const & pv)
case structureArray:
return terseStructureArray(o, static_pointer_cast<PVStructureArray>(pv));
break;
case union_:
return terseUnion(o, static_pointer_cast<PVUnion>(pv));
break;
case unionArray:
return terseUnionArray(o, static_pointer_cast<PVUnionArray>(pv));
break;
default:
std::ostringstream msg("unknown Field type: ");
msg << type;
@@ -95,6 +101,12 @@ std::ostream& terse(std::ostream& o, PVField::shared_pointer const & pv)
std::ostream& terseStructure(std::ostream& o, PVStructure::shared_pointer const & pvStructure)
{
if (!pvStructure)
{
o << "(null)";
return o;
}
PVFieldPtrArray fieldsData = pvStructure->getPVFields();
size_t length = pvStructure->getStructure()->getNumberFields();
bool first = true;
@@ -109,6 +121,17 @@ std::ostream& terseStructure(std::ostream& o, PVStructure::shared_pointer const
return o;
}
std::ostream& terseUnion(std::ostream& o, PVUnion::shared_pointer const & pvUnion)
{
if (!pvUnion || !pvUnion->get())
{
o << "(null)";
return o;
}
return terse(o, pvUnion->get());
}
std::ostream& terseScalarArray(std::ostream& o, PVScalarArray::shared_pointer const & pvArray)
{
size_t length = pvArray->getLength();
@@ -166,6 +189,31 @@ std::ostream& terseStructureArray(std::ostream& o, PVStructureArray::shared_poin
return o;
}
std::ostream& terseUnionArray(std::ostream& o, PVUnionArray::shared_pointer const & pvArray)
{
size_t length = pvArray->getLength();
if (arrayCountFlag)
{
if (length<=0)
{
o << '0';
return o;
}
o << length << separator;
}
PVUnionArray::const_svector data = pvArray->view();
bool first = true;
for (size_t i = 0; i < length; i++) {
if (first)
first = false;
else
o << separator;
terseUnion(o, data[i]);
}
return o;
}

View File

@@ -10,9 +10,11 @@ void convertStructureArray(std::string*, epics::pvData::PVStructureArray * pvdat
void terseSeparator(char c);
void terseArrayCount(bool flag);
std::ostream& terse(std::ostream& o, epics::pvData::PVField::shared_pointer const & pv);
std::ostream& terseUnion(std::ostream& o, epics::pvData::PVUnion::shared_pointer const & pvUnion);
std::ostream& terseStructure(std::ostream& o, epics::pvData::PVStructure::shared_pointer const & pvStructure);
std::ostream& terseScalarArray(std::ostream& o, epics::pvData::PVScalarArray::shared_pointer const & pvArray);
std::ostream& terseStructureArray(std::ostream& o, epics::pvData::PVStructureArray::shared_pointer const & pvArray);
std::ostream& terseUnionArray(std::ostream& o, epics::pvData::PVUnionArray::shared_pointer const & pvArray);
/* Converts a hex character to its integer value */

View File

@@ -54,7 +54,7 @@ bool Version::isDevelopmentVersion() const {
const string Version::getVersionString() const {
stringstream ret;
ret<<getProductName()<<" v"<<getMajorVersion()<<"."<<getMinorVersion()<<'.'<<getMaintenanceVersion();
ret<<getProductName()<<" v"<<getMajorVersion()<<'.'<<getMinorVersion()<<'.'<<getMaintenanceVersion();
if (isDevelopmentVersion())
ret<<"-SNAPSHOT";

View File

@@ -4,6 +4,12 @@
* in file LICENSE that is included with this distribution.
*/
#ifdef __vxworks
#include <taskLib.h>
#endif
#include <sstream>
#include <pv/responseHandlers.h>
#include <pv/remote.h>
#include <pv/hexDump.h>
@@ -13,6 +19,7 @@
#include <pv/byteBuffer.h>
#include <osiSock.h>
#include <osiProcess.h>
#include <pv/logger.h>
#include <sstream>
@@ -454,6 +461,7 @@ private:
static Structure::const_shared_pointer helpStructure;
static Structure::const_shared_pointer channelListStructure;
static Structure::const_shared_pointer infoStructure;
static std::string helpString;
@@ -511,6 +519,44 @@ public:
PVStringArray::shared_pointer pvArray = result->getSubField<PVStringArray>("value");
pvArray->replace(listListener->channelNames);
return result;
}
else if (op == "info")
{
PVStructure::shared_pointer result =
getPVDataCreate()->createPVStructure(infoStructure);
// TODO cache hostname in InetAddressUtil
char buffer[256];
std::string hostName("localhost");
if (gethostname(buffer, sizeof(buffer)) == 0)
hostName = buffer;
std::stringstream ret;
ret << EPICS_PVA_MAJOR_VERSION << '.' <<
EPICS_PVA_MINOR_VERSION << '.' <<
EPICS_PVA_MAINTENANCE_VERSION;
if (EPICS_PVA_DEVELOPMENT_FLAG)
ret << "-SNAPSHOT";
result->getSubField<PVString>("version")->put(ret.str());
result->getSubField<PVString>("implLang")->put("cpp");
result->getSubField<PVString>("host")->put(hostName);
std::stringstream sspid;
#ifdef __vxworks
sspid << taskIdSelf();
#else
sspid << getpid();
#endif
result->getSubField<PVString>("process")->put(sspid.str());
char timeText[64];
epicsTimeToStrftime(timeText, 64, "%Y-%m-%dT%H:%M:%S.%03f", &m_serverContext->getStartTime());
result->getSubField<PVString>("startTime")->put(timeText);
return result;
}
else
@@ -531,14 +577,28 @@ Structure::const_shared_pointer ServerRPCService::channelListStructure =
addArray("value", pvString)->
createStructure();
Structure::const_shared_pointer ServerRPCService::infoStructure =
getFieldCreate()->createFieldBuilder()->
add("process", pvString)->
add("startTime", pvString)->
add("version", pvString)->
add("implLang", pvString)->
add("host", pvString)->
// add("os", pvString)->
// add("arch", pvString)->
// add("CPUs", pvInt)->
createStructure();
std::string ServerRPCService::helpString =
"pvAccess server RPC service.\n"
"arguments:\n"
"\tstring op\toperation to execute\n"
"\n"
"\toperations:\n"
"\t\tinfo\t\treturns some information about the server\n"
"\t\tchannels\treturns a list of 'static' channels the server can provide\n"
"\t\t\t (no arguments)\n"
// "\t\t\t (no arguments)\n"
"\n";
std::string ServerCreateChannelHandler::SERVER_CHANNEL_NAME = "server";

View File

@@ -40,9 +40,12 @@ ServerContextImpl::ServerContextImpl():
_channelProviderRegistry(),
_channelProviderNames(PVACCESS_DEFAULT_PROVIDER),
_channelProviders(),
_beaconServerStatusProvider()
_beaconServerStatusProvider(),
_startTime()
{
epicsTimeGetCurrent(&_startTime);
// TODO maybe there is a better place for this (when there will be some factory)
epicsSignalInstallSigAlarmIgnore ();
epicsSignalInstallSigPipeIgnore ();
@@ -674,6 +677,12 @@ void ServerContextImpl::newServerDetected()
// not used
}
epicsTimeStamp& ServerContextImpl::getStartTime()
{
return _startTime;
}
std::map<std::string, std::tr1::shared_ptr<SecurityPlugin> >& ServerContextImpl::getSecurityPlugins()
{
return SecurityPluginRegistry::instance().getServerSecurityPlugins();

View File

@@ -92,6 +92,8 @@ public:
*/
virtual void dispose() = 0;
virtual epicsTimeStamp& getStartTime() = 0;
// ************************************************************************** //
// **************************** [ Plugins ] ********************************* //
// ************************************************************************** //
@@ -146,6 +148,9 @@ public:
BlockingUDPTransport::shared_pointer getLocalMulticastTransport();
epicsTimeStamp& getStartTime();
/**
* Version.
*/
@@ -440,6 +445,9 @@ private:
void destroyAllTransports();
Configuration::shared_pointer configuration;
epicsTimeStamp _startTime;
};
epicsShareExtern ServerContext::shared_pointer startPVAServer(

View File

@@ -70,7 +70,9 @@ bool decodeAsIPv6Address(ByteBuffer* buffer, osiSockAddr* address) {
// first 80-bit are 0
if (buffer->getLong() != 0) return false;
if (buffer->getShort() != 0) return false;
if (buffer->getShort() != (int16)0xFFFF) return false;
int16 ffff = buffer->getShort();
// allow all zeros address
//if (ffff != (int16)0xFFFF) return false;
uint32_t ipv4Addr =
((uint32_t)(buffer->getByte()&0xFF))<<24 |
@@ -78,6 +80,9 @@ bool decodeAsIPv6Address(ByteBuffer* buffer, osiSockAddr* address) {
((uint32_t)(buffer->getByte()&0xFF))<<8 |
((uint32_t)(buffer->getByte()&0xFF));
if (ffff != (int16)0xFFFF && ipv4Addr != (uint32_t)0)
return false;
address->ia.sin_addr.s_addr = htonl(ipv4Addr);
return true;