From b445c4efd828e716c8edd11e8c2dabc66a7cad9d Mon Sep 17 00:00:00 2001 From: Stefan Becker Date: Sun, 18 Apr 2010 03:00:53 +0300 Subject: [PATCH] core cleanup: move purple specific transport code to backend I hope I didn't break anything, at least TLS seems to work. OBS builds are OK. --- po/POTFILES.in | 1 + src/api/core-depurple.h | 6 +- src/api/sipe-backend.h | 10 + src/api/sipe-core.h | 15 +- src/core/sipe-core-private.h | 1 + src/core/sipe.c | 422 +++------------------ src/core/sipe.h | 15 - src/purple/Makefile.am | 1 + src/purple/purple-plugin.c | 39 +- .../{purple-transport.c => purple-private.h} | 27 +- src/purple/purple-transport.c | 333 +++++++++++++++- 11 files changed, 453 insertions(+), 417 deletions(-) copy src/purple/{purple-transport.c => purple-private.h} (65%) diff --git a/po/POTFILES.in b/po/POTFILES.in index 8ab36b68..f13096ea 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -9,3 +9,4 @@ src/core/sipe-core.c src/core/sipe-domino.c src/core/sipe-ft.c src/purple/purple-plugin.c +src/purple/purple-transport.c diff --git a/src/api/core-depurple.h b/src/api/core-depurple.h index 45c22188..e541fe1e 100644 --- a/src/api/core-depurple.h +++ b/src/api/core-depurple.h @@ -30,8 +30,7 @@ void sipe_search_contact_with_cb(PurpleConnection *gc, GList *sipe_buddy_menu(PurpleBuddy *buddy); GList *sipe_chat_menu(PurpleChat *chat); void sipe_purple_setup(struct sipe_core_public *sipe_public, - PurpleConnection *gc, - PurpleAccount *account); + PurpleConnection *gc); void sipe_close(PurpleConnection *gc); int sipe_im_send(PurpleConnection *gc, const char *who, const char *what, PurpleMessageFlags flags); @@ -47,7 +46,6 @@ void sipe_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy, void sipe_chat_leave(PurpleConnection *gc, int id); int sipe_chat_send(PurpleConnection *gc, int id, const char *what, PurpleMessageFlags flags); -void sipe_keep_alive(PurpleConnection *gc); void sipe_group_buddy(PurpleConnection *gc, const char *who, const char *old_group_name, const char *new_group_name); @@ -76,8 +74,6 @@ void sipe_ft_send_file(PurpleConnection *gc, const char *who, PurpleXfer *sipe_ft_new_xfer(PurpleConnection *gc, const char *who); -int sipe_send_raw(PurpleConnection *gc, const char *buf, int len); - /* Convenience macros */ #define PURPLE_ACCOUNT_TO_SIPE_ACCOUNT_DATA ((struct sipe_core_private *)account->gc->proto_data)->temporary #define PURPLE_BUDDY_TO_SIPE_ACCOUNT_DATA ((struct sipe_core_private *)buddy->account->gc->proto_data)->temporary diff --git a/src/api/sipe-backend.h b/src/api/sipe-backend.h index 27315174..e78c847a 100644 --- a/src/api/sipe-backend.h +++ b/src/api/sipe-backend.h @@ -20,6 +20,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* Forward declarations */ +struct sipe_core_public; + /** DEBUGGING ****************************************************************/ typedef enum { @@ -60,3 +63,10 @@ gchar *sipe_backend_markup_strip_html(const gchar *html); /** NETWORK ******************************************************************/ const gchar *sipe_backend_network_ip_address(void); + +/** TRANSPORT ****************************************************************/ + +void sipe_backend_transport_sip_connect(struct sipe_core_public *sipe_public); +void sipe_backend_transport_sip_disconnect(struct sipe_core_public *sipe_public); +void sipe_backend_transport_sip_message(struct sipe_core_public *sipe_public, + const gchar *buffer); diff --git a/src/api/sipe-core.h b/src/api/sipe-core.h index 742d0000..18a922f8 100644 --- a/src/api/sipe-core.h +++ b/src/api/sipe-core.h @@ -69,7 +69,7 @@ struct sipe_transport_connection { gsize buffer_used; /* 0 < buffer_used < buffer_length */ gsize buffer_length; /* read-only */ sipe_transport_type type; /* read-only */ - guint client_port; /* read-only (will disappear to backend) */ + guint client_port; /* read-only */ }; /** @@ -99,6 +99,7 @@ struct sipe_core_public { sipe_transport_type transport_type; /* same as transport->type */ gchar *server_name; guint server_port; + guint keepalive_timeout; }; /** @@ -110,6 +111,7 @@ void sipe_core_destroy(void); /** Utility functions exported by the core to backends ***********************/ gboolean sipe_strequal(const gchar *left, const gchar *right); +char *fix_newlines(const char *st); /*****************************************************************************/ @@ -177,10 +179,13 @@ struct sipe_core_public *sipe_core_allocate(const gchar *signin_name, /** * Connect to server */ -void sipe_core_connect(struct sipe_core_public *sipe_public, - sipe_transport_type transport, - const gchar *server, - const gchar *port); +void sipe_core_transport_sip_connect(struct sipe_core_public *sipe_public, + sipe_transport_type transport, + const gchar *server, + const gchar *port); +void sipe_core_transport_sip_connected(struct sipe_core_public *sipe_public); +void sipe_core_transport_sip_message(struct sipe_core_public *sipe_public); +void sipe_core_transport_sip_ssl_connect_failure(struct sipe_core_public *sipe_public); /** * Create a new chat diff --git a/src/core/sipe-core-private.h b/src/core/sipe-core-private.h index 25165571..ed8ace4f 100644 --- a/src/core/sipe-core-private.h +++ b/src/core/sipe-core-private.h @@ -45,6 +45,7 @@ struct sipe_core_private { /* Convenience macros */ #define SIPE_CORE_PRIVATE ((struct sipe_core_private *)sipe_public) +#define SIPE_CORE_PUBLIC ((struct sipe_core_public *)sipe_private) /* Transition macros */ #define SIPE_ACCOUNT_DATA SIPE_CORE_PRIVATE->temporary diff --git a/src/core/sipe.c b/src/core/sipe.c index edbe4462..0a395b6f 100644 --- a/src/core/sipe.c +++ b/src/core/sipe.c @@ -293,22 +293,6 @@ static gboolean process_register_response(struct sipe_account_data *sip, struct static void send_presence_status(struct sipe_core_private *sipe_private, void *unused); -static void sendout_pkt(PurpleConnection *gc, const char *buf); - -void sipe_keep_alive(PurpleConnection *gc) -{ - struct sipe_account_data *sip = PURPLE_GC_TO_SIPE_ACCOUNT_DATA; - time_t now = time(NULL); - if ((sip->keepalive_timeout > 0) && - ((guint) (now - sip->last_keepalive) >= sip->keepalive_timeout) && - ((guint) (now - gc->last_received) >= sip->keepalive_timeout) - ) { - SIPE_DEBUG_INFO("sending keep alive %d", sip->keepalive_timeout); - sendout_pkt(gc, "\r\n\r\n"); - sip->last_keepalive = now; - } -} - static void sipe_auth_free(struct sip_auth *auth) { g_free(auth->opaque); @@ -532,68 +516,6 @@ static void fill_auth(const gchar *hdr, struct sip_auth *auth) return; } -static void sipe_canwrite_cb(gpointer data, - SIPE_UNUSED_PARAMETER gint source, - SIPE_UNUSED_PARAMETER PurpleInputCondition cond) -{ - PurpleConnection *gc = data; - struct sipe_account_data *sip = PURPLE_GC_TO_SIPE_ACCOUNT_DATA; - gsize max_write; - - max_write = purple_circ_buffer_get_max_read(sip->txbuf); - if (max_write > 0) { - gssize written = sip->gsc ? - (gssize) purple_ssl_write(sip->gsc, - sip->txbuf->outptr, - max_write) : - write(sip->fd, - sip->txbuf->outptr, - max_write); - - if (written < 0 && errno == EAGAIN) { - return; - } else if (written <= 0) { - /*TODO: do we really want to disconnect on a failure to write?*/ - purple_connection_error_reason(gc, - PURPLE_CONNECTION_ERROR_NETWORK_ERROR, - _("Could not write")); - return; - } - - purple_circ_buffer_mark_read(sip->txbuf, written); - - } else { - /* buffer is empty -> stop sending */ - purple_input_remove(sip->tx_handler); - sip->tx_handler = 0; - } -} - -static void sendout_pkt(PurpleConnection *gc, const char *buf) -{ - struct sipe_account_data *sip = PURPLE_GC_TO_SIPE_ACCOUNT_DATA; - time_t currtime = time(NULL); - char *tmp; - - SIPE_DEBUG_INFO("sending - %s######\n%s######", ctime(&currtime), tmp = fix_newlines(buf)); - g_free(tmp); - - /* add packet to circular buffer */ - purple_circ_buffer_append(sip->txbuf, buf, strlen(buf)); - - /* initiate transmission */ - if (!sip->tx_handler) { - sip->tx_handler = purple_input_add(sip->fd, PURPLE_INPUT_WRITE, - sipe_canwrite_cb, gc); - } -} - -int sipe_send_raw(PurpleConnection *gc, const char *buf, int len) -{ - sendout_pkt(gc, buf); - return len; -} - static void sipe_make_signature(struct sipe_account_data *sip, struct sipmsg *msg) @@ -694,7 +616,7 @@ void send_sip_response(PurpleConnection *gc, struct sipmsg *msg, int code, tmp = g_slist_next(tmp); } g_string_append_printf(outstr, "\r\n%s", body ? body : ""); - sendout_pkt(gc, outstr->str); + sipe_backend_transport_sip_message(gc->proto_data, outstr->str); g_string_free(outstr, TRUE); } @@ -764,7 +686,8 @@ send_sip_request(PurpleConnection *gc, const gchar *method, const gchar *url, const gchar *to, const gchar *addheaders, const gchar *body, struct sip_dialog *dialog, TransCallback tc) { - struct sipe_account_data *sip = PURPLE_GC_TO_SIPE_ACCOUNT_DATA; + struct sipe_core_private *sipe_private = gc->proto_data; + struct sipe_account_data *sip = SIPE_ACCOUNT_DATA_PRIVATE; char *buf; struct sipmsg *msg; gchar *ourtag = dialog && dialog->ourtag ? g_strdup(dialog->ourtag) : NULL; @@ -818,7 +741,7 @@ send_sip_request(PurpleConnection *gc, const gchar *method, dialog && dialog->request ? dialog->request : url, TRANSPORT_DESCRIPTOR, sipe_backend_network_ip_address(), - sip->port, + sipe_private->public.transport->client_port, branch ? ";branch=" : "", branch ? branch : "", sip->username, @@ -863,7 +786,7 @@ send_sip_request(PurpleConnection *gc, const gchar *method, } else { sipmsg_free(msg); } - sendout_pkt(gc, buf); + sipe_backend_transport_sip_message(SIPE_CORE_PUBLIC, buf); g_free(buf); return trans; @@ -918,7 +841,7 @@ static void do_register_exp(struct sipe_account_data *sip, int expire) "ms-keep-alive: UAC;hop-hop=yes\r\n" "%s", sipe_backend_network_ip_address(), - sip->port, + SIP_TO_CORE_PUBLIC->transport->client_port, TRANSPORT_DESCRIPTOR, uuid, expires); @@ -5398,60 +5321,27 @@ sipe_get_auth_scheme_name(struct sipe_account_data *sip) return res; } -static void sipe_connection_cleanup(struct sipe_account_data *); -static void create_connection(struct sipe_account_data *); - /* server_name must be g_alloc()'ed */ static void sipe_server_register(struct sipe_core_private *sipe_private, sipe_transport_type type, gchar *server_name, guint server_port) { - struct sipe_account_data *sip = SIPE_ACCOUNT_DATA_PRIVATE; - sipe_private->public.transport_type = type; sipe_private->public.server_name = server_name; sipe_private->public.server_port = (server_port != 0) ? server_port : (type == SIPE_TRANSPORT_TLS) ? 5061 : 5060; - create_connection(sip); + sipe_backend_transport_sip_connect(SIPE_CORE_PUBLIC); } -static void sipe_server_disconnect(struct sipe_core_private *sipe_private) -{ - struct sipe_account_data *sip = SIPE_ACCOUNT_DATA_PRIVATE; - - if (sip->gsc != NULL) { - purple_ssl_close(sip->gsc); - sip->gsc = NULL; - } else if (sip->fd > 0) { - close(sip->fd); - } - sip->fd = -1; - - if (sip->txbuf) - purple_circ_buffer_destroy(sip->txbuf); - sip->txbuf = NULL; - if (sip->tx_handler) - purple_input_remove(sip->tx_handler); - sip->tx_handler = 0; - - if (sip->rx_conn.inputhandler) - purple_input_remove(sip->rx_conn.inputhandler); - sip->rx_conn.inputhandler = 0; - sip->rx_conn.inbuflen = 0; - sip->rx_conn.inbufused = 0; - g_free(sip->rx_conn.inbuf); - sip->rx_conn.inbuf = NULL; - - g_free(sipe_private->public.server_name); - sipe_private->public.server_name = NULL; -} +static void sipe_connection_cleanup(struct sipe_account_data *); gboolean process_register_response(struct sipe_account_data *sip, struct sipmsg *msg, SIPE_UNUSED_PARAMETER struct transaction *trans) { + struct sipe_core_private *sipe_private = SIP_TO_CORE_PRIVATE; gchar *tmp; const gchar *expires_header; int expires, i; @@ -5481,7 +5371,7 @@ gboolean process_register_response(struct sipe_account_data *sip, struct sipmsg expires, do_register_cb, NULL, - SIP_TO_CORE_PRIVATE, + sipe_private, NULL); g_free(action_name); sip->reregister_set = TRUE; @@ -5518,7 +5408,7 @@ gboolean process_register_response(struct sipe_account_data *sip, struct sipmsg reauth_timeout, do_reauthenticate_cb, NULL, - SIP_TO_CORE_PRIVATE, + sipe_private, NULL); g_free(action_name); sip->reauthenticate_set = TRUE; @@ -5551,7 +5441,11 @@ gboolean process_register_response(struct sipe_account_data *sip, struct sipmsg g_free(gruu); } else { //SIPE_DEBUG_INFO_NOFORMAT("didn't find gruu in a Contact hdr"); - sip->contact = g_strdup_printf(";proxy=replace", sip->username, sip->port, sipe_backend_network_ip_address(), TRANSPORT_DESCRIPTOR); + sip->contact = g_strdup_printf(";proxy=replace", + sip->username, + sipe_private->public.transport->client_port, + sipe_backend_network_ip_address(), + TRANSPORT_DESCRIPTOR); } sip->ocs2007 = FALSE; sip->batched_support = FALSE; @@ -5614,7 +5508,7 @@ gboolean process_register_response(struct sipe_account_data *sip, struct sipmsg /* For 2005- servers */ else { - //sipe_options_request(sip, SIP_TO_CORE_PUBLIC->sip_domain); + //sipe_options_request(sip, sipe_private->public.sip_domain); if (g_slist_find_custom(sip->allow_events, "vnd-microsoft-roaming-ACL", (GCompareFunc)g_ascii_strcasecmp)) { @@ -5626,7 +5520,7 @@ gboolean process_register_response(struct sipe_account_data *sip, struct sipmsg } if (g_slist_find_custom(sip->allow_events, "presence.wpending", (GCompareFunc)g_ascii_strcasecmp)) { - sipe_subscribe_presence_wpending(SIP_TO_CORE_PRIVATE, + sipe_subscribe_presence_wpending(sipe_private, msg); } @@ -5649,9 +5543,9 @@ gboolean process_register_response(struct sipe_account_data *sip, struct sipmsg timeout = sipmsg_find_part_of_header(sipmsg_find_header(msg, "ms-keep-alive"), "timeout=", ";", NULL); if (timeout != NULL) { - sscanf(timeout, "%u", &sip->keepalive_timeout); + sscanf(timeout, "%u", &sipe_private->public.keepalive_timeout); SIPE_DEBUG_INFO("server determined keep alive timeout is %u seconds", - sip->keepalive_timeout); + sipe_private->public.keepalive_timeout); g_free(timeout); } @@ -5693,7 +5587,7 @@ gboolean process_register_response(struct sipe_account_data *sip, struct sipmsg sipe_connection_cleanup(sip); /* Create new connection */ - sipe_server_register(SIP_TO_CORE_PRIVATE, transport, hostname, port); + sipe_server_register(sipe_private, transport, hostname, port); SIPE_DEBUG_INFO("process_register_response: redirected to host %s port %d transport %s", hostname, port, TRANSPORT_DESCRIPTOR); } @@ -8020,7 +7914,7 @@ static void process_input_message(struct sipe_account_data *sip,struct sipmsg *m g_free(auth); resend = sipmsg_to_string(trans->msg); /* resend request */ - sendout_pkt(sip->gc, resend); + sipe_backend_transport_sip_message(sip->gc->proto_data, resend); g_free(resend); } else { if (msg->response < 200) { @@ -8066,7 +7960,7 @@ static void process_input_message(struct sipe_account_data *sip,struct sipmsg *m g_free(auth); resend = sipmsg_to_string(trans->msg); /* resend request */ - sendout_pkt(sip->gc, resend); + sipe_backend_transport_sip_message(sip->gc->proto_data, resend); g_free(resend); } } @@ -8092,48 +7986,53 @@ static void process_input_message(struct sipe_account_data *sip,struct sipmsg *m } } -static void process_input(struct sipe_account_data *sip, struct sip_connection *conn) +static void sipe_shrink_buffer(struct sipe_transport_connection *conn, + const gchar *to_here) { - char *cur; - char *dummy; - char *tmp; - struct sipmsg *msg; - int restlen; - cur = conn->inbuf; + conn->buffer_used -= to_here - conn->buffer; + /* string terminator is not included in buffer_used */ + memmove(conn->buffer, to_here, conn->buffer_used + 1); +} + +void sipe_core_transport_sip_message(struct sipe_core_public *sipe_public) +{ + struct sipe_transport_connection *conn = sipe_public->transport; + struct sipe_account_data *sip = SIPE_ACCOUNT_DATA; + gchar *cur = conn->buffer; /* according to the RFC remove CRLF at the beginning */ while (*cur == '\r' || *cur == '\n') { cur++; } - if (cur != conn->inbuf) { - memmove(conn->inbuf, cur, conn->inbufused - (cur - conn->inbuf)); - conn->inbufused = strlen(conn->inbuf); - } + if (cur != conn->buffer) + sipe_shrink_buffer(conn, cur); /* Received a full Header? */ sip->processing_input = TRUE; while (sip->processing_input && - ((cur = strstr(conn->inbuf, "\r\n\r\n")) != NULL)) { + ((cur = strstr(conn->buffer, "\r\n\r\n")) != NULL)) { + struct sipmsg *msg; + gchar *tmp; + guint remainder; time_t currtime = time(NULL); cur += 2; cur[0] = '\0'; - SIPE_DEBUG_INFO("received - %s######\n%s\n#######", ctime(&currtime), tmp = fix_newlines(conn->inbuf)); + SIPE_DEBUG_INFO("received - %s######\n%s\n#######", ctime(&currtime), tmp = fix_newlines(conn->buffer)); g_free(tmp); - msg = sipmsg_parse_header(conn->inbuf); + msg = sipmsg_parse_header(conn->buffer); cur[0] = '\r'; cur += 2; - restlen = conn->inbufused - (cur - conn->inbuf); - if (msg && restlen >= msg->bodylen) { - dummy = g_malloc(msg->bodylen + 1); + remainder = conn->buffer_used - (cur - conn->buffer); + if (msg && remainder >= (guint) msg->bodylen) { + char *dummy = g_malloc(msg->bodylen + 1); memcpy(dummy, cur, msg->bodylen); dummy[msg->bodylen] = '\0'; msg->body = dummy; cur += msg->bodylen; - memmove(conn->inbuf, cur, conn->inbuflen - (cur - conn->inbuf)); - conn->inbufused = strlen(conn->inbuf); + sipe_shrink_buffer(conn, cur); } else { if (msg){ - SIPE_DEBUG_INFO("process_input: body too short (%d < %d, strlen %d) - ignoring message", restlen, msg->bodylen, (int)strlen(conn->inbuf)); + SIPE_DEBUG_INFO("process_input: body too short (%d < %d, strlen %d) - ignoring message", remainder, msg->bodylen, (int)strlen(conn->buffer)); sipmsg_free(msg); } return; @@ -8181,100 +8080,6 @@ static void process_input(struct sipe_account_data *sip, struct sip_connection * } } -static void sipe_invalidate_connection(PurpleConnection *gc, - const char *msg, const char *debug) -{ - struct sipe_account_data *sip = PURPLE_GC_TO_SIPE_ACCOUNT_DATA; - - SIPE_DEBUG_ERROR("%s", debug); - purple_connection_error_reason(gc, - PURPLE_CONNECTION_ERROR_NETWORK_ERROR, - msg); - - sipe_server_disconnect(SIP_TO_CORE_PRIVATE); -} - -static void sipe_input_ssl_cb(gpointer data, PurpleSslConnection *gsc, - SIPE_UNUSED_PARAMETER PurpleInputCondition cond) -{ - PurpleConnection *gc = data; - struct sipe_account_data *sip; - struct sip_connection *conn; - int readlen, len; - gboolean firstread = TRUE; - - /* NOTE: This check *IS* necessary */ - if (!PURPLE_CONNECTION_IS_VALID(gc)) { - purple_ssl_close(gsc); - return; - } - - sip = PURPLE_GC_TO_SIPE_ACCOUNT_DATA; - conn = &sip->rx_conn; - - /* Read all available data from the SSL connection */ - do { - /* Increase input buffer size as needed */ - if (conn->inbuflen < conn->inbufused + SIMPLE_BUF_INC) { - conn->inbuflen += SIMPLE_BUF_INC; - conn->inbuf = g_realloc(conn->inbuf, conn->inbuflen); - SIPE_DEBUG_INFO("sipe_input_ssl_cb: new input buffer length %d", conn->inbuflen); - } - - /* Try to read as much as there is space left in the buffer */ - readlen = conn->inbuflen - conn->inbufused - 1; - len = purple_ssl_read(gsc, conn->inbuf + conn->inbufused, readlen); - - if (len < 0 && errno == EAGAIN) { - /* Try again later */ - return; - } else if (len < 0) { - sipe_invalidate_connection(gc, _("SSL read error"), "SSL read error\n"); - return; - } else if (firstread && (len == 0)) { - sipe_invalidate_connection(gc, _("Server has disconnected"), "Server has disconnected\n"); - return; - } - - conn->inbufused += len; - firstread = FALSE; - - /* Equivalence indicates that there is possibly more data to read */ - } while (len == readlen); - - conn->inbuf[conn->inbufused] = '\0'; - process_input(sip, conn); -} - -static void sipe_input_tcp_cb(gpointer data, - SIPE_UNUSED_PARAMETER gint source, - SIPE_UNUSED_PARAMETER PurpleInputCondition cond) -{ - PurpleConnection *gc = data; - struct sipe_account_data *sip = PURPLE_GC_TO_SIPE_ACCOUNT_DATA; - int len; - struct sip_connection *conn = &sip->rx_conn; - - if (conn->inbuflen < conn->inbufused + SIMPLE_BUF_INC) { - conn->inbuflen += SIMPLE_BUF_INC; - conn->inbuf = g_realloc(conn->inbuf, conn->inbuflen); - } - - len = read(sip->fd, conn->inbuf + conn->inbufused, SIMPLE_BUF_INC - 1); - - if (len < 0 && errno == EAGAIN) - return; - else if (len <= 0) { - sipe_invalidate_connection(gc, _("Server has disconnected"), "Server has disconnected\n"); - return; - } - - conn->inbufused += len; - conn->inbuf[conn->inbufused] = '\0'; - - process_input(sip, conn); -} - static guint sipe_ht_hash_nick(const char *nick) { char *lc = g_utf8_strdown(nick, -1); @@ -8312,125 +8117,19 @@ struct sipe_service_data { static const struct sipe_service_data *current_service = NULL; -static void sipe_ssl_connect_failure(SIPE_UNUSED_PARAMETER PurpleSslConnection *gsc, - PurpleSslErrorType error, - gpointer data) +void sipe_core_transport_sip_ssl_connect_failure(struct sipe_core_public *sipe_public) { - PurpleConnection *gc = data; - struct sipe_account_data *sip; - - /* If the connection is already disconnected, we don't need to do anything else */ - if (!PURPLE_CONNECTION_IS_VALID(gc)) - return; - - sip = PURPLE_GC_TO_SIPE_ACCOUNT_DATA; - current_service = sip->service_data; + current_service = SIPE_ACCOUNT_DATA->service_data; if (current_service) { SIPE_DEBUG_INFO("current_service: transport '%s' service '%s'", current_service->transport ? current_service->transport : "NULL", current_service->service ? current_service->service : "NULL"); } - - sip->fd = -1; - sip->gsc = NULL; - - purple_connection_ssl_error(gc, error); } -static void login_common(PurpleConnection *gc, - PurpleSslConnection *gsc, - int fd) +void sipe_core_transport_sip_connected(struct sipe_core_public *sipe_public) { - struct sipe_account_data *sip; - - if (!PURPLE_CONNECTION_IS_VALID(gc)) - { - if (gsc) { - purple_ssl_close(gsc); - } else if (fd >= 0) { - close(fd); - } - return; - } - - if (fd < 0) { - purple_connection_error_reason(gc, - PURPLE_CONNECTION_ERROR_NETWORK_ERROR, - _("Could not connect")); - return; - } - - sip = PURPLE_GC_TO_SIPE_ACCOUNT_DATA; - sip->fd = fd; - sip->port = purple_network_get_port_from_fd(fd); - sip->last_keepalive = time(NULL); - - if (gsc) { - sip->gsc = gsc; - purple_ssl_input_add(gsc, sipe_input_ssl_cb, gc); - } else { - sip->rx_conn.inputhandler = purple_input_add(fd, - PURPLE_INPUT_READ, - sipe_input_tcp_cb, - gc); - } - - do_register(sip); -} - - -static void login_ssl_cb(gpointer data, PurpleSslConnection *gsc, - SIPE_UNUSED_PARAMETER PurpleInputCondition cond) -{ - login_common(data, gsc, gsc ? gsc->fd : -1); -} - -static void login_tcp_cb(gpointer data, gint source, - SIPE_UNUSED_PARAMETER const gchar *error_message) -{ - login_common(data, NULL, source); -} - -static void create_connection(struct sipe_account_data *sip) -{ - struct sipe_core_public *sipe_public = SIP_TO_CORE_PUBLIC; - PurpleAccount *account = sip->account; - PurpleConnection *gc = sip->gc; - - SIPE_DEBUG_INFO("create_connection - hostname: %s port: %d", - sipe_public->server_name, - sipe_public->server_port); - - sip->txbuf = purple_circ_buffer_new(0); - - if (sipe_public->transport_type == SIPE_TRANSPORT_TLS) { - /* SSL case */ - SIPE_DEBUG_INFO_NOFORMAT("using SSL"); - - if (purple_ssl_connect(account, - sipe_public->server_name, - sipe_public->server_port, - login_ssl_cb, - sipe_ssl_connect_failure, gc) == NULL) { - purple_connection_error_reason(gc, - PURPLE_CONNECTION_ERROR_NETWORK_ERROR, - _("Could not create SSL context")); - return; - } - } else { - /* TCP case */ - SIPE_DEBUG_INFO_NOFORMAT("using TCP"); - - if (purple_proxy_connect(gc, account, - sipe_public->server_name, - sipe_public->server_port, - login_tcp_cb, gc) == NULL) { - purple_connection_error_reason(gc, - PURPLE_CONNECTION_ERROR_NETWORK_ERROR, - _("Could not create socket")); - return; - } - } + do_register(SIPE_ACCOUNT_DATA); } /* Service list for autodection */ @@ -8511,12 +8210,11 @@ static void srvresolved(PurpleSrvResponse *resp, int results, gpointer data) /* temporary function */ void sipe_purple_setup(struct sipe_core_public *sipe_public, - PurpleConnection *gc, - PurpleAccount *account) + PurpleConnection *gc) { struct sipe_account_data *sip = SIPE_ACCOUNT_DATA; sip->gc = gc; - sip->account = account; + sip->account = purple_connection_get_account(gc); } struct sipe_core_public *sipe_core_allocate(const gchar *signin_name, @@ -8594,10 +8292,10 @@ struct sipe_core_public *sipe_core_allocate(const gchar *signin_name, return((struct sipe_core_public *)sipe_private); } -void sipe_core_connect(struct sipe_core_public *sipe_public, - sipe_transport_type transport, - const gchar *server, - const gchar *port) +void sipe_core_transport_sip_connect(struct sipe_core_public *sipe_public, + sipe_transport_type transport, + const gchar *server, + const gchar *port) { struct sipe_account_data *sip = SIPE_ACCOUNT_DATA; @@ -8649,7 +8347,9 @@ static void sipe_connection_cleanup(struct sipe_account_data *sip) purple_srv_cancel(sip->srv_query_data); sip->srv_query_data = NULL; - sipe_server_disconnect(sipe_private); + sipe_backend_transport_sip_disconnect(SIPE_CORE_PUBLIC); + g_free(sipe_private->public.server_name); + sipe_private->public.server_name = NULL; sipe_auth_free(&sip->registrar); sipe_auth_free(&sip->proxy); diff --git a/src/core/sipe.h b/src/core/sipe.h index deae373f..e4e03244 100644 --- a/src/core/sipe.h +++ b/src/core/sipe.h @@ -28,20 +28,15 @@ * * * - * "sip-sec.h" */ /* Forward declarations */ struct sipmsg; struct _PurpleAccount; -struct _PurpleCircBuffer; struct _PurpleConnection; struct _PurpleDnsQueryData; struct _PurpleGroup; -struct _PurpleNetworkListenData; -struct _PurplePlugin; struct _PurpleSrvQueryData; -struct _PurpleSslConnection; struct sip_sec_context; struct sipe_core_private; struct sipe_service_data; @@ -149,7 +144,6 @@ struct sipe_account_data { gboolean ocs2007; /*if there is support for batched category subscription [SIP-PRES]*/ gboolean batched_support; /*if there is support for batched subscription*/ GSList *containers; /* MS-PRES containers */ - guint keepalive_timeout; struct _PurpleAccount *account; gchar *regcallid; GSList *transactions; @@ -170,15 +164,6 @@ struct sipe_account_data { * - User status */ gchar *user_states; - - /* transport-related state. This will be moved to backend... */ - struct _PurpleSslConnection *gsc; - int fd; - int port; /* client port */ - guint tx_handler; - struct _PurpleCircBuffer *txbuf; - struct sip_connection rx_conn; - time_t last_keepalive; }; struct sipe_auth_job { diff --git a/src/purple/Makefile.am b/src/purple/Makefile.am index 02f5c847..d979fb7b 100644 --- a/src/purple/Makefile.am +++ b/src/purple/Makefile.am @@ -8,6 +8,7 @@ MAINTAINERCLEANFILES = \ Makefile.in libsipe_backend_la_SOURCES = \ + purple-private.h \ purple-debug.c \ purple-markup.c \ purple-network.c \ diff --git a/src/purple/purple-plugin.c b/src/purple/purple-plugin.c index 4ddcb9ed..2be37933 100644 --- a/src/purple/purple-plugin.c +++ b/src/purple/purple-plugin.c @@ -25,6 +25,7 @@ #endif #include +#include #include @@ -44,6 +45,8 @@ #include "status.h" #include "version.h" +#include "purple-private.h" + #include "sipe-backend.h" #include "sipe-core.h" #include "sipe-nls.h" @@ -221,6 +224,7 @@ static void sipe_login(PurpleAccount *account) gchar *login_account = NULL; const gchar *errmsg; sipe_transport_type type; + struct sipe_backend_private *purple_private; /* username format: ,[] */ SIPE_DEBUG_INFO("sipe_login: username '%s'", username); @@ -255,8 +259,11 @@ static void sipe_login(PurpleAccount *account) return; } + sipe_public->backend_private = purple_private = g_new0(struct sipe_backend_private, 1); + purple_private->gc = gc; + gc->proto_data = sipe_public; - sipe_purple_setup(sipe_public, gc, account); + sipe_purple_setup(sipe_public, gc); gc->flags |= PURPLE_CONNECTION_HTML | PURPLE_CONNECTION_FORMATTING_WBFO | PURPLE_CONNECTION_NO_BGCOLOR | PURPLE_CONNECTION_NO_FONTSIZE | PURPLE_CONNECTION_NO_URLDESC | PURPLE_CONNECTION_ALLOW_CUSTOM_SMILEY; purple_connection_set_display_name(gc, sipe_public->sip_name); @@ -271,10 +278,10 @@ static void sipe_login(PurpleAccount *account) } else { type = SIPE_TRANSPORT_TCP; } - sipe_core_connect(sipe_public, - type, - username_split[0], - username_split[1]); + sipe_core_transport_sip_connect(sipe_public, + type, + username_split[0], + username_split[1]); g_strfreev(username_split); } @@ -295,12 +302,34 @@ static void sipe_chat_invite(PurpleConnection *gc, int id, sipe_core_chat_create(gc->proto_data, id, name); } +static void sipe_keep_alive(PurpleConnection *gc) +{ + struct sipe_core_public *sipe_public = gc->proto_data; + struct sipe_backend_private *purple_private = sipe_public->backend_private; + time_t now = time(NULL); + + if ((sipe_public->keepalive_timeout > 0) && + ((guint) (now - purple_private->last_keepalive) >= sipe_public->keepalive_timeout) && + ((guint) (now - gc->last_received) >= sipe_public->keepalive_timeout) + ) { + SIPE_DEBUG_INFO("sending keep alive %d", sipe_public->keepalive_timeout); + sipe_backend_transport_sip_message(sipe_public, "\r\n\r\n"); + purple_private->last_keepalive = now; + } +} + static void sipe_alias_buddy(PurpleConnection *gc, const char *name, SIPE_UNUSED_PARAMETER const char *alias) { sipe_core_group_set_user(gc->proto_data, name); } +static int sipe_send_raw(PurpleConnection *gc, const gchar *buf, int len) +{ + sipe_backend_transport_sip_message(gc->proto_data, buf); + return len; +} + #if PURPLE_VERSION_CHECK(2,5,0) static GHashTable * sipe_get_account_text_table(SIPE_UNUSED_PARAMETER PurpleAccount *account) diff --git a/src/purple/purple-transport.c b/src/purple/purple-private.h similarity index 65% copy from src/purple/purple-transport.c copy to src/purple/purple-private.h index e2d1bf2e..bfe892ef 100644 --- a/src/purple/purple-transport.c +++ b/src/purple/purple-private.h @@ -1,5 +1,5 @@ /** - * @file purple-transport.c + * @file purple-private.h * * pidgin-sipe * @@ -20,27 +20,12 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include +/* Forward declarations */ +struct _PurpleConnection; -#include - -#include "circbuffer.h" -#include "sslconn.h" - -#include -#include - -struct sipe_transport_purple { - /* public part shared with core */ - struct sipe_transport_connection public; - - /* purple private part */ - struct PurpleSslConnection *gsc; - struct PurpleCircBuffer *transmit_buffer; - guint transmit_handler; - guint receive_handler; - int socket; - guint port; /* port number associated with "socket" */ +struct sipe_backend_private { + struct _PurpleConnection *gc; + time_t last_keepalive; }; /* diff --git a/src/purple/purple-transport.c b/src/purple/purple-transport.c index e2d1bf2e..b767042a 100644 --- a/src/purple/purple-transport.c +++ b/src/purple/purple-transport.c @@ -20,28 +20,351 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include #include +#include #include +#include "sipe-common.h" + #include "circbuffer.h" +#include "connection.h" +#include "network.h" #include "sslconn.h" -#include -#include +#include "purple-private.h" + +#include "sipe-backend.h" +#include "sipe-core.h" +#include "sipe-nls.h" struct sipe_transport_purple { /* public part shared with core */ struct sipe_transport_connection public; /* purple private part */ - struct PurpleSslConnection *gsc; - struct PurpleCircBuffer *transmit_buffer; + PurpleSslConnection *gsc; + PurpleCircBuffer *transmit_buffer; guint transmit_handler; guint receive_handler; int socket; - guint port; /* port number associated with "socket" */ }; +#define PURPLE_TRANSPORT ((struct sipe_transport_purple *) sipe_public->transport) + +static void transport_invalidate_connection(PurpleConnection *gc, + const char *msg, const char *debug) +{ + SIPE_DEBUG_ERROR("%s", debug); + purple_connection_error_reason(gc, + PURPLE_CONNECTION_ERROR_NETWORK_ERROR, + msg); + + sipe_backend_transport_sip_disconnect(gc->proto_data); +} + +static void transport_input_common(PurpleConnection *gc) +{ + struct sipe_core_public *sipe_public = gc->proto_data; + struct sipe_transport_purple *transport = PURPLE_TRANSPORT; + struct sipe_transport_connection *conn = sipe_public->transport; + gssize readlen, len; + gboolean firstread = TRUE; + + /* Read all available data from the connection */ + do { + /* Increase input buffer size as needed */ +#define BUFFER_SIZE_INCREMENT 4096 + if (conn->buffer_length < conn->buffer_used + BUFFER_SIZE_INCREMENT) { + conn->buffer_length += BUFFER_SIZE_INCREMENT; + conn->buffer = g_realloc(conn->buffer, conn->buffer_length); + SIPE_DEBUG_INFO("transport_input_common: new buffer length %" G_GSIZE_FORMAT, + conn->buffer_length); + } + + /* Try to read as much as there is space left in the buffer */ + /* minus 1 for the string terminator */ + readlen = conn->buffer_length - conn->buffer_used - 1; + len = transport->gsc ? + (gssize) purple_ssl_read(transport->gsc, + conn->buffer + conn->buffer_used, + readlen) : + read(transport->socket, + conn->buffer + conn->buffer_used, + readlen); + + if (len < 0 && errno == EAGAIN) { + /* Try again later */ + return; + } else if (len < 0) { + transport_invalidate_connection(gc, + _("Read error"), + "Read error"); + return; + } else if (firstread && (len == 0)) { + transport_invalidate_connection(gc, + _("Server has disconnected"), + "Server has disconnected"); + return; + } + + conn->buffer_used += len; + firstread = FALSE; + + /* Equivalence indicates that there is possibly more data to read */ + } while (len == readlen); + + conn->buffer[conn->buffer_used] = '\0'; + sipe_core_transport_sip_message(sipe_public); +} + +static void transport_input_ssl_cb(gpointer data, + PurpleSslConnection *gsc, + SIPE_UNUSED_PARAMETER PurpleInputCondition cond) +{ + PurpleConnection *gc = data; + + /* NOTE: This check *IS* necessary */ + if (!PURPLE_CONNECTION_IS_VALID(gc)) { + purple_ssl_close(gsc); + return; + } + transport_input_common(gc); +} + +static void transport_input_tcp_cb(gpointer data, + gint source, + SIPE_UNUSED_PARAMETER PurpleInputCondition cond) +{ + PurpleConnection *gc = data; + + /* NOTE: This check *IS* necessary */ + if (!PURPLE_CONNECTION_IS_VALID(gc)) { + close(source); + return; + } + transport_input_common(gc); +} + +static void transport_ssl_connect_failure(SIPE_UNUSED_PARAMETER PurpleSslConnection *gsc, + PurpleSslErrorType error, + gpointer data) +{ + PurpleConnection *gc = data; + struct sipe_core_public *sipe_public; + struct sipe_transport_purple *transport; + + /* If the connection is already disconnected + then we don't need to do anything else */ + if (!PURPLE_CONNECTION_IS_VALID(gc)) + return; + + sipe_public = gc->proto_data; + sipe_core_transport_sip_ssl_connect_failure(sipe_public); + + transport = PURPLE_TRANSPORT; + transport->socket = -1; + transport->gsc = NULL; + + purple_connection_ssl_error(gc, error); +} + +static void transport_connected_common(PurpleConnection *gc, + PurpleSslConnection *gsc, + int fd) +{ + struct sipe_core_public *sipe_public; + struct sipe_transport_purple *transport; + + if (!PURPLE_CONNECTION_IS_VALID(gc)) + { + if (gsc) { + purple_ssl_close(gsc); + } else if (fd >= 0) { + close(fd); + } + return; + } + + if (fd < 0) { + purple_connection_error_reason(gc, + PURPLE_CONNECTION_ERROR_NETWORK_ERROR, + _("Could not connect")); + return; + } + + sipe_public = gc->proto_data; + transport = PURPLE_TRANSPORT; + transport->socket = fd; + sipe_public->transport->client_port = purple_network_get_port_from_fd(fd); + sipe_public->backend_private->last_keepalive = time(NULL); + + if (gsc) { + transport->gsc = gsc; + purple_ssl_input_add(gsc, transport_input_ssl_cb, gc); + } else { + transport->receive_handler = purple_input_add(fd, + PURPLE_INPUT_READ, + transport_input_tcp_cb, + gc); + } + + sipe_core_transport_sip_connected(sipe_public); +} + + +static void transport_connected_ssl_cb(gpointer data, + PurpleSslConnection *gsc, + SIPE_UNUSED_PARAMETER PurpleInputCondition cond) +{ + transport_connected_common(data, gsc, gsc ? gsc->fd : -1); +} + +static void transport_connected_tcp_cb(gpointer data, + gint source, + SIPE_UNUSED_PARAMETER const gchar *error_message) +{ + transport_connected_common(data, NULL, source); +} + +void sipe_backend_transport_sip_connect(struct sipe_core_public *sipe_public) +{ + struct sipe_backend_private *purple_private = sipe_public->backend_private; + PurpleConnection *gc = purple_private->gc; + PurpleAccount *account = purple_connection_get_account(gc); + struct sipe_transport_purple *transport = g_new0(struct sipe_transport_purple, 1); + + SIPE_DEBUG_INFO("create_connection - hostname: %s port: %d", + sipe_public->server_name, + sipe_public->server_port); + + transport->public.type = sipe_public->transport_type; + transport->transmit_buffer = purple_circ_buffer_new(0); + sipe_public->transport = (struct sipe_transport_connection *) transport; + + if (sipe_public->transport_type == SIPE_TRANSPORT_TLS) { + /* SSL case */ + SIPE_DEBUG_INFO_NOFORMAT("using SSL"); + + if (purple_ssl_connect(account, + sipe_public->server_name, + sipe_public->server_port, + transport_connected_ssl_cb, + transport_ssl_connect_failure, + gc) == NULL) { + purple_connection_error_reason(gc, + PURPLE_CONNECTION_ERROR_NETWORK_ERROR, + _("Could not create SSL context")); + return; + } + } else { + /* TCP case */ + SIPE_DEBUG_INFO_NOFORMAT("using TCP"); + + if (purple_proxy_connect(gc, account, + sipe_public->server_name, + sipe_public->server_port, + transport_connected_tcp_cb, + gc) == NULL) { + purple_connection_error_reason(gc, + PURPLE_CONNECTION_ERROR_NETWORK_ERROR, + _("Could not create socket")); + return; + } + } +} + +void sipe_backend_transport_sip_disconnect(struct sipe_core_public *sipe_public) +{ + struct sipe_transport_purple *transport = PURPLE_TRANSPORT; + + if (!transport) return; + + if (transport->gsc) { + purple_ssl_close(transport->gsc); + } else if (transport->socket > 0) { + close(transport->socket); + } + + if (transport->transmit_handler) + purple_input_remove(transport->transmit_handler); + if (transport->receive_handler) + purple_input_remove(transport->receive_handler); + + if (transport->transmit_buffer) + purple_circ_buffer_destroy(transport->transmit_buffer); + g_free(transport->public.buffer); + + g_free(transport); + sipe_public->transport = NULL; +} + +static void transport_canwrite_cb(gpointer data, + SIPE_UNUSED_PARAMETER gint source, + SIPE_UNUSED_PARAMETER PurpleInputCondition cond) +{ + PurpleConnection *gc = data; + struct sipe_core_public *sipe_public = gc->proto_data; + struct sipe_transport_purple *transport = PURPLE_TRANSPORT; + gsize max_write; + + max_write = purple_circ_buffer_get_max_read(transport->transmit_buffer); + if (max_write > 0) { + gssize written = transport->gsc ? + (gssize) purple_ssl_write(transport->gsc, + transport->transmit_buffer->outptr, + max_write) : + write(transport->socket, + transport->transmit_buffer->outptr, + max_write); + + if (written < 0 && errno == EAGAIN) { + return; + } else if (written <= 0) { + purple_connection_error_reason(gc, + PURPLE_CONNECTION_ERROR_NETWORK_ERROR, + _("Write error")); + return; + } + + purple_circ_buffer_mark_read(transport->transmit_buffer, + written); + + } else { + /* buffer is empty -> stop sending */ + purple_input_remove(transport->transmit_handler); + transport->transmit_handler = 0; + } +} + +void sipe_backend_transport_sip_message(struct sipe_core_public *sipe_public, + const gchar *buffer) +{ + struct sipe_transport_purple *transport = PURPLE_TRANSPORT; + time_t currtime = time(NULL); + char *tmp; + + SIPE_DEBUG_INFO("sending - %s######\n%s######", + ctime(&currtime), tmp = fix_newlines(buffer)); + g_free(tmp); + + /* add packet to circular buffer */ + purple_circ_buffer_append(transport->transmit_buffer, + buffer, strlen(buffer)); + + /* initiate transmission */ + if (!transport->transmit_handler) { + transport->transmit_handler = purple_input_add(transport->socket, + PURPLE_INPUT_WRITE, + transport_canwrite_cb, + sipe_public->backend_private->gc); + } +} /* Local Variables: -- 2.11.4.GIT