summaryrefslogtreecommitdiff
path: root/cpp/src/qpid/sys/posix
diff options
context:
space:
mode:
authorKim van der Riet <kpvdr@apache.org>2013-02-28 16:14:30 +0000
committerKim van der Riet <kpvdr@apache.org>2013-02-28 16:14:30 +0000
commit9c73ef7a5ac10acd6a50d5d52bd721fc2faa5919 (patch)
tree2a890e1df09e5b896a9b4168a7b22648f559a1f2 /cpp/src/qpid/sys/posix
parent172d9b2a16cfb817bbe632d050acba7e31401cd2 (diff)
downloadqpid-python-asyncstore.tar.gz
Update from trunk r1375509 through r1450773asyncstore
git-svn-id: https://svn.apache.org/repos/asf/qpid/branches/asyncstore@1451244 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'cpp/src/qpid/sys/posix')
-rw-r--r--cpp/src/qpid/sys/posix/AsynchIO.cpp67
-rw-r--r--cpp/src/qpid/sys/posix/BSDSocket.cpp (renamed from cpp/src/qpid/sys/posix/Socket.cpp)127
-rw-r--r--cpp/src/qpid/sys/posix/BSDSocket.h113
-rwxr-xr-xcpp/src/qpid/sys/posix/FileSysDir.cpp26
-rw-r--r--cpp/src/qpid/sys/posix/IOHandle.cpp15
-rw-r--r--cpp/src/qpid/sys/posix/PollableCondition.cpp7
-rw-r--r--cpp/src/qpid/sys/posix/PosixPoller.cpp8
-rw-r--r--cpp/src/qpid/sys/posix/SocketAddress.cpp5
-rwxr-xr-xcpp/src/qpid/sys/posix/SystemInfo.cpp133
9 files changed, 310 insertions, 191 deletions
diff --git a/cpp/src/qpid/sys/posix/AsynchIO.cpp b/cpp/src/qpid/sys/posix/AsynchIO.cpp
index 31355627cd..353a55f50c 100644
--- a/cpp/src/qpid/sys/posix/AsynchIO.cpp
+++ b/cpp/src/qpid/sys/posix/AsynchIO.cpp
@@ -143,6 +143,7 @@ class AsynchConnector : public qpid::sys::AsynchConnector,
private:
void connComplete(DispatchHandle& handle);
+ void requestedCall(RequestCallback rCb);
private:
ConnectedCallback connCallback;
@@ -158,6 +159,7 @@ public:
FailedCallback failCb);
void start(Poller::shared_ptr poller);
void stop();
+ void requestCallback(RequestCallback rCb);
};
AsynchConnector::AsynchConnector(const Socket& s,
@@ -191,11 +193,30 @@ void AsynchConnector::stop()
stopWatch();
}
+void AsynchConnector::requestCallback(RequestCallback callback) {
+ // TODO creating a function object every time isn't all that
+ // efficient - if this becomes heavily used do something better (what?)
+ assert(callback);
+ DispatchHandle::call(boost::bind(&AsynchConnector::requestedCall, this, callback));
+}
+
+void AsynchConnector::requestedCall(RequestCallback callback) {
+ assert(callback);
+ callback(*this);
+}
+
void AsynchConnector::connComplete(DispatchHandle& h)
{
int errCode = socket.getError();
if (errCode == 0) {
h.stopWatch();
+ try {
+ socket.finishConnect(sa);
+ } catch (const std::exception& e) {
+ failCallback(socket, 0, e.what());
+ DispatchHandle::doDelete();
+ return;
+ }
connCallback(socket);
} else {
// Retry while we cause an immediate exception
@@ -247,10 +268,9 @@ public:
virtual void notifyPendingWrite();
virtual void queueWriteClose();
virtual bool writeQueueEmpty();
- virtual void startReading();
- virtual void stopReading();
virtual void requestCallback(RequestCallback);
virtual BufferBase* getQueuedBuffer();
+ virtual SecuritySettings getSecuritySettings();
private:
~AsynchIO();
@@ -282,13 +302,6 @@ private:
* thread processing this handle.
*/
volatile bool writePending;
- /**
- * This records whether we've been reading is flow controlled:
- * it's safe as a simple boolean as the only way to be stopped
- * is in calls only allowed in the callback context, the only calls
- * checking it are also in calls only allowed in callback context.
- */
- volatile bool readingStopped;
};
AsynchIO::AsynchIO(const Socket& s,
@@ -307,8 +320,7 @@ AsynchIO::AsynchIO(const Socket& s,
idleCallback(iCb),
socket(s),
queuedClose(false),
- writePending(false),
- readingStopped(false) {
+ writePending(false) {
s.setNonblocking();
}
@@ -344,7 +356,7 @@ void AsynchIO::queueReadBuffer(BufferBase* buff) {
bool queueWasEmpty = bufferQueue.empty();
bufferQueue.push_back(buff);
- if (queueWasEmpty && !readingStopped)
+ if (queueWasEmpty)
DispatchHandle::rewatchRead();
}
@@ -354,7 +366,7 @@ void AsynchIO::unread(BufferBase* buff) {
bool queueWasEmpty = bufferQueue.empty();
bufferQueue.push_front(buff);
- if (queueWasEmpty && !readingStopped)
+ if (queueWasEmpty)
DispatchHandle::rewatchRead();
}
@@ -386,17 +398,6 @@ bool AsynchIO::writeQueueEmpty() {
return writeQueue.empty();
}
-// This can happen outside the callback context
-void AsynchIO::startReading() {
- readingStopped = false;
- DispatchHandle::rewatchRead();
-}
-
-void AsynchIO::stopReading() {
- readingStopped = true;
- DispatchHandle::unwatchRead();
-}
-
void AsynchIO::requestCallback(RequestCallback callback) {
// TODO creating a function object every time isn't all that
// efficient - if this becomes heavily used do something better (what?)
@@ -429,11 +430,6 @@ AsynchIO::BufferBase* AsynchIO::getQueuedBuffer() {
* to put it in and reading is not stopped by flow control.
*/
void AsynchIO::readable(DispatchHandle& h) {
- if (readingStopped) {
- // We have been flow controlled.
- QPID_PROBE1(asynchio_read_flowcontrolled, &h);
- return;
- }
AbsTime readStartTime = AbsTime::now();
size_t total = 0;
int readCalls = 0;
@@ -455,12 +451,6 @@ void AsynchIO::readable(DispatchHandle& h) {
total += rc;
readCallback(*this, buff);
- if (readingStopped) {
- // We have been flow controlled.
- QPID_PROBE4(asynchio_read_finished_flowcontrolled, &h, duration, total, readCalls);
- break;
- }
-
if (rc != readCount) {
// If we didn't fill the read buffer then time to stop reading
QPID_PROBE4(asynchio_read_finished_done, &h, duration, total, readCalls);
@@ -626,6 +616,13 @@ void AsynchIO::close(DispatchHandle& h) {
}
}
+SecuritySettings AsynchIO::getSecuritySettings() {
+ SecuritySettings settings;
+ settings.ssf = socket.getKeyLen();
+ settings.authid = socket.getClientAuthId();
+ return settings;
+}
+
} // namespace posix
AsynchAcceptor* AsynchAcceptor::create(const Socket& s,
diff --git a/cpp/src/qpid/sys/posix/Socket.cpp b/cpp/src/qpid/sys/posix/BSDSocket.cpp
index 77ae1af60c..7c31b13ae9 100644
--- a/cpp/src/qpid/sys/posix/Socket.cpp
+++ b/cpp/src/qpid/sys/posix/BSDSocket.cpp
@@ -19,7 +19,7 @@
*
*/
-#include "qpid/sys/Socket.h"
+#include "qpid/sys/posix/BSDSocket.h"
#include "qpid/sys/SocketAddress.h"
#include "qpid/sys/posix/check.h"
@@ -67,25 +67,41 @@ uint16_t getLocalPort(int fd)
}
}
-Socket::Socket() :
- IOHandle(new IOHandlePrivate),
+BSDSocket::BSDSocket() :
+ fd(-1),
+ handle(new IOHandle),
nonblocking(false),
nodelay(false)
{}
-Socket::Socket(IOHandlePrivate* h) :
- IOHandle(h),
+Socket* createSocket()
+{
+ return new BSDSocket;
+}
+
+BSDSocket::BSDSocket(int fd0) :
+ fd(fd0),
+ handle(new IOHandle(fd)),
nonblocking(false),
nodelay(false)
{}
-void Socket::createSocket(const SocketAddress& sa) const
+BSDSocket::~BSDSocket()
+{}
+
+BSDSocket::operator const IOHandle&() const
+{
+ return *handle;
+}
+
+void BSDSocket::createSocket(const SocketAddress& sa) const
{
- int& socket = impl->fd;
- if (socket != -1) Socket::close();
+ int& socket = fd;
+ if (socket != -1) BSDSocket::close();
int s = ::socket(getAddrInfo(sa).ai_family, getAddrInfo(sa).ai_socktype, 0);
if (s < 0) throw QPID_POSIX_ERROR(errno);
socket = s;
+ *handle = IOHandle(s);
try {
if (nonblocking) setNonblocking();
@@ -98,50 +114,31 @@ void Socket::createSocket(const SocketAddress& sa) const
} catch (std::exception&) {
::close(s);
socket = -1;
+ *handle = IOHandle();
throw;
}
}
-Socket* Socket::createSameTypeSocket() const {
- int& socket = impl->fd;
- // Socket currently has no actual socket attached
- if (socket == -1)
- return new Socket;
-
- ::sockaddr_storage sa;
- ::socklen_t salen = sizeof(sa);
- QPID_POSIX_CHECK(::getsockname(socket, (::sockaddr*)&sa, &salen));
- int s = ::socket(sa.ss_family, SOCK_STREAM, 0); // Currently only work with SOCK_STREAM
- if (s < 0) throw QPID_POSIX_ERROR(errno);
- return new Socket(new IOHandlePrivate(s));
-}
-
-void Socket::setNonblocking() const {
- int& socket = impl->fd;
+void BSDSocket::setNonblocking() const {
+ int& socket = fd;
nonblocking = true;
if (socket != -1) {
QPID_POSIX_CHECK(::fcntl(socket, F_SETFL, O_NONBLOCK));
}
}
-void Socket::setTcpNoDelay() const
+void BSDSocket::setTcpNoDelay() const
{
- int& socket = impl->fd;
+ int& socket = fd;
nodelay = true;
if (socket != -1) {
int flag = 1;
- int result = ::setsockopt(impl->fd, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(flag));
+ int result = ::setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(flag));
QPID_POSIX_CHECK(result);
}
}
-void Socket::connect(const std::string& host, const std::string& port) const
-{
- SocketAddress sa(host, port);
- connect(sa);
-}
-
-void Socket::connect(const SocketAddress& addr) const
+void BSDSocket::connect(const SocketAddress& addr) const
{
// The display name for an outbound connection needs to be the name that was specified
// for the address rather than a resolved IP address as we don't know which of
@@ -154,7 +151,7 @@ void Socket::connect(const SocketAddress& addr) const
createSocket(addr);
- const int& socket = impl->fd;
+ const int& socket = fd;
// TODO the correct thing to do here is loop on failure until you've used all the returned addresses
if ((::connect(socket, getAddrInfo(addr).ai_addr, getAddrInfo(addr).ai_addrlen) < 0) &&
(errno != EINPROGRESS)) {
@@ -165,11 +162,6 @@ void Socket::connect(const SocketAddress& addr) const
// remote port (which is unoccupied) as the port to bind the local
// end of the socket, resulting in a "circular" connection.
//
- // This seems like something the OS should prevent but I have
- // confirmed that sporadic hangs in
- // cluster_tests.LongTests.test_failover on RHEL5 are caused by
- // such a circular connection.
- //
// Raise an error if we see such a connection, since we know there is
// no listener on the peer address.
//
@@ -179,26 +171,25 @@ void Socket::connect(const SocketAddress& addr) const
}
}
+void BSDSocket::finishConnect(const SocketAddress&) const
+{
+}
+
void
-Socket::close() const
+BSDSocket::close() const
{
- int& socket = impl->fd;
+ int& socket = fd;
if (socket == -1) return;
if (::close(socket) < 0) throw QPID_POSIX_ERROR(errno);
socket = -1;
+ *handle = IOHandle();
}
-int Socket::listen(const std::string& host, const std::string& port, int backlog) const
-{
- SocketAddress sa(host, port);
- return listen(sa, backlog);
-}
-
-int Socket::listen(const SocketAddress& sa, int backlog) const
+int BSDSocket::listen(const SocketAddress& sa, int backlog) const
{
createSocket(sa);
- const int& socket = impl->fd;
+ const int& socket = fd;
int yes=1;
QPID_POSIX_CHECK(::setsockopt(socket,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(yes)));
@@ -210,11 +201,11 @@ int Socket::listen(const SocketAddress& sa, int backlog) const
return getLocalPort(socket);
}
-Socket* Socket::accept() const
+Socket* BSDSocket::accept() const
{
- int afd = ::accept(impl->fd, 0, 0);
+ int afd = ::accept(fd, 0, 0);
if ( afd >= 0) {
- Socket* s = new Socket(new IOHandlePrivate(afd));
+ BSDSocket* s = new BSDSocket(afd);
s->localname = localname;
return s;
}
@@ -223,41 +214,51 @@ Socket* Socket::accept() const
else throw QPID_POSIX_ERROR(errno);
}
-int Socket::read(void *buf, size_t count) const
+int BSDSocket::read(void *buf, size_t count) const
{
- return ::read(impl->fd, buf, count);
+ return ::read(fd, buf, count);
}
-int Socket::write(const void *buf, size_t count) const
+int BSDSocket::write(const void *buf, size_t count) const
{
- return ::write(impl->fd, buf, count);
+ return ::write(fd, buf, count);
}
-std::string Socket::getPeerAddress() const
+std::string BSDSocket::getPeerAddress() const
{
if (peername.empty()) {
- peername = getName(impl->fd, false);
+ peername = getName(fd, false);
}
return peername;
}
-std::string Socket::getLocalAddress() const
+std::string BSDSocket::getLocalAddress() const
{
if (localname.empty()) {
- localname = getName(impl->fd, true);
+ localname = getName(fd, true);
}
return localname;
}
-int Socket::getError() const
+int BSDSocket::getError() const
{
int result;
socklen_t rSize = sizeof (result);
- if (::getsockopt(impl->fd, SOL_SOCKET, SO_ERROR, &result, &rSize) < 0)
+ if (::getsockopt(fd, SOL_SOCKET, SO_ERROR, &result, &rSize) < 0)
throw QPID_POSIX_ERROR(errno);
return result;
}
+int BSDSocket::getKeyLen() const
+{
+ return 0;
+}
+
+std::string BSDSocket::getClientAuthId() const
+{
+ return std::string();
+}
+
}} // namespace qpid::sys
diff --git a/cpp/src/qpid/sys/posix/BSDSocket.h b/cpp/src/qpid/sys/posix/BSDSocket.h
new file mode 100644
index 0000000000..862d36c1b9
--- /dev/null
+++ b/cpp/src/qpid/sys/posix/BSDSocket.h
@@ -0,0 +1,113 @@
+#ifndef QPID_SYS_BSDSOCKET_H
+#define QPID_SYS_BSDSOCKET_H
+
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "qpid/sys/Socket.h"
+#include "qpid/sys/IntegerTypes.h"
+#include "qpid/CommonImportExport.h"
+#include <string>
+
+#include <boost/scoped_ptr.hpp>
+
+namespace qpid {
+namespace sys {
+
+class Duration;
+class IOHandle;
+class SocketAddress;
+
+namespace ssl {
+class SslMuxSocket;
+}
+
+class QPID_COMMON_CLASS_EXTERN BSDSocket : public Socket
+{
+public:
+ /** Create a socket wrapper for descriptor. */
+ QPID_COMMON_EXTERN BSDSocket();
+ QPID_COMMON_EXTERN ~BSDSocket();
+
+ QPID_COMMON_EXTERN operator const IOHandle&() const;
+
+ /** Set socket non blocking */
+ QPID_COMMON_EXTERN virtual void setNonblocking() const;
+
+ QPID_COMMON_EXTERN virtual void setTcpNoDelay() const;
+
+ QPID_COMMON_EXTERN virtual void connect(const SocketAddress&) const;
+ QPID_COMMON_EXTERN virtual void finishConnect(const SocketAddress&) const;
+
+ QPID_COMMON_EXTERN virtual void close() const;
+
+ /** Bind to a port and start listening.
+ *@return The bound port number
+ */
+ QPID_COMMON_EXTERN virtual int listen(const SocketAddress&, int backlog = 10) const;
+
+ /**
+ * Returns an address (host and port) for the remote end of the
+ * socket
+ */
+ QPID_COMMON_EXTERN std::string getPeerAddress() const;
+ /**
+ * Returns an address (host and port) for the local end of the
+ * socket
+ */
+ QPID_COMMON_EXTERN std::string getLocalAddress() const;
+
+ /**
+ * Returns the error code stored in the socket. This may be used
+ * to determine the result of a non-blocking connect.
+ */
+ QPID_COMMON_EXTERN int getError() const;
+
+ /** Accept a connection from a socket that is already listening
+ * and has an incoming connection
+ */
+ QPID_COMMON_EXTERN virtual Socket* accept() const;
+
+ // TODO The following are raw operations, maybe they need better wrapping?
+ QPID_COMMON_EXTERN virtual int read(void *buf, size_t count) const;
+ QPID_COMMON_EXTERN virtual int write(const void *buf, size_t count) const;
+
+ QPID_COMMON_EXTERN int getKeyLen() const;
+ QPID_COMMON_EXTERN std::string getClientAuthId() const;
+
+protected:
+ /** Create socket */
+ void createSocket(const SocketAddress&) const;
+
+ mutable int fd;
+ mutable boost::scoped_ptr<IOHandle> handle;
+ mutable std::string localname;
+ mutable std::string peername;
+ mutable bool nonblocking;
+ mutable bool nodelay;
+
+ /** Construct socket with existing handle */
+ BSDSocket(int fd);
+ friend class qpid::sys::ssl::SslMuxSocket; // Needed for this constructor
+};
+
+}}
+#endif /*!QPID_SYS_BSDSOCKET_H*/
diff --git a/cpp/src/qpid/sys/posix/FileSysDir.cpp b/cpp/src/qpid/sys/posix/FileSysDir.cpp
index 22dc487e74..cec580164d 100755
--- a/cpp/src/qpid/sys/posix/FileSysDir.cpp
+++ b/cpp/src/qpid/sys/posix/FileSysDir.cpp
@@ -18,6 +18,7 @@
#include "qpid/sys/FileSysDir.h"
#include "qpid/sys/StrError.h"
+#include "qpid/log/Statement.h"
#include "qpid/Exception.h"
#include <sys/types.h>
@@ -25,6 +26,8 @@
#include <fcntl.h>
#include <cerrno>
#include <unistd.h>
+#include <dirent.h>
+#include <stdlib.h>
namespace qpid {
namespace sys {
@@ -51,4 +54,27 @@ void FileSysDir::mkdir(void)
throw Exception ("Can't create directory: " + dirPath);
}
+void FileSysDir::forEachFile(Callback cb) const {
+
+ ::dirent** namelist;
+
+ int n = scandir(dirPath.c_str(), &namelist, 0, alphasort);
+ if (n == -1) throw Exception (strError(errno) + ": Can't scan directory: " + dirPath);
+
+ for (int i = 0; i<n; ++i) {
+ std::string fullpath = dirPath + "/" + namelist[i]->d_name;
+ // Filter out non files/stat problems etc.
+ struct ::stat s;
+ // Can't throw here without leaking memory, so just do nothing with
+ // entries for which stat() fails.
+ if (!::stat(fullpath.c_str(), &s)) {
+ if (S_ISREG(s.st_mode)) {
+ cb(fullpath);
+ }
+ }
+ ::free(namelist[i]);
+ }
+ ::free(namelist);
+}
+
}} // namespace qpid::sys
diff --git a/cpp/src/qpid/sys/posix/IOHandle.cpp b/cpp/src/qpid/sys/posix/IOHandle.cpp
index 9c049ee1de..d3f502a63c 100644
--- a/cpp/src/qpid/sys/posix/IOHandle.cpp
+++ b/cpp/src/qpid/sys/posix/IOHandle.cpp
@@ -19,26 +19,11 @@
*
*/
-#include "qpid/sys/IOHandle.h"
-
#include "qpid/sys/posix/PrivatePosix.h"
namespace qpid {
namespace sys {
-int toFd(const IOHandlePrivate* h)
-{
- return h->fd;
-}
-
NullIOHandle DummyIOHandle;
-IOHandle::IOHandle(IOHandlePrivate* h) :
- impl(h)
-{}
-
-IOHandle::~IOHandle() {
- delete impl;
-}
-
}} // namespace qpid::sys
diff --git a/cpp/src/qpid/sys/posix/PollableCondition.cpp b/cpp/src/qpid/sys/posix/PollableCondition.cpp
index abff8a5be8..aa129faf20 100644
--- a/cpp/src/qpid/sys/posix/PollableCondition.cpp
+++ b/cpp/src/qpid/sys/posix/PollableCondition.cpp
@@ -21,7 +21,6 @@
#include "qpid/sys/PollableCondition.h"
#include "qpid/sys/DispatchHandle.h"
-#include "qpid/sys/IOHandle.h"
#include "qpid/sys/posix/PrivatePosix.h"
#include "qpid/Exception.h"
@@ -58,14 +57,14 @@ PollableConditionPrivate::PollableConditionPrivate(
const sys::PollableCondition::Callback& cb,
sys::PollableCondition& parent,
const boost::shared_ptr<sys::Poller>& poller
-) : IOHandle(new sys::IOHandlePrivate), cb(cb), parent(parent)
+) : cb(cb), parent(parent)
{
int fds[2];
if (::pipe(fds) == -1)
throw ErrnoException(QPID_MSG("Can't create PollableCondition"));
- impl->fd = fds[0];
+ fd = fds[0];
writeFd = fds[1];
- if (::fcntl(impl->fd, F_SETFL, O_NONBLOCK) == -1)
+ if (::fcntl(fd, F_SETFL, O_NONBLOCK) == -1)
throw ErrnoException(QPID_MSG("Can't create PollableCondition"));
if (::fcntl(writeFd, F_SETFL, O_NONBLOCK) == -1)
throw ErrnoException(QPID_MSG("Can't create PollableCondition"));
diff --git a/cpp/src/qpid/sys/posix/PosixPoller.cpp b/cpp/src/qpid/sys/posix/PosixPoller.cpp
index eb0c3384d1..ae839b2e20 100644
--- a/cpp/src/qpid/sys/posix/PosixPoller.cpp
+++ b/cpp/src/qpid/sys/posix/PosixPoller.cpp
@@ -88,12 +88,12 @@ class PollerHandlePrivate {
};
short events;
- const IOHandlePrivate* ioHandle;
+ const IOHandle* ioHandle;
PollerHandle* pollerHandle;
FDStat stat;
Mutex lock;
- PollerHandlePrivate(const IOHandlePrivate* h, PollerHandle* p) :
+ PollerHandlePrivate(const IOHandle* h, PollerHandle* p) :
events(0),
ioHandle(h),
pollerHandle(p),
@@ -101,7 +101,7 @@ class PollerHandlePrivate {
}
int fd() const {
- return toFd(ioHandle);
+ return ioHandle->fd;
}
bool isActive() const {
@@ -162,7 +162,7 @@ class PollerHandlePrivate {
};
PollerHandle::PollerHandle(const IOHandle& h) :
- impl(new PollerHandlePrivate(h.impl, this))
+ impl(new PollerHandlePrivate(&h, this))
{}
PollerHandle::~PollerHandle() {
diff --git a/cpp/src/qpid/sys/posix/SocketAddress.cpp b/cpp/src/qpid/sys/posix/SocketAddress.cpp
index 344bd28669..cd23442226 100644
--- a/cpp/src/qpid/sys/posix/SocketAddress.cpp
+++ b/cpp/src/qpid/sys/posix/SocketAddress.cpp
@@ -102,6 +102,11 @@ std::string SocketAddress::asString(bool numeric) const
return asString(ai.ai_addr, ai.ai_addrlen);
}
+std::string SocketAddress::getHost() const
+{
+ return host;
+}
+
bool SocketAddress::nextAddress() {
bool r = currentAddrInfo->ai_next != 0;
if (r)
diff --git a/cpp/src/qpid/sys/posix/SystemInfo.cpp b/cpp/src/qpid/sys/posix/SystemInfo.cpp
index cfd2c64aee..ea7f521f2b 100755
--- a/cpp/src/qpid/sys/posix/SystemInfo.cpp
+++ b/cpp/src/qpid/sys/posix/SystemInfo.cpp
@@ -21,7 +21,6 @@
#include "qpid/log/Statement.h"
#include "qpid/sys/SystemInfo.h"
#include "qpid/sys/posix/check.h"
-#include <set>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <sys/utsname.h>
@@ -33,6 +32,7 @@
#include <iostream>
#include <fstream>
#include <sstream>
+#include <map>
#include <netdb.h>
#include <string.h>
@@ -77,84 +77,70 @@ inline bool isLoopback(const ::sockaddr* addr) {
}
}
-void SystemInfo::getLocalIpAddresses (uint16_t port,
- std::vector<Address> &addrList) {
- ::ifaddrs* ifaddr = 0;
- QPID_POSIX_CHECK(::getifaddrs(&ifaddr));
- for (::ifaddrs* ifap = ifaddr; ifap != 0; ifap = ifap->ifa_next) {
- if (ifap->ifa_addr == 0) continue;
- if (isLoopback(ifap->ifa_addr)) continue;
- int family = ifap->ifa_addr->sa_family;
- switch (family) {
- case AF_INET6: {
- // Ignore link local addresses as:
- // * The scope id is illegal in URL syntax
- // * Clients won't be able to use a link local address
- // without adding their own (potentially different) scope id
- sockaddr_in6* sa6 = (sockaddr_in6*)((void*)ifap->ifa_addr);
- if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr)) break;
- // Fallthrough
- }
- case AF_INET: {
- char dispName[NI_MAXHOST];
- int rc = ::getnameinfo(
- ifap->ifa_addr,
- (family == AF_INET)
- ? sizeof(struct sockaddr_in)
- : sizeof(struct sockaddr_in6),
- dispName, sizeof(dispName),
- 0, 0, NI_NUMERICHOST);
- if (rc != 0) {
- throw QPID_POSIX_ERROR(rc);
- }
- string addr(dispName);
- addrList.push_back(Address(TCP, addr, port));
- break;
- }
- default:
- continue;
+namespace {
+ inline socklen_t sa_len(::sockaddr* sa)
+ {
+ switch (sa->sa_family) {
+ case AF_INET:
+ return sizeof(struct sockaddr_in);
+ case AF_INET6:
+ return sizeof(struct sockaddr_in6);
+ default:
+ return sizeof(struct sockaddr_storage);
}
}
- ::freeifaddrs(ifaddr);
- if (addrList.empty()) {
- addrList.push_back(Address(TCP, LOOPBACK, port));
+ inline bool isInetOrInet6(::sockaddr* sa) {
+ switch (sa->sa_family) {
+ case AF_INET:
+ case AF_INET6:
+ return true;
+ default:
+ return false;
+ }
+ }
+ typedef std::map<std::string, std::vector<std::string> > InterfaceInfo;
+ std::map<std::string, std::vector<std::string> > cachedInterfaces;
+
+ void cacheInterfaceInfo() {
+ // Get interface info
+ ::ifaddrs* interfaceInfo;
+ QPID_POSIX_CHECK( ::getifaddrs(&interfaceInfo) );
+
+ char name[NI_MAXHOST];
+ for (::ifaddrs* info = interfaceInfo; info != 0; info = info->ifa_next) {
+
+ // Only use IPv4/IPv6 interfaces
+ if (!isInetOrInet6(info->ifa_addr)) continue;
+
+ int rc=::getnameinfo(info->ifa_addr, sa_len(info->ifa_addr),
+ name, sizeof(name), 0, 0,
+ NI_NUMERICHOST);
+ if (rc >= 0) {
+ std::string address(name);
+ cachedInterfaces[info->ifa_name].push_back(address);
+ } else {
+ throw qpid::Exception(QPID_MSG(gai_strerror(rc)));
+ }
+ }
+ ::freeifaddrs(interfaceInfo);
}
}
-namespace {
-struct AddrInfo {
- struct addrinfo* ptr;
- AddrInfo(const std::string& host) : ptr(0) {
- ::addrinfo hints;
- ::memset(&hints, 0, sizeof(hints));
- hints.ai_family = AF_UNSPEC; // Allow both IPv4 and IPv6
- if (::getaddrinfo(host.c_str(), NULL, &hints, &ptr) != 0)
- ptr = 0;
- }
- ~AddrInfo() { if (ptr) ::freeaddrinfo(ptr); }
-};
+bool SystemInfo::getInterfaceAddresses(const std::string& interface, std::vector<std::string>& addresses) {
+ if ( cachedInterfaces.empty() ) cacheInterfaceInfo();
+ InterfaceInfo::iterator i = cachedInterfaces.find(interface);
+ if ( i==cachedInterfaces.end() ) return false;
+ std::copy(i->second.begin(), i->second.end(), std::back_inserter(addresses));
+ return true;
}
-bool SystemInfo::isLocalHost(const std::string& host) {
- std::vector<Address> myAddrs;
- getLocalIpAddresses(0, myAddrs);
- std::set<string> localHosts;
- for (std::vector<Address>::const_iterator i = myAddrs.begin(); i != myAddrs.end(); ++i)
- localHosts.insert(i->host);
- // Resolve host
- AddrInfo ai(host);
- if (!ai.ptr) return false;
- for (struct addrinfo *res = ai.ptr; res != NULL; res = res->ai_next) {
- if (isLoopback(res->ai_addr)) return true;
- // Get string form of IP addr
- char addr[NI_MAXHOST] = "";
- int error = ::getnameinfo(res->ai_addr, res->ai_addrlen, addr, NI_MAXHOST, NULL, 0,
- NI_NUMERICHOST | NI_NUMERICSERV);
- if (error) return false;
- if (localHosts.find(addr) != localHosts.end()) return true;
+void SystemInfo::getInterfaceNames(std::vector<std::string>& names ) {
+ if ( cachedInterfaces.empty() ) cacheInterfaceInfo();
+
+ for (InterfaceInfo::const_iterator i = cachedInterfaces.begin(); i!=cachedInterfaces.end(); ++i) {
+ names.push_back(i->first);
}
- return false;
}
void SystemInfo::getSystemId (std::string &osName,
@@ -205,4 +191,11 @@ string SystemInfo::getProcessName()
return value;
}
+// Always true. Only Windows has exception cases.
+bool SystemInfo::threadSafeShutdown()
+{
+ return true;
+}
+
+
}} // namespace qpid::sys