SocketDescriptor.hxx 5.89 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
/*
 * Copyright (C) 2012-2017 Max Kellermann <max.kellermann@gmail.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the
 * distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef SOCKET_DESCRIPTOR_HXX
#define SOCKET_DESCRIPTOR_HXX

#include "system/FileDescriptor.hxx"

#include <type_traits>

class SocketAddress;
class StaticSocketAddress;

/**
 * An OO wrapper for a UNIX socket descriptor.
 */
class SocketDescriptor : protected FileDescriptor {
protected:
	explicit constexpr SocketDescriptor(FileDescriptor _fd)
		:FileDescriptor(_fd) {}

public:
	SocketDescriptor() = default;

51 52 53
	explicit constexpr SocketDescriptor(int _fd)
		:FileDescriptor(_fd) {}

54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
	constexpr bool operator==(SocketDescriptor other) const {
		return fd == other.fd;
	}

#ifndef _WIN32
	/**
	 * Convert a #FileDescriptor to a #SocketDescriptor.  This is only
	 * possible on operating systems where socket descriptors are the
	 * same as file descriptors (i.e. not on Windows).  Use this only
	 * when you know what you're doing.
	 */
	static constexpr SocketDescriptor FromFileDescriptor(FileDescriptor fd) {
		return SocketDescriptor(fd);
	}

	/**
	 * Convert this object to a #FileDescriptor instance.  This is only
	 * possible on operating systems where socket descriptors are the
	 * same as file descriptors (i.e. not on Windows).  Use this only
	 * when you know what you're doing.
	 */
	constexpr const FileDescriptor &ToFileDescriptor() const {
		return *this;
	}
#endif

	using FileDescriptor::IsDefined;
81
#ifndef _WIN32
82
	using FileDescriptor::IsValid;
83
#endif
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
	using FileDescriptor::Get;
	using FileDescriptor::Set;
	using FileDescriptor::Steal;
	using FileDescriptor::SetUndefined;

	static constexpr SocketDescriptor Undefined() {
		return SocketDescriptor(FileDescriptor::Undefined());
	}

#ifndef _WIN32
	using FileDescriptor::SetNonBlocking;
	using FileDescriptor::SetBlocking;
	using FileDescriptor::EnableCloseOnExec;
	using FileDescriptor::DisableCloseOnExec;
	using FileDescriptor::Duplicate;
	using FileDescriptor::Close;
#else
101 102
	bool SetNonBlocking() noexcept;

103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
	/**
	 * This method replaces FileDescriptor::Close(), using closesocket()
	 * on Windows.  FileDescriptor::Close() is not virtual, so be
	 * careful when dealing with a FileDescriptor reference that is
	 * really a SocketDescriptor.
	 */
	void Close();
#endif

	/**
	 * Create a socket.
	 *
	 * @param domain is the address domain
	 * @param type is the sochet type
	 * @param protocol is the protocol
	 * @return True on success, False on failure
	 * See man 2 socket for detailed information
	 */
	bool Create(int domain, int type, int protocol);

	/**
	 * Like Create(), but enable non-blocking mode.
	 */
	bool CreateNonBlock(int domain, int type, int protocol);

128
#ifndef _WIN32
129 130 131 132
	static bool CreateSocketPair(int domain, int type, int protocol,
				     SocketDescriptor &a, SocketDescriptor &b);
	static bool CreateSocketPairNonBlock(int domain, int type, int protocol,
					     SocketDescriptor &a, SocketDescriptor &b);
133
#endif
134 135 136 137 138 139 140 141 142 143

	int GetError();

	bool SetOption(int level, int name, const void *value, size_t size);

	bool SetBoolOption(int level, int name, bool _value) {
		const int value = _value;
		return SetOption(level, name, &value, sizeof(value));
	}

144
	bool SetKeepAlive(bool value=true);
145
	bool SetReuseAddress(bool value=true);
146 147

#ifdef __linux__
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
	bool SetReusePort(bool value=true);
	bool SetFreeBind(bool value=true);
	bool SetNoDelay(bool value=true);
	bool SetCork(bool value=true);

	bool SetTcpDeferAccept(const int &seconds);
	bool SetV6Only(bool value);

	/**
	 * Setter for SO_BINDTODEVICE.
	 */
	bool SetBindToDevice(const char *name);

	bool SetTcpFastOpen(int qlen=16);
#endif

	bool Bind(SocketAddress address);

#ifdef __linux__
	/**
	 * Binds the socket to a unique abstract address.
	 */
	bool AutoBind();
#endif

	bool Listen(int backlog);

	SocketDescriptor Accept();
176
	SocketDescriptor AcceptNonBlock() const;
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
	SocketDescriptor AcceptNonBlock(StaticSocketAddress &address) const;

	bool Connect(SocketAddress address);

	gcc_pure
	StaticSocketAddress GetLocalAddress() const;

	gcc_pure
	StaticSocketAddress GetPeerAddress() const;

	ssize_t Read(void *buffer, size_t length);
	ssize_t Write(const void *buffer, size_t length);

#ifdef _WIN32
	int WaitReadable(int timeout_ms) const;
	int WaitWritable(int timeout_ms) const;
#else
	using FileDescriptor::WaitReadable;
	using FileDescriptor::WaitWritable;
	using FileDescriptor::IsReadyForWriting;
#endif

	/**
	 * Receive a datagram and return the source address.
	 */
	ssize_t Read(void *buffer, size_t length,
		     StaticSocketAddress &address);

	/**
	 * Send a datagram to the specified address.
	 */
	ssize_t Write(const void *buffer, size_t length,
		      SocketAddress address);
};

static_assert(std::is_trivial<SocketDescriptor>::value, "type is not trivial");

#endif