* 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, write to the
- * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <stdlib.h>
#include <string.h>
-#include "gioalias.h"
/**
* SECTION:gsrvtarget
* then connect to whatever host was pointed to by that record.
*
* You can use g_resolver_lookup_service() or
- * g_resolver_lookup_service_async() to find the #GSrvTarget<!-- -->s
+ * g_resolver_lookup_service_async() to find the #GSrvTargets
* for a given service. However, if you are simply planning to connect
* to the remote service, you can use #GNetworkService's
* #GSocketConnectable interface and not need to worry about
* #GSrvTarget at all.
- **/
+ */
struct _GSrvTarget {
gchar *hostname;
* A single target host/port that a network service is running on.
*/
-GType
-g_srv_target_get_type (void)
-{
- static volatile gsize type_volatile = 0;
-
- if (g_once_init_enter (&type_volatile))
- {
- GType type = g_boxed_type_register_static (
- g_intern_static_string ("GSrvTarget"),
- (GBoxedCopyFunc) g_srv_target_copy,
- (GBoxedFreeFunc) g_srv_target_free);
- g_once_init_leave (&type_volatile, type);
- }
- return type_volatile;
-}
+G_DEFINE_BOXED_TYPE (GSrvTarget, g_srv_target,
+ g_srv_target_copy, g_srv_target_free)
/**
* g_srv_target_new:
*
* Creates a new #GSrvTarget with the given parameters.
*
- * You should not need to use this; normally #GSrvTarget<!-- -->s are
+ * You should not need to use this; normally #GSrvTargets are
* created by #GResolver.
*
- * Return value: a new #GSrvTarget.
+ * Returns: a new #GSrvTarget.
*
* Since: 2.22
- **/
+ */
GSrvTarget *
g_srv_target_new (const gchar *hostname,
guint16 port,
*
* Copies @target
*
- * Return value: a copy of @target
+ * Returns: a copy of @target
*
* Since: 2.22
- **/
+ */
GSrvTarget *
g_srv_target_copy (GSrvTarget *target)
{
* Frees @target
*
* Since: 2.22
- **/
+ */
void
g_srv_target_free (GSrvTarget *target)
{
* check if it contains encoded Unicode segments, and use
* g_hostname_to_unicode() to convert it if it does.)
*
- * Return value: @target's hostname
+ * Returns: @target's hostname
*
* Since: 2.22
- **/
+ */
const gchar *
g_srv_target_get_hostname (GSrvTarget *target)
{
*
* Gets @target's port
*
- * Return value: @target's port
+ * Returns: @target's port
*
* Since: 2.22
- **/
+ */
guint16
g_srv_target_get_port (GSrvTarget *target)
{
* #GResolver already sorts the targets according to the algorithm in
* RFC 2782.
*
- * Return value: @target's priority
+ * Returns: @target's priority
*
* Since: 2.22
- **/
+ */
guint16
g_srv_target_get_priority (GSrvTarget *target)
{
* #GResolver already sorts the targets according to the algorithm in
* RFC 2782.
*
- * Return value: @target's weight
+ * Returns: @target's weight
*
* Since: 2.22
- **/
+ */
guint16
g_srv_target_get_weight (GSrvTarget *target)
{
return target->weight;
}
-gint
+static gint
compare_target (gconstpointer a, gconstpointer b)
{
GSrvTarget *ta = (GSrvTarget *)a;
* that all those with weight 0 are placed at the beginning of
* the list"
*/
- if (ta->weight == 0)
- return -1;
- else if (tb->weight == 0)
- return 1;
- else
- return g_random_int_range (-1, 1);
+ return ta->weight - tb->weight;
}
else
return ta->priority - tb->priority;
}
/**
- * g_srv_target_list_sort:
+ * g_srv_target_list_sort: (skip)
* @targets: a #GList of #GSrvTarget
*
* Sorts @targets in place according to the algorithm in RFC 2782.
*
- * Return value: the head of the sorted list.
+ * Returns: (transfer full): the head of the sorted list.
*
* Since: 2.22
- **/
+ */
GList *
g_srv_target_list_sort (GList *targets)
{
- gint sum, val, priority, weight;
- GList *first, *last, *n;
+ gint sum, num, val, priority, weight;
+ GList *t, *out, *tail;
GSrvTarget *target;
- gpointer tmp;
if (!targets)
return NULL;
}
}
- /* Sort by priority, and partly by weight */
+ /* Sort input list by priority, and put the 0-weight targets first
+ * in each priority group. Initialize output list to %NULL.
+ */
targets = g_list_sort (targets, compare_target);
+ out = tail = NULL;
- /* For each group of targets with the same priority, rebalance them
- * according to weight.
+ /* For each group of targets with the same priority, remove them
+ * from @targets and append them to @out in a valid order.
*/
- for (first = targets; first; first = last->next)
+ while (targets)
{
- /* Skip @first to a non-0-weight target. */
- while (first && ((GSrvTarget *)first->data)->weight == 0)
- first = first->next;
- if (!first)
- break;
-
- /* Skip @last to the last target of the same priority. */
- priority = ((GSrvTarget *)first->data)->priority;
- last = first;
- while (last->next &&
- ((GSrvTarget *)last->next->data)->priority == priority)
- last = last->next;
-
- /* If there's only one non-0 weight target at this priority,
- * we can move on to the next priority level.
- */
- if (last == first)
- continue;
-
- /* Randomly reorder the non-0 weight targets, giving precedence
- * to the ones with higher weight. RFC 2782 describes this in
- * terms of assigning a running sum to each target and building
- * a new list. We do things slightly differently, but should get
- * the same result.
+ priority = ((GSrvTarget *)targets->data)->priority;
+
+ /* Count the number of targets at this priority level, and
+ * compute the sum of their weights.
*/
- for (n = first, sum = 0; n != last->next; n = n->next)
- sum += ((GSrvTarget *)n->data)->weight;
- while (first != last)
+ sum = num = 0;
+ for (t = targets; t; t = t->next)
{
- val = g_random_int_range (0, sum);
- for (n = first; n != last; n = n->next)
+ target = (GSrvTarget *)t->data;
+ if (target->priority != priority)
+ break;
+ sum += target->weight;
+ num++;
+ }
+
+ /* While there are still targets at this priority level... */
+ while (num)
+ {
+ /* Randomly select from the targets at this priority level,
+ * giving precedence to the ones with higher weight,
+ * according to the rules from RFC 2782.
+ */
+ val = g_random_int_range (0, sum + 1);
+ for (t = targets; ; t = t->next)
{
- weight = ((GSrvTarget *)n->data)->weight;
- if (val < weight)
+ weight = ((GSrvTarget *)t->data)->weight;
+ if (weight >= val)
break;
val -= weight;
}
- tmp = first->data;
- first->data = n->data;
- n->data = tmp;
+ targets = g_list_remove_link (targets, t);
+
+ if (!out)
+ out = t;
+ else
+ tail->next = t;
+ tail = t;
sum -= weight;
- first = first->next;
+ num--;
}
}
- return targets;
+ return out;
}
-
-#define __G_SRV_TARGET_C__
-#include "gioaliasdef.c"