--- include/service.h | 27 +++ src/service.c | 629 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 651 insertions(+), 5 deletions(-)
diff --git a/include/service.h b/include/service.h index 170cd6c..22ee8df 100644 --- a/include/service.h +++ b/include/service.h @@ -22,6 +22,8 @@ #ifndef __CONNMAN_SERVICE_H #define __CONNMAN_SERVICE_H +#include <stdint.h> +#include <glib.h> #include <connman/types.h> #ifdef __cplusplus @@ -84,6 +86,27 @@ enum connman_service_error { CONNMAN_SERVICE_ERROR_CONNECT_FAILED = 4, }; +enum connman_service_proxy_method { + CONNMAN_SERVICE_PROXY_METHOD_DIRECT = 0, + CONNMAN_SERVICE_PROXY_METHOD_AUTO = 1, + CONNMAN_SERVICE_PROXY_METHOD_MANUAL = 2, + CONNMAN_SERVICE_PROXY_METHOD_AUTO_CONFIG = 3, +}; + +struct connman_manual_proxy { + char *http; + uint16_t http_port; + char *https; + uint16_t https_port; + char *ftp; + uint16_t ftp_port; + char *socks; + uint16_t socks_port; + char *rtsp; + uint16_t rtsp_port; + GSList *ignore; +}; + struct connman_service; struct connman_service *connman_service_create(void); @@ -93,6 +116,10 @@ void connman_service_unref(struct connman_service *service); enum connman_service_type connman_service_get_type(struct connman_service *service); char *connman_service_get_interface(struct connman_service *service); +struct connman_manual_proxy * +connman_service_get_default_proxy(struct connman_service *service, + enum connman_service_proxy_method *method); + #ifdef __cplusplus } #endif diff --git a/src/service.c b/src/service.c index eb467a0..08b003b 100644 --- a/src/service.c +++ b/src/service.c @@ -117,6 +117,9 @@ struct connman_service { struct connman_location *location; struct connman_stats stats; struct connman_stats stats_roaming; + + enum connman_service_proxy_method proxy_method; + struct connman_manual_proxy *manual_proxy; }; static void append_path(gpointer value, gpointer user_data) @@ -642,7 +645,490 @@ static void reset_stats(struct connman_service *service) g_timer_reset(service->stats_roaming.timer); } -static struct connman_service *get_default(void) +static void free_proxy_ignore(GSList *ignore_list) +{ + GSList *list; + for (list = ignore_list; list; list = list->next) { + g_free(list->data); + list->data = NULL; + } + + g_slist_free(ignore_list); +} + +static void free_proxy(struct connman_manual_proxy *proxy) +{ + if (!proxy) + return; + + g_free(proxy->http); + g_free(proxy->https); + g_free(proxy->ftp); + g_free(proxy->socks); + g_free(proxy->rtsp); + + proxy->http = proxy->https = proxy->ftp = proxy->socks = + proxy->rtsp = NULL; + proxy->http_port = proxy->https_port = proxy->ftp_port = + proxy->socks_port = proxy->rtsp_port = 0; + + free_proxy_ignore(proxy->ignore); + proxy->ignore = NULL; +} + +static int update_proxy(char **host, uint16_t *port, + char *new_host, uint16_t new_port) +{ + int num_proxies = 0; + + if (new_host) { + /* Proxy host update requested */ + if (new_host[0]) { + num_proxies++; + if (new_port) + *port = new_port; + + if (*port) { + /* Update proxy only if port is valid */ + g_free(*host); + *host = g_strdup(new_host); + } + } else { + /* Empty proxy, clear settings */ + g_free(*host); + *host = NULL; + *port = 0; + } + } + + if (*host) { + /* Update port if new one is valid */ + num_proxies++; + + if (new_port) + *port = new_port; + } + + return num_proxies; +} + +static struct connman_manual_proxy * +update_manual_proxy(struct connman_manual_proxy *proxy, + char *proxy_http, + uint16_t proxy_http_port, + char *proxy_https, + uint16_t proxy_https_port, + char *proxy_ftp, + uint16_t proxy_ftp_port, + char *proxy_socks, + uint16_t proxy_socks_port, + char *proxy_rtsp, + uint16_t proxy_rtsp_port, + GSList *proxy_ignore) +{ + int num_proxies = 0; + + DBG("proxy %p/%s:%d/%s:%d/%s:%d/%s:%d/%s:%d/%p", proxy, + proxy_http, proxy_http_port, proxy_https, proxy_https_port, + proxy_ftp, proxy_ftp_port, proxy_socks, proxy_socks_port, + proxy_rtsp, proxy_rtsp_port, proxy_ignore); + + if (!proxy) { + proxy = g_try_new0(struct connman_manual_proxy, 1); + if (proxy == NULL) + return NULL; + } + + num_proxies += update_proxy(&proxy->http, &proxy->http_port, + proxy_http, proxy_http_port); + num_proxies += update_proxy(&proxy->https, &proxy->https_port, + proxy_https, proxy_https_port); + num_proxies += update_proxy(&proxy->ftp, &proxy->ftp_port, + proxy_ftp, proxy_ftp_port); + num_proxies += update_proxy(&proxy->socks, &proxy->socks_port, + proxy_socks, proxy_socks_port); + num_proxies += update_proxy(&proxy->rtsp, &proxy->rtsp_port, + proxy_rtsp, proxy_rtsp_port); + + if (proxy_ignore) { + free_proxy_ignore(proxy->ignore); + proxy->ignore = NULL; + if (proxy_ignore && proxy_ignore->data && + ((char *)(proxy_ignore->data))[0]) { + proxy->ignore = proxy_ignore; + num_proxies++; + } + if (!proxy->ignore) + free_proxy_ignore(proxy_ignore); + } + + DBG("proxy %p, proxies %d", proxy, num_proxies); + + if (num_proxies == 0) { + free_proxy(proxy); + proxy = NULL; + } + + return proxy; +} + +static enum connman_service_proxy_method string2proxymethod(const char *method) +{ + if (!g_strcmp0(method, "direct")) + return CONNMAN_SERVICE_PROXY_METHOD_DIRECT; + else if (!g_strcmp0(method, "auto")) + return CONNMAN_SERVICE_PROXY_METHOD_AUTO; + else if (!g_strcmp0(method, "manual")) + return CONNMAN_SERVICE_PROXY_METHOD_MANUAL; + else if (!g_strcmp0(method, "auto-config")) + return CONNMAN_SERVICE_PROXY_METHOD_AUTO_CONFIG; + else + return CONNMAN_SERVICE_PROXY_METHOD_DIRECT; +} + +static const char *proxymethod2string(enum connman_service_proxy_method method) +{ + switch(method) { + case CONNMAN_SERVICE_PROXY_METHOD_AUTO: + return "auto"; + case CONNMAN_SERVICE_PROXY_METHOD_MANUAL: + return "manual"; + case CONNMAN_SERVICE_PROXY_METHOD_AUTO_CONFIG: + return "auto-config"; + } + return "direct"; +} + +static int set_proxy_configuration(struct connman_service *service, + DBusMessageIter *array) +{ + enum connman_service_proxy_method method = CONNMAN_SERVICE_PROXY_METHOD_DIRECT; + DBusMessageIter dict; + char *proxy_http = NULL; + uint16_t proxy_http_port = 0; + char *proxy_https = NULL; + uint16_t proxy_https_port = 0; + char *proxy_ftp = NULL; + uint16_t proxy_ftp_port = 0; + char *proxy_socks = NULL; + uint16_t proxy_socks_port = 0; + char *proxy_rtsp = NULL; + uint16_t proxy_rtsp_port = 0; + GSList *proxy_ignore = NULL; + char *url = NULL; + + DBG("service %p", service); + + if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY) + return -EINVAL; + + dbus_message_iter_recurse(array, &dict); + + while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) { + DBusMessageIter entry, variant; + const char *key; + int type; + + dbus_message_iter_recurse(&dict, &entry); + + if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING) + return -EINVAL; + + dbus_message_iter_get_basic(&entry, &key); + dbus_message_iter_next(&entry); + + dbus_message_iter_recurse(&entry, &variant); + type = dbus_message_iter_get_arg_type(&variant); + + if (g_str_equal(key, "Method") == TRUE) { + const char *str; + if (type != DBUS_TYPE_STRING) + return -EINVAL; + + dbus_message_iter_get_basic(&variant, &str); + method = string2proxymethod(str); + } else if (g_str_equal(key, "URL") == TRUE) { + if (type != DBUS_TYPE_STRING) + return -EINVAL; + + dbus_message_iter_get_basic(&variant, &url); + } else if (g_str_equal(key, "Http") == TRUE) { + if (type != DBUS_TYPE_STRING) + return -EINVAL; + + dbus_message_iter_get_basic(&variant, &proxy_http); + } else if (g_str_equal(key, "HttpPort") == TRUE) { + if (type != DBUS_TYPE_UINT16) + return -EINVAL; + + dbus_message_iter_get_basic(&variant, &proxy_http_port); + } else if (g_str_equal(key, "Https") == TRUE) { + if (type != DBUS_TYPE_STRING) + return -EINVAL; + + dbus_message_iter_get_basic(&variant, &proxy_https); + } else if (g_str_equal(key, "HttpsPort") == TRUE) { + if (type != DBUS_TYPE_UINT16) + return -EINVAL; + + dbus_message_iter_get_basic(&variant, &proxy_https_port); + } else if (g_str_equal(key, "Ftp") == TRUE) { + if (type != DBUS_TYPE_STRING) + return -EINVAL; + + dbus_message_iter_get_basic(&variant, &proxy_ftp); + } else if (g_str_equal(key, "FtpPort") == TRUE) { + if (type != DBUS_TYPE_UINT16) + return -EINVAL; + + dbus_message_iter_get_basic(&variant, &proxy_ftp_port); + } else if (g_str_equal(key, "Socks") == TRUE) { + if (type != DBUS_TYPE_STRING) + return -EINVAL; + + dbus_message_iter_get_basic(&variant, &proxy_socks); + } else if (g_str_equal(key, "SocksPort") == TRUE) { + if (type != DBUS_TYPE_UINT16) + return -EINVAL; + + dbus_message_iter_get_basic(&variant, &proxy_socks_port); + } else if (g_str_equal(key, "Rtsp") == TRUE) { + if (type != DBUS_TYPE_STRING) + return -EINVAL; + + dbus_message_iter_get_basic(&variant, &proxy_rtsp); + } else if (g_str_equal(key, "RtspPort") == TRUE) { + if (type != DBUS_TYPE_UINT16) + return -EINVAL; + + dbus_message_iter_get_basic(&variant, &proxy_rtsp_port); + } else if (g_str_equal(key, "Ignore") == TRUE) { + DBusMessageIter str_array; + + if (type != DBUS_TYPE_ARRAY) + return -EINVAL; + + dbus_message_iter_recurse(&variant, &str_array); + + while (dbus_message_iter_get_arg_type(&str_array) == + DBUS_TYPE_STRING) { + char *val = NULL; + dbus_message_iter_get_basic(&str_array, &val); + proxy_ignore = g_slist_append(proxy_ignore, + g_strdup(val)); + dbus_message_iter_next(&str_array); + } + } + dbus_message_iter_next(&dict); + } + + DBG("method %d", method); + + switch (method) { + case CONNMAN_SERVICE_PROXY_METHOD_MANUAL: + + service->manual_proxy = + update_manual_proxy(service->manual_proxy, + proxy_http, + proxy_http_port, + proxy_https, + proxy_https_port, + proxy_ftp, + proxy_ftp_port, + proxy_socks, + proxy_socks_port, + proxy_rtsp, + proxy_rtsp_port, + proxy_ignore); + + if (service->manual_proxy) + service->proxy_method = CONNMAN_SERVICE_PROXY_METHOD_MANUAL; + else + service->proxy_method = CONNMAN_SERVICE_PROXY_METHOD_DIRECT; + + break; + + case CONNMAN_SERVICE_PROXY_METHOD_AUTO_CONFIG: + service->proxy_method = CONNMAN_SERVICE_PROXY_METHOD_AUTO_CONFIG; + __connman_ipconfig_set_proxy_autoconfig(service->ipconfig, + url); + break; + + case CONNMAN_SERVICE_PROXY_METHOD_DIRECT: + case CONNMAN_SERVICE_PROXY_METHOD_AUTO: + default: + service->proxy_method = CONNMAN_SERVICE_PROXY_METHOD_DIRECT; + break; + } + + return 0; +} + +static void append_ignore_list(DBusMessageIter *iter, void *user_data) +{ + GSList *list, *proxy_ignore = user_data; + int i; + + for (list = proxy_ignore; list; list = list->next) + dbus_message_iter_append_basic(iter, + DBUS_TYPE_STRING, &list->data); +} + +static int proxy_load(struct connman_service *service, GKeyFile *keyfile) +{ + const char *str; + enum connman_service_proxy_method method; + + str = g_key_file_get_string(keyfile, service->identifier, + "Proxy.method", NULL); + + service->proxy_method = string2proxymethod(str); + g_free(str); + + if (service->proxy_method == CONNMAN_SERVICE_PROXY_METHOD_MANUAL) { + char *http, *https, *ftp, *socks, *rtsp, **ignore; + uint16_t http_port, https_port, ftp_port, socks_port, + rtsp_port; + gsize len; + GSList *ignore_list = NULL; + + http = g_key_file_get_string(keyfile, service->identifier, + "Proxy.http", NULL); + http_port = g_key_file_get_integer(keyfile, service->identifier, + "Proxy.http_port", NULL); + + https = g_key_file_get_string(keyfile, service->identifier, + "Proxy.https", NULL); + https_port = g_key_file_get_integer(keyfile, service->identifier, + "Proxy.https_port", NULL); + + ftp = g_key_file_get_string(keyfile, service->identifier, + "Proxy.ftp", NULL); + ftp_port = g_key_file_get_integer(keyfile, service->identifier, + "Proxy.ftp_port", NULL); + + socks = g_key_file_get_string(keyfile, service->identifier, + "Proxy.socks", NULL); + socks_port = g_key_file_get_integer(keyfile, service->identifier, + "Proxy.socks_port", NULL); + + rtsp = g_key_file_get_string(keyfile, service->identifier, + "Proxy.rtsp", NULL); + rtsp_port = g_key_file_get_integer(keyfile, service->identifier, + "Proxy.rtsp_port", NULL); + + ignore = g_key_file_get_string_list(keyfile, service->identifier, + "Proxy.ignore", &len, NULL); + if (ignore && len>0) { + int i; + for (i=0; i<len; i++) + ignore_list = g_slist_append(ignore_list, + ignore[i]); + g_free(ignore); + } + + service->manual_proxy = + update_manual_proxy(service->manual_proxy, + http, http_port, + https, https_port, + ftp, ftp_port, + socks, socks_port, + rtsp, rtsp_port, + ignore_list); + } + + return 0; +} + +static void proxy_save_entry(GKeyFile *keyfile, char *identifier, + char **host, uint16_t *port, + char *host_key, char *port_key) +{ + if (host && *host && (*host)[0]) { + g_key_file_set_string(keyfile, identifier, host_key, *host); + g_key_file_set_integer(keyfile, identifier, port_key, *port); + } else { + g_key_file_remove_key(keyfile, identifier, host_key, NULL); + g_key_file_remove_key(keyfile, identifier, port_key, NULL); + + if (host) { + g_free(*host); + *host = NULL; + if (port) + *port = 0; + } + } +} + +static int proxy_save(struct connman_service *service, GKeyFile *keyfile) +{ + struct connman_manual_proxy *proxy = service->manual_proxy; + + DBG("service %p identifier %s method %d", service, + service->identifier, service->proxy_method); + + g_key_file_set_string(keyfile, service->identifier, "Proxy.method", + proxymethod2string(service->proxy_method)); + + proxy_save_entry(keyfile, service->identifier, + proxy ? &proxy->http : NULL, + proxy ? &proxy->http_port : NULL, + "Proxy.http", "Proxy.http_port"); + + proxy_save_entry(keyfile, service->identifier, + proxy ? &proxy->https : NULL, + proxy ? &proxy->https_port : NULL, + "Proxy.https", "Proxy.https_port"); + + proxy_save_entry(keyfile, service->identifier, + proxy ? &proxy->ftp : NULL, + proxy ? &proxy->ftp_port : NULL, + "Proxy.ftp", "Proxy.ftp_port"); + + proxy_save_entry(keyfile, service->identifier, + proxy ? &proxy->socks : NULL, + proxy ? &proxy->socks_port : NULL, + "Proxy.socks", "Proxy.socks_port"); + + proxy_save_entry(keyfile, service->identifier, + proxy ? &proxy->rtsp : NULL, + proxy ? &proxy->rtsp_port : NULL, + "Proxy.rtsp", "Proxy.rtsp_port"); + + if (proxy && proxy->ignore) { + GSList *lst; + char **array = 0; + int num = 0; + + for (lst = proxy->ignore; lst; lst = lst->next) { + array = (char **)g_realloc(array, + (num + 1) * sizeof(char *)); + array[num++] = lst->data; + } + + if (num) + g_key_file_set_string_list(keyfile, + service->identifier, + "Proxy.ignore", + (const char **)array, + num); + else { + g_key_file_remove_key(keyfile, + service->identifier, + "Proxy.ignore", + NULL); + free_proxy_ignore(proxy->ignore); + proxy->ignore = NULL; + } + g_free(array); + } else + g_key_file_remove_key(keyfile, service->identifier, + "Proxy.ignore", NULL); + + return 0; +} + +static struct connman_service *get_default_service() { struct connman_service *service; GSequenceIter *iter; @@ -654,6 +1140,18 @@ static struct connman_service *get_default(void) service = g_sequence_get(iter); + return service; +} + +static struct connman_service *get_default() +{ + struct connman_service *service; + + service = get_default_service(); + + if (!service) + return NULL; + if (is_connected(service) == FALSE) return NULL; @@ -961,12 +1459,86 @@ static void append_domainconfig(DBusMessageIter *iter, void *user_data) static void append_proxy(DBusMessageIter *iter, void *user_data) { struct connman_service *service = user_data; + const char *method = "direct"; - if (is_connected(service) == FALSE) - return; + if (service->proxy_method == + CONNMAN_SERVICE_PROXY_METHOD_AUTO_CONFIG) { - if (service->ipconfig != NULL) - __connman_ipconfig_append_proxy(service->ipconfig, iter); + method = "auto-config"; + + if (service->ipconfig) + __connman_ipconfig_append_proxy(service->ipconfig, + iter); + + } else if (service->proxy_method == + CONNMAN_SERVICE_PROXY_METHOD_MANUAL) { + + struct connman_manual_proxy *proxy = service->manual_proxy; + if (proxy == NULL) + goto done; + + method = "manual"; + + if (proxy->http) { + connman_dbus_dict_append_basic(iter, "Http", + DBUS_TYPE_STRING, + &proxy->http); + connman_dbus_dict_append_basic(iter, "HttpPort", + DBUS_TYPE_UINT16, + &proxy->http_port); + } + + if (proxy->https) { + connman_dbus_dict_append_basic(iter, "Https", + DBUS_TYPE_STRING, + &proxy->https); + connman_dbus_dict_append_basic(iter, "HttpsPort", + DBUS_TYPE_UINT16, + &proxy->https_port); + } + + if (proxy->ftp) { + connman_dbus_dict_append_basic(iter, "Ftp", + DBUS_TYPE_STRING, + &proxy->ftp); + connman_dbus_dict_append_basic(iter, "FtpPort", + DBUS_TYPE_UINT16, + &proxy->ftp_port); + } + + if (proxy->socks) { + connman_dbus_dict_append_basic(iter, "Socks", + DBUS_TYPE_STRING, + &proxy->socks); + connman_dbus_dict_append_basic(iter, "SocksPort", + DBUS_TYPE_UINT16, + &proxy->socks_port); + } + + if (proxy->rtsp) { + connman_dbus_dict_append_basic(iter, "Rtsp", + DBUS_TYPE_STRING, + &proxy->rtsp); + connman_dbus_dict_append_basic(iter, "RtspPort", + DBUS_TYPE_UINT16, + &proxy->rtsp_port); + } + + if (proxy->ignore) + connman_dbus_dict_append_array(iter, "Ignore", + DBUS_TYPE_STRING, + append_ignore_list, + proxy->ignore); + } + +done: + connman_dbus_dict_append_basic(iter, "Method", + DBUS_TYPE_STRING, &method); +} + +static void append_proxyconfig(DBusMessageIter *iter, void *user_data) +{ + append_proxy(iter, user_data); } static void append_provider(DBusMessageIter *iter, void *user_data) @@ -1051,6 +1623,14 @@ static void proxy_changed(struct connman_service *service) append_proxy, service); } +static void proxy_configuration_changed(struct connman_service *service) +{ + connman_dbus_property_changed_dict(service->path, + CONNMAN_SERVICE_INTERFACE, + "Proxy.Configuration", + append_proxyconfig, service); +} + static void stats_append(DBusMessageIter *dict, struct connman_stats *stats, connman_bool_t append_all) @@ -1285,6 +1865,9 @@ static void append_properties(DBusMessageIter *dict, dbus_bool_t limited, connman_dbus_dict_append_dict(dict, "Proxy", append_proxy, service); + connman_dbus_dict_append_dict(dict, "Proxy.Configuration", + append_proxyconfig, service); + connman_dbus_dict_append_dict(dict, "Provider", append_provider, service); } @@ -1663,6 +2246,13 @@ static DBusMessage *set_property(DBusConnection *conn, service->ipconfig); __connman_storage_save_service(service); + } else if (g_str_equal(name, "Proxy.Configuration") == TRUE) { + + if (!set_proxy_configuration(service, &value)) { + proxy_configuration_changed(service); + __connman_storage_save_service(service); + } + } else return __connman_error_invalid_property(msg); @@ -2186,6 +2776,9 @@ static void service_free(gpointer user_data) g_free(service->private_key_passphrase); g_free(service->phase2); + free_proxy(service->manual_proxy); + g_free(service->manual_proxy); + if (service->stats.timer != NULL) g_timer_destroy(service->stats.timer); if (service->stats_roaming.timer != NULL) @@ -2398,6 +2991,30 @@ char *connman_service_get_interface(struct connman_service *service) } /** + * connman_service_get_active_proxy: + * @service: service structure + * @method: current proxy method for this service + * + * Get the proxy settings for currently default service + */ +struct connman_manual_proxy * +connman_service_get_default_proxy(struct connman_service *service, + enum connman_service_proxy_method *method) +{ + if (!service) + return NULL; + + if (service == get_default_service()) { + if (method) + *method = service->proxy_method; + + return service->manual_proxy; + } + + return NULL; +} + +/** * connman_service_get_network: * @service: service structure * @@ -3927,6 +4544,7 @@ static int service_load(struct connman_service *service) } stats_load(service, keyfile); + proxy_load(service, keyfile); done: g_key_file_free(keyfile); @@ -4089,6 +4707,7 @@ update: "Domains", NULL); stats_save(service, keyfile); + proxy_save(service, keyfile); data = g_key_file_to_data(keyfile, &length, NULL); -- 1.7.0.4 _______________________________________________ connman mailing list connman@connman.net http://lists.connman.net/listinfo/connman