X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=tools%2Fwispr.c;h=88f09c1377381c746475cddf0768f4b8a1e7470e;hb=505c3fb154e1fd4b04305d688363b0280b4d58f1;hp=7e7db21f7d366174aeb2872fe0901cb5341e1c1b;hpb=a95f2716f609c2b1dbf49a11830535d88177dffd;p=framework%2Fconnectivity%2Fconnman.git diff --git a/tools/wispr.c b/tools/wispr.c index 7e7db21..88f09c1 100644 --- a/tools/wispr.c +++ b/tools/wispr.c @@ -23,77 +23,599 @@ #include #endif +#define _GNU_SOURCE #include -#include +#include #include +#include #include #include -#include -#include +#include -#include "gweb/giognutls.h" +#include + +#define DEFAULT_URL "http://www.connman.net/online/status.html" + +static GTimer *timer; static GMainLoop *main_loop; +static void web_debug(const char *str, void *data) +{ + g_print("%s: %s\n", (const char *) data, str); +} + static void sig_term(int sig) { g_main_loop_quit(main_loop); } -static int create_connection(const char *address, unsigned short port) +static const char *message_type_to_string(int message_type) +{ + switch (message_type) { + case 100: + return "Initial redirect message"; + case 110: + return "Proxy notification"; + case 120: + return "Authentication notification"; + case 130: + return "Logoff notification"; + case 140: + return "Response to Authentication Poll"; + case 150: + return "Response to Abort Login"; + } + + return NULL; +} + +static const char *response_code_to_string(int response_code) +{ + switch (response_code) { + case 0: + return "No error"; + case 50: + return "Login succeeded"; + case 100: + return "Login failed"; + case 102: + return "RADIUS server error/timeout"; + case 105: + return "RADIUS server not enabled"; + case 150: + return "Logoff succeeded"; + case 151: + return "Login aborted"; + case 200: + return "Proxy detection/repeat operation"; + case 201: + return "Authentication pending"; + case 255: + return "Access gateway internal error"; + } + + return NULL; +} + +struct wispr_msg { + gboolean has_error; + const char *current_element; + int message_type; + int response_code; + char *login_url; + char *abort_login_url; + char *logoff_url; + char *access_procedure; + char *access_location; + char *location_name; +}; + +static inline void wispr_msg_init(struct wispr_msg *msg) +{ + msg->has_error = FALSE; + msg->current_element = NULL; + + msg->message_type = -1; + msg->response_code = -1; + + g_free(msg->login_url); + msg->login_url = NULL; + + g_free(msg->abort_login_url); + msg->abort_login_url = NULL; + + g_free(msg->logoff_url); + msg->logoff_url = NULL; + + g_free(msg->access_procedure); + msg->access_procedure = NULL; + + g_free(msg->access_location); + msg->access_location = NULL; + + g_free(msg->location_name); + msg->location_name = NULL; +} + +struct wispr_session { + GWeb *web; + GWebParser *parser; + guint request; + struct wispr_msg msg; + char *username; + char *password; + char *originurl; + char *formdata; +}; + +static gboolean execute_login(gpointer user_data); + +static struct { + const char *str; + enum { + WISPR_ELEMENT_NONE, + WISPR_ELEMENT_ACCESS_PROCEDURE, + WISPR_ELEMENT_ACCESS_LOCATION, + WISPR_ELEMENT_LOCATION_NAME, + WISPR_ELEMENT_LOGIN_URL, + WISPR_ELEMENT_ABORT_LOGIN_URL, + WISPR_ELEMENT_MESSAGE_TYPE, + WISPR_ELEMENT_RESPONSE_CODE, + WISPR_ELEMENT_NEXT_URL, + WISPR_ELEMENT_DELAY, + WISPR_ELEMENT_REPLY_MESSAGE, + WISPR_ELEMENT_LOGIN_RESULTS_URL, + WISPR_ELEMENT_LOGOFF_URL, + } element; +} wispr_element_map[] = { + { "AccessProcedure", WISPR_ELEMENT_ACCESS_PROCEDURE }, + { "AccessLocation", WISPR_ELEMENT_ACCESS_LOCATION }, + { "LocationName", WISPR_ELEMENT_LOCATION_NAME }, + { "LoginURL", WISPR_ELEMENT_LOGIN_URL }, + { "AbortLoginURL", WISPR_ELEMENT_ABORT_LOGIN_URL }, + { "MessageType", WISPR_ELEMENT_MESSAGE_TYPE }, + { "ResponseCode", WISPR_ELEMENT_RESPONSE_CODE }, + { "NextURL", WISPR_ELEMENT_NEXT_URL }, + { "Delay", WISPR_ELEMENT_DELAY }, + { "ReplyMessage", WISPR_ELEMENT_REPLY_MESSAGE }, + { "LoginResultsURL", WISPR_ELEMENT_LOGIN_RESULTS_URL }, + { "LogoffURL", WISPR_ELEMENT_LOGOFF_URL }, + { NULL, WISPR_ELEMENT_NONE }, +}; + +static void start_element_handler(GMarkupParseContext *context, + const gchar *element_name, + const gchar **attribute_names, + const gchar **attribute_values, + gpointer user_data, GError **error) +{ + struct wispr_msg *msg = user_data; + + msg->current_element = element_name; +} + +static void end_element_handler(GMarkupParseContext *context, + const gchar *element_name, + gpointer user_data, GError **error) +{ + struct wispr_msg *msg = user_data; + + msg->current_element = NULL; +} + +static void text_handler(GMarkupParseContext *context, + const gchar *text, gsize text_len, + gpointer user_data, GError **error) { - struct sockaddr_in sin; - int sk; + struct wispr_msg *msg = user_data; + int i; + + if (msg->current_element == NULL) + return; + + for (i = 0; wispr_element_map[i].str; i++) { + if (g_str_equal(wispr_element_map[i].str, + msg->current_element) == FALSE) + continue; + + switch (wispr_element_map[i].element) { + case WISPR_ELEMENT_NONE: + case WISPR_ELEMENT_ACCESS_PROCEDURE: + g_free(msg->access_procedure); + msg->access_procedure = g_strdup(text); + break; + case WISPR_ELEMENT_ACCESS_LOCATION: + g_free(msg->access_location); + msg->access_location = g_strdup(text); + break; + case WISPR_ELEMENT_LOCATION_NAME: + g_free(msg->location_name); + msg->location_name = g_strdup(text); + break; + case WISPR_ELEMENT_LOGIN_URL: + g_free(msg->login_url); + msg->login_url = g_strdup(text); + break; + case WISPR_ELEMENT_ABORT_LOGIN_URL: + g_free(msg->abort_login_url); + msg->abort_login_url = g_strdup(text); + break; + case WISPR_ELEMENT_MESSAGE_TYPE: + msg->message_type = atoi(text); + break; + case WISPR_ELEMENT_RESPONSE_CODE: + msg->response_code = atoi(text); + break; + case WISPR_ELEMENT_NEXT_URL: + case WISPR_ELEMENT_DELAY: + case WISPR_ELEMENT_REPLY_MESSAGE: + case WISPR_ELEMENT_LOGIN_RESULTS_URL: + break; + case WISPR_ELEMENT_LOGOFF_URL: + g_free(msg->logoff_url); + msg->logoff_url = g_strdup(text); + break; + } + } +} + +static void error_handler(GMarkupParseContext *context, + GError *error, gpointer user_data) +{ + struct wispr_msg *msg = user_data; + + msg->has_error = TRUE; +} + +static const GMarkupParser wispr_parser = { + start_element_handler, + end_element_handler, + text_handler, + NULL, + error_handler, +}; + +static void parser_callback(const char *str, gpointer user_data) +{ + struct wispr_session *wispr = user_data; + GMarkupParseContext *context; + gboolean result; - sk = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - if (sk < 0) - return -EIO; + //printf("%s\n", str); - memset(&sin, 0, sizeof(sin)); - sin.sin_family = AF_INET; - sin.sin_port = htons(port); - sin.sin_addr.s_addr = inet_addr(address); + context = g_markup_parse_context_new(&wispr_parser, + G_MARKUP_TREAT_CDATA_AS_TEXT, &wispr->msg, NULL); - if (connect(sk, (struct sockaddr *) &sin, sizeof(sin)) < 0) { - close(sk); - return -EIO; + result = g_markup_parse_context_parse(context, str, strlen(str), NULL); + if (result == TRUE) + result = g_markup_parse_context_end_parse(context, NULL); + + g_markup_parse_context_free(context); +} + +typedef void (*user_input_cb)(const char *value, gpointer user_data); + +struct user_input_data { + GString *str; + user_input_cb cb; + gpointer user_data; + gboolean hidden; + int fd; + struct termios saved_termios; +}; + +static void user_callback(struct user_input_data *data) +{ + char *value; + + if (data->hidden == TRUE) { + ssize_t len; + + len = write(data->fd, "\n", 1); + if (len < 0) + return; } - return sk; + tcsetattr(data->fd, TCSADRAIN, &data->saved_termios); + + close(data->fd); + + value = g_string_free(data->str, FALSE); + + if (data->cb) + data->cb(value, data->user_data); + + g_free(value); + + g_free(data); } -static gboolean received_data(GIOChannel *channel, GIOCondition cond, +static gboolean keyboard_input(GIOChannel *channel, GIOCondition condition, gpointer user_data) { - gchar buf[2048]; - gsize bytes_read; - GIOStatus status; + struct user_input_data *data = user_data; + char buf[1]; + int len; + + len = read(data->fd, buf, 1); - if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) { - g_main_loop_quit(main_loop); + if (len != 1) + return TRUE; + + if (buf[0] == '\n') { + user_callback(data); return FALSE; } - memset(buf, 0, sizeof(buf)); + g_string_append_c(data->str, buf[0]); - status = g_io_channel_read_chars(channel, buf, sizeof(buf) - 1, - &bytes_read, NULL); + if (data->hidden == TRUE) + len = write(data->fd, "*", 1); - printf("%s\n", buf); + return TRUE; +} - if (bytes_read == 0) { - g_main_loop_quit(main_loop); +static gboolean user_input(const char *label, gboolean hidden, + user_input_cb func, gpointer user_data) +{ + struct user_input_data *data; + struct termios new_termios; + GIOChannel *channel; + guint watch; + ssize_t len; + + data = g_try_new0(struct user_input_data, 1); + if (data == NULL) return FALSE; + + data->str = g_string_sized_new(32); + data->cb = func; + data->user_data = user_data; + data->hidden = hidden; + + data->fd = open("/dev/tty", O_RDWR | O_NOCTTY | O_CLOEXEC); + if (data->fd < 0) + goto error; + + if (tcgetattr(data->fd, &data->saved_termios) < 0) { + close(data->fd); + goto error; } + new_termios = data->saved_termios; + if (data->hidden == TRUE) + new_termios.c_lflag &= ~(ICANON|ECHO); + else + new_termios.c_lflag &= ~ICANON; + new_termios.c_cc[VMIN] = 1; + new_termios.c_cc[VTIME] = 0; + + tcsetattr(data->fd, TCSADRAIN, &new_termios); + + channel = g_io_channel_unix_new(data->fd); + g_io_channel_set_encoding(channel, NULL, NULL); + g_io_channel_set_buffered(channel, FALSE); + watch = g_io_add_watch(channel, G_IO_IN, keyboard_input, data); + g_io_channel_unref(channel); + + if (watch == 0) + goto error; + + len = write(data->fd, label, strlen(label)); + if (len < 0) + goto error; + + len = write(data->fd, ": ", 2); + if (len < 0) + goto error; + return TRUE; + +error: + g_string_free(data->str, TRUE); + g_free(data); + + return FALSE; +} + +static void password_callback(const char *value, gpointer user_data) +{ + struct wispr_session *wispr = user_data; + + g_free(wispr->password); + wispr->password = g_strdup(value); + + printf("\n"); + + execute_login(wispr); +} + +static void username_callback(const char *value, gpointer user_data) +{ + struct wispr_session *wispr = user_data; + + g_free(wispr->username); + wispr->username = g_strdup(value); + + if (wispr->password == NULL) { + user_input("Password", TRUE, password_callback, wispr); + return; + } + + printf("\n"); + + execute_login(wispr); +} + +static gboolean wispr_input(const guint8 **data, gsize *length, + gpointer user_data) +{ + struct wispr_session *wispr = user_data; + GString *buf; + gsize count; + + buf = g_string_sized_new(100); + + g_string_append(buf, "button=Login&UserName="); + g_string_append_uri_escaped(buf, wispr->username, NULL, FALSE); + g_string_append(buf, "&Password="); + g_string_append_uri_escaped(buf, wispr->password, NULL, FALSE); + g_string_append(buf, "&FNAME=0&OriginatingServer="); + g_string_append_uri_escaped(buf, wispr->originurl, NULL, FALSE); + + count = buf->len; + + g_free(wispr->formdata); + wispr->formdata = g_string_free(buf, FALSE); + + *data = (guint8 *) wispr->formdata; + *length = count; + + return FALSE; +} + +static gboolean wispr_result(GWebResult *result, gpointer user_data) +{ + struct wispr_session *wispr = user_data; + const guint8 *chunk; + gsize length; + guint16 status; + gdouble elapsed; + + g_web_result_get_chunk(result, &chunk, &length); + + if (length > 0) { + //printf("%s\n", (char *) chunk); + g_web_parser_feed_data(wispr->parser, chunk, length); + return TRUE; + } + + g_web_parser_end_data(wispr->parser); + + status = g_web_result_get_status(result); + + g_print("status: %03u\n", status); + + elapsed = g_timer_elapsed(timer, NULL); + + g_print("elapse: %f seconds\n", elapsed); + + if (wispr->msg.message_type < 0) { + const char *redirect; + + if (status != 302) + goto done; + + if (g_web_result_get_header(result, "Location", + &redirect) == FALSE) + goto done; + + printf("Redirect URL: %s\n", redirect); + printf("\n"); + + wispr->request = g_web_request_get(wispr->web, redirect, + wispr_result, wispr); + + return FALSE; + } + + printf("Message type: %s (%d)\n", + message_type_to_string(wispr->msg.message_type), + wispr->msg.message_type); + printf("Response code: %s (%d)\n", + response_code_to_string(wispr->msg.response_code), + wispr->msg.response_code); + if (wispr->msg.access_procedure != NULL) + printf("Access procedure: %s\n", wispr->msg.access_procedure); + if (wispr->msg.access_location != NULL) + printf("Access location: %s\n", wispr->msg.access_location); + if (wispr->msg.location_name != NULL) + printf("Location name: %s\n", wispr->msg.location_name); + if (wispr->msg.login_url != NULL) + printf("Login URL: %s\n", wispr->msg.login_url); + if (wispr->msg.abort_login_url != NULL) + printf("Abort login URL: %s\n", wispr->msg.abort_login_url); + if (wispr->msg.logoff_url != NULL) + printf("Logoff URL: %s\n", wispr->msg.logoff_url); + printf("\n"); + + if (status != 200 && status != 302 && status != 404) + goto done; + + if (wispr->msg.message_type == 100) { + if (wispr->username == NULL) { + user_input("Username", FALSE, username_callback, wispr); + return FALSE; + } + + if (wispr->password == NULL) { + user_input("Password", TRUE, password_callback, wispr); + return FALSE; + } + + g_idle_add(execute_login, wispr); + return FALSE; + } else if (wispr->msg.message_type == 120 || + wispr->msg.message_type == 140) { + int code = wispr->msg.response_code; + printf("Login process: %s\n", + code == 50 ? "SUCCESS" : "FAILURE"); + } + + if (status == 302) { + const char *redirect; + + if (g_web_result_get_header(result, "Location", + &redirect) == FALSE) + goto done; + + printf("\n"); + printf("Redirect URL: %s\n", redirect); + printf("\n"); + + wispr->request = g_web_request_get(wispr->web, redirect, + wispr_result, wispr); + + return FALSE; + } + +done: + g_main_loop_quit(main_loop); + + return FALSE; +} + +static gboolean execute_login(gpointer user_data) +{ + struct wispr_session *wispr = user_data; + + wispr->request = g_web_request_post(wispr->web, wispr->msg.login_url, + "application/x-www-form-urlencoded", + wispr_input, wispr_result, wispr); + + wispr_msg_init(&wispr->msg); + + return FALSE; } static gboolean option_debug = FALSE; +static gchar *option_nameserver = NULL; +static gchar *option_username = NULL; +static gchar *option_password = NULL; +static gchar *option_url = NULL; static GOptionEntry options[] = { { "debug", 'd', 0, G_OPTION_ARG_NONE, &option_debug, "Enable debug output" }, + { "nameserver", 'n', 0, G_OPTION_ARG_STRING, &option_nameserver, + "Specify nameserver", "ADDRESS" }, + { "username", 'u', 0, G_OPTION_ARG_STRING, &option_username, + "Specify username", "USERNAME" }, + { "password", 'p', 0, G_OPTION_ARG_STRING, &option_password, + "Specify password", "PASSWORD" }, + { "url", 'U', 0, G_OPTION_ARG_STRING, &option_url, + "Specify arbitrary request", "URL" }, { NULL }, }; @@ -102,9 +624,8 @@ int main(int argc, char *argv[]) GOptionContext *context; GError *error = NULL; struct sigaction sa; - GIOChannel *channel; - gsize written; - int sk; + struct wispr_session wispr; + int index = 0; context = g_option_context_new(NULL); g_option_context_add_main_entries(context, options, NULL); @@ -120,39 +641,70 @@ int main(int argc, char *argv[]) g_option_context_free(context); - sk = create_connection("140.211.169.100", 443); - if (sk < 0) { - fprintf(stderr, "Failed to create connection\n"); + memset(&wispr, 0, sizeof(wispr)); + wispr_msg_init(&wispr.msg); + + wispr.web = g_web_new(index); + if (wispr.web == NULL) { + fprintf(stderr, "Failed to create web service\n"); return 1; } + if (option_debug == TRUE) + g_web_set_debug(wispr.web, web_debug, "WEB"); + main_loop = g_main_loop_new(NULL, FALSE); - channel = g_io_channel_gnutls_new(sk); - if (channel == NULL) { - fprintf(stderr, "Failed to create GnuTLS IO channel\n"); - return 1; + if (option_nameserver != NULL) { + g_web_add_nameserver(wispr.web, option_nameserver); + g_free(option_nameserver); } - g_io_channel_set_close_on_unref(channel, TRUE); + g_web_set_accept(wispr.web, NULL); + g_web_set_user_agent(wispr.web, "SmartClient/%s wispr", VERSION); + g_web_set_close_connection(wispr.web, TRUE); + + if (option_url == NULL) + option_url = g_strdup(DEFAULT_URL); + + wispr.username = option_username; + wispr.password = option_password; + wispr.originurl = option_url; + + timer = g_timer_new(); + + wispr.parser = g_web_parser_new("", + parser_callback, &wispr); + + wispr.request = g_web_request_get(wispr.web, option_url, + wispr_result, &wispr); + + if (wispr.request == 0) { + fprintf(stderr, "Failed to start request\n"); + return 1; + } memset(&sa, 0, sizeof(sa)); sa.sa_handler = sig_term; sigaction(SIGINT, &sa, NULL); sigaction(SIGTERM, &sa, NULL); - g_io_add_watch(channel, G_IO_IN | G_IO_ERR | G_IO_HUP, - received_data, NULL); + g_main_loop_run(main_loop); -#define MSG "GET / HTTP/1.0\r\n\r\n" + g_timer_destroy(timer); - g_io_channel_write_chars(channel, MSG, strlen(MSG), &written, NULL); + if (wispr.request > 0) + g_web_cancel_request(wispr.web, wispr.request); - g_main_loop_run(main_loop); + g_web_parser_unref(wispr.parser); + g_web_unref(wispr.web); g_main_loop_unref(main_loop); - g_io_channel_unref(channel); + g_free(wispr.username); + g_free(wispr.password); + g_free(wispr.originurl); return 0; }