Updated French translation
[glib.git] / gio / gsrvtarget.c
blob526b0ddfbfa1fdd381243994f5fd316dd191edbb
1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
3 /* GIO - GLib Input, Output and Streaming Library
5 * Copyright (C) 2008 Red Hat, Inc.
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General
18 * Public License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
20 * Boston, MA 02111-1307, USA.
23 #include "config.h"
24 #include <glib.h>
25 #include "glibintl.h"
27 #include "gsrvtarget.h"
29 #include <stdlib.h>
30 #include <string.h>
32 #include "gioalias.h"
34 /**
35 * SECTION:gsrvtarget
36 * @short_description: DNS SRV record target
37 * @include: gio/gio.h
39 * SRV (service) records are used by some network protocols to provide
40 * service-specific aliasing and load-balancing. For example, XMPP
41 * (Jabber) uses SRV records to locate the XMPP server for a domain;
42 * rather than connecting directly to "example.com" or assuming a
43 * specific server hostname like "xmpp.example.com", an XMPP client
44 * would look up the "xmpp-client" SRV record for "example.com", and
45 * then connect to whatever host was pointed to by that record.
47 * You can use g_resolver_lookup_service() or
48 * g_resolver_lookup_service_async() to find the #GSrvTarget<!-- -->s
49 * for a given service. However, if you are simply planning to connect
50 * to the remote service, you can use #GNetworkService's
51 * #GSocketConnectable interface and not need to worry about
52 * #GSrvTarget at all.
55 struct _GSrvTarget {
56 gchar *hostname;
57 guint16 port;
59 guint16 priority;
60 guint16 weight;
63 /**
64 * GSrvTarget:
66 * A single target host/port that a network service is running on.
69 GType
70 g_srv_target_get_type (void)
72 static volatile gsize type_volatile = 0;
74 if (g_once_init_enter (&type_volatile))
76 GType type = g_boxed_type_register_static (
77 g_intern_static_string ("GSrvTarget"),
78 (GBoxedCopyFunc) g_srv_target_copy,
79 (GBoxedFreeFunc) g_srv_target_free);
80 g_once_init_leave (&type_volatile, type);
82 return type_volatile;
85 /**
86 * g_srv_target_new:
87 * @hostname: the host that the service is running on
88 * @port: the port that the service is running on
89 * @priority: the target's priority
90 * @weight: the target's weight
92 * Creates a new #GSrvTarget with the given parameters.
94 * You should not need to use this; normally #GSrvTarget<!-- -->s are
95 * created by #GResolver.
97 * Return value: a new #GSrvTarget.
99 * Since: 2.22
101 GSrvTarget *
102 g_srv_target_new (const gchar *hostname,
103 guint16 port,
104 guint16 priority,
105 guint16 weight)
107 GSrvTarget *target = g_slice_new0 (GSrvTarget);
109 target->hostname = g_strdup (hostname);
110 target->port = port;
111 target->priority = priority;
112 target->weight = weight;
114 return target;
118 * g_srv_target_copy:
119 * @target: a #GSrvTarget
121 * Copies @target
123 * Return value: a copy of @target
125 * Since: 2.22
127 GSrvTarget *
128 g_srv_target_copy (GSrvTarget *target)
130 return g_srv_target_new (target->hostname, target->port,
131 target->priority, target->weight);
135 * g_srv_target_free:
136 * @target: a #GSrvTarget
138 * Frees @target
140 * Since: 2.22
142 void
143 g_srv_target_free (GSrvTarget *target)
145 g_free (target->hostname);
146 g_slice_free (GSrvTarget, target);
150 * g_srv_target_get_hostname:
151 * @target: a #GSrvTarget
153 * Gets @target's hostname (in ASCII form; if you are going to present
154 * this to the user, you should use g_hostname_is_ascii_encoded() to
155 * check if it contains encoded Unicode segments, and use
156 * g_hostname_to_unicode() to convert it if it does.)
158 * Return value: @target's hostname
160 * Since: 2.22
162 const gchar *
163 g_srv_target_get_hostname (GSrvTarget *target)
165 return target->hostname;
169 * g_srv_target_get_port:
170 * @target: a #GSrvTarget
172 * Gets @target's port
174 * Return value: @target's port
176 * Since: 2.22
178 guint16
179 g_srv_target_get_port (GSrvTarget *target)
181 return target->port;
185 * g_srv_target_get_priority:
186 * @target: a #GSrvTarget
188 * Gets @target's priority. You should not need to look at this;
189 * #GResolver already sorts the targets according to the algorithm in
190 * RFC 2782.
192 * Return value: @target's priority
194 * Since: 2.22
196 guint16
197 g_srv_target_get_priority (GSrvTarget *target)
199 return target->priority;
203 * g_srv_target_get_weight:
204 * @target: a #GSrvTarget
206 * Gets @target's weight. You should not need to look at this;
207 * #GResolver already sorts the targets according to the algorithm in
208 * RFC 2782.
210 * Return value: @target's weight
212 * Since: 2.22
214 guint16
215 g_srv_target_get_weight (GSrvTarget *target)
217 return target->weight;
220 gint
221 compare_target (gconstpointer a, gconstpointer b)
223 GSrvTarget *ta = (GSrvTarget *)a;
224 GSrvTarget *tb = (GSrvTarget *)b;
226 if (ta->priority == tb->priority)
228 /* Arrange targets of the same priority "in any order, except
229 * that all those with weight 0 are placed at the beginning of
230 * the list"
232 return ta->weight - tb->weight;
234 else
235 return ta->priority - tb->priority;
239 * g_srv_target_list_sort:
240 * @targets: a #GList of #GSrvTarget
242 * Sorts @targets in place according to the algorithm in RFC 2782.
244 * Return value: the head of the sorted list.
246 * Since: 2.22
248 GList *
249 g_srv_target_list_sort (GList *targets)
251 gint sum, num, val, priority, weight;
252 GList *t, *out, *tail;
253 GSrvTarget *target;
255 if (!targets)
256 return NULL;
258 if (!targets->next)
260 target = targets->data;
261 if (!strcmp (target->hostname, "."))
263 /* 'A Target of "." means that the service is decidedly not
264 * available at this domain.'
266 g_srv_target_free (target);
267 g_list_free (targets);
268 return NULL;
272 /* Sort input list by priority, and put the 0-weight targets first
273 * in each priority group. Initialize output list to %NULL.
275 targets = g_list_sort (targets, compare_target);
276 out = tail = NULL;
278 /* For each group of targets with the same priority, remove them
279 * from @targets and append them to @out in a valid order.
281 while (targets)
283 priority = ((GSrvTarget *)targets->data)->priority;
285 /* Count the number of targets at this priority level, and
286 * compute the sum of their weights.
288 sum = num = 0;
289 for (t = targets; t; t = t->next)
291 target = (GSrvTarget *)t->data;
292 if (target->priority != priority)
293 break;
294 sum += target->weight;
295 num++;
298 /* While there are still targets at this priority level... */
299 while (num)
301 /* Randomly select from the targets at this priority level,
302 * giving precedence to the ones with higher weight,
303 * according to the rules from RFC 2782.
305 val = g_random_int_range (0, sum + 1);
306 for (t = targets; ; t = t->next)
308 weight = ((GSrvTarget *)t->data)->weight;
309 if (weight >= val)
310 break;
311 val -= weight;
314 targets = g_list_remove_link (targets, t);
316 if (!out)
317 out = t;
318 else
319 tail->next = t;
320 tail = t;
322 sum -= weight;
323 num--;
327 return out;
330 #define __G_SRV_TARGET_C__
331 #include "gioaliasdef.c"