1 /* 2 * This file is part of gtkD. 3 * 4 * gtkD is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU Lesser General Public License 6 * as published by the Free Software Foundation; either version 3 7 * of the License, or (at your option) any later version, with 8 * some exceptions, please read the COPYING file. 9 * 10 * gtkD is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU Lesser General Public License for more details. 14 * 15 * You should have received a copy of the GNU Lesser General Public License 16 * along with gtkD; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA 18 */ 19 20 // generated automatically - do not change 21 // find conversion definition on APILookup.txt 22 // implement new conversion functionalities on the wrap.utils pakage 23 24 25 module gio.SocketService; 26 27 private import gio.SocketConnection; 28 private import gio.SocketListener; 29 private import glib.ConstructionException; 30 private import gobject.ObjectG; 31 private import gobject.Signals; 32 private import gtkc.gio; 33 public import gtkc.giotypes; 34 private import std.algorithm; 35 36 37 /** 38 * A #GSocketService is an object that represents a service that 39 * is provided to the network or over local sockets. When a new 40 * connection is made to the service the #GSocketService::incoming 41 * signal is emitted. 42 * 43 * A #GSocketService is a subclass of #GSocketListener and you need 44 * to add the addresses you want to accept connections on with the 45 * #GSocketListener APIs. 46 * 47 * There are two options for implementing a network service based on 48 * #GSocketService. The first is to create the service using 49 * g_socket_service_new() and to connect to the #GSocketService::incoming 50 * signal. The second is to subclass #GSocketService and override the 51 * default signal handler implementation. 52 * 53 * In either case, the handler must immediately return, or else it 54 * will block additional incoming connections from being serviced. 55 * If you are interested in writing connection handlers that contain 56 * blocking code then see #GThreadedSocketService. 57 * 58 * The socket service runs on the main loop of the 59 * [thread-default context][g-main-context-push-thread-default-context] 60 * of the thread it is created in, and is not 61 * threadsafe in general. However, the calls to start and stop the 62 * service are thread-safe so these can be used from threads that 63 * handle incoming clients. 64 * 65 * Since: 2.22 66 */ 67 public class SocketService : SocketListener 68 { 69 /** the main Gtk struct */ 70 protected GSocketService* gSocketService; 71 72 /** Get the main Gtk struct */ 73 public GSocketService* getSocketServiceStruct(bool transferOwnership = false) 74 { 75 if (transferOwnership) 76 ownedRef = false; 77 return gSocketService; 78 } 79 80 /** the main Gtk struct as a void* */ 81 protected override void* getStruct() 82 { 83 return cast(void*)gSocketService; 84 } 85 86 protected override void setStruct(GObject* obj) 87 { 88 gSocketService = cast(GSocketService*)obj; 89 super.setStruct(obj); 90 } 91 92 /** 93 * Sets our main struct and passes it to the parent class. 94 */ 95 public this (GSocketService* gSocketService, bool ownedRef = false) 96 { 97 this.gSocketService = gSocketService; 98 super(cast(GSocketListener*)gSocketService, ownedRef); 99 } 100 101 102 /** */ 103 public static GType getType() 104 { 105 return g_socket_service_get_type(); 106 } 107 108 /** 109 * Creates a new #GSocketService with no sockets to listen for. 110 * New listeners can be added with e.g. g_socket_listener_add_address() 111 * or g_socket_listener_add_inet_port(). 112 * 113 * New services are created active, there is no need to call 114 * g_socket_service_start(), unless g_socket_service_stop() has been 115 * called before. 116 * 117 * Returns: a new #GSocketService. 118 * 119 * Since: 2.22 120 * 121 * Throws: ConstructionException GTK+ fails to create the object. 122 */ 123 public this() 124 { 125 auto p = g_socket_service_new(); 126 127 if(p is null) 128 { 129 throw new ConstructionException("null returned by new"); 130 } 131 132 this(cast(GSocketService*) p, true); 133 } 134 135 /** 136 * Check whether the service is active or not. An active 137 * service will accept new clients that connect, while 138 * a non-active service will let connecting clients queue 139 * up until the service is started. 140 * 141 * Returns: %TRUE if the service is active, %FALSE otherwise 142 * 143 * Since: 2.22 144 */ 145 public bool isActive() 146 { 147 return g_socket_service_is_active(gSocketService) != 0; 148 } 149 150 /** 151 * Restarts the service, i.e. start accepting connections 152 * from the added sockets when the mainloop runs. This only needs 153 * to be called after the service has been stopped from 154 * g_socket_service_stop(). 155 * 156 * This call is thread-safe, so it may be called from a thread 157 * handling an incoming client request. 158 * 159 * Since: 2.22 160 */ 161 public void start() 162 { 163 g_socket_service_start(gSocketService); 164 } 165 166 /** 167 * Stops the service, i.e. stops accepting connections 168 * from the added sockets when the mainloop runs. 169 * 170 * This call is thread-safe, so it may be called from a thread 171 * handling an incoming client request. 172 * 173 * Note that this only stops accepting new connections; it does not 174 * close the listening sockets, and you can call 175 * g_socket_service_start() again later to begin listening again. To 176 * close the listening sockets, call g_socket_listener_close(). (This 177 * will happen automatically when the #GSocketService is finalized.) 178 * 179 * This must be called before calling g_socket_listener_close() as 180 * the socket service will start accepting connections immediately 181 * when a new socket is added. 182 * 183 * Since: 2.22 184 */ 185 public void stop() 186 { 187 g_socket_service_stop(gSocketService); 188 } 189 190 protected class OnIncomingDelegateWrapper 191 { 192 static OnIncomingDelegateWrapper[] listeners; 193 bool delegate(SocketConnection, ObjectG, SocketService) dlg; 194 gulong handlerId; 195 196 this(bool delegate(SocketConnection, ObjectG, SocketService) dlg) 197 { 198 this.dlg = dlg; 199 this.listeners ~= this; 200 } 201 202 void remove(OnIncomingDelegateWrapper source) 203 { 204 foreach(index, wrapper; listeners) 205 { 206 if (wrapper.handlerId == source.handlerId) 207 { 208 listeners[index] = null; 209 listeners = std.algorithm.remove(listeners, index); 210 break; 211 } 212 } 213 } 214 } 215 216 /** 217 * The ::incoming signal is emitted when a new incoming connection 218 * to @service needs to be handled. The handler must initiate the 219 * handling of @connection, but may not block; in essence, 220 * asynchronous operations must be used. 221 * 222 * @connection will be unreffed once the signal handler returns, 223 * so you need to ref it yourself if you are planning to use it. 224 * 225 * Params: 226 * connection = a new #GSocketConnection object 227 * sourceObject = the source_object passed to 228 * g_socket_listener_add_address() 229 * 230 * Returns: %TRUE to stop other handlers from being called 231 * 232 * Since: 2.22 233 */ 234 gulong addOnIncoming(bool delegate(SocketConnection, ObjectG, SocketService) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 235 { 236 auto wrapper = new OnIncomingDelegateWrapper(dlg); 237 wrapper.handlerId = Signals.connectData( 238 this, 239 "incoming", 240 cast(GCallback)&callBackIncoming, 241 cast(void*)wrapper, 242 cast(GClosureNotify)&callBackIncomingDestroy, 243 connectFlags); 244 return wrapper.handlerId; 245 } 246 247 extern(C) static int callBackIncoming(GSocketService* socketserviceStruct, GSocketConnection* connection, GObject* sourceObject, OnIncomingDelegateWrapper wrapper) 248 { 249 return wrapper.dlg(ObjectG.getDObject!(SocketConnection)(connection), ObjectG.getDObject!(ObjectG)(sourceObject), wrapper.outer); 250 } 251 252 extern(C) static void callBackIncomingDestroy(OnIncomingDelegateWrapper wrapper, GClosure* closure) 253 { 254 wrapper.remove(wrapper); 255 } 256 }