Drop use of xinclude in GTestDBus docs
[platform/upstream/glib.git] / gio / gnetworkservice.c
1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2
3 /* GIO - GLib Input, Output and Streaming Library
4  *
5  * Copyright (C) 2008 Red Hat, Inc.
6  *
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.
11  *
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.
16  *
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/>.
19  */
20
21 #include "config.h"
22 #include <glib.h>
23 #include "glibintl.h"
24
25 #include "gnetworkservice.h"
26
27 #include "gcancellable.h"
28 #include "ginetaddress.h"
29 #include "ginetsocketaddress.h"
30 #include "gioerror.h"
31 #include "gnetworkaddress.h"
32 #include "gnetworkingprivate.h"
33 #include "gresolver.h"
34 #include "gtask.h"
35 #include "gsocketaddressenumerator.h"
36 #include "gsocketconnectable.h"
37 #include "gsrvtarget.h"
38
39 #include <stdlib.h>
40 #include <string.h>
41
42
43 /**
44  * SECTION:gnetworkservice
45  * @short_description: A GSocketConnectable for resolving SRV records
46  * @include: gio/gio.h
47  *
48  * Like #GNetworkAddress does with hostnames, #GNetworkService
49  * provides an easy way to resolve a SRV record, and then attempt to
50  * connect to one of the hosts that implements that service, handling
51  * service priority/weighting, multiple IP addresses, and multiple
52  * address families.
53  *
54  * See #GSrvTarget for more information about SRV records, and see
55  * #GSocketConnectable for and example of using the connectable
56  * interface.
57  */
58
59 /**
60  * GNetworkService:
61  *
62  * A #GSocketConnectable for resolving a SRV record and connecting to
63  * that service.
64  */
65
66 struct _GNetworkServicePrivate
67 {
68   gchar *service, *protocol, *domain, *scheme;
69   GList *targets;
70 };
71
72 enum {
73   PROP_0,
74   PROP_SERVICE,
75   PROP_PROTOCOL,
76   PROP_DOMAIN,
77   PROP_SCHEME
78 };
79
80 static void g_network_service_set_property (GObject      *object,
81                                             guint         prop_id,
82                                             const GValue *value,
83                                             GParamSpec   *pspec);
84 static void g_network_service_get_property (GObject      *object,
85                                             guint         prop_id,
86                                             GValue       *value,
87                                             GParamSpec   *pspec);
88
89 static void                      g_network_service_connectable_iface_init       (GSocketConnectableIface *iface);
90 static GSocketAddressEnumerator *g_network_service_connectable_enumerate        (GSocketConnectable      *connectable);
91 static GSocketAddressEnumerator *g_network_service_connectable_proxy_enumerate  (GSocketConnectable      *connectable);
92
93 G_DEFINE_TYPE_WITH_CODE (GNetworkService, g_network_service, G_TYPE_OBJECT,
94                          G_ADD_PRIVATE (GNetworkService)
95                          G_IMPLEMENT_INTERFACE (G_TYPE_SOCKET_CONNECTABLE,
96                                                 g_network_service_connectable_iface_init))
97
98 static void
99 g_network_service_finalize (GObject *object)
100 {
101   GNetworkService *srv = G_NETWORK_SERVICE (object);
102
103   g_free (srv->priv->service);
104   g_free (srv->priv->protocol);
105   g_free (srv->priv->domain);
106   g_free (srv->priv->scheme);
107
108   if (srv->priv->targets)
109     g_resolver_free_targets (srv->priv->targets);
110
111   G_OBJECT_CLASS (g_network_service_parent_class)->finalize (object);
112 }
113
114 static void
115 g_network_service_class_init (GNetworkServiceClass *klass)
116 {
117   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
118
119   gobject_class->set_property = g_network_service_set_property;
120   gobject_class->get_property = g_network_service_get_property;
121   gobject_class->finalize = g_network_service_finalize;
122
123   g_object_class_install_property (gobject_class, PROP_SERVICE,
124                                    g_param_spec_string ("service",
125                                                         P_("Service"),
126                                                         P_("Service name, eg \"ldap\""),
127                                                         NULL,
128                                                         G_PARAM_READWRITE |
129                                                         G_PARAM_CONSTRUCT_ONLY |
130                                                         G_PARAM_STATIC_STRINGS));
131   g_object_class_install_property (gobject_class, PROP_PROTOCOL,
132                                    g_param_spec_string ("protocol",
133                                                         P_("Protocol"),
134                                                         P_("Network protocol, eg \"tcp\""),
135                                                         NULL,
136                                                         G_PARAM_READWRITE |
137                                                         G_PARAM_CONSTRUCT_ONLY |
138                                                         G_PARAM_STATIC_STRINGS));
139   g_object_class_install_property (gobject_class, PROP_DOMAIN,
140                                    g_param_spec_string ("domain",
141                                                         P_("Domain"),
142                                                         P_("Network domain, eg, \"example.com\""),
143                                                         NULL,
144                                                         G_PARAM_READWRITE |
145                                                         G_PARAM_CONSTRUCT_ONLY |
146                                                         G_PARAM_STATIC_STRINGS));
147   g_object_class_install_property (gobject_class, PROP_DOMAIN,
148                                    g_param_spec_string ("scheme",
149                                                         P_("Scheme"),
150                                                         P_("Network scheme (default is to use service)"),
151                                                         NULL,
152                                                         G_PARAM_READWRITE |
153                                                         G_PARAM_STATIC_STRINGS));
154
155 }
156
157 static void
158 g_network_service_connectable_iface_init (GSocketConnectableIface *connectable_iface)
159 {
160   connectable_iface->enumerate = g_network_service_connectable_enumerate;
161   connectable_iface->proxy_enumerate = g_network_service_connectable_proxy_enumerate;
162 }
163
164 static void
165 g_network_service_init (GNetworkService *srv)
166 {
167   srv->priv = g_network_service_get_instance_private (srv);
168 }
169
170 static void
171 g_network_service_set_property (GObject      *object,
172                                 guint         prop_id,
173                                 const GValue *value,
174                                 GParamSpec   *pspec)
175 {
176   GNetworkService *srv = G_NETWORK_SERVICE (object);
177
178   switch (prop_id)
179     {
180     case PROP_SERVICE:
181       srv->priv->service = g_value_dup_string (value);
182       break;
183
184     case PROP_PROTOCOL:
185       srv->priv->protocol = g_value_dup_string (value);
186       break;
187
188     case PROP_DOMAIN:
189       srv->priv->domain = g_value_dup_string (value);
190       break;
191
192     case PROP_SCHEME:
193       g_network_service_set_scheme (srv, g_value_get_string (value));
194       break;
195
196     default:
197       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
198       break;
199     }
200 }
201
202 static void
203 g_network_service_get_property (GObject    *object,
204                                 guint       prop_id,
205                                 GValue     *value,
206                                 GParamSpec *pspec)
207 {
208   GNetworkService *srv = G_NETWORK_SERVICE (object);
209
210   switch (prop_id)
211     {
212     case PROP_SERVICE:
213       g_value_set_string (value, g_network_service_get_service (srv));
214       break;
215
216     case PROP_PROTOCOL:
217       g_value_set_string (value, g_network_service_get_protocol (srv));
218       break;
219
220     case PROP_DOMAIN:
221       g_value_set_string (value, g_network_service_get_domain (srv));
222       break;
223
224     case PROP_SCHEME:
225       g_value_set_string (value, g_network_service_get_scheme (srv));
226       break;
227
228     default:
229       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
230       break;
231     }
232 }
233
234 /**
235  * g_network_service_new:
236  * @service: the service type to look up (eg, "ldap")
237  * @protocol: the networking protocol to use for @service (eg, "tcp")
238  * @domain: the DNS domain to look up the service in
239  *
240  * Creates a new #GNetworkService representing the given @service,
241  * @protocol, and @domain. This will initially be unresolved; use the
242  * #GSocketConnectable interface to resolve it.
243  *
244  * Return value: (transfer full) (type GNetworkService): a new #GNetworkService
245  *
246  * Since: 2.22
247  */
248 GSocketConnectable *
249 g_network_service_new (const gchar *service,
250                        const gchar *protocol,
251                        const gchar *domain)
252 {
253   return g_object_new (G_TYPE_NETWORK_SERVICE,
254                        "service", service,
255                        "protocol", protocol,
256                        "domain", domain,
257                        NULL);
258 }
259
260 /**
261  * g_network_service_get_service:
262  * @srv: a #GNetworkService
263  *
264  * Gets @srv's service name (eg, "ldap").
265  *
266  * Return value: @srv's service name
267  *
268  * Since: 2.22
269  */
270 const gchar *
271 g_network_service_get_service (GNetworkService *srv)
272 {
273   g_return_val_if_fail (G_IS_NETWORK_SERVICE (srv), NULL);
274
275   return srv->priv->service;
276 }
277
278 /**
279  * g_network_service_get_protocol:
280  * @srv: a #GNetworkService
281  *
282  * Gets @srv's protocol name (eg, "tcp").
283  *
284  * Return value: @srv's protocol name
285  *
286  * Since: 2.22
287  */
288 const gchar *
289 g_network_service_get_protocol (GNetworkService *srv)
290 {
291   g_return_val_if_fail (G_IS_NETWORK_SERVICE (srv), NULL);
292
293   return srv->priv->protocol;
294 }
295
296 /**
297  * g_network_service_get_domain:
298  * @srv: a #GNetworkService
299  *
300  * Gets the domain that @srv serves. This might be either UTF-8 or
301  * ASCII-encoded, depending on what @srv was created with.
302  *
303  * Return value: @srv's domain name
304  *
305  * Since: 2.22
306  */
307 const gchar *
308 g_network_service_get_domain (GNetworkService *srv)
309 {
310   g_return_val_if_fail (G_IS_NETWORK_SERVICE (srv), NULL);
311
312   return srv->priv->domain;
313 }
314
315 /**
316  * g_network_service_get_scheme:
317  * @srv: a #GNetworkService
318  *
319  * Get's the URI scheme used to resolve proxies. By default, the service name
320  * is used as scheme.
321  *
322  * Return value: @srv's scheme name
323  *
324  * Since: 2.26
325  */
326 const gchar *
327 g_network_service_get_scheme (GNetworkService *srv)
328 {
329   g_return_val_if_fail (G_IS_NETWORK_SERVICE (srv), NULL);
330
331   if (srv->priv->scheme)
332     return srv->priv->scheme;
333   else
334     return srv->priv->service;
335 }
336
337 /**
338  * g_network_service_set_scheme:
339  * @srv: a #GNetworkService
340  * @scheme: a URI scheme
341  *
342  * Set's the URI scheme used to resolve proxies. By default, the service name
343  * is used as scheme.
344  *
345  * Since: 2.26
346  */
347 void
348 g_network_service_set_scheme (GNetworkService *srv,
349                               const gchar     *scheme)
350 {
351   g_return_if_fail (G_IS_NETWORK_SERVICE (srv));
352
353   if (srv->priv->scheme)
354     g_free (srv->priv->scheme);
355   srv->priv->scheme = g_strdup (scheme);
356
357   g_object_notify (G_OBJECT (srv), "scheme");
358 }
359
360 static GList *
361 g_network_service_fallback_targets (GNetworkService *srv)
362 {
363   GSrvTarget *target;
364   struct servent *entry;
365   guint16 port;
366
367   entry = getservbyname (srv->priv->service, "tcp");
368   port = entry ? g_ntohs (entry->s_port) : 0;
369 #ifdef HAVE_ENDSERVENT
370   endservent ();
371 #endif
372
373   if (entry == NULL)
374       return NULL;
375
376   target = g_srv_target_new (srv->priv->domain, port, 0, 0);
377   return g_list_append (NULL, target);
378 }
379
380 #define G_TYPE_NETWORK_SERVICE_ADDRESS_ENUMERATOR (_g_network_service_address_enumerator_get_type ())
381 #define G_NETWORK_SERVICE_ADDRESS_ENUMERATOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_NETWORK_SERVICE_ADDRESS_ENUMERATOR, GNetworkServiceAddressEnumerator))
382
383 typedef struct {
384   GSocketAddressEnumerator parent_instance;
385
386   GResolver *resolver;
387   GNetworkService *srv;
388   GSocketAddressEnumerator *addr_enum;
389   GList *t;
390   gboolean use_proxy;
391
392   GError *error;
393
394 } GNetworkServiceAddressEnumerator;
395
396 typedef struct {
397   GSocketAddressEnumeratorClass parent_class;
398
399 } GNetworkServiceAddressEnumeratorClass;
400
401 static GType _g_network_service_address_enumerator_get_type (void);
402 G_DEFINE_TYPE (GNetworkServiceAddressEnumerator, _g_network_service_address_enumerator, G_TYPE_SOCKET_ADDRESS_ENUMERATOR)
403
404 static GSocketAddress *
405 g_network_service_address_enumerator_next (GSocketAddressEnumerator  *enumerator,
406                                            GCancellable              *cancellable,
407                                            GError                   **error)
408 {
409   GNetworkServiceAddressEnumerator *srv_enum =
410     G_NETWORK_SERVICE_ADDRESS_ENUMERATOR (enumerator);
411   GSocketAddress *ret = NULL;
412
413   /* If we haven't yet resolved srv, do that */
414   if (!srv_enum->srv->priv->targets)
415     {
416       GList *targets;
417       GError *my_error = NULL;
418
419       targets = g_resolver_lookup_service (srv_enum->resolver,
420                                            srv_enum->srv->priv->service,
421                                            srv_enum->srv->priv->protocol,
422                                            srv_enum->srv->priv->domain,
423                                            cancellable, &my_error);
424       if (!targets && g_error_matches (my_error, G_RESOLVER_ERROR,
425                                        G_RESOLVER_ERROR_NOT_FOUND))
426         {
427           targets = g_network_service_fallback_targets (srv_enum->srv);
428           if (targets)
429             g_clear_error (&my_error);
430         }
431
432       if (my_error)
433         {
434           g_propagate_error (error, my_error);
435           return NULL;
436         }
437
438       srv_enum->srv->priv->targets = targets;
439       srv_enum->t = srv_enum->srv->priv->targets;
440     }
441
442   /* Delegate to GNetworkAddress */
443   do
444     {
445       if (srv_enum->addr_enum == NULL && srv_enum->t)
446         {
447           GError *error = NULL;
448           gchar *uri;
449           gchar *hostname;
450           GSocketConnectable *addr;
451           GSrvTarget *target = srv_enum->t->data;
452
453           srv_enum->t = g_list_next (srv_enum->t);
454
455           hostname = g_hostname_to_ascii (g_srv_target_get_hostname (target));
456
457           if (hostname == NULL)
458             {
459               if (srv_enum->error == NULL)
460                 srv_enum->error =
461                   g_error_new (G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
462                                "Received invalid hostname '%s' from GSrvTarget",
463                                g_srv_target_get_hostname (target));
464               continue;
465             }
466
467           uri = _g_uri_from_authority (g_network_service_get_scheme (srv_enum->srv),
468                                        hostname,
469                                        g_srv_target_get_port (target),
470                                        NULL);
471           g_free (hostname);
472
473           addr = g_network_address_parse_uri (uri,
474                                               g_srv_target_get_port (target),
475                                               &error);
476           g_free (uri);
477
478           if (addr == NULL)
479             {
480               if (srv_enum->error == NULL)
481                 srv_enum->error = error;
482               continue;
483             }
484
485           if (srv_enum->use_proxy)
486             srv_enum->addr_enum = g_socket_connectable_proxy_enumerate (addr);
487           else
488             srv_enum->addr_enum = g_socket_connectable_enumerate (addr);
489           g_object_unref (addr);
490         }
491
492       if (srv_enum->addr_enum)
493         {
494           GError *error = NULL;
495
496           ret = g_socket_address_enumerator_next (srv_enum->addr_enum,
497                                                   cancellable,
498                                                   &error);
499
500           if (error)
501             {
502               if (srv_enum->error == NULL)
503                 srv_enum->error = error;
504               else
505                 g_error_free (error);
506             }
507
508           if (!ret)
509             {
510               g_object_unref (srv_enum->addr_enum);
511               srv_enum->addr_enum = NULL;
512             }
513         }
514     }
515   while (srv_enum->addr_enum == NULL && srv_enum->t);
516
517   if (ret == NULL && srv_enum->error)
518     {
519       g_propagate_error (error, srv_enum->error);
520       srv_enum->error = NULL;
521     }
522
523   return ret;
524 }
525
526 static void next_async_resolved_targets   (GObject      *source_object,
527                                            GAsyncResult *result,
528                                            gpointer      user_data);
529 static void next_async_have_targets       (GTask        *srv_enum);
530 static void next_async_have_address       (GObject      *source_object,
531                                            GAsyncResult *result,
532                                            gpointer      user_data);
533
534 static void
535 g_network_service_address_enumerator_next_async (GSocketAddressEnumerator  *enumerator,
536                                                  GCancellable              *cancellable,
537                                                  GAsyncReadyCallback        callback,
538                                                  gpointer                   user_data)
539 {
540   GNetworkServiceAddressEnumerator *srv_enum =
541     G_NETWORK_SERVICE_ADDRESS_ENUMERATOR (enumerator);
542   GTask *task;
543
544   task = g_task_new (enumerator, cancellable, callback, user_data);
545
546   /* If we haven't yet resolved srv, do that */
547   if (!srv_enum->srv->priv->targets)
548     {
549       g_resolver_lookup_service_async (srv_enum->resolver,
550                                        srv_enum->srv->priv->service,
551                                        srv_enum->srv->priv->protocol,
552                                        srv_enum->srv->priv->domain,
553                                        cancellable,
554                                        next_async_resolved_targets,
555                                        task);
556     }
557   else
558     next_async_have_targets (task);
559 }
560
561 static void
562 next_async_resolved_targets (GObject      *source_object,
563                              GAsyncResult *result,
564                              gpointer      user_data)
565 {
566   GTask *task = user_data;
567   GNetworkServiceAddressEnumerator *srv_enum = g_task_get_source_object (task);
568   GError *error = NULL;
569   GList *targets;
570
571   targets = g_resolver_lookup_service_finish (srv_enum->resolver,
572                                               result, &error);
573
574   if (!targets && g_error_matches (error, G_RESOLVER_ERROR,
575                                    G_RESOLVER_ERROR_NOT_FOUND))
576     {
577       targets = g_network_service_fallback_targets (srv_enum->srv);
578       if (targets)
579         g_clear_error (&error);
580     }
581
582   if (error)
583     {
584       g_task_return_error (task, error);
585       g_object_unref (task);
586     }
587   else
588     {
589       srv_enum->t = srv_enum->srv->priv->targets = targets;
590       next_async_have_targets (task);
591     }
592 }
593
594 static void
595 next_async_have_targets (GTask *task)
596 {
597   GNetworkServiceAddressEnumerator *srv_enum = g_task_get_source_object (task);
598
599   /* Delegate to GNetworkAddress */
600   if (srv_enum->addr_enum == NULL && srv_enum->t)
601     {
602       GSocketConnectable *addr;
603       GSrvTarget *target = srv_enum->t->data;
604
605       srv_enum->t = g_list_next (srv_enum->t);
606       addr = g_network_address_new (g_srv_target_get_hostname (target),
607                                     (guint16) g_srv_target_get_port (target));
608
609       if (srv_enum->use_proxy)
610         srv_enum->addr_enum = g_socket_connectable_proxy_enumerate (addr);
611       else
612         srv_enum->addr_enum = g_socket_connectable_enumerate (addr);
613
614       g_object_unref (addr);
615     }
616
617   if (srv_enum->addr_enum)
618     {
619       g_socket_address_enumerator_next_async (srv_enum->addr_enum,
620                                               g_task_get_cancellable (task),
621                                               next_async_have_address,
622                                               task);
623     }
624   else
625     {
626       if (srv_enum->error)
627         {
628           g_task_return_error (task, srv_enum->error);
629           srv_enum->error = NULL;
630         }
631       else
632         g_task_return_pointer (task, NULL, NULL);
633
634       g_object_unref (task);
635     }
636 }
637
638 static void
639 next_async_have_address (GObject      *source_object,
640                          GAsyncResult *result,
641                          gpointer      user_data)
642 {
643   GTask *task = user_data;
644   GNetworkServiceAddressEnumerator *srv_enum = g_task_get_source_object (task);
645   GSocketAddress *address;
646   GError *error = NULL;
647   
648   address = g_socket_address_enumerator_next_finish (srv_enum->addr_enum,
649                                                      result,
650                                                      &error);
651
652   if (error)
653     {
654       if (srv_enum->error == NULL)
655         srv_enum->error = error;
656       else
657         g_error_free (error);
658     }
659
660   if (!address)
661     {
662       g_object_unref (srv_enum->addr_enum);
663       srv_enum->addr_enum = NULL;
664
665       next_async_have_targets (task);
666     }
667   else
668     {
669       g_task_return_pointer (task, address, g_object_unref);
670       g_object_unref (task);
671     }
672 }
673
674 static GSocketAddress *
675 g_network_service_address_enumerator_next_finish (GSocketAddressEnumerator  *enumerator,
676                                                   GAsyncResult              *result,
677                                                   GError                   **error)
678 {
679   return g_task_propagate_pointer (G_TASK (result), error);
680 }
681
682 static void
683 _g_network_service_address_enumerator_init (GNetworkServiceAddressEnumerator *enumerator)
684 {
685 }
686
687 static void
688 g_network_service_address_enumerator_finalize (GObject *object)
689 {
690   GNetworkServiceAddressEnumerator *srv_enum =
691     G_NETWORK_SERVICE_ADDRESS_ENUMERATOR (object);
692
693   if (srv_enum->srv)
694     g_object_unref (srv_enum->srv);
695
696   if (srv_enum->addr_enum)
697     g_object_unref (srv_enum->addr_enum);
698
699   if (srv_enum->resolver)
700     g_object_unref (srv_enum->resolver);
701
702   if (srv_enum->error)
703     g_error_free (srv_enum->error);
704
705   G_OBJECT_CLASS (_g_network_service_address_enumerator_parent_class)->finalize (object);
706 }
707
708 static void
709 _g_network_service_address_enumerator_class_init (GNetworkServiceAddressEnumeratorClass *srvenum_class)
710 {
711   GObjectClass *object_class = G_OBJECT_CLASS (srvenum_class);
712   GSocketAddressEnumeratorClass *enumerator_class =
713     G_SOCKET_ADDRESS_ENUMERATOR_CLASS (srvenum_class);
714
715   enumerator_class->next        = g_network_service_address_enumerator_next;
716   enumerator_class->next_async  = g_network_service_address_enumerator_next_async;
717   enumerator_class->next_finish = g_network_service_address_enumerator_next_finish;
718
719   object_class->finalize = g_network_service_address_enumerator_finalize;
720 }
721
722 static GSocketAddressEnumerator *
723 g_network_service_connectable_enumerate (GSocketConnectable *connectable)
724 {
725   GNetworkServiceAddressEnumerator *srv_enum;
726
727   srv_enum = g_object_new (G_TYPE_NETWORK_SERVICE_ADDRESS_ENUMERATOR, NULL);
728   srv_enum->srv = g_object_ref (connectable);
729   srv_enum->resolver = g_resolver_get_default ();
730   srv_enum->use_proxy = FALSE;
731
732   return G_SOCKET_ADDRESS_ENUMERATOR (srv_enum);
733 }
734
735 static GSocketAddressEnumerator *
736 g_network_service_connectable_proxy_enumerate (GSocketConnectable *connectable)
737 {
738   GSocketAddressEnumerator *addr_enum;
739   GNetworkServiceAddressEnumerator *srv_enum;
740
741   addr_enum = g_network_service_connectable_enumerate (connectable);
742   srv_enum = G_NETWORK_SERVICE_ADDRESS_ENUMERATOR (addr_enum);
743   srv_enum->use_proxy = TRUE;
744
745   return addr_enum;
746 }