PageRenderTime 473ms CodeModel.GetById 40ms app.highlight 362ms RepoModel.GetById 52ms app.codeStats 1ms

/mordor/socket.h

http://github.com/mozy/mordor
C Header | 361 lines | 277 code | 58 blank | 26 comment | 0 complexity | c1f5f89cff6dc96b83f70a2939945506 MD5 | raw file
  1#ifndef __MORDOR_SOCKET_H__
  2#define __MORDOR_SOCKET_H__
  3// Copyright (c) 2009 - Mozy, Inc.
  4
  5#include <vector>
  6
  7#include <boost/enable_shared_from_this.hpp>
  8#include <boost/noncopyable.hpp>
  9#include <boost/shared_ptr.hpp>
 10#include <boost/signals2/signal.hpp>
 11
 12#include "endian.h"
 13#include "exception.h"
 14#include "version.h"
 15
 16#ifdef WINDOWS
 17#include <ws2tcpip.h>
 18#include "iomanager.h"
 19#else
 20#include <stdint.h>
 21#include <sys/socket.h>
 22#include <sys/types.h>
 23#include <netinet/in.h>
 24#ifndef OSX
 25# include <netinet/in_systm.h>
 26# include <netinet/ip.h>
 27#endif
 28#include <sys/un.h>
 29#endif
 30
 31namespace Mordor {
 32
 33class IOManager;
 34
 35#ifdef WINDOWS
 36struct iovec
 37{
 38    union
 39    {
 40        WSABUF wsabuf;
 41        struct {
 42            u_long iov_len;
 43            void *iov_base;
 44        };
 45    };
 46};
 47#define SHUT_RD SD_RECEIVE
 48#define SHUT_WR SD_SEND
 49#define SHUT_RDWR SD_BOTH
 50typedef u_long iov_len_t;
 51typedef SOCKET socket_t;
 52#else
 53typedef size_t iov_len_t;
 54typedef int socket_t;
 55#endif
 56
 57struct SocketException : virtual NativeException {};
 58
 59struct AddressInUseException : virtual SocketException {};
 60struct ConnectionAbortedException : virtual SocketException {};
 61struct ConnectionResetException : virtual SocketException {};
 62struct ConnectionRefusedException : virtual SocketException {};
 63struct HostDownException : virtual SocketException {};
 64struct HostUnreachableException : virtual SocketException {};
 65struct NetworkDownException : virtual SocketException {};
 66struct NetworkResetException : virtual SocketException {};
 67struct NetworkUnreachableException : virtual SocketException {};
 68struct TimedOutException : virtual SocketException {};
 69
 70struct Address;
 71
 72class Socket : public boost::enable_shared_from_this<Socket>, boost::noncopyable
 73{
 74public:
 75    typedef boost::shared_ptr<Socket> ptr;
 76    typedef boost::weak_ptr<Socket> weak_ptr;
 77private:
 78    Socket(IOManager *ioManager, int family, int type, int protocol, int initialize);
 79public:
 80    Socket(int family, int type, int protocol = 0);
 81    Socket(IOManager &ioManager, int family, int type, int protocol = 0);
 82    ~Socket();
 83
 84    unsigned long long receiveTimeout() { return m_receiveTimeout; }
 85    void receiveTimeout(unsigned long long us) { m_receiveTimeout = us; }
 86    unsigned long long sendTimeout() { return m_sendTimeout; }
 87    void sendTimeout(unsigned long long us) { m_sendTimeout = us; }
 88
 89    void bind(const Address &addr);
 90    void bind(const boost::shared_ptr<Address> addr);
 91    void connect(const Address &to);
 92    void connect(const boost::shared_ptr<Address> addr)
 93    { connect(*addr.get()); }
 94    void listen(int backlog = SOMAXCONN);
 95
 96    Socket::ptr accept();
 97    void shutdown(int how = SHUT_RDWR);
 98
 99    void getOption(int level, int option, void *result, size_t *len);
100    template <class T>
101    T getOption(int level, int option)
102    {
103        T result;
104        size_t length = sizeof(T);
105        getOption(level, option, &result, &length);
106        return result;
107    }
108    void setOption(int level, int option, const void *value, size_t len);
109    template <class T>
110    void setOption(int level, int option, const T &value)
111    {
112        setOption(level, option, &value, sizeof(T));
113    }
114
115    void cancelAccept();
116    void cancelConnect();
117    void cancelSend();
118    void cancelReceive();
119
120    size_t send(const void *buffer, size_t length, int flags = 0);
121    size_t send(const iovec *buffers, size_t length, int flags = 0);
122    size_t sendTo(const void *buffer, size_t length, int flags, const Address &to);
123    size_t sendTo(const void *buffer, size_t length, int flags, const boost::shared_ptr<Address> to)
124    { return sendTo(buffer, length, flags, *to.get()); }
125    size_t sendTo(const iovec *buffers, size_t length, int flags, const Address &to);
126    size_t sendTo(const iovec *buffers, size_t length, int flags, const boost::shared_ptr<Address> to)
127    { return sendTo(buffers, length, flags, *to.get()); }
128
129    size_t receive(void *buffer, size_t length, int *flags = NULL);
130    size_t receive(iovec *buffers, size_t length, int *flags = NULL);
131    size_t receiveFrom(void *buffer, size_t length, Address &from, int *flags = NULL);
132    size_t receiveFrom(iovec *buffers, size_t length, Address &from, int *flags = NULL);
133
134    boost::shared_ptr<Address> emptyAddress();
135    boost::shared_ptr<Address> remoteAddress();
136    boost::shared_ptr<Address> localAddress();
137
138    int family() { return m_family; }
139    int type();
140    int protocol() { return m_protocol; }
141
142    /// Event triggered when the remote end of the connection closes the
143    /// virtual circuit
144    ///
145    /// Only triggered for connected stream sockets.  This event is trigerred
146    /// out-of-band of any receive operations (i.e. there may still be data on
147    /// the socket to be read after this event has been received)
148    boost::signals2::connection onRemoteClose(
149        const boost::signals2::slot<void ()> &slot);
150
151private:
152    template <bool isSend>
153    size_t doIO(iovec *buffers, size_t length, int &flags, Address *address = NULL);
154    static void callOnRemoteClose(weak_ptr self);
155    void registerForRemoteClose();
156    void accept(Socket &target);
157
158#ifdef WINDOWS
159    // For WSAEventSelect
160    void cancelIo(error_t &cancelled, error_t error);
161#else
162    void cancelIo(int event, error_t &cancelled, error_t error);
163#endif
164
165private:
166    socket_t m_sock;
167    int m_family, m_protocol;
168    IOManager *m_ioManager;
169    unsigned long long m_receiveTimeout, m_sendTimeout;
170    error_t m_cancelledSend, m_cancelledReceive;
171    boost::shared_ptr<Address> m_localAddress, m_remoteAddress;
172#ifdef WINDOWS
173    bool m_skipCompletionPortOnSuccess;
174    // All this, just so a connect/accept can be cancelled on win2k
175    bool m_unregistered;
176    HANDLE m_hEvent;
177    boost::shared_ptr<Fiber> m_fiber;
178    Scheduler *m_scheduler;
179
180    AsyncEvent m_sendEvent, m_receiveEvent;
181    bool m_useAcceptEx;         //Cache the values in case they are changed in the registry at
182    bool m_useConnectEx;        //runtime
183
184#endif
185    bool m_isConnected, m_isRegisteredForRemoteClose;
186    boost::signals2::signal<void ()> m_onRemoteClose;
187};
188
189#ifdef WINDOWS
190typedef errinfo_lasterror errinfo_gaierror;
191#else
192typedef boost::error_info<struct tag_gaierror, int> errinfo_gaierror;
193std::string to_string( errinfo_gaierror const & e );
194#endif
195
196struct NameLookupException : virtual SocketException {};
197struct TemporaryNameServerFailureException : virtual NameLookupException {};
198struct PermanentNameServerFailureException : virtual NameLookupException {};
199struct NoNameServerDataException : virtual NameLookupException {};
200struct HostNotFoundException : virtual NameLookupException {};
201
202struct Address
203{
204public:
205    typedef boost::shared_ptr<Address> ptr;
206protected:
207    Address() {}
208public:
209    virtual ~Address() {}
210
211    static std::vector<ptr>
212        lookup(const std::string& host, int family = AF_UNSPEC,
213            int type = 0, int protocol = 0);
214    /// @returns interface => (address, prefixLength)
215    static std::multimap<std::string, std::pair<ptr, unsigned int> >
216        getInterfaceAddresses(int family = AF_UNSPEC);
217    // @param iface Interface name, or "*" to indicate all interfaces
218    static std::vector<std::pair<ptr, unsigned int> >
219        getInterfaceAddresses(const std::string &iface,
220        int family = AF_UNSPEC);
221    static ptr create(const sockaddr *name, socklen_t nameLen);
222
223    ptr clone();
224
225    Socket::ptr createSocket(int type, int protocol = 0);
226    Socket::ptr createSocket(IOManager &ioManager, int type, int protocol = 0);
227
228    int family() const { return name()->sa_family; }
229    virtual const sockaddr *name() const = 0;
230    virtual sockaddr *name() = 0;
231    virtual socklen_t nameLen() const = 0;
232    virtual std::ostream & insert(std::ostream &os) const;
233
234    bool operator<(const Address &rhs) const;
235    bool operator==(const Address &rhs) const;
236    bool operator!=(const Address &rhs) const;
237};
238
239struct IPAddress : public Address
240{
241public:
242    typedef boost::shared_ptr<IPAddress> ptr;
243
244public:
245    /// Create an IPAddress from a numeric string
246    /// @note port should be provided in native-endian format
247    /// @note std::invalid_argument may be thrown if it is an IPv6 address and
248    ///       IPv6 is not supported
249    static ptr create(const char *address, unsigned short port = 0);
250
251    ptr clone();
252
253    virtual ptr broadcastAddress(unsigned int prefixLength) = 0;
254    virtual ptr networkAddress(unsigned int prefixLength) = 0;
255    virtual ptr subnetMask(unsigned int prefixLength) = 0;
256
257    virtual unsigned short port() const = 0;
258    virtual void port(unsigned short p) = 0;
259};
260
261struct IPv4Address : public IPAddress
262{
263public:
264    /// @note address and port should be provided in native-endian format
265    IPv4Address(unsigned int address = INADDR_ANY, unsigned short port = 0);
266    /// @note port should be provided in native-endian format
267    IPv4Address(const char *address, unsigned short port = 0);
268
269    ptr broadcastAddress(unsigned int prefixLength);
270    ptr networkAddress(unsigned int prefixLength);
271    ptr subnetMask(unsigned int prefixLength)
272    { return IPv4Address::createSubnetMask(prefixLength); }
273    static ptr createSubnetMask(unsigned int prefixLength);
274
275    unsigned short port() const { return byteswapOnLittleEndian(sin.sin_port); }
276    void port(unsigned short p) { sin.sin_port = byteswapOnLittleEndian(p); }
277
278    const sockaddr *name() const { return (sockaddr*)&sin; }
279    sockaddr *name() { return (sockaddr*)&sin; }
280    socklen_t nameLen() const { return sizeof(sockaddr_in); }
281
282    std::ostream & insert(std::ostream &os) const;
283private:
284    sockaddr_in sin;
285};
286
287struct IPv6Address : public IPAddress
288{
289public:
290    IPv6Address();
291    IPv6Address(const unsigned char address[16], unsigned short port = 0);
292    IPv6Address(const char *address, unsigned short port = 0);
293
294    ptr broadcastAddress(unsigned int prefixLength);
295    ptr networkAddress(unsigned int prefixLength);
296    ptr subnetMask(unsigned int prefixLength)
297    { return createSubnetMask(prefixLength); }
298    static ptr createSubnetMask(unsigned int prefixLength);
299
300    unsigned short port() const { return byteswapOnLittleEndian(sin.sin6_port); }
301    void port(unsigned short p) { sin.sin6_port = byteswapOnLittleEndian(p); }
302
303    const sockaddr *name() const { return (sockaddr*)&sin; }
304    sockaddr *name() { return (sockaddr*)&sin; }
305    socklen_t nameLen() const { return sizeof(sockaddr_in6); }
306
307    std::ostream & insert(std::ostream &os) const;
308private:
309    sockaddr_in6 sin;
310};
311
312#ifndef WINDOWS
313struct UnixAddress : public Address
314{
315public:
316    /// @pre @c path.length() is less or equal to MAX_PATH_LEN
317    UnixAddress(const std::string &path);
318    /// create a dummy instance of @c UnixAddress
319    ///
320    /// an all '\0' string sized @c MAX_PATH_LEN is used as the path for the
321    /// address.
322    ///
323    /// @note one is supposed to fill the sockaddr returned by @name() before
324    ///       actually start using it, and to set the @length correctly using
325    ///       @c nameLen(size_t).
326    UnixAddress();
327    const sockaddr *name() const { return (sockaddr*)&sun; }
328    sockaddr *name() { return (sockaddr*)&sun; }
329    socklen_t nameLen() const { return length; }
330    void nameLen(socklen_t len) { length = len; }
331
332    std::ostream & insert(std::ostream &os) const;
333    static const size_t MAX_PATH_LEN;
334private:
335    socklen_t length;
336    struct sockaddr_un sun;
337};
338#endif
339
340struct UnknownAddress : public Address
341{
342public:
343    UnknownAddress(int family);
344
345    const sockaddr *name() const { return &sa; }
346    sockaddr *name() { return &sa; }
347    socklen_t nameLen() const { return sizeof(sockaddr); }
348private:
349    sockaddr sa;
350};
351
352std::ostream &operator <<(std::ostream &os, const Address &addr);
353
354bool operator<(const Address::ptr &lhs, const Address::ptr &rhs);
355
356std::ostream &includePort(std::ostream &os);
357std::ostream &excludePort(std::ostream &os);
358
359}
360
361#endif