From 14161da7a1fd0e00522a1e6c2d6b5171d8de7aac Mon Sep 17 00:00:00 2001 From: paulc Date: Tue, 26 Sep 2006 18:26:36 +0000 Subject: [PATCH] Added a socket packet data filter - preparing for a nice STUN implementation. git-svn-id: http://yate.null.ro/svn/yate/trunk@1058 acf43c95-373e-0410-b603-e72c3f656dc1 --- engine/Socket.cpp | 69 +++++++++++++++++++++++++++++++++++-- yateclass.h | 87 ++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 153 insertions(+), 3 deletions(-) diff --git a/engine/Socket.cpp b/engine/Socket.cpp index 67bee612..7a4cfece 100644 --- a/engine/Socket.cpp +++ b/engine/Socket.cpp @@ -295,6 +295,30 @@ bool SocketAddr::supports(int family) } +SocketFilter::SocketFilter() + : m_socket(0) +{ +} + +SocketFilter::~SocketFilter() +{ + if (m_socket) + m_socket->removeFilter(this); +} + +void* SocketFilter::getObject(const String& name) const +{ + if (name == "SocketFilter") + return const_cast(this); + return GenObject::getObject(name); +} + +bool SocketFilter::valid() const +{ + return m_socket && m_socket->valid(); +} + + Stream::~Stream() { } @@ -650,6 +674,7 @@ Socket::Socket(int domain, int type, int protocol) Socket::~Socket() { DDebug(DebugAll,"Socket::~Socket() handle=%d [%p]",m_handle,this); + clearFilters(); terminate(); } @@ -891,6 +916,8 @@ bool Socket::getPeerName(SocketAddr& addr) int Socket::sendTo(const void* buffer, int length, const struct sockaddr* addr, socklen_t adrlen, int flags) { + if (!addr) + return send(buffer,length,flags); if (!buffer) length = 0; int res = ::sendto(m_handle,(const char*)buffer,length,flags,addr,adrlen); @@ -927,7 +954,10 @@ int Socket::recvFrom(void* buffer, int length, struct sockaddr* addr, socklen_t* if (adrlen && !addr) *adrlen = 0; int res = ::recvfrom(m_handle,(char*)buffer,length,flags,addr,adrlen); - checkError(res,true); + if (checkError(res,true) && applyFilters(buffer,res,flags,addr,(adrlen ? *adrlen : 0))) { + m_error = EAGAIN; + res = socketError(); + } return res; } @@ -946,7 +976,10 @@ int Socket::recv(void* buffer, int length, int flags) if (!buffer) length = 0; int res = ::recv(m_handle,(char*)buffer,length,flags); - checkError(res,true); + if (checkError(res,true) && applyFilters(buffer,res,flags)) { + m_error = EAGAIN; + res = socketError(); + } return res; } @@ -1108,4 +1141,36 @@ bool Socket::createPair(Socket& sock1, Socket& sock2, int domain) return false; } +bool Socket::installFilter(SocketFilter* filter) +{ + if (!filter || filter->socket()) + return false; + if (m_filters.find(filter)) + return false; + filter->m_socket = this; + m_filters.append(filter); + return true; +} + +void Socket::removeFilter(SocketFilter* filter, bool delobj) +{ + if (m_filters.remove(filter,delobj)) + filter->m_socket = 0; +} + +void Socket::clearFilters() +{ + m_filters.clear(); +} + +bool Socket::applyFilters(void* buffer, int length, int flags, const struct sockaddr* addr, socklen_t adrlen) +{ + for (ObjList* l = &m_filters; l; l = l->next()) { + SocketFilter* filter = static_cast(l->get()); + if (filter && filter->received(buffer,length,flags,addr,adrlen)) + return true; + } + return false; +} + /* vi: set ts=8 sw=4 sts=4 noet: */ diff --git a/yateclass.h b/yateclass.h index ea9f1e2e..cf757dac 100644 --- a/yateclass.h +++ b/yateclass.h @@ -3258,6 +3258,8 @@ private: bool m_locking; }; +class Socket; + /** * Wrapper class to keep a socket address * @short A socket address holder @@ -3425,6 +3427,59 @@ protected: String m_host; }; +/** + * Abstract interface for an object that filters socket received data packets + * @short A filter for received socket data + */ +class YATE_API SocketFilter : public GenObject +{ + friend class Socket; +public: + /** + * Constructor + */ + SocketFilter(); + + /** + * Destructor, unregisters from socket + */ + virtual ~SocketFilter(); + + /** + * Get a pointer to a derived class given that class name + * @param name Name of the class we are asking for + * @return Pointer to the requested class or NULL if this object doesn't implement it + */ + virtual void* getObject(const String& name) const; + + /** + * Notify this filter about a received block of data + * @param buffer Buffer for received data + * @param length Length of the data in buffer + * @param flags Operating system specific bit flags of the operation + * @param addr Address of the incoming data, may be NULL + * @param adrlen Length of the valid data in address structure + * @return True if this filter claimed the data + */ + virtual bool received(void* buffer, int length, int flags, const struct sockaddr* addr, socklen_t adrlen) = 0; + + /** + * Get the socket to which the filter is currently attached + * @return Pointer to the socket of this filter + */ + inline Socket* socket() const + { return m_socket; } + + /** + * Check if the socket of this filter is valid + * @return True if the filter has a valid socket + */ + bool valid() const; + +private: + Socket* m_socket; +}; + /** * Base class for encapsulating system dependent stream capable objects * @short An abstract stream class capable of reading and writing @@ -3954,7 +4009,7 @@ public: * Send a message over a connected or unconnected socket * @param buffer Buffer for data transfer * @param length Length of the buffer - * @param addr Address to send the message to + * @param addr Address to send the message to, if NULL will behave like @ref send() * @param adrlen Length of the address structure * @param flags Operating system specific bit flags that change the behaviour * @return Number of bytes transferred, @ref socketError() if an error occurred @@ -4047,6 +4102,24 @@ public: */ bool select(bool* readok, bool* writeok, bool* except, int64_t timeout); + /** + * Install a new packet filter in the socket + * @param filter Pointer to the packet filter to install + * @return True if the filter was installed + */ + bool installFilter(SocketFilter* filter); + + /** + * Removes a packet filter and optionally destroys it + * @param delobj Set to true to also delete the filter + */ + void removeFilter(SocketFilter* filter, bool delobj = false); + + /** + * Removes and destroys all packet filters + */ + void clearFilters(); + /** * Create a pair of bidirectionally connected sockets * @param sock1 Reference to first Socket to be paired @@ -4071,7 +4144,19 @@ protected: */ bool checkError(int retcode, bool strict = false); + /** + * Apply installed filters to a received block of data + * @param buffer Buffer for received data + * @param length Length of the data in buffer + * @param flags Operating system specific bit flags of the operation + * @param addr Address of the incoming data, may be NULL + * @param adrlen Length of the valid data in address structure + * @return True if one of the filters claimed the data + */ + bool applyFilters(void* buffer, int length, int flags, const struct sockaddr* addr = 0, socklen_t adrlen = 0); + SOCKET m_handle; + ObjList m_filters; }; /**