/* * Licensed under the GNU Lesser General Public License Version 3 * * 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 3 of the license, or * (at your option) any later version. * * This software 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 . */ // generated automatically - do not change module gio.SocketService; private import gio.SocketConnection; private import gio.SocketListener; private import gio.c.functions; public import gio.c.types; private import glib.ConstructionException; private import gobject.ObjectG; private import gobject.Signals; private import std.algorithm; /** * A #GSocketService is an object that represents a service that * is provided to the network or over local sockets. When a new * connection is made to the service the #GSocketService::incoming * signal is emitted. * * A #GSocketService is a subclass of #GSocketListener and you need * to add the addresses you want to accept connections on with the * #GSocketListener APIs. * * There are two options for implementing a network service based on * #GSocketService. The first is to create the service using * g_socket_service_new() and to connect to the #GSocketService::incoming * signal. The second is to subclass #GSocketService and override the * default signal handler implementation. * * In either case, the handler must immediately return, or else it * will block additional incoming connections from being serviced. * If you are interested in writing connection handlers that contain * blocking code then see #GThreadedSocketService. * * The socket service runs on the main loop of the * [thread-default context][g-main-context-push-thread-default-context] * of the thread it is created in, and is not * threadsafe in general. However, the calls to start and stop the * service are thread-safe so these can be used from threads that * handle incoming clients. * * Since: 2.22 */ public class SocketService : SocketListener { /** the main Gtk struct */ protected GSocketService* gSocketService; /** Get the main Gtk struct */ public GSocketService* getSocketServiceStruct(bool transferOwnership = false) { if (transferOwnership) ownedRef = false; return gSocketService; } /** the main Gtk struct as a void* */ protected override void* getStruct() { return cast(void*)gSocketService; } protected override void setStruct(GObject* obj) { gSocketService = cast(GSocketService*)obj; super.setStruct(obj); } /** * Sets our main struct and passes it to the parent class. */ public this (GSocketService* gSocketService, bool ownedRef = false) { this.gSocketService = gSocketService; super(cast(GSocketListener*)gSocketService, ownedRef); } /** */ public static GType getType() { return g_socket_service_get_type(); } /** * Creates a new #GSocketService with no sockets to listen for. * New listeners can be added with e.g. g_socket_listener_add_address() * or g_socket_listener_add_inet_port(). * * Returns: a new #GSocketService. * * Since: 2.22 * * Throws: ConstructionException GTK+ fails to create the object. */ public this() { auto p = g_socket_service_new(); if(p is null) { throw new ConstructionException("null returned by new"); } this(cast(GSocketService*) p, true); } /** * Check whether the service is active or not. An active * service will accept new clients that connect, while * a non-active service will let connecting clients queue * up until the service is started. * * Returns: %TRUE if the service is active, %FALSE otherwise * * Since: 2.22 */ public bool isActive() { return g_socket_service_is_active(gSocketService) != 0; } /** * Starts the service, i.e. start accepting connections * from the added sockets when the mainloop runs. * * This call is thread-safe, so it may be called from a thread * handling an incoming client request. * * Since: 2.22 */ public void start() { g_socket_service_start(gSocketService); } /** * Stops the service, i.e. stops accepting connections * from the added sockets when the mainloop runs. * * This call is thread-safe, so it may be called from a thread * handling an incoming client request. * * Note that this only stops accepting new connections; it does not * close the listening sockets, and you can call * g_socket_service_start() again later to begin listening again. To * close the listening sockets, call g_socket_listener_close(). (This * will happen automatically when the #GSocketService is finalized.) * * Since: 2.22 */ public void stop() { g_socket_service_stop(gSocketService); } protected class OnIncomingDelegateWrapper { static OnIncomingDelegateWrapper[] listeners; bool delegate(SocketConnection, ObjectG, SocketService) dlg; gulong handlerId; this(bool delegate(SocketConnection, ObjectG, SocketService) dlg) { this.dlg = dlg; this.listeners ~= this; } void remove(OnIncomingDelegateWrapper source) { foreach(index, wrapper; listeners) { if (wrapper.handlerId == source.handlerId) { listeners[index] = null; listeners = std.algorithm.remove(listeners, index); break; } } } } /** * The ::incoming signal is emitted when a new incoming connection * to @service needs to be handled. The handler must initiate the * handling of @connection, but may not block; in essence, * asynchronous operations must be used. * * @connection will be unreffed once the signal handler returns, * so you need to ref it yourself if you are planning to use it. * * Params: * connection = a new #GSocketConnection object * sourceObject = the source_object passed to * g_socket_listener_add_address() * * Returns: %TRUE to stop other handlers from being called * * Since: 2.22 */ gulong addOnIncoming(bool delegate(SocketConnection, ObjectG, SocketService) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) { auto wrapper = new OnIncomingDelegateWrapper(dlg); wrapper.handlerId = Signals.connectData( this, "incoming", cast(GCallback)&callBackIncoming, cast(void*)wrapper, cast(GClosureNotify)&callBackIncomingDestroy, connectFlags); return wrapper.handlerId; } extern(C) static int callBackIncoming(GSocketService* socketserviceStruct, GSocketConnection* connection, GObject* sourceObject, OnIncomingDelegateWrapper wrapper) { return wrapper.dlg(ObjectG.getDObject!(SocketConnection)(connection), ObjectG.getDObject!(ObjectG)(sourceObject), wrapper.outer); } extern(C) static void callBackIncomingDestroy(OnIncomingDelegateWrapper wrapper, GClosure* closure) { wrapper.remove(wrapper); } }