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, see <http://www.gnu.org/licenses/>.
25 #include "gsrvtarget.h"
33 * @short_description: DNS SRV record target
36 * SRV (service) records are used by some network protocols to provide
37 * service-specific aliasing and load-balancing. For example, XMPP
38 * (Jabber) uses SRV records to locate the XMPP server for a domain;
39 * rather than connecting directly to "example.com" or assuming a
40 * specific server hostname like "xmpp.example.com", an XMPP client
41 * would look up the "xmpp-client" SRV record for "example.com", and
42 * then connect to whatever host was pointed to by that record.
44 * You can use g_resolver_lookup_service() or
45 * g_resolver_lookup_service_async() to find the #GSrvTargets
46 * for a given service. However, if you are simply planning to connect
47 * to the remote service, you can use #GNetworkService's
48 * #GSocketConnectable interface and not need to worry about
63 * A single target host/port that a network service is running on.
66 G_DEFINE_BOXED_TYPE (GSrvTarget
, g_srv_target
,
67 g_srv_target_copy
, g_srv_target_free
)
71 * @hostname: the host that the service is running on
72 * @port: the port that the service is running on
73 * @priority: the target's priority
74 * @weight: the target's weight
76 * Creates a new #GSrvTarget with the given parameters.
78 * You should not need to use this; normally #GSrvTargets are
79 * created by #GResolver.
81 * Returns: a new #GSrvTarget.
86 g_srv_target_new (const gchar
*hostname
,
91 GSrvTarget
*target
= g_slice_new0 (GSrvTarget
);
93 target
->hostname
= g_strdup (hostname
);
95 target
->priority
= priority
;
96 target
->weight
= weight
;
103 * @target: a #GSrvTarget
107 * Returns: a copy of @target
112 g_srv_target_copy (GSrvTarget
*target
)
114 return g_srv_target_new (target
->hostname
, target
->port
,
115 target
->priority
, target
->weight
);
120 * @target: a #GSrvTarget
127 g_srv_target_free (GSrvTarget
*target
)
129 g_free (target
->hostname
);
130 g_slice_free (GSrvTarget
, target
);
134 * g_srv_target_get_hostname:
135 * @target: a #GSrvTarget
137 * Gets @target's hostname (in ASCII form; if you are going to present
138 * this to the user, you should use g_hostname_is_ascii_encoded() to
139 * check if it contains encoded Unicode segments, and use
140 * g_hostname_to_unicode() to convert it if it does.)
142 * Returns: @target's hostname
147 g_srv_target_get_hostname (GSrvTarget
*target
)
149 return target
->hostname
;
153 * g_srv_target_get_port:
154 * @target: a #GSrvTarget
156 * Gets @target's port
158 * Returns: @target's port
163 g_srv_target_get_port (GSrvTarget
*target
)
169 * g_srv_target_get_priority:
170 * @target: a #GSrvTarget
172 * Gets @target's priority. You should not need to look at this;
173 * #GResolver already sorts the targets according to the algorithm in
176 * Returns: @target's priority
181 g_srv_target_get_priority (GSrvTarget
*target
)
183 return target
->priority
;
187 * g_srv_target_get_weight:
188 * @target: a #GSrvTarget
190 * Gets @target's weight. You should not need to look at this;
191 * #GResolver already sorts the targets according to the algorithm in
194 * Returns: @target's weight
199 g_srv_target_get_weight (GSrvTarget
*target
)
201 return target
->weight
;
205 compare_target (gconstpointer a
, gconstpointer b
)
207 GSrvTarget
*ta
= (GSrvTarget
*)a
;
208 GSrvTarget
*tb
= (GSrvTarget
*)b
;
210 if (ta
->priority
== tb
->priority
)
212 /* Arrange targets of the same priority "in any order, except
213 * that all those with weight 0 are placed at the beginning of
216 return ta
->weight
- tb
->weight
;
219 return ta
->priority
- tb
->priority
;
223 * g_srv_target_list_sort: (skip)
224 * @targets: a #GList of #GSrvTarget
226 * Sorts @targets in place according to the algorithm in RFC 2782.
228 * Returns: (transfer full): the head of the sorted list.
233 g_srv_target_list_sort (GList
*targets
)
235 gint sum
, num
, val
, priority
, weight
;
236 GList
*t
, *out
, *tail
;
244 target
= targets
->data
;
245 if (!strcmp (target
->hostname
, "."))
247 /* 'A Target of "." means that the service is decidedly not
248 * available at this domain.'
250 g_srv_target_free (target
);
251 g_list_free (targets
);
256 /* Sort input list by priority, and put the 0-weight targets first
257 * in each priority group. Initialize output list to %NULL.
259 targets
= g_list_sort (targets
, compare_target
);
262 /* For each group of targets with the same priority, remove them
263 * from @targets and append them to @out in a valid order.
267 priority
= ((GSrvTarget
*)targets
->data
)->priority
;
269 /* Count the number of targets at this priority level, and
270 * compute the sum of their weights.
273 for (t
= targets
; t
; t
= t
->next
)
275 target
= (GSrvTarget
*)t
->data
;
276 if (target
->priority
!= priority
)
278 sum
+= target
->weight
;
282 /* While there are still targets at this priority level... */
285 /* Randomly select from the targets at this priority level,
286 * giving precedence to the ones with higher weight,
287 * according to the rules from RFC 2782.
289 val
= g_random_int_range (0, sum
+ 1);
290 for (t
= targets
; ; t
= t
->next
)
292 weight
= ((GSrvTarget
*)t
->data
)->weight
;
298 targets
= g_list_remove_link (targets
, t
);