示例#1
0
/**
 * Takes a new incoming FLAP frame and sends it to the appropriate
 * handler function to be parsed.
 */
static void
parse_flap(OscarData *od, FlapConnection *conn, FlapFrame *frame)
{
	if (frame->channel == 0x01) {
		guint32 flap_version = byte_stream_get32(&frame->data);
		if (flap_version != 0x00000001)
		{
				/* Error! */
				purple_debug_warning("oscar", "Expecting FLAP version "
					"0x00000001 but received FLAP version %08x.  Closing connection.\n",
					flap_version);
				flap_connection_schedule_destroy(conn,
						OSCAR_DISCONNECT_INVALID_DATA, NULL);
		}
		else
			conn->connected = TRUE;

	} else if (frame->channel == 0x02) {
		parse_snac(od, conn, frame);

	} else if (frame->channel == 0x04) {
		parse_flap_ch4(od, conn, frame);

	} else if (frame->channel == 0x05) {
		/* TODO: Reset our keepalive watchdog? */

	}
}
/**
 * @param source When this function is called as a callback source is
 *        set to the fd that triggered the callback.  But this function
 *        is also called directly from flap_connection_send_byte_stream(),
 *        in which case source will be -1.  So don't use source--use
 *        conn->gsc or conn->fd instead.
 */
static void
send_cb(gpointer data, gint source, PurpleInputCondition cond)
{
	FlapConnection *conn;
	int writelen, ret;
	const gchar *output = NULL;

	conn = data;
	writelen = purple_circular_buffer_get_max_read(conn->buffer_outgoing);
	output = purple_circular_buffer_get_output(conn->buffer_outgoing);

	if (writelen == 0)
	{
		purple_input_remove(conn->watcher_outgoing);
		conn->watcher_outgoing = 0;
		return;
	}

	if (conn->gsc)
		ret = purple_ssl_write(conn->gsc, output, writelen);
	else
		ret = send(conn->fd, output, writelen, 0);
	if (ret <= 0)
	{
		if (ret < 0 && (errno == EAGAIN || errno == EWOULDBLOCK))
			/* No worries */
			return;

		/* Error! */
		purple_input_remove(conn->watcher_outgoing);
		conn->watcher_outgoing = 0;
		if (conn->gsc) {
			purple_ssl_close(conn->gsc);
			conn->gsc = NULL;
		} else {
			close(conn->fd);
			conn->fd = -1;
		}
		flap_connection_schedule_destroy(conn,
				OSCAR_DISCONNECT_LOST_CONNECTION, g_strerror(errno));
		return;
	}

	purple_circular_buffer_mark_read(conn->buffer_outgoing, ret);
}
示例#3
0
static void
parse_flap_ch4(OscarData *od, FlapConnection *conn, FlapFrame *frame)
{
	GSList *tlvlist;
	char *msg = NULL;

	if (byte_stream_bytes_left(&frame->data) == 0) {
		/* XXX should do something with this */
		return;
	}

	/* An ICQ account is logging in */
	if (conn->type == SNAC_FAMILY_AUTH)
	{
		parse_fakesnac(od, conn, frame, 0x0017, 0x0003);
		return;
	}

	tlvlist = aim_tlvlist_read(&frame->data);

	if (aim_tlv_gettlv(tlvlist, 0x0009, 1))
		conn->disconnect_code = aim_tlv_get16(tlvlist, 0x0009, 1);

	if (aim_tlv_gettlv(tlvlist, 0x000b, 1))
		msg = aim_tlv_getstr(tlvlist, 0x000b, 1);

	/*
	 * The server ended this FLAP connnection, so let's be nice and
	 * close the physical TCP connection
	 */
	flap_connection_schedule_destroy(conn,
			OSCAR_DISCONNECT_REMOTE_CLOSED, msg);

	aim_tlvlist_free(tlvlist);

	g_free(msg);
}
示例#4
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;
	}
}