summaryrefslogtreecommitdiff
path: root/gio/src/socket.hg
blob: 1069eb2b929c00a0535e4efd5b7cec462ae7909b (plain)
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
51
52
53
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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
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
176
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
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
/* Copyright (C) 2009 Jonathon Jongsma
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <glibmm/iochannel.h>
#include <glibmm/object.h>
#include <giomm/initable.h>
#include <giomm/credentials.h>
#include <giomm/socketconnectable.h>
#include <giomm/socketaddress.h>
#include <giomm/enums.h>
#include <giomm/inetaddress.h>

_DEFS(giomm,gio)
_PINCLUDE(glibmm/private/object_p.h)

namespace Gio
{
class SocketSource;


/** @defgroup NetworkIO Portable Network I/O Functionality
 */

/** Low-level socket object
 *
 * A Socket is a low-level networking primitive. It is a more or less direct
 * mapping of the BSD socket API in a portable GObject based API. It supports
 * both the UNIX socket implementations and winsock2 on Windows.
 *
 * Socket is the platform independent base upon which the higher level network
 * primitives are based. Applications are not typically meant to use it
 * directly, but rather through classes like SocketClient, SocketService and
 * SocketConnection. However there may be cases where direct use of Socket is
 * useful.
 *
 * Socket implements the Initable interface, and since initialization can fail,
 * the constructor may throw an exception.
 *
 * Sockets operate in two general modes, blocking or non-blocking. When in
 * blocking mode all operations block until the requested operation is finished
 * or there is an error. In non-blocking mode all calls that would block return
 * immediately with a Gio::Error::WOULD_BLOCK error. To know when a call would
 * successfully run you can call condition_check(), or condition_wait(). You can
 * also use create_source() and attach it to a Glib::MainContext to get
 * callbacks when I/O is possible. Note that all sockets are always set to non
 * blocking mode in the system, and blocking mode is emulated in Socket.
 *
 * When working in non-blocking mode applications should always be able to
 * handle getting a Gio::Error::WOULD_BLOCK error even when some other function
 * said that I/O was possible. This can easily happen in case of a race
 * condition in the application, but it can also happen for other reasons. For
 * instance, on Windows a socket is always seen as writable until a write
 * returns Gio::Error::WOULD_BLOCK.
 *
 * Sockets can be either connection oriented or datagram based. For connection
 * oriented types you must first establish a connection by either connecting to
 * an address or accepting a connection from another address. For connectionless
 * socket types the target/source address is specified or received in each I/O
 * operation.
 *
 * All socket file descriptors are set to be close-on-exec.
 *
 * Note that creating a Socket causes the signal SIGPIPE to be ignored for the
 * remainder of the program. If you are writing a command-line utility that uses
 * Socket, you may need to take into account the fact that your program will not
 * automatically be killed if it tries to write to stdout after it has been
 * closed.
 *
 * @newin{2,24}
 * @ingroup NetworkIO
 */
class Socket : public Glib::Object, public Initable
{
  _CLASS_GOBJECT(Socket, GSocket, G_SOCKET, Glib::Object, GObject)
  _IMPLEMENTS_INTERFACE(Initable)

public:
  _WRAP_ENUM(Type, GSocketType)
  _WRAP_ENUM(Protocol, GSocketProtocol)
  _WRAP_ENUM(MsgFlags, GSocketMsgFlags)

protected:
  Socket(SocketFamily family, Type type, Protocol protocol,
         const Glib::RefPtr<Cancellable>& cancellable);

  Socket(int fd, const Glib::RefPtr<Cancellable>& cancellable);

public:
  _WRAP_METHOD_DOCS_ONLY(g_socket_new)

  /** @param cancellable A Cancellable object which can be used to cancel the operation.
   * @throw Glib::Error
   */
  static Glib::RefPtr<Socket>
  create(SocketFamily family, Type type, Protocol protocol,
         const Glib::RefPtr<Cancellable>& cancellable = {});

  // gmmproc thinks that this function should be wrapped in this class because
  // its only parameter is a GSocket.  In fact, it is wrapped in the
  // SocketConnection class.
  _IGNORE(g_socket_connection_factory_create_connection)

  _WRAP_METHOD_DOCS_ONLY(g_socket_new_from_fd)
  /** @param cancellable A Cancellable object which can be used to cancel the operation.
   * @throw Glib::Error
   */
  static Glib::RefPtr<Socket> create_from_fd(int fd, const Glib::RefPtr<Cancellable>&
                                             cancellable = {});

  /** When a socket is created it is attached to an address family, but it doesn't
   * have an address in this family. Socket::bind() assigns the address (sometimes
   * called name) of the socket.
   *
   * It is generally required to bind to a local address before you can receive
   * connections. (See Socket::listen() and Socket::accept()). In certain situations,
   * you may also want to bind a socket that will be used to initiate connections,
   * though this is not normally required.
   *
   * If socket is a TCP socket, then @a allow_reuse controls the setting of the SO_REUSEADDR
   * socket option; normally it should be <tt>true</tt> for server sockets (sockets that you
   * will eventually call Socket::accept() on), and <tt>false</tt> for client sockets.
   * (Failing to set this flag on a server socket may cause Socket::bind() to
   * throw Gio::Error with ADDRESS_IN_USE if the server program
   * is stopped and then immediately restarted.)
   *
   * If socket is a UDP socket, then @a allow_reuse determines whether or not
   * other UDP sockets can be bound to the same address at the same time. In particular,
   * you can have several UDP sockets bound to the same address, and they will all
   * receive all of the multicast and broadcast packets sent to that address.
   * (The behavior of unicast UDP packets to an address with multiple listeners is not defined.)
   *
   * @param address a SocketAddress specifying the local address.
   * @param allow_reuse whether to allow reusing this address
   *
   * @throw Gio::Error
   */
  _WRAP_METHOD(void bind(const Glib::RefPtr<SocketAddress>& address, bool allow_reuse), g_socket_bind, errthrow)

  /** Marks the socket as a server socket - a socket that is used to accept
   * incoming requests using Socket::accept().
   *
   * Before calling this the socket must be bound to a local address using Socket::bind().
   *
   * To set the maximum amount of outstanding clients, use Socket::set_listen_backlog().
   *
   * @throw Gio::Error
   */
  _WRAP_METHOD(void listen(), g_socket_listen, errthrow)

  /** Accept incoming connections on a connection-based socket. This removes the
   * first outstanding connection request from the listening socket and creates
   * a GSocket object for it.
   *
   * The socket must be bound to a local address with g_socket_bind() and must
   * be listening for incoming connections (Socket::listen()).
   *
   * If there are no outstanding connections then the operation will block or
   * throw Gio::Error with ERROR_WOULD_BLOCK if non-blocking
   * I/O is enabled. To be notified of an incoming connection, wait for the
   * Glib::IO_IN condition.
   *
   * @param cancellable A Cancellable object which can be used to cancel the operation.
   *
   * @return a Gio::Socket
   *
   * @throw Gio::Error
   */
  _WRAP_METHOD(Glib::RefPtr<Socket> accept(const Glib::RefPtr<Cancellable>& cancellable{?}), g_socket_accept, errthrow)

  /** Connect the socket to the specified remote address.
   *
   * For connection oriented socket this generally means we attempt to make a
   * connection to the address . For a connection-less socket it sets the default
   * address for Socket::send() and discards all incoming datagrams from other sources.
   *
   * Generally connection oriented sockets can only connect once, but
   * connection-less sockets can connect multiple times to change the default address.
   *
   * If the connect call needs to do network I/O it will block, unless non-blocking
   * I/O is enabled. Then Gio::Error with ERROR_PENDING is thrown
   * and the user can be notified of the connection finishing by waiting for the
   * Glib::IO_OUT condition. The result of the connection must then be checked
   * with Socket::check_connect_result().
   *
   * @param address	a SocketAddress specifying the remote address.
   * @param cancellable	A Cancellable object which can be used to cancel the operation.
   *
   * @throw Gio::Error
   */
  _WRAP_METHOD(void connect(const Glib::RefPtr<SocketAddress>& address, const Glib::RefPtr<Cancellable>& cancellable{?}), g_socket_connect, errthrow)

  // FIXME: it doesn't really seem like this is a proper use of exceptions...
  _WRAP_METHOD(void check_connect_result(), g_socket_check_connect_result, errthrow)

  // TODO: std::string overload?
  _WRAP_METHOD(gssize receive(char* buffer, gsize size, const Glib::RefPtr<Cancellable>& cancellable{?}), g_socket_receive, errthrow)

  _IGNORE(g_socket_receive_from)
  gssize receive_from(Glib::RefPtr<SocketAddress>& address, char* buffer, gsize size, const Glib::RefPtr<Cancellable>& cancellable);
  gssize receive_from(Glib::RefPtr<SocketAddress>& address, char* buffer, gsize size);
  // TODO: wrap g_socket_receive_message -- figure out this GInputVector thing
  // TODO: std::string overload?

  _WRAP_METHOD(gssize send(const gchar* buffer, gsize size, const Glib::RefPtr<Cancellable>& cancellable{?}), g_socket_send, errthrow)

  // TODO: std::string overload?
  _WRAP_METHOD(gssize send_to(const Glib::RefPtr<SocketAddress>& address, const char* buffer, gsize size, const Glib::RefPtr<Cancellable>& cancellable{?}), g_socket_send_to, errthrow)

  // TODO: wrap g_socket_send_message -- figure out this GOutputVector thing
  _WRAP_METHOD(void close(), g_socket_close, errthrow)
  _WRAP_METHOD(bool is_closed(), g_socket_is_closed)

  /** Creates a SocketSource that can be attached to a Glib::MainContext to monitor
   * for the availability of the specified @a condition on the socket.
   *
   * Create a slot from a function to be called when @a condition is met
   * for the socket with sigc::ptr_fun() or sigc::mem_fun() and pass
   * it into the connect() function of the returned SocketSource object.
   * Polling of the socket will start when you attach a Glib::MainContext
   * object to the returned SocketSource object using its attach() function.
   *
   * It is meaningless to specify Glib::IO_ERR or Glib::IO_HUP in @a condition;
   * these conditions will always be reported output if they are true.
   *
   * @a cancellable can be used to cancel the source, which will
   * cause the source to trigger, reporting the current condition (which
   * is likely 0 unless cancellation happened at the same time as a
   * condition change). You can check for this in the callback using
   * Cancellable::is_cancelled().
   *
   * If the socket has a timeout set, and it is reached before @a condition
   * occurs, the source will then trigger anyway, reporting Glib::IO_IN or
   * Glib::IO_OUT depending on @a condition. However, the socket will have been
   * marked as having had a timeout, and so the next Socket I/O method
   * you call will then fail with a Gio::IO_ERROR_TIMED_OUT.
   *
   * Gio::signal_socket().connect() is a simpler interface to the same functionality.
   *
   * @newin{2,42}
   *
   * @param condition A Glib::IOCondition mask to monitor.
   * @param cancellable A Cancellable. The default value means the source is not cancellable.
   * @return A newly allocated SocketSource.
   */
  Glib::RefPtr<SocketSource> create_source(Glib::IOCondition condition, const Glib::RefPtr<Cancellable>& cancellable = {});
  _IGNORE(g_socket_create_source)

  _WRAP_METHOD(void shutdown(bool shutdown_read, bool shutdown_write), g_socket_shutdown, errthrow)
  _WRAP_METHOD(bool is_connected(), g_socket_is_connected)

  _WRAP_METHOD(gssize get_available_bytes() const,  g_socket_get_available_bytes)

  _WRAP_METHOD(Glib::IOCondition condition_check(Glib::IOCondition condition), g_socket_condition_check)

  _WRAP_METHOD(void condition_wait(Glib::IOCondition condition, const Glib::RefPtr<Cancellable>& cancellable{?}), g_socket_condition_wait, errthrow)

  _WRAP_METHOD(void condition_timed_wait(Glib::IOCondition condition, gint64 timeout, const Glib::RefPtr<Cancellable>& cancellable{?}), g_socket_condition_timed_wait, errthrow)

  _WRAP_METHOD(void set_listen_backlog(int backlog), g_socket_set_listen_backlog)
  _WRAP_METHOD(int get_listen_backlog() const, g_socket_get_listen_backlog)
  _WRAP_METHOD(void set_blocking(bool blocking), g_socket_set_blocking)
  _WRAP_METHOD(bool get_blocking() const, g_socket_get_blocking)
  _WRAP_METHOD(void set_keepalive(bool keepalive), g_socket_set_keepalive)
  _WRAP_METHOD(bool get_keepalive() const, g_socket_get_keepalive)
  _WRAP_METHOD(SocketFamily get_family() const, g_socket_get_family)
  _WRAP_METHOD(int get_fd() const, g_socket_get_fd)
  _WRAP_METHOD(Glib::RefPtr<SocketAddress> get_local_address() const, g_socket_get_local_address, errthrow)
  _WRAP_METHOD(Glib::RefPtr<SocketAddress> get_remote_address() const, g_socket_get_remote_address, errthrow)
  _WRAP_METHOD(Protocol get_protocol() const, g_socket_get_protocol)
  _WRAP_METHOD(Type get_socket_type() const, g_socket_get_socket_type)
  _WRAP_METHOD(bool speaks_ipv4() const, g_socket_speaks_ipv4)

  _WRAP_METHOD(Glib::RefPtr<Credentials> get_credentials(), g_socket_get_credentials, errthrow)
  _WRAP_METHOD(Glib::RefPtr<const Credentials> get_credentials() const, g_socket_get_credentials, errthrow)

  _WRAP_METHOD(guint get_timeout() const, g_socket_get_timeout)
  _WRAP_METHOD(void set_timeout(guint timeout), g_socket_set_timeout)

  _WRAP_METHOD_DOCS_ONLY(g_socket_receive_with_blocking)
  gssize receive_with_blocking(gchar* buffer, gsize size, bool blocking, const Glib::RefPtr<Cancellable>& cancellable = {});

  _WRAP_METHOD_DOCS_ONLY(g_socket_send_with_blocking)
  gssize send_with_blocking(gchar* buffer, gsize size, bool blocking, const Glib::RefPtr<Cancellable>& cancellable = {});

  _WRAP_METHOD(bool get_option(int level, int optname, int& value) const, g_socket_get_option, errthrow)
  _WRAP_METHOD(bool set_option(int level, int optname, int value), g_socket_set_option, errthrow)

  _WRAP_METHOD(guint get_ttl() const, g_socket_get_ttl)
  _WRAP_METHOD(void set_ttl(guint ttl), g_socket_set_ttl)

  _WRAP_METHOD(bool get_broadcast() const, g_socket_get_broadcast )
  _WRAP_METHOD(void set_broadcast(bool broadcast), g_socket_set_broadcast)

  _WRAP_METHOD(bool get_multicast_loopback() const, g_socket_get_multicast_loopback)
  _WRAP_METHOD(void set_multicast_loopback(bool loopback), g_socket_set_multicast_loopback)
  _WRAP_METHOD(guint get_multicast_ttl() const, g_socket_get_multicast_ttl)
  _WRAP_METHOD(void set_multicast_ttl(guint ttl), g_socket_set_multicast_ttl)

  _WRAP_METHOD(bool join_multicast_group(const Glib::RefPtr<InetAddress>& group, bool source_specific, const std::string& iface{?}), g_socket_join_multicast_group, errthrow)
  _WRAP_METHOD(bool leave_multicast_group(const Glib::RefPtr<InetAddress>& group, bool source_specific, const std::string& iface{?}), g_socket_leave_multicast_group, errthrow)


  _WRAP_PROPERTY("blocking", bool)
  _WRAP_PROPERTY("family", SocketFamily)
  _WRAP_PROPERTY("fd", int)
  _WRAP_PROPERTY("keepalive", bool)
  _WRAP_PROPERTY("listen-backlog", int)
  _WRAP_PROPERTY("local-address", Glib::RefPtr<SocketAddress>)
  _WRAP_PROPERTY("remote-address", Glib::RefPtr<SocketAddress>)
  _WRAP_PROPERTY("timeout", guint)
  _WRAP_PROPERTY("protocol", Protocol)
  _WRAP_PROPERTY("broadcast", bool)
  _WRAP_PROPERTY("type", Type)
  _WRAP_PROPERTY("ttl", guint)
  _WRAP_PROPERTY("multicast-loopback", bool)
  _WRAP_PROPERTY("multicast-ttl", guint)
};

} // namespace Gio