File:  [Coherent Logic Development] / ChivanetAimPidgin / oscarprpl / src / c / peer_proxy.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Mon Jan 27 19:48:25 2025 UTC (6 months ago) by snw
Branches: MAIN, CoherentLogicDevelopment
CVS tags: test-tag, start, HEAD
Pidgin AIM Plugin for ChivaNet

    1: /*
    2:  * Purple's oscar protocol plugin
    3:  * This file is the legal property of its developers.
    4:  * Please see the AUTHORS file distributed alongside this file.
    5:  *
    6:  * This library is free software; you can redistribute it and/or
    7:  * modify it under the terms of the GNU Lesser General Public
    8:  * License as published by the Free Software Foundation; either
    9:  * version 2 of the License, or (at your option) any later version.
   10:  *
   11:  * This library is distributed in the hope that it will be useful,
   12:  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   13:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   14:  * Lesser General Public License for more details.
   15:  *
   16:  * You should have received a copy of the GNU Lesser General Public
   17:  * License along with this library; if not, write to the Free Software
   18:  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
   19: */
   20: 
   21: #ifdef HAVE_CONFIG_H
   22: #include  <config.h>
   23: #endif
   24: 
   25: #include "oscar.h"
   26: #include "peer.h"
   27: 
   28: static void
   29: peer_proxy_send(PeerConnection *conn, ProxyFrame *frame)
   30: {
   31: 	size_t length;
   32: 	ByteStream bs;
   33: 
   34: 	purple_debug_info("oscar", "Outgoing peer proxy frame with "
   35: 			"type=0x%04hx, unknown=0x%08x, flags=0x%04hx, and "
   36: 			"payload length=%" G_GSIZE_FORMAT "\n",
   37: 			frame->type, frame->unknown,
   38: 			frame->flags, frame->payload.len);
   39: 
   40: 	length = 12 + frame->payload.len;
   41: 	byte_stream_new(&bs, length);
   42: 	byte_stream_put16(&bs, length - 2);
   43: 	byte_stream_put16(&bs, PEER_PROXY_PACKET_VERSION);
   44: 	byte_stream_put16(&bs, frame->type);
   45: 	byte_stream_put32(&bs, frame->unknown);
   46: 	byte_stream_put16(&bs, frame->flags);
   47: 	byte_stream_putraw(&bs, frame->payload.data, frame->payload.len);
   48: 
   49: 	peer_connection_send(conn, &bs);
   50: 
   51: 	byte_stream_destroy(&bs);
   52: }
   53: 
   54: /**
   55:  * Create a rendezvous "init send" packet and send it on its merry way.
   56:  * This is the first packet sent to the proxy server by the first client
   57:  * to indicate that this will be a proxied connection
   58:  *
   59:  * @param conn The peer connection.
   60:  */
   61: static void
   62: peer_proxy_send_create_new_conn(PeerConnection *conn)
   63: {
   64: 	ProxyFrame frame;
   65: 	PurpleAccount *account;
   66: 	const gchar *bn;
   67: 	guint8 bn_length;
   68: 
   69: 	memset(&frame, 0, sizeof(ProxyFrame));
   70: 	frame.type = PEER_PROXY_TYPE_CREATE;
   71: 	frame.flags = 0x0000;
   72: 
   73: 	account = purple_connection_get_account(conn->od->gc);
   74: 	bn = purple_account_get_username(account);
   75: 	bn_length = strlen(bn);
   76: 	byte_stream_new(&frame.payload, 1 + bn_length + 8 + 20);
   77: 	byte_stream_put8(&frame.payload, bn_length);
   78: 	byte_stream_putraw(&frame.payload, (const guint8 *)bn, bn_length);
   79: 	byte_stream_putraw(&frame.payload, conn->cookie, 8);
   80: 
   81: 	byte_stream_put16(&frame.payload, 0x0001); /* Type */
   82: 	byte_stream_put16(&frame.payload, 16); /* Length */
   83: 	byte_stream_putcaps(&frame.payload, conn->type); /* Value */
   84: 
   85: 	peer_proxy_send(conn, &frame);
   86: 
   87: 	byte_stream_destroy(&frame.payload);
   88: }
   89: 
   90: /**
   91:  * Create a rendezvous "init recv" packet and send it on its merry way.
   92:  * This is the first packet sent to the proxy server by the second client
   93:  * involved in this rendezvous proxy session.
   94:  *
   95:  * @param conn The peer connection.
   96:  * @param pin The 2 byte PIN sent to us by the other user.  This acts
   97:  *        as our passcode when establishing the proxy session.
   98:  */
   99: static void
  100: peer_proxy_send_join_existing_conn(PeerConnection *conn, guint16 pin)
  101: {
  102: 	ProxyFrame frame;
  103: 	PurpleAccount *account;
  104: 	const gchar *bn;
  105: 	guint8 bn_length;
  106: 
  107: 	memset(&frame, 0, sizeof(ProxyFrame));
  108: 	frame.type = PEER_PROXY_TYPE_JOIN;
  109: 	frame.flags = 0x0000;
  110: 
  111: 	account = purple_connection_get_account(conn->od->gc);
  112: 	bn = purple_account_get_username(account);
  113: 	bn_length = strlen(bn);
  114: 	byte_stream_new(&frame.payload, 1 + bn_length + 2 + 8 + 20);
  115: 	byte_stream_put8(&frame.payload, bn_length);
  116: 	byte_stream_putraw(&frame.payload, (const guint8 *)bn, bn_length);
  117: 	byte_stream_put16(&frame.payload, pin);
  118: 	byte_stream_putraw(&frame.payload, conn->cookie, 8);
  119: 
  120: 	byte_stream_put16(&frame.payload, 0x0001); /* Type */
  121: 	byte_stream_put16(&frame.payload, 16); /* Length */
  122: 	byte_stream_putcaps(&frame.payload, conn->type); /* Value */
  123: 
  124: 	peer_proxy_send(conn, &frame);
  125: 
  126: 	byte_stream_destroy(&frame.payload);
  127: }
  128: 
  129: /**
  130:  * Handle an incoming peer proxy negotiation frame.
  131:  */
  132: static void
  133: peer_proxy_recv_frame(PeerConnection *conn, ProxyFrame *frame)
  134: {
  135: 	purple_debug_info("oscar", "Incoming peer proxy frame with "
  136: 			"type=0x%04hx, unknown=0x%08x, flags=0x%04hx, and "
  137: 			"payload length=%" G_GSIZE_FORMAT "\n", frame->type,
  138: 			frame->unknown, frame->flags, frame->payload.len);
  139: 
  140: 	if (frame->type == PEER_PROXY_TYPE_CREATED)
  141: 	{
  142: 		/*
  143: 		 * Read in 2 byte port then 4 byte IP and tell the
  144: 		 * remote user to connect to it by sending an ICBM.
  145: 		 */
  146: 		guint16 pin;
  147: 		int i;
  148: 		guint8 ip[4];
  149: 
  150: 		pin = byte_stream_get16(&frame->payload);
  151: 		for (i = 0; i < 4; i++)
  152: 			ip[i] = byte_stream_get8(&frame->payload);
  153: 		if (conn->type == OSCAR_CAPABILITY_DIRECTIM)
  154: 			aim_im_sendch2_odc_requestproxy(conn->od,
  155: 					conn->cookie,
  156: 					conn->bn, ip, pin, ++conn->lastrequestnumber);
  157: 		else if (conn->type == OSCAR_CAPABILITY_SENDFILE)
  158: 		{
  159: 			aim_im_sendch2_sendfile_requestproxy(conn->od,
  160: 					conn->cookie, conn->bn,
  161: 					ip, pin, ++conn->lastrequestnumber,
  162: 					(const gchar *)conn->xferdata.name,
  163: 					conn->xferdata.size, conn->xferdata.totfiles);
  164: 		}
  165: 	}
  166: 	else if (frame->type == PEER_PROXY_TYPE_READY)
  167: 	{
  168: 		purple_input_remove(conn->watcher_incoming);
  169: 		conn->watcher_incoming = 0;
  170: 
  171: 		peer_connection_finalize_connection(conn);
  172: 	}
  173: 	else if (frame->type == PEER_PROXY_TYPE_ERROR)
  174: 	{
  175: 		if (byte_stream_bytes_left(&frame->payload) >= 2)
  176: 		{
  177: 			guint16 error;
  178: 			const char *msg;
  179: 			error = byte_stream_get16(&frame->payload);
  180: 			if (error == 0x000d)
  181: 				msg = "bad request";
  182: 			else if (error == 0x0010)
  183: 				msg = "initial request timed out";
  184: 			else if (error == 0x001a)
  185: 				msg ="accept period timed out";
  186: 			else
  187: 				msg = "unknown reason";
  188: 			purple_debug_info("oscar", "Proxy negotiation failed with "
  189: 					"error 0x%04hx: %s\n", error, msg);
  190: 		}
  191: 		else
  192: 		{
  193: 			purple_debug_warning("oscar", "Proxy negotiation failed with "
  194: 					"an unknown error\n");
  195: 		}
  196: 		peer_connection_trynext(conn);
  197: 	}
  198: 	else
  199: 	{
  200: 		purple_debug_warning("oscar", "Unknown peer proxy frame type 0x%04hx.\n",
  201: 				frame->type);
  202: 	}
  203: }
  204: 
  205: static void
  206: peer_proxy_connection_recv_cb(gpointer data, gint source, PurpleInputCondition cond)
  207: {
  208: 	PeerConnection *conn;
  209: 	gssize read;
  210: 	ProxyFrame *frame;
  211: 
  212: 	conn = data;
  213: 	frame = conn->frame;
  214: 
  215: 	/* Start reading a new proxy frame */
  216: 	if (frame == NULL)
  217: 	{
  218: 		/* Read the first 12 bytes (frame length and header) */
  219: 		read = recv(conn->fd, conn->proxy_header + conn->proxy_header_received,
  220: 				12 - conn->proxy_header_received, 0);
  221: 
  222: 		/* Check if the proxy server closed the connection */
  223: 		if (read == 0)
  224: 		{
  225: 			purple_debug_info("oscar", "Peer proxy server closed connection\n");
  226: 			peer_connection_trynext(conn);
  227: 			return;
  228: 		}
  229: 
  230: 		/* If there was an error then close the connection */
  231: 		if (read < 0)
  232: 		{
  233: 			if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
  234: 				/* No worries */
  235: 				return;
  236: 
  237: 			purple_debug_info("oscar", "Lost connection with peer proxy server\n");
  238: 			peer_connection_trynext(conn);
  239: 			return;
  240: 		}
  241: 
  242: 		conn->lastactivity = time(NULL);
  243: 
  244: 		/* If we don't even have the first 12 bytes then do nothing */
  245: 		conn->proxy_header_received += read;
  246: 		if (conn->proxy_header_received < 12)
  247: 			return;
  248: 
  249: 		/* We only support a specific version of the proxy protocol */
  250: 		if (aimutil_get16(&conn->proxy_header[2]) != PEER_PROXY_PACKET_VERSION)
  251: 		{
  252: 			purple_debug_warning("oscar", "Expected peer proxy protocol "
  253: 				"version %u but received version %u.  Closing "
  254: 				"connection.\n", PEER_PROXY_PACKET_VERSION,
  255: 				aimutil_get16(&conn->proxy_header[2]));
  256: 			peer_connection_trynext(conn);
  257: 			return;
  258: 		}
  259: 
  260: 		/* Initialize a new temporary ProxyFrame for incoming data */
  261: 		frame = g_new0(ProxyFrame, 1);
  262: 		frame->payload.len = aimutil_get16(&conn->proxy_header[0]) - 10;
  263: 		frame->version = aimutil_get16(&conn->proxy_header[2]);
  264: 		frame->type = aimutil_get16(&conn->proxy_header[4]);
  265: 		frame->unknown = aimutil_get16(&conn->proxy_header[6]);
  266: 		frame->flags = aimutil_get16(&conn->proxy_header[10]);
  267: 		if (frame->payload.len > 0)
  268: 			frame->payload.data = g_new(guint8, frame->payload.len);
  269: 		conn->frame = frame;
  270: 	}
  271: 
  272: 	/* If this frame has a payload then attempt to read it */
  273: 	if (frame->payload.len - frame->payload.offset > 0)
  274: 	{
  275: 		/* Read data into the temporary buffer until it is complete */
  276: 		read = recv(conn->fd,
  277: 					&frame->payload.data[frame->payload.offset],
  278: 					frame->payload.len - frame->payload.offset,
  279: 					0);
  280: 
  281: 		/* Check if the proxy server closed the connection */
  282: 		if (read == 0)
  283: 		{
  284: 			purple_debug_info("oscar", "Peer proxy server closed connection\n");
  285: 			g_free(frame->payload.data);
  286: 			g_free(frame);
  287: 			conn->frame = NULL;
  288: 			peer_connection_trynext(conn);
  289: 			return;
  290: 		}
  291: 
  292: 		/* If there was an error then close the connection */
  293: 		if (read < 0)
  294: 		{
  295: 			if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
  296: 				/* No worries */
  297: 				return;
  298: 
  299: 			purple_debug_info("oscar", "Lost connection with peer proxy server\n");
  300: 			g_free(frame->payload.data);
  301: 			g_free(frame);
  302: 			conn->frame = NULL;
  303: 			peer_connection_trynext(conn);
  304: 			return;
  305: 		}
  306: 
  307: 		frame->payload.offset += read;
  308: 	}
  309: 
  310: 	conn->lastactivity = time(NULL);
  311: 	if (frame->payload.offset < frame->payload.len)
  312: 		/* Waiting for more data to arrive */
  313: 		return;
  314: 
  315: 	/* We have a complete proxy frame!  Handle it and continue reading */
  316: 	conn->frame = NULL;
  317: 	byte_stream_rewind(&frame->payload);
  318: 	peer_proxy_recv_frame(conn, frame);
  319: 
  320: 	g_free(frame->payload.data);
  321: 	g_free(frame);
  322: 
  323: 	conn->proxy_header_received = 0;
  324: }
  325: 
  326: /**
  327:  * We tried to make an outgoing connection to a proxy server.  It
  328:  * either connected or failed to connect.
  329:  */
  330: void
  331: peer_proxy_connection_established_cb(gpointer data, gint source, const gchar *error_message)
  332: {
  333: 	PeerConnection *conn;
  334: 
  335: 	conn = data;
  336: 
  337: 	conn->verified_connect_data = NULL;
  338: 
  339: 	if (source < 0)
  340: 	{
  341: 		peer_connection_trynext(conn);
  342: 		return;
  343: 	}
  344: 
  345: 	conn->fd = source;
  346: 	conn->watcher_incoming = purple_input_add(conn->fd,
  347: 			PURPLE_INPUT_READ, peer_proxy_connection_recv_cb, conn);
  348: 
  349: 	if (conn->proxyip != NULL)
  350: 		/* Connect to the session created by the remote user */
  351: 		peer_proxy_send_join_existing_conn(conn, conn->port);
  352: 	else
  353: 		/* Create a new session */
  354: 		peer_proxy_send_create_new_conn(conn);
  355: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>