1 module soup.Socket;
2 
3 private import gio.Cancellable;
4 private import gio.Socket: GIOSocket = Socket;
5 private import gio.IOStream;
6 private import gio.InitableIF;
7 private import gio.InitableT;
8 private import glib.ConstructionException;
9 private import glib.ErrorG;
10 private import glib.GException;
11 private import glib.Str;
12 private import gobject.ObjectG;
13 private import gobject.Signals;
14 private import soup.Address;
15 private import soup.c.functions;
16 public  import soup.c.types;
17 private import std.algorithm;
18 
19 
20 /**
21  * #SoupSocket is libsoup's TCP socket type. While it is primarily
22  * intended for internal use, #SoupSocket<!-- -->s are exposed in the
23  * API in various places, and some of their methods (eg,
24  * soup_socket_get_remote_address()) may be useful to applications.
25  */
26 public class Socket : ObjectG, InitableIF
27 {
28 	/** the main Gtk struct */
29 	protected SoupSocket* soupSocket;
30 
31 	/** Get the main Gtk struct */
32 	public SoupSocket* getSocketStruct(bool transferOwnership = false)
33 	{
34 		if (transferOwnership)
35 			ownedRef = false;
36 		return soupSocket;
37 	}
38 
39 	/** the main Gtk struct as a void* */
40 	protected override void* getStruct()
41 	{
42 		return cast(void*)soupSocket;
43 	}
44 
45 	/**
46 	 * Sets our main struct and passes it to the parent class.
47 	 */
48 	public this (SoupSocket* soupSocket, bool ownedRef = false)
49 	{
50 		this.soupSocket = soupSocket;
51 		super(cast(GObject*)soupSocket, ownedRef);
52 	}
53 
54 	// add the Initable capabilities
55 	mixin InitableT!(SoupSocket);
56 
57 
58 	/** */
59 	public static GType getType()
60 	{
61 		return soup_socket_get_type();
62 	}
63 
64 	/**
65 	 * Begins asynchronously connecting to @sock's remote address. The
66 	 * socket will call @callback when it succeeds or fails (but not
67 	 * before returning from this function).
68 	 *
69 	 * If @cancellable is non-%NULL, it can be used to cancel the
70 	 * connection. @callback will still be invoked in this case, with a
71 	 * status of %SOUP_STATUS_CANCELLED.
72 	 *
73 	 * Params:
74 	 *     cancellable = a #GCancellable, or %NULL
75 	 *     callback = callback to call after connecting
76 	 *     userData = data to pass to @callback
77 	 */
78 	public void connectAsync(Cancellable cancellable, SoupSocketCallback callback, void* userData)
79 	{
80 		soup_socket_connect_async(soupSocket, (cancellable is null) ? null : cancellable.getCancellableStruct(), callback, userData);
81 	}
82 
83 	/**
84 	 * Attempt to synchronously connect @sock to its remote address.
85 	 *
86 	 * If @cancellable is non-%NULL, it can be used to cancel the
87 	 * connection, in which case soup_socket_connect_sync() will return
88 	 * %SOUP_STATUS_CANCELLED.
89 	 *
90 	 * Params:
91 	 *     cancellable = a #GCancellable, or %NULL
92 	 *
93 	 * Returns: a success or failure code.
94 	 */
95 	public uint connectSync(Cancellable cancellable)
96 	{
97 		return soup_socket_connect_sync(soupSocket, (cancellable is null) ? null : cancellable.getCancellableStruct());
98 	}
99 
100 	/**
101 	 * Disconnects @sock. Any further read or write attempts on it will
102 	 * fail.
103 	 */
104 	public void disconnect()
105 	{
106 		soup_socket_disconnect(soupSocket);
107 	}
108 
109 	/**
110 	 * Gets @sock's underlying file descriptor.
111 	 *
112 	 * Note that fiddling with the file descriptor may break the
113 	 * #SoupSocket.
114 	 *
115 	 * Returns: @sock's file descriptor.
116 	 */
117 	public int getFd()
118 	{
119 		return soup_socket_get_fd(soupSocket);
120 	}
121 
122 	/**
123 	 * Returns the #SoupAddress corresponding to the local end of @sock.
124 	 *
125 	 * Calling this method on an unconnected socket is considered to be
126 	 * an error, and produces undefined results.
127 	 *
128 	 * Returns: the #SoupAddress
129 	 */
130 	public Address getLocalAddress()
131 	{
132 		auto __p = soup_socket_get_local_address(soupSocket);
133 
134 		if(__p is null)
135 		{
136 			return null;
137 		}
138 
139 		return ObjectG.getDObject!(Address)(cast(SoupAddress*) __p);
140 	}
141 
142 	/**
143 	 * Returns the #SoupAddress corresponding to the remote end of @sock.
144 	 *
145 	 * Calling this method on an unconnected socket is considered to be
146 	 * an error, and produces undefined results.
147 	 *
148 	 * Returns: the #SoupAddress
149 	 */
150 	public Address getRemoteAddress()
151 	{
152 		auto __p = soup_socket_get_remote_address(soupSocket);
153 
154 		if(__p is null)
155 		{
156 			return null;
157 		}
158 
159 		return ObjectG.getDObject!(Address)(cast(SoupAddress*) __p);
160 	}
161 
162 	/**
163 	 * Tests if @sock is connected to another host
164 	 *
165 	 * Returns: %TRUE or %FALSE.
166 	 */
167 	public bool isConnected()
168 	{
169 		return soup_socket_is_connected(soupSocket) != 0;
170 	}
171 
172 	/**
173 	 * Tests if @sock is doing (or has attempted to do) SSL.
174 	 *
175 	 * Returns: %TRUE if @sock has SSL credentials set
176 	 */
177 	public bool isSsl()
178 	{
179 		return soup_socket_is_ssl(soupSocket) != 0;
180 	}
181 
182 	/**
183 	 * Makes @sock start listening on its local address. When connections
184 	 * come in, @sock will emit #SoupSocket::new_connection.
185 	 *
186 	 * Returns: whether or not @sock is now listening.
187 	 */
188 	public bool listen()
189 	{
190 		return soup_socket_listen(soupSocket) != 0;
191 	}
192 
193 	/**
194 	 * Attempts to read up to @len bytes from @sock into @buffer. If some
195 	 * data is successfully read, soup_socket_read() will return
196 	 * %SOUP_SOCKET_OK, and *@nread will contain the number of bytes
197 	 * actually read (which may be less than @len).
198 	 *
199 	 * If @sock is non-blocking, and no data is available, the return
200 	 * value will be %SOUP_SOCKET_WOULD_BLOCK. In this case, the caller
201 	 * can connect to the #SoupSocket::readable signal to know when there
202 	 * is more data to read. (NB: You MUST read all available data off the
203 	 * socket first. #SoupSocket::readable is only emitted after
204 	 * soup_socket_read() returns %SOUP_SOCKET_WOULD_BLOCK, and it is only
205 	 * emitted once. See the documentation for #SoupSocket:non-blocking.)
206 	 *
207 	 * Params:
208 	 *     buffer = buffer to read
209 	 *         into
210 	 *     nread = on return, the number of bytes read into @buffer
211 	 *     cancellable = a #GCancellable, or %NULL
212 	 *
213 	 * Returns: a #SoupSocketIOStatus, as described above (or
214 	 *     %SOUP_SOCKET_EOF if the socket is no longer connected, or
215 	 *     %SOUP_SOCKET_ERROR on any other error, in which case @error will
216 	 *     also be set).
217 	 *
218 	 * Throws: GException on failure.
219 	 */
220 	public SoupSocketIOStatus read(ubyte[] buffer, out size_t nread, Cancellable cancellable)
221 	{
222 		GError* err = null;
223 
224 		auto __p = soup_socket_read(soupSocket, buffer.ptr, cast(size_t)buffer.length, &nread, (cancellable is null) ? null : cancellable.getCancellableStruct(), &err);
225 
226 		if (err !is null)
227 		{
228 			throw new GException( new ErrorG(err) );
229 		}
230 
231 		return __p;
232 	}
233 
234 	/**
235 	 * Like soup_socket_read(), but reads no further than the first
236 	 * occurrence of @boundary. (If the boundary is found, it will be
237 	 * included in the returned data, and *@got_boundary will be set to
238 	 * %TRUE.) Any data after the boundary will returned in future reads.
239 	 *
240 	 * soup_socket_read_until() will almost always return fewer than @len
241 	 * bytes: if the boundary is found, then it will only return the bytes
242 	 * up until the end of the boundary, and if the boundary is not found,
243 	 * then it will leave the last <literal>(boundary_len - 1)</literal>
244 	 * bytes in its internal buffer, in case they form the start of the
245 	 * boundary string. Thus, @len normally needs to be at least 1 byte
246 	 * longer than @boundary_len if you want to make any progress at all.
247 	 *
248 	 * Params:
249 	 *     buffer = buffer to read
250 	 *         into
251 	 *     boundary = boundary to read until
252 	 *     boundaryLen = length of @boundary in bytes
253 	 *     nread = on return, the number of bytes read into @buffer
254 	 *     gotBoundary = on return, whether or not the data in @buffer
255 	 *         ends with the boundary string
256 	 *     cancellable = a #GCancellable, or %NULL
257 	 *
258 	 * Returns: as for soup_socket_read()
259 	 *
260 	 * Throws: GException on failure.
261 	 */
262 	public SoupSocketIOStatus readUntil(ubyte[] buffer, void* boundary, size_t boundaryLen, out size_t nread, bool* gotBoundary, Cancellable cancellable)
263 	{
264 		GError* err = null;
265 
266 		auto __p = soup_socket_read_until(soupSocket, buffer.ptr, cast(size_t)buffer.length, boundary, boundaryLen, &nread, cast(int*)gotBoundary, (cancellable is null) ? null : cancellable.getCancellableStruct(), &err);
267 
268 		if (err !is null)
269 		{
270 			throw new GException( new ErrorG(err) );
271 		}
272 
273 		return __p;
274 	}
275 
276 	/**
277 	 * Starts using SSL on @socket, expecting to find a host named
278 	 * @ssl_host.
279 	 *
280 	 * Params:
281 	 *     sslHost = hostname of the SSL server
282 	 *     cancellable = a #GCancellable
283 	 *
284 	 * Returns: success or failure
285 	 */
286 	public bool startProxySsl(string sslHost, Cancellable cancellable)
287 	{
288 		return soup_socket_start_proxy_ssl(soupSocket, Str.toStringz(sslHost), (cancellable is null) ? null : cancellable.getCancellableStruct()) != 0;
289 	}
290 
291 	/**
292 	 * Starts using SSL on @socket.
293 	 *
294 	 * Params:
295 	 *     cancellable = a #GCancellable
296 	 *
297 	 * Returns: success or failure
298 	 */
299 	public bool startSsl(Cancellable cancellable)
300 	{
301 		return soup_socket_start_ssl(soupSocket, (cancellable is null) ? null : cancellable.getCancellableStruct()) != 0;
302 	}
303 
304 	/**
305 	 * Attempts to write @len bytes from @buffer to @sock. If some data is
306 	 * successfully written, the return status will be %SOUP_SOCKET_OK,
307 	 * and *@nwrote will contain the number of bytes actually written
308 	 * (which may be less than @len).
309 	 *
310 	 * If @sock is non-blocking, and no data could be written right away,
311 	 * the return value will be %SOUP_SOCKET_WOULD_BLOCK. In this case,
312 	 * the caller can connect to the #SoupSocket::writable signal to know
313 	 * when more data can be written. (NB: #SoupSocket::writable is only
314 	 * emitted after soup_socket_write() returns %SOUP_SOCKET_WOULD_BLOCK,
315 	 * and it is only emitted once. See the documentation for
316 	 * #SoupSocket:non-blocking.)
317 	 *
318 	 * Params:
319 	 *     buffer = data to write
320 	 *     nwrote = on return, number of bytes written
321 	 *     cancellable = a #GCancellable, or %NULL
322 	 *
323 	 * Returns: a #SoupSocketIOStatus, as described above (or
324 	 *     %SOUP_SOCKET_EOF or %SOUP_SOCKET_ERROR. @error will be set if the
325 	 *     return value is %SOUP_SOCKET_ERROR.)
326 	 *
327 	 * Throws: GException on failure.
328 	 */
329 	public SoupSocketIOStatus write(ubyte[] buffer, out size_t nwrote, Cancellable cancellable)
330 	{
331 		GError* err = null;
332 
333 		auto __p = soup_socket_write(soupSocket, buffer.ptr, cast(size_t)buffer.length, &nwrote, (cancellable is null) ? null : cancellable.getCancellableStruct(), &err);
334 
335 		if (err !is null)
336 		{
337 			throw new GException( new ErrorG(err) );
338 		}
339 
340 		return __p;
341 	}
342 
343 	/**
344 	 * Emitted when the socket is disconnected, for whatever
345 	 * reason.
346 	 */
347 	gulong addOnDisconnected(void delegate(Socket) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
348 	{
349 		return Signals.connect(this, "disconnected", dlg, connectFlags ^ ConnectFlags.SWAPPED);
350 	}
351 
352 	/**
353 	 * Emitted when a network-related event occurs. See
354 	 * #GSocketClient::event for more details.
355 	 *
356 	 * Params:
357 	 *     event = the event that occurred
358 	 *     connection = the current connection state
359 	 *
360 	 * Since: 2.38
361 	 */
362 	gulong addOnEvent(void delegate(GSocketClientEvent, IOStream, Socket) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
363 	{
364 		return Signals.connect(this, "event", dlg, connectFlags ^ ConnectFlags.SWAPPED);
365 	}
366 
367 	/**
368 	 * Emitted when a listening socket (set up with
369 	 * soup_socket_listen()) receives a new connection.
370 	 *
371 	 * You must ref the @new if you want to keep it; otherwise it
372 	 * will be destroyed after the signal is emitted.
373 	 *
374 	 * Params:
375 	 *     new_ = the new socket
376 	 */
377 	gulong addOnNewConnection(void delegate(Socket, Socket) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
378 	{
379 		return Signals.connect(this, "new-connection", dlg, connectFlags ^ ConnectFlags.SWAPPED);
380 	}
381 
382 	/**
383 	 * Emitted when an async socket is readable. See
384 	 * soup_socket_read(), soup_socket_read_until() and
385 	 * #SoupSocket:non-blocking.
386 	 */
387 	gulong addOnReadable(void delegate(Socket) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
388 	{
389 		return Signals.connect(this, "readable", dlg, connectFlags ^ ConnectFlags.SWAPPED);
390 	}
391 
392 	/**
393 	 * Emitted when an async socket is writable. See
394 	 * soup_socket_write() and #SoupSocket:non-blocking.
395 	 */
396 	gulong addOnWritable(void delegate(Socket) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
397 	{
398 		return Signals.connect(this, "writable", dlg, connectFlags ^ ConnectFlags.SWAPPED);
399 	}
400 }