⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 flap_connection.c

📁 Linux下的多协议即时通讯程序源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Purple's oscar protocol plugin * This file is the legal property of its developers. * Please see the AUTHORS file distributed alongside this file. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA*/#include "oscar.h"#include "eventloop.h"#include "proxy.h"#ifndef _WIN32#include <netdb.h>#include <sys/socket.h>#include <netinet/in.h>#endif#ifdef _WIN32#include "win32dep.h"#endif/** * This sends a channel 1 SNAC containing the FLAP version. * The FLAP version is sent by itself at the beginning of every * connection to a FLAP server.  It is always the very first * packet sent by both the server and the client after the SYN, * SYN/ACK, ACK handshake. */voidflap_connection_send_version(OscarData *od, FlapConnection *conn){	FlapFrame *frame;	frame = flap_frame_new(od, 0x01, 4);	byte_stream_put32(&frame->data, 0x00000001);	flap_connection_send(conn, frame);}/** * This sends a channel 1 FLAP containing the FLAP version and * the authentication cookie.  This is sent when connecting to * any FLAP server after the initial connection to the auth * server.  It is always the very first packet sent by both the * server and the client after the SYN, SYN/ACK, ACK handshake. */voidflap_connection_send_version_with_cookie(OscarData *od, FlapConnection *conn, guint16 length, const guint8 *chipsahoy){	FlapFrame *frame;	GSList *tlvlist = NULL;	frame = flap_frame_new(od, 0x01, 4 + 2 + 2 + length);	byte_stream_put32(&frame->data, 0x00000001);	aim_tlvlist_add_raw(&tlvlist, 0x0006, length, chipsahoy);	aim_tlvlist_write(&frame->data, &tlvlist);	aim_tlvlist_free(tlvlist);	flap_connection_send(conn, frame);}static struct rateclass *flap_connection_get_rateclass(FlapConnection *conn, guint16 family, guint16 subtype){	GSList *tmp1;	gconstpointer key;	key = GUINT_TO_POINTER((family << 16) + subtype);	for (tmp1 = conn->rateclasses; tmp1 != NULL; tmp1 = tmp1->next)	{		struct rateclass *rateclass;		rateclass = tmp1->data;		if (g_hash_table_lookup(rateclass->members, key))			return rateclass;	}	return NULL;}/* * Attempt to calculate what our new current average would be if we * were to send a SNAC in this rateclass at the given time. */static guint32rateclass_get_new_current(FlapConnection *conn, struct rateclass *rateclass, struct timeval *now){	unsigned long timediff; /* In milliseconds */	timediff = (now->tv_sec - rateclass->last.tv_sec) * 1000 + (now->tv_usec - rateclass->last.tv_usec) / 1000;	/* This formula is taken from the joscar API docs. Preesh. */	return MIN(((rateclass->current * (rateclass->windowsize - 1)) + timediff) / rateclass->windowsize, rateclass->max);}static gboolean flap_connection_send_queued(gpointer data){	FlapConnection *conn;	struct timeval now;	conn = data;	gettimeofday(&now, NULL);	while (!g_queue_is_empty(conn->queued_snacs))	{		QueuedSnac *queued_snac;		struct rateclass *rateclass;		queued_snac = g_queue_peek_head(conn->queued_snacs);		rateclass = flap_connection_get_rateclass(conn, queued_snac->family, queued_snac->subtype);		if (rateclass != NULL)		{			guint32 new_current;			new_current = rateclass_get_new_current(conn, rateclass, &now);			if (new_current < rateclass->alert + 100)				/* (Add 100ms padding to account for inaccuracies in the calculation) */				/* Not ready to send this SNAC yet--keep waiting. */				return TRUE;			rateclass->current = new_current;			rateclass->last.tv_sec = now.tv_sec;			rateclass->last.tv_usec = now.tv_usec;		}		flap_connection_send(conn, queued_snac->frame);		g_free(queued_snac);		g_queue_pop_head(conn->queued_snacs);	}	conn->queued_timeout = 0;	return FALSE;}/** * This sends a channel 2 FLAP containing a SNAC.  The SNAC family and * subtype are looked up in the rate info for this connection, and if * sending this SNAC will induce rate limiting then we delay sending * of the SNAC by putting it into an outgoing holding queue. * * @param data The optional bytestream that makes up the data portion *        of this SNAC.  For empty SNACs this should be NULL. */voidflap_connection_send_snac(OscarData *od, FlapConnection *conn, guint16 family, guint16 subtype, guint16 flags, aim_snacid_t snacid, ByteStream *data){	FlapFrame *frame;	guint32 length;	gboolean enqueue = FALSE;	struct rateclass *rateclass;	length = data != NULL ? data->offset : 0;	frame = flap_frame_new(od, 0x02, 10 + length);	aim_putsnac(&frame->data, family, subtype, flags, snacid);	if (length > 0)	{		byte_stream_rewind(data);		byte_stream_putbs(&frame->data, data, length);	}	if (conn->queued_timeout != 0)		enqueue = TRUE;	else if ((rateclass = flap_connection_get_rateclass(conn, family, subtype)) != NULL)	{		struct timeval now;		guint32 new_current;		gettimeofday(&now, NULL);		new_current = rateclass_get_new_current(conn, rateclass, &now);		if (new_current < rateclass->alert + 100)		{			/* (Add 100ms padding to account for inaccuracies in the calculation) */			enqueue = TRUE;		}		else		{			rateclass->current = new_current;			rateclass->last.tv_sec = now.tv_sec;			rateclass->last.tv_usec = now.tv_usec;		}	}	if (enqueue)	{		/* We've been sending too fast, so delay this message */		QueuedSnac *queued_snac;		queued_snac = g_new(QueuedSnac, 1);		queued_snac->family = family;		queued_snac->subtype = subtype;		queued_snac->frame = frame;		g_queue_push_tail(conn->queued_snacs, queued_snac);		if (conn->queued_timeout == 0)			conn->queued_timeout = purple_timeout_add(500, flap_connection_send_queued, conn);		return;	}	flap_connection_send(conn, frame);}/** * This sends an empty channel 4 FLAP.  This is sent to signify * that we're logging off.  This shouldn't really be necessary-- * usually the AIM server will detect that the TCP connection has * been destroyed--but it's good practice. */static voidflap_connection_send_close(OscarData *od, FlapConnection *conn){	FlapFrame *frame;	frame = flap_frame_new(od, 0x04, 0);	flap_connection_send(conn, frame);}/** * This sends an empty channel 5 FLAP.  This is used as a keepalive * packet in FLAP connections.  WinAIM 4.x and higher send these * _every minute_ to keep the connection alive. */voidflap_connection_send_keepalive(OscarData *od, FlapConnection *conn){	FlapFrame *frame;	frame = flap_frame_new(od, 0x05, 0);	flap_connection_send(conn, frame);	/* clean out SNACs over 60sec old */	aim_cleansnacs(od, 60);}/** * Allocate a new empty connection structure. * * @param od The oscar session associated with this connection. * @param type Type of connection to create * * @return Returns the new connection structure. */FlapConnection *flap_connection_new(OscarData *od, int type){	FlapConnection *conn;	conn = g_new0(FlapConnection, 1);	conn->od = od;	conn->buffer_outgoing = purple_circ_buffer_new(0);	conn->fd = -1;	conn->subtype = -1;	conn->type = type;	conn->queued_snacs = g_queue_new();	od->oscar_connections = g_slist_prepend(od->oscar_connections, conn);	return conn;}/** * Close (but not free) a connection. * * This cancels any currently pending connection attempt, * closes any open fd and frees the auth cookie. * * @param conn The connection to close. */voidflap_connection_close(OscarData *od, FlapConnection *conn){	if (conn->connect_data != NULL)	{		purple_proxy_connect_cancel(conn->connect_data);		conn->connect_data = NULL;	}	if (conn->connect_data != NULL)	{		if (conn->type == SNAC_FAMILY_CHAT)		{			oscar_chat_destroy(conn->new_conn_data);			conn->connect_data = NULL;		}	}	if (conn->fd >= 0)	{		if (conn->type == SNAC_FAMILY_LOCATE)			flap_connection_send_close(od, conn);		close(conn->fd);		conn->fd = -1;	}	if (conn->watcher_incoming != 0)	{		purple_input_remove(conn->watcher_incoming);		conn->watcher_incoming = 0;	}	if (conn->watcher_outgoing != 0)	{		purple_input_remove(conn->watcher_outgoing);		conn->watcher_outgoing = 0;	}	g_free(conn->buffer_incoming.data.data);	conn->buffer_incoming.data.data = NULL;	purple_circ_buffer_destroy(conn->buffer_outgoing);	conn->buffer_outgoing = NULL;}static voidflap_connection_destroy_rateclass(struct rateclass *rateclass){	g_hash_table_destroy(rateclass->members);	g_free(rateclass);}/** * Free a FlapFrame * * @param frame The frame to free. */static voidflap_frame_destroy(FlapFrame *frame){	g_free(frame->data.data);	g_free(frame);}static gbooleanflap_connection_destroy_cb(gpointer data){	FlapConnection *conn;	OscarData *od;	PurpleAccount *account;	conn = data;	od = conn->od;	account = (PURPLE_CONNECTION_IS_VALID(od->gc) ? purple_connection_get_account(od->gc) : NULL);	purple_debug_info("oscar", "Destroying oscar connection of "			"type 0x%04hx\n", conn->type);	od->oscar_connections = g_slist_remove(od->oscar_connections, conn);	/*	 * TODO: If we don't have a SNAC_FAMILY_LOCATE connection then	 * we should try to request one instead of disconnecting.	 */	if (account && !account->disconnecting &&		((od->oscar_connections == NULL) || (!flap_connection_getbytype(od, SNAC_FAMILY_LOCATE))))	{		/* No more FLAP connections!  Sign off this PurpleConnection! */		gchar *tmp;		if (conn->disconnect_reason == OSCAR_DISCONNECT_REMOTE_CLOSED)			tmp = g_strdup(_("Server closed the connection."));		else if (conn->disconnect_reason == OSCAR_DISCONNECT_LOST_CONNECTION)			tmp = g_strdup_printf(_("Lost connection with server:\n%s"),					conn->error_message);		else if (conn->disconnect_reason == OSCAR_DISCONNECT_INVALID_DATA)			tmp = g_strdup(_("Received invalid data on connection with server."));		else if (conn->disconnect_reason == OSCAR_DISCONNECT_COULD_NOT_CONNECT)			tmp = g_strdup_printf(_("Could not establish a connection with the server:\n%s"),					conn->error_message);		else			/*			 * We shouldn't print a message for some disconnect_reasons.			 * Like OSCAR_DISCONNECT_LOCAL_CLOSED.			 */			tmp = NULL;		if (tmp != NULL)		{			purple_connection_error(od->gc, tmp);			g_free(tmp);		}	}	flap_connection_close(od, conn);	g_free(conn->error_message);	g_free(conn->cookie);	/*	 * Free conn->internal, if necessary	 */	if (conn->type == SNAC_FAMILY_CHAT)		flap_connection_destroy_chat(od, conn);	g_slist_free(conn->groups);	while (conn->rateclasses != NULL)	{		flap_connection_destroy_rateclass(conn->rateclasses->data);		conn->rateclasses = g_slist_delete_link(conn->rateclasses, conn->rateclasses);	}	while (!g_queue_is_empty(conn->queued_snacs))	{		QueuedSnac *queued_snac;		queued_snac = g_queue_pop_head(conn->queued_snacs);		flap_frame_destroy(queued_snac->frame);		g_free(queued_snac);	}	g_queue_free(conn->queued_snacs);	if (conn->queued_timeout > 0)		purple_timeout_remove(conn->queued_timeout);	g_free(conn);	return FALSE;}/** * See the comments for the parameters of * flap_connection_schedule_destroy(). */voidflap_connection_destroy(FlapConnection *conn, OscarDisconnectReason reason, const gchar *error_message){	if (conn->destroy_timeout != 0)		purple_timeout_remove(conn->destroy_timeout);	conn->disconnect_reason = reason;	g_free(conn->error_message);	conn->error_message = g_strdup(error_message);	flap_connection_destroy_cb(conn);}/** * Schedule Purple to destroy the given FlapConnection as soon as we * return control back to the program's main loop.  We must do this * if we want to destroy the connection but we are still using it * for some reason. * * @param reason The reason for the disconnection. * @param error_message A brief error message that gives more detail *        regarding the reason for the disconnecting.  This should *        be NULL for everything except OSCAR_DISCONNECT_LOST_CONNECTION, *        in which case it should contain the value of strerror(errno), *        and OSCAR_DISCONNECT_COULD_NOT_CONNECT, in which case it *        should contain the error_message passed back from the call *        to purple_proxy_connect(). */voidflap_connection_schedule_destroy(FlapConnection *conn, OscarDisconnectReason reason, const gchar *error_message){	if (conn->destroy_timeout != 0)		/* Already taken care of */		return;	purple_debug_info("oscar", "Scheduling destruction of FLAP "			"connection of type 0x%04hx\n", conn->type);	conn->disconnect_reason = reason;	g_free(conn->error_message);	conn->error_message = g_strdup(error_message);	conn->destroy_timeout = purple_timeout_add(0, flap_connection_destroy_cb, conn);}/** * In OSCAR, every connection has a set of SNAC groups associated * with it.  These are the groups that you can send over this connection * without being guaranteed a "Not supported" SNAC error. * * The grand theory of things says that these associations transcend * what libfaim calls "connection types" (conn->type).  You can probably * see the elegance here, but since I want to revel in it for a bit, you * get to hear it all spelled out. * * So let us say that you have your core BOS connection running.  One

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -