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() 74 { 75 return gSocketService; 76 } 77 78 /** the main Gtk struct as a void* */ 79 protected override void* getStruct() 80 { 81 return cast(void*)gSocketService; 82 } 83 84 protected override void setStruct(GObject* obj) 85 { 86 gSocketService = cast(GSocketService*)obj; 87 super.setStruct(obj); 88 } 89 90 /** 91 * Sets our main struct and passes it to the parent class. 92 */ 93 public this (GSocketService* gSocketService, bool ownedRef = false) 94 { 95 this.gSocketService = gSocketService; 96 super(cast(GSocketListener*)gSocketService, ownedRef); 97 } 98 99 100 /** */ 101 public static GType getType() 102 { 103 return g_socket_service_get_type(); 104 } 105 106 /** 107 * Creates a new #GSocketService with no sockets to listen for. 108 * New listeners can be added with e.g. g_socket_listener_add_address() 109 * or g_socket_listener_add_inet_port(). 110 * 111 * New services are created active, there is no need to call 112 * g_socket_service_start(), unless g_socket_service_stop() has been 113 * called before. 114 * 115 * Returns: a new #GSocketService. 116 * 117 * Since: 2.22 118 * 119 * Throws: ConstructionException GTK+ fails to create the object. 120 */ 121 public this() 122 { 123 auto p = g_socket_service_new(); 124 125 if(p is null) 126 { 127 throw new ConstructionException("null returned by new"); 128 } 129 130 this(cast(GSocketService*) p, true); 131 } 132 133 /** 134 * Check whether the service is active or not. An active 135 * service will accept new clients that connect, while 136 * a non-active service will let connecting clients queue 137 * up until the service is started. 138 * 139 * Returns: %TRUE if the service is active, %FALSE otherwise 140 * 141 * Since: 2.22 142 */ 143 public bool isActive() 144 { 145 return g_socket_service_is_active(gSocketService) != 0; 146 } 147 148 /** 149 * Restarts the service, i.e. start accepting connections 150 * from the added sockets when the mainloop runs. This only needs 151 * to be called after the service has been stopped from 152 * g_socket_service_stop(). 153 * 154 * This call is thread-safe, so it may be called from a thread 155 * handling an incoming client request. 156 * 157 * Since: 2.22 158 */ 159 public void start() 160 { 161 g_socket_service_start(gSocketService); 162 } 163 164 /** 165 * Stops the service, i.e. stops accepting connections 166 * from the added sockets when the mainloop runs. 167 * 168 * This call is thread-safe, so it may be called from a thread 169 * handling an incoming client request. 170 * 171 * Note that this only stops accepting new connections; it does not 172 * close the listening sockets, and you can call 173 * g_socket_service_start() again later to begin listening again. To 174 * close the listening sockets, call g_socket_listener_close(). (This 175 * will happen automatically when the #GSocketService is finalized.) 176 * 177 * This must be called before calling g_socket_listener_close() as 178 * the socket service will start accepting connections immediately 179 * when a new socket is added. 180 * 181 * Since: 2.22 182 */ 183 public void stop() 184 { 185 g_socket_service_stop(gSocketService); 186 } 187 188 protected class OnIncomingDelegateWrapper 189 { 190 static OnIncomingDelegateWrapper[] listeners; 191 bool delegate(SocketConnection, ObjectG, SocketService) dlg; 192 gulong handlerId; 193 194 this(bool delegate(SocketConnection, ObjectG, SocketService) dlg) 195 { 196 this.dlg = dlg; 197 this.listeners ~= this; 198 } 199 200 void remove(OnIncomingDelegateWrapper source) 201 { 202 foreach(index, wrapper; listeners) 203 { 204 if (wrapper.handlerId == source.handlerId) 205 { 206 listeners[index] = null; 207 listeners = std.algorithm.remove(listeners, index); 208 break; 209 } 210 } 211 } 212 } 213 214 /** 215 * The ::incoming signal is emitted when a new incoming connection 216 * to @service needs to be handled. The handler must initiate the 217 * handling of @connection, but may not block; in essence, 218 * asynchronous operations must be used. 219 * 220 * @connection will be unreffed once the signal handler returns, 221 * so you need to ref it yourself if you are planning to use it. 222 * 223 * Params: 224 * connection = a new #GSocketConnection object 225 * sourceObject = the source_object passed to 226 * g_socket_listener_add_address() 227 * 228 * Returns: %TRUE to stop other handlers from being called 229 * 230 * Since: 2.22 231 */ 232 gulong addOnIncoming(bool delegate(SocketConnection, ObjectG, SocketService) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 233 { 234 auto wrapper = new OnIncomingDelegateWrapper(dlg); 235 wrapper.handlerId = Signals.connectData( 236 this, 237 "incoming", 238 cast(GCallback)&callBackIncoming, 239 cast(void*)wrapper, 240 cast(GClosureNotify)&callBackIncomingDestroy, 241 connectFlags); 242 return wrapper.handlerId; 243 } 244 245 extern(C) static int callBackIncoming(GSocketService* socketserviceStruct, GSocketConnection* connection, GObject* sourceObject, OnIncomingDelegateWrapper wrapper) 246 { 247 return wrapper.dlg(ObjectG.getDObject!(SocketConnection)(connection), ObjectG.getDObject!(ObjectG)(sourceObject), wrapper.outer); 248 } 249 250 extern(C) static void callBackIncomingDestroy(OnIncomingDelegateWrapper wrapper, GClosure* closure) 251 { 252 wrapper.remove(wrapper); 253 } 254 }