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

📄 peer.c

📁 Linux下的多协议即时通讯程序源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * 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*//* * Functions dealing with peer connections.  This includes the code * used to establish a peer connection for both Oscar File transfer * (OFT) and Oscar Direct Connect (ODC).  (ODC is also referred to * as DirectIM and IM Image.) */#ifdef HAVE_CONFIG_H#include  <config.h>#endif/* From the oscar PRPL */#include "oscar.h"#include "peer.h"/* From Purple */#include "conversation.h"#include "ft.h"#include "network.h"#include "notify.h"#include "request.h"#include "util.h"#ifndef _WIN32#include <stdio.h>#include <netdb.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h> /* for inet_ntoa */#include <limits.h> /* for UINT_MAX */#endif#ifdef _WIN32#include "win32dep.h"#endif/* * I really want to switch all our networking code to using IPv6 only, * but that really isn't a good idea at all.  Evan S. of Adium says * OS X sets all connections as "AF_INET6/PF_INET6," even if there is * nothing inherently IPv6 about them.  And I feel like Linux kernel * 2.6.5 is doing the same thing.  So we REALLY should accept * connections if they're showing up as IPv6.  Old OSes (Solaris?) * that might not have full IPv6 support yet will fail if we try * to use PF_INET6 but it isn't defined.  --Mark Doliner */#ifndef PF_INET6#define PF_INET6 PF_INET#endifPeerConnection *peer_connection_find_by_type(OscarData *od, const char *sn, OscarCapability type){	GSList *cur;	PeerConnection *conn;	for (cur = od->peer_connections; cur != NULL; cur = cur->next)	{		conn = cur->data;		if ((conn->type == type) && !aim_sncmp(conn->sn, sn))			return conn;	}	return NULL;}/** * @param cookie This must be exactly 8 characters. */PeerConnection *peer_connection_find_by_cookie(OscarData *od, const char *sn, const guchar *cookie){	GSList *cur;	PeerConnection *conn;	for (cur = od->peer_connections; cur != NULL; cur = cur->next)	{		conn = cur->data;		if (!memcmp(conn->cookie, cookie, 8) && !aim_sncmp(conn->sn, sn))			return conn;	}	return NULL;}PeerConnection *peer_connection_new(OscarData *od, OscarCapability type, const char *sn){	PeerConnection *conn;	PurpleAccount *account;	account = purple_connection_get_account(od->gc);	conn = g_new0(PeerConnection, 1);	conn->od = od;	conn->type = type;	conn->sn = g_strdup(sn);	conn->buffer_outgoing = purple_circ_buffer_new(0);	conn->listenerfd = -1;	conn->fd = -1;	conn->lastactivity = time(NULL);	conn->use_proxy |= purple_account_get_bool(account, "always_use_rv_proxy", FALSE);	if (type == OSCAR_CAPABILITY_DIRECTIM)		memcpy(conn->magic, "ODC2", 4);	else if (type == OSCAR_CAPABILITY_SENDFILE)		memcpy(conn->magic, "OFT2", 4);	od->peer_connections = g_slist_prepend(od->peer_connections, conn);	return conn;}static voidpeer_connection_close(PeerConnection *conn){	if (conn->type == OSCAR_CAPABILITY_DIRECTIM)		peer_odc_close(conn);	else if (conn->type == OSCAR_CAPABILITY_SENDFILE)		peer_oft_close(conn);	if (conn->verified_connect_data != NULL)	{		purple_proxy_connect_cancel(conn->verified_connect_data);		conn->verified_connect_data = NULL;	}	if (conn->client_connect_data != NULL)	{		purple_proxy_connect_cancel(conn->client_connect_data);		conn->client_connect_data = NULL;	}	if (conn->listen_data != NULL)	{		purple_network_listen_cancel(conn->listen_data);		conn->listen_data = NULL;	}	if (conn->connect_timeout_timer != 0)	{		purple_timeout_remove(conn->connect_timeout_timer);		conn->connect_timeout_timer = 0;	}	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;	}	if (conn->listenerfd >= 0)	{		close(conn->listenerfd);		conn->listenerfd = -1;	}	if (conn->fd >= 0)	{		close(conn->fd);		conn->fd = -1;	}	g_free(conn->buffer_incoming.data);	conn->buffer_incoming.data = NULL;	conn->buffer_incoming.len = 0;	conn->buffer_incoming.offset = 0;	purple_circ_buffer_destroy(conn->buffer_outgoing);	conn->buffer_outgoing = purple_circ_buffer_new(0);	conn->flags &= ~PEER_CONNECTION_FLAG_IS_INCOMING;}static gbooleanpeer_connection_destroy_cb(gpointer data){	PeerConnection *conn;	conn = data;	purple_request_close_with_handle(conn);	peer_connection_close(conn);	if (conn->checksum_data != NULL)		peer_oft_checksum_destroy(conn->checksum_data);	if (conn->xfer != NULL)	{		PurpleXferStatusType status;		conn->xfer->data = NULL;		status = purple_xfer_get_status(conn->xfer);		if ((status != PURPLE_XFER_STATUS_DONE) &&			(status != PURPLE_XFER_STATUS_CANCEL_LOCAL) &&			(status != PURPLE_XFER_STATUS_CANCEL_REMOTE))		{			if ((conn->disconnect_reason == OSCAR_DISCONNECT_REMOTE_CLOSED) ||				(conn->disconnect_reason == OSCAR_DISCONNECT_REMOTE_REFUSED))				purple_xfer_cancel_remote(conn->xfer);			else				purple_xfer_cancel_local(conn->xfer);		}		purple_xfer_unref(conn->xfer);		conn->xfer = NULL;	}	g_free(conn->sn);	g_free(conn->error_message);	g_free(conn->proxyip);	g_free(conn->clientip);	g_free(conn->verifiedip);	g_free(conn->xferdata.name);	purple_circ_buffer_destroy(conn->buffer_outgoing);	conn->od->peer_connections = g_slist_remove(conn->od->peer_connections, conn);	g_free(conn);	return FALSE;}voidpeer_connection_destroy(PeerConnection *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);	peer_connection_destroy_cb(conn);}voidpeer_connection_schedule_destroy(PeerConnection *conn, OscarDisconnectReason reason, const gchar *error_message){	if (conn->destroy_timeout != 0)		/* Already taken care of */		return;	purple_debug_info("oscar", "Scheduling destruction of peer connection\n");	conn->disconnect_reason = reason;	g_free(conn->error_message);	conn->error_message = g_strdup(error_message);	conn->destroy_timeout = purple_timeout_add(0, peer_connection_destroy_cb, conn);}/*******************************************************************//* Begin code for receiving data on a peer connection                *//*******************************************************************//** * This should be used to read ODC and OFT framing info.  It should * NOT be used to read the payload sent across the connection (IMs, * file data, etc), and it should NOT be used to read proxy negotiation * headers. * * Unlike flap_connection_recv_cb(), this only reads one frame at a * time.  This is done so that the watcher can be changed during the * handling of the frame.  If the watcher is changed then this * function will not read in any more data.  This happens when * reading the payload of a direct IM frame, or when we're * receiving a file from the remote user.  Once the data has been * read, the watcher will be switched back to this function to * continue reading the next frame. */voidpeer_connection_recv_cb(gpointer data, gint source, PurpleInputCondition cond){	PeerConnection *conn;	ssize_t read;	conn = data;	/* Start reading a new ODC/OFT frame */	if (conn->buffer_incoming.data == NULL)	{		/* Read the first 6 bytes (magic string and frame length) */		read = recv(conn->fd, conn->header + conn->header_received,				6 - conn->header_received, 0);		/* Check if the remote user closed the connection */		if (read == 0)		{			peer_connection_destroy(conn, OSCAR_DISCONNECT_REMOTE_CLOSED, NULL);			return;		}		/* If there was an error then close the connection */		if (read < 0)		{			if ((errno == EAGAIN) || (errno == EWOULDBLOCK))				/* No worries */				return;			peer_connection_destroy(conn,					OSCAR_DISCONNECT_LOST_CONNECTION, strerror(errno));			return;		}		conn->lastactivity = time(NULL);		/* If we don't even have the first 6 bytes then do nothing */		conn->header_received += read;		if (conn->header_received < 6)			return;		/* All ODC/OFT frames must start with a magic string */		if (memcmp(conn->magic, conn->header, 4))		{			purple_debug_warning("oscar", "Expecting magic string to "				"be %c%c%c%c but received magic string %c%c%c%c.  "				"Closing connection.\n",				conn->magic[0], conn->magic[1], conn->magic[2],				conn->magic[3], conn->header[0], conn->header[1],				conn->header[2], conn->header[3]);			peer_connection_destroy(conn, OSCAR_DISCONNECT_INVALID_DATA, NULL);			return;		}		/* Initialize a new temporary ByteStream for incoming data */		conn->buffer_incoming.len = aimutil_get16(&conn->header[4]) - 6;		conn->buffer_incoming.data = g_new(guint8, conn->buffer_incoming.len);		conn->buffer_incoming.offset = 0;	}	/* Read data into the temporary buffer until it is complete */	read = recv(conn->fd,				&conn->buffer_incoming.data[conn->buffer_incoming.offset],				conn->buffer_incoming.len - conn->buffer_incoming.offset,				0);	/* Check if the remote user closed the connection */	if (read == 0)	{		peer_connection_destroy(conn, OSCAR_DISCONNECT_REMOTE_CLOSED, NULL);		return;	}

⌨️ 快捷键说明

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