Example #1
0
static void
sendframe_flap(FlapConnection *conn, FlapFrame *frame)
{
	ByteStream bs;
	int payloadlen, bslen;

	payloadlen = byte_stream_curpos(&frame->data);

	byte_stream_new(&bs, 6 + payloadlen);

	/* FLAP header */
	byte_stream_put8(&bs, 0x2a);
	byte_stream_put8(&bs, frame->channel);
	byte_stream_put16(&bs, frame->seqnum);
	byte_stream_put16(&bs, payloadlen);

	/* Payload */
	byte_stream_rewind(&frame->data);
	byte_stream_putbs(&bs, &frame->data, payloadlen);

	bslen = byte_stream_curpos(&bs);
	byte_stream_rewind(&bs);
	flap_connection_send_byte_stream(&bs, conn, bslen);

	byte_stream_destroy(&bs);
}
/* Subtype 0x0006 */
static int
userinfo(OscarData *od, FlapConnection *conn, aim_module_t *mod, FlapFrame *frame, aim_modsnac_t *snac, ByteStream *bs)
{
	int ret = 0;
	aim_userinfo_t *userinfo, *userinfo2;
	GSList *tlvlist;
	aim_tlv_t *tlv = NULL;

	userinfo = (aim_userinfo_t *)g_malloc(sizeof(aim_userinfo_t));
	aim_info_extract(od, bs, userinfo);
	tlvlist = aim_tlvlist_read(bs);

	/* Profile will be 1 and 2 */
	userinfo->info_encoding = aim_tlv_getstr(tlvlist, 0x0001, 1);
	if ((tlv = aim_tlv_gettlv(tlvlist, 0x0002, 1))) {
		userinfo->info = (char *)g_malloc(tlv->length);
		memcpy(userinfo->info, tlv->value, tlv->length);
		userinfo->info_len = tlv->length;
	}

	/* Away message will be 3 and 4 */
	userinfo->away_encoding = aim_tlv_getstr(tlvlist, 0x0003, 1);
	if ((tlv = aim_tlv_gettlv(tlvlist, 0x0004, 1))) {
		userinfo->away = (char *)g_malloc(tlv->length);
		memcpy(userinfo->away, tlv->value, tlv->length);
		userinfo->away_len = tlv->length;
	}

	/* Caps will be 5 */
	if ((tlv = aim_tlv_gettlv(tlvlist, 0x0005, 1))) {
		ByteStream cbs;
		PurpleAccount *account = purple_connection_get_account(od->gc);
		const char *mood;

		byte_stream_init(&cbs, tlv->value, tlv->length);
		userinfo->capabilities = aim_locate_getcaps(od, &cbs, tlv->length);
		byte_stream_rewind(&cbs);
		userinfo->present = AIM_USERINFO_PRESENT_CAPABILITIES;

		mood = aim_receive_custom_icon(od, &cbs, tlv->length);
		if (mood)
			purple_prpl_got_user_status(account, userinfo->bn, "mood",
					PURPLE_MOOD_NAME, mood,
					NULL);
		else
			purple_prpl_got_user_status_deactive(account, userinfo->bn, "mood");
	}
	aim_tlvlist_free(tlvlist);

	aim_locate_adduserinfo(od, userinfo);
	userinfo2 = aim_locate_finduserinfo(od, userinfo->bn);
	aim_info_free(userinfo);
	g_free(userinfo);

	/* Show the info to the user */
	oscar_user_info_display_aim(od, userinfo2);

	return ret;
}
Example #3
0
/**
 * 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.
 */
void
peer_connection_recv_cb(gpointer data, gint source, PurpleInputCondition cond)
{
	PeerConnection *conn;
	gssize 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, g_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;
	}

	if (read < 0)
	{
		if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
			/* No worries */
			return;

		peer_connection_destroy(conn,
				OSCAR_DISCONNECT_LOST_CONNECTION, g_strerror(errno));
		return;
	}

	conn->lastactivity = time(NULL);
	conn->buffer_incoming.offset += read;
	if (conn->buffer_incoming.offset < conn->buffer_incoming.len)
		/* Waiting for more data to arrive */
		return;

	/* We have a complete ODC/OFT frame!  Handle it and continue reading */
	byte_stream_rewind(&conn->buffer_incoming);
	if (conn->type == OSCAR_CAPABILITY_DIRECTIM)
	{
		peer_odc_recv_frame(conn, &conn->buffer_incoming);
	}
	else if (conn->type == OSCAR_CAPABILITY_SENDFILE)
	{
		peer_oft_recv_frame(conn, &conn->buffer_incoming);
	}

	g_free(conn->buffer_incoming.data);
	conn->buffer_incoming.data = NULL;

	conn->header_received = 0;
}
Example #4
0
static void
peer_proxy_connection_recv_cb(gpointer data, gint source, PurpleInputCondition cond)
{
	PeerConnection *conn;
	gssize read;
	ProxyFrame *frame;

	conn = data;
	frame = conn->frame;

	/* Start reading a new proxy frame */
	if (frame == NULL)
	{
		/* Read the first 12 bytes (frame length and header) */
		read = recv(conn->fd, conn->proxy_header + conn->proxy_header_received,
				12 - conn->proxy_header_received, 0);

		/* Check if the proxy server closed the connection */
		if (read == 0)
		{
			purple_debug_info("oscar", "Peer proxy server closed connection\n");
			peer_connection_trynext(conn);
			return;
		}

		/* If there was an error then close the connection */
		if (read < 0)
		{
			if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
				/* No worries */
				return;

			purple_debug_info("oscar", "Lost connection with peer proxy server\n");
			peer_connection_trynext(conn);
			return;
		}

		conn->lastactivity = time(NULL);

		/* If we don't even have the first 12 bytes then do nothing */
		conn->proxy_header_received += read;
		if (conn->proxy_header_received < 12)
			return;

		/* We only support a specific version of the proxy protocol */
		if (aimutil_get16(&conn->proxy_header[2]) != PEER_PROXY_PACKET_VERSION)
		{
			purple_debug_warning("oscar", "Expected peer proxy protocol "
				"version %u but received version %u.  Closing "
				"connection.\n", PEER_PROXY_PACKET_VERSION,
				aimutil_get16(&conn->proxy_header[2]));
			peer_connection_trynext(conn);
			return;
		}

		/* Initialize a new temporary ProxyFrame for incoming data */
		frame = g_new0(ProxyFrame, 1);
		frame->payload.len = aimutil_get16(&conn->proxy_header[0]) - 10;
		frame->version = aimutil_get16(&conn->proxy_header[2]);
		frame->type = aimutil_get16(&conn->proxy_header[4]);
		frame->unknown = aimutil_get16(&conn->proxy_header[6]);
		frame->flags = aimutil_get16(&conn->proxy_header[10]);
		if (frame->payload.len > 0)
			frame->payload.data = g_new(guint8, frame->payload.len);
		conn->frame = frame;
	}

	/* If this frame has a payload then attempt to read it */
	if (frame->payload.len - frame->payload.offset > 0)
	{
		/* Read data into the temporary buffer until it is complete */
		read = recv(conn->fd,
					&frame->payload.data[frame->payload.offset],
					frame->payload.len - frame->payload.offset,
					0);

		/* Check if the proxy server closed the connection */
		if (read == 0)
		{
			purple_debug_info("oscar", "Peer proxy server closed connection\n");
			g_free(frame->payload.data);
			g_free(frame);
			conn->frame = NULL;
			peer_connection_trynext(conn);
			return;
		}

		/* If there was an error then close the connection */
		if (read < 0)
		{
			if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
				/* No worries */
				return;

			purple_debug_info("oscar", "Lost connection with peer proxy server\n");
			g_free(frame->payload.data);
			g_free(frame);
			conn->frame = NULL;
			peer_connection_trynext(conn);
			return;
		}

		frame->payload.offset += read;
	}

	conn->lastactivity = time(NULL);
	if (frame->payload.offset < frame->payload.len)
		/* Waiting for more data to arrive */
		return;

	/* We have a complete proxy frame!  Handle it and continue reading */
	conn->frame = NULL;
	byte_stream_rewind(&frame->payload);
	peer_proxy_recv_frame(conn, frame);

	g_free(frame->payload.data);
	g_free(frame);

	conn->proxy_header_received = 0;
}
Example #5
0
/**
 * Read in all available data on the socket for a given connection.
 * All complete FLAPs handled immedate after they're received.
 * Incomplete FLAP data is stored locally and appended to the next
 * time this callback is triggered.
 *
 * This is called by flap_connection_recv_cb and
 * flap_connection_recv_cb_ssl for unencrypted/encrypted connections.
 */
static void
flap_connection_recv(FlapConnection *conn)
{
	gpointer buf;
	gsize buflen;
	gssize read;

	/* Read data until we run out of data and break out of the loop */
	while (TRUE)
	{
		/* Start reading a new FLAP */
		if (conn->buffer_incoming.data.data == NULL)
		{
			buf = conn->header + conn->header_received;
			buflen = 6 - conn->header_received;

			/* Read the first 6 bytes (the FLAP header) */
			if (conn->gsc)
				read = purple_ssl_read(conn->gsc, buf, buflen);
			else
				read = recv(conn->fd, buf, buflen, 0);

			/* Check if the FLAP server closed the connection */
			if (read == 0)
			{
				flap_connection_schedule_destroy(conn,
						OSCAR_DISCONNECT_REMOTE_CLOSED, NULL);
				break;
			}

			/* If there was an error then close the connection */
			if (read < 0)
			{
				if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
					/* No worries */
					break;

				/* Error! */
				flap_connection_schedule_destroy(conn,
						OSCAR_DISCONNECT_LOST_CONNECTION, g_strerror(errno));
				break;
			}
			conn->od->gc->last_received = time(NULL);

			/* If we don't even have a complete FLAP header then do nothing */
			conn->header_received += read;
			if (conn->header_received < 6)
				break;

			/* All FLAP frames must start with the byte 0x2a */
			if (aimutil_get8(&conn->header[0]) != 0x2a)
			{
				flap_connection_schedule_destroy(conn,
						OSCAR_DISCONNECT_INVALID_DATA, NULL);
				break;
			}

			/* Initialize a new temporary FlapFrame for incoming data */
			conn->buffer_incoming.channel = aimutil_get8(&conn->header[1]);
			conn->buffer_incoming.seqnum = aimutil_get16(&conn->header[2]);
			conn->buffer_incoming.data.len = aimutil_get16(&conn->header[4]);
			conn->buffer_incoming.data.data = g_new(guint8, conn->buffer_incoming.data.len);
			conn->buffer_incoming.data.offset = 0;
		}

		buflen = conn->buffer_incoming.data.len - conn->buffer_incoming.data.offset;
		if (buflen)
		{
			buf = &conn->buffer_incoming.data.data[conn->buffer_incoming.data.offset];
			/* Read data into the temporary FlapFrame until it is complete */
			if (conn->gsc)
				read = purple_ssl_read(conn->gsc, buf, buflen);
			else
				read = recv(conn->fd, buf, buflen, 0);

			/* Check if the FLAP server closed the connection */
			if (read == 0)
			{
				flap_connection_schedule_destroy(conn,
						OSCAR_DISCONNECT_REMOTE_CLOSED, NULL);
				break;
			}

			if (read < 0)
			{
				if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
					/* No worries */
					break;

				/* Error! */
				flap_connection_schedule_destroy(conn,
						OSCAR_DISCONNECT_LOST_CONNECTION, g_strerror(errno));
				break;
			}

			conn->buffer_incoming.data.offset += read;
			if (conn->buffer_incoming.data.offset < conn->buffer_incoming.data.len)
				/* Waiting for more data to arrive */
				break;
		}

		/* We have a complete FLAP!  Handle it and continue reading */
		byte_stream_rewind(&conn->buffer_incoming.data);
		parse_flap(conn->od, conn, &conn->buffer_incoming);
		conn->lastactivity = time(NULL);

		g_free(conn->buffer_incoming.data.data);
		conn->buffer_incoming.data.data = NULL;

		conn->header_received = 0;
	}
}
Example #6
0
/**
 * 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.
 * @param high_priority If TRUE, the SNAC will be queued normally if
 *        needed. If FALSE, it will be queued separately, to be sent
 *        only if all high priority SNACs have been sent.
 */
void
flap_connection_send_snac_with_priority(OscarData *od, FlapConnection *conn, guint16 family, const guint16 subtype, aim_snacid_t snacid, ByteStream *data, gboolean high_priority)
{
	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, 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 (rateclass->dropping_snacs || new_current <= rateclass->alert)
		{
			purple_debug_info("oscar", "Current rate for conn %p would be %u, but we alert at %u; enqueueing\n", conn, new_current, rateclass->alert);

			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;

		if (high_priority) {
			if (!conn->queued_snacs)
				conn->queued_snacs = g_queue_new();
			g_queue_push_tail(conn->queued_snacs, queued_snac);
		} else {
			if (!conn->queued_lowpriority_snacs)
				conn->queued_lowpriority_snacs = g_queue_new();
			g_queue_push_tail(conn->queued_lowpriority_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);
}