Ejemplo n.º 1
0
void
fb_mqtt_write(FbMqtt *mqtt, FbMqttMessage *msg)
{
	const GByteArray *bytes;
	FbMqttMessagePrivate *mriv;
	FbMqttPrivate *priv;

	g_return_if_fail(FB_IS_MQTT(mqtt));
	g_return_if_fail(FB_IS_MQTT_MESSAGE(msg));
	priv = mqtt->priv;
	mriv = msg->priv;

	bytes = fb_mqtt_message_bytes(msg);

	if (G_UNLIKELY(bytes == NULL)) {
		fb_mqtt_error(mqtt, FB_MQTT_ERROR_GENERAL,
		              _("Failed to format data"));
		return;
	}

	fb_util_debug_hexdump(FB_UTIL_DEBUG_INFO, mriv->bytes,
	                      "Writing %d (flags: 0x%0X)",
		              mriv->type, mriv->flags);

	g_byte_array_append(priv->wbuf, bytes->data, bytes->len);
	fb_mqtt_cb_write(mqtt, priv->gsc->fd, PURPLE_INPUT_WRITE);

	if (priv->wev > 0) {
		priv->wev = purple_input_add(priv->gsc->fd,
		                             PURPLE_INPUT_WRITE,
		                             fb_mqtt_cb_write, mqtt);
	}
}
Ejemplo n.º 2
0
/**
 * Implemented #b_event_handler for #fb_mqtt_timeout().
 *
 * @param data The user defined data, which is #fb_mqtt.
 * @param fd   The event file descriptor.
 * @param cond The #b_input_condition.
 *
 * @return FALSE to prevent continued event handling.
 **/
static gboolean fb_mqtt_cb_timeout(gpointer data, gint fd,
                                   b_input_condition cond)
{
    fb_mqtt_t *mqtt = data;

    mqtt->tev = 0;
    fb_mqtt_error(mqtt, FB_MQTT_ERROR_GENERAL, "Connection timed out");
    return FALSE;
}
Ejemplo n.º 3
0
static gboolean
fb_mqtt_cb_timeout(gpointer data)
{
	FbMqtt *mqtt = data;
	FbMqttPrivate *priv = mqtt->priv;

	priv->tev = 0;
	fb_mqtt_error(mqtt, FB_MQTT_ERROR_GENERAL, _("Connection timed out"));
	return FALSE;
}
Ejemplo n.º 4
0
/**
 * Checks the #fb_mqtt connection.
 *
 * @param mqtt  The #fb_mqtt.
 * @param error TRUE to error upon no connection, FALSE otherwise.
 *
 * @return TRUE if the #fb_mqtt is connected, FALSE otherwise.
 **/
gboolean fb_mqtt_connected(fb_mqtt_t *mqtt, gboolean error)
{
    gboolean connected;

    g_return_val_if_fail(mqtt != NULL, FALSE);

    connected = (mqtt->ssl != NULL) && mqtt->connected;

    if (!connected && error)
        fb_mqtt_error(mqtt, FB_MQTT_ERROR_GENERAL, "Not connected");

    return connected;
}
Ejemplo n.º 5
0
gboolean
fb_mqtt_connected(FbMqtt *mqtt, gboolean error)
{
	FbMqttPrivate *priv;
	gboolean connected;

	g_return_val_if_fail(FB_IS_MQTT(mqtt), FALSE);
	priv = mqtt->priv;
	connected = (priv->gsc != NULL) && priv->connected;

	if (!connected && error) {
		fb_mqtt_error(mqtt, FB_MQTT_ERROR_GENERAL,
		              _("Not connected"));
	}

	return connected;
}
Ejemplo n.º 6
0
/**
 * Implemented #ssl_input_function for the connection of #fb_mqtt->ssl.
 *
 * @param data  The user defined data, which is #fb_mqtt.
 * @param error The SSL error. (0 on success)
 * @param ssl   The SSL source.
 * @param cond  The #b_input_condition.
 *
 * @return TRUE for continued event handling, otherwise FALSE.
 **/
static gboolean fb_mqtt_cb_open(gpointer data, gint error, gpointer ssl,
                                b_input_condition cond)
{
    fb_mqtt_t *mqtt = data;
    gint       fd;

    if ((ssl == NULL) || (error != SSL_OK)) {
        fb_mqtt_error(mqtt, FB_MQTT_ERROR_GENERAL, "Failed to connect");
        return FALSE;
    }

    fb_mqtt_timeout_clear(mqtt);
    fd = ssl_getfd(mqtt->ssl);
    mqtt->rev = b_input_add(fd, B_EV_IO_READ, fb_mqtt_cb_read, mqtt);

    FB_MQTT_FUNC(mqtt, open);
    return FALSE;
}
Ejemplo n.º 7
0
static void
fb_mqtt_cb_write(gpointer data, gint fd, PurpleInputCondition cond)
{
	FbMqtt *mqtt = data;
	FbMqttPrivate *priv = mqtt->priv;
	gssize wize;

	wize = purple_ssl_write(priv->gsc, priv->wbuf->data, priv->wbuf->len);

	if (wize < 0) {
		fb_mqtt_error(mqtt, FB_MQTT_ERROR_GENERAL,
		              _("Failed to write data"));
		return;
	}

	if (wize > 0) {
		g_byte_array_remove_range(priv->wbuf, 0, wize);
	}

	if (priv->wbuf->len < 1) {
		priv->wev = 0;
	}
}
Ejemplo n.º 8
0
/**
 * Writes a #fb_mqtt_msg to the #fb_mqtt.
 *
 * @param mqtt The #fb_mqtt.
 * @param msg  The #fb_mqtt_msg.
 **/
void fb_mqtt_write(fb_mqtt_t *mqtt, fb_mqtt_msg_t *msg)
{
    const GByteArray *bytes;
    gint fd;

    g_return_if_fail(mqtt != NULL);

    bytes = fb_mqtt_msg_bytes(msg);

    if (G_UNLIKELY(bytes == NULL)) {
        fb_mqtt_error(mqtt, FB_MQTT_ERROR_GENERAL, "Failed to format data");
        return;
    }

    fb_util_hexdump(bytes, 2, "Writing %d (flags: 0x%0X)",
                    msg->type, msg->flags);

    fd = ssl_getfd(mqtt->ssl);
    g_byte_array_append(mqtt->wbuf, bytes->data, bytes->len);

    if ((mqtt->wev < 1) && fb_mqtt_cb_write(mqtt, fd, B_EV_IO_WRITE))
        mqtt->wev = b_input_add(fd, B_EV_IO_WRITE, fb_mqtt_cb_write, mqtt);
}
Ejemplo n.º 9
0
/**
 * Implemented #b_event_handler for the writing of #fb_mqtt->fd.
 *
 * @param data The user defined data, which is #fb_mqtt.
 * @param fd   The event file descriptor.
 * @param cond The #b_input_condition.
 *
 * @return TRUE for continued event handling, otherwise FALSE.
 **/
static gboolean fb_mqtt_cb_write(gpointer data, gint fd,
                                 b_input_condition cond)
{
    fb_mqtt_t *mqtt = data;
    gssize     wize;

    wize = ssl_write(mqtt->ssl, (gchar*) mqtt->wbuf->data, mqtt->wbuf->len);

    if (wize < 0) {
        fb_mqtt_error(mqtt, FB_MQTT_ERROR_GENERAL, "Failed to write data");
        return FALSE;
    }

    if (wize > 0)
        g_byte_array_remove_range(mqtt->wbuf, 0, wize);

    if (mqtt->wbuf->len < 1) {
        mqtt->wev = 0;
        return FALSE;
    }

    return TRUE;
}
Ejemplo n.º 10
0
void
fb_mqtt_read(FbMqtt *mqtt, FbMqttMessage *msg)
{
	FbMqttMessage *nsg;
	FbMqttPrivate *priv;
	FbMqttMessagePrivate *mriv;
	GByteArray *wytes;
	gchar *str;
	guint8 chr;
	guint16 mid;

	g_return_if_fail(FB_IS_MQTT(mqtt));
	g_return_if_fail(FB_IS_MQTT_MESSAGE(msg));
	priv = mqtt->priv;
	mriv = msg->priv;

	fb_util_debug_hexdump(FB_UTIL_DEBUG_INFO, mriv->bytes,
	                      "Reading %d (flags: 0x%0X)",
			      mriv->type, mriv->flags);

	switch (mriv->type) {
	case FB_MQTT_MESSAGE_TYPE_CONNACK:
		if (!fb_mqtt_message_read_byte(msg, NULL) ||
		    !fb_mqtt_message_read_byte(msg, &chr))
		{
			break;
		}

		if (chr != FB_MQTT_ERROR_SUCCESS) {
			fb_mqtt_error(mqtt, chr, _("Connection failed (%u)"),
			              chr);
			return;
		}

		priv->connected = TRUE;
		fb_mqtt_ping(mqtt);
		g_signal_emit_by_name(mqtt, "connect");
		return;

	case FB_MQTT_MESSAGE_TYPE_PUBLISH:
		if (!fb_mqtt_message_read_str(msg, &str)) {
			break;
		}

		if ((mriv->flags & FB_MQTT_MESSAGE_FLAG_QOS1) ||
		    (mriv->flags & FB_MQTT_MESSAGE_FLAG_QOS2))
		{
			if (mriv->flags & FB_MQTT_MESSAGE_FLAG_QOS1) {
				chr = FB_MQTT_MESSAGE_TYPE_PUBACK;
			} else {
				chr = FB_MQTT_MESSAGE_TYPE_PUBREC;
			}

			if (!fb_mqtt_message_read_mid(msg, &mid)) {
				break;
			}

			nsg = fb_mqtt_message_new(chr, 0);
			fb_mqtt_message_write_u16(nsg, mid);
			fb_mqtt_write(mqtt, nsg);
			g_object_unref(nsg);
		}

		wytes = g_byte_array_new();
		fb_mqtt_message_read_r(msg, wytes);
		g_signal_emit_by_name(mqtt, "publish", str, wytes);
		g_byte_array_free(wytes, TRUE);
		g_free(str);
		return;

	case FB_MQTT_MESSAGE_TYPE_PUBREL:
		if (!fb_mqtt_message_read_mid(msg, &mid)) {
			break;
		}

		nsg = fb_mqtt_message_new(FB_MQTT_MESSAGE_TYPE_PUBCOMP, 0);
		fb_mqtt_message_write_u16(nsg, mid); /* Message identifier */
		fb_mqtt_write(mqtt, nsg);
		g_object_unref(nsg);
		return;

	case FB_MQTT_MESSAGE_TYPE_PINGRESP:
		fb_mqtt_ping(mqtt);
		return;

	case FB_MQTT_MESSAGE_TYPE_PUBACK:
	case FB_MQTT_MESSAGE_TYPE_PUBCOMP:
	case FB_MQTT_MESSAGE_TYPE_SUBACK:
	case FB_MQTT_MESSAGE_TYPE_UNSUBACK:
		return;

	default:
		fb_mqtt_error(mqtt, FB_MQTT_ERROR_GENERAL,
		              _("Unknown packet (%u)"), mriv->type);
		return;
	}

	/* Since no case returned, there was a parse error. */
	fb_mqtt_error(mqtt, FB_MQTT_ERROR_GENERAL,
	              _("Failed to parse message"));
}
Ejemplo n.º 11
0
static void
fb_mqtt_cb_read(gpointer data, gint fd, PurpleInputCondition cond)
{
	FbMqtt *mqtt = data;
	FbMqttMessage *msg;
	FbMqttPrivate *priv = mqtt->priv;
	gint res;
	guint mult;
	guint8 buf[1024];
	guint8 byte;
	gsize size;
	gssize rize;

	if (priv->remz < 1) {
		/* Reset the read buffer */
		g_byte_array_set_size(priv->rbuf, 0);

		res = purple_ssl_read(priv->gsc, &byte, sizeof byte);
		g_byte_array_append(priv->rbuf, &byte, sizeof byte);

		if (res != sizeof byte) {
			fb_mqtt_error(mqtt, FB_MQTT_ERROR_GENERAL,
			              _("Failed to read fixed header"));
			return;
		}

		mult = 1;

		do {
			res = purple_ssl_read(priv->gsc, &byte, sizeof byte);
			g_byte_array_append(priv->rbuf, &byte, sizeof byte);

			if (res != sizeof byte) {
				fb_mqtt_error(mqtt, FB_MQTT_ERROR_GENERAL,
				              _("Failed to read packet size"));
				return;
			}

			priv->remz += (byte & 127) * mult;
			mult *= 128;
		} while ((byte & 128) != 0);
	}

	if (priv->remz > 0) {
		size = MIN(priv->remz, sizeof buf);
		rize = purple_ssl_read(priv->gsc, buf, size);

		if (rize < 1) {
			fb_mqtt_error(mqtt, FB_MQTT_ERROR_GENERAL,
			              _("Failed to read packet data"));
			return;
		}

		g_byte_array_append(priv->rbuf, buf, rize);
		priv->remz -= rize;
	}

	if (priv->remz < 1) {
		msg = fb_mqtt_message_new_bytes(priv->rbuf);
		priv->remz = 0;

		if (G_UNLIKELY(msg == NULL)) {
			fb_mqtt_error(mqtt, FB_MQTT_ERROR_GENERAL,
			              _("Failed to parse message"));
			return;
		}

		fb_mqtt_read(mqtt, msg);
		g_object_unref(msg);
	}
}
Ejemplo n.º 12
0
/**
 * Read a #GByteArray to the #fb_mqtt.
 *
 * @param mqtt  The #fb_mqtt.
 * @param bytes The #GByteArray.
 **/
void fb_mqtt_read(fb_mqtt_t *mqtt, fb_mqtt_msg_t *msg)
{
    fb_mqtt_msg_t *nsg;
    GByteArray    *wytes;
    gchar         *str;
    guint8         chr;
    guint16        mid;

    g_return_if_fail(mqtt != NULL);
    g_return_if_fail(msg  != NULL);

    fb_util_hexdump(msg->bytes, 2, "Reading %d (flags: 0x%0X)",
                    msg->type, msg->flags);

    switch (msg->type) {
    case FB_MQTT_MSG_TYPE_CONNACK:
        if (!fb_mqtt_msg_read_byte(msg, NULL) ||
            !fb_mqtt_msg_read_byte(msg, &chr))
        {
            break;
        }

        if (chr != FB_MQTT_ERROR_SUCCESS) {
            fb_mqtt_error(mqtt, chr, "Connection failed (%u)", chr);
            return;
        }

        mqtt->connected = TRUE;
        fb_mqtt_ping(mqtt);
        FB_MQTT_FUNC(mqtt, connack);
        return;

    case FB_MQTT_MSG_TYPE_PUBLISH:
        if (!fb_mqtt_msg_read_str(msg, &str))
            break;

        if ((msg->flags & FB_MQTT_MSG_FLAG_QOS1) ||
            (msg->flags & FB_MQTT_MSG_FLAG_QOS2))
        {
            if (msg->flags & FB_MQTT_MSG_FLAG_QOS1)
                chr = FB_MQTT_MSG_TYPE_PUBACK;
            else
                chr = FB_MQTT_MSG_TYPE_PUBREC;

            if (!fb_mqtt_msg_read_mid(msg, &mid))
                break;

            nsg = fb_mqtt_msg_new(chr, 0);
            fb_mqtt_msg_write_u16(nsg, mid);
            fb_mqtt_write(mqtt, nsg);
            fb_mqtt_msg_free(nsg);
        }

        wytes = g_byte_array_new();
        fb_mqtt_msg_read_r(msg, wytes);
        FB_MQTT_FUNC(mqtt, publish, str, wytes);
        g_byte_array_free(wytes, TRUE);
        g_free(str);
        return;

    case FB_MQTT_MSG_TYPE_PUBREL:
        if (!fb_mqtt_msg_read_mid(msg, &mid))
            break;

        nsg = fb_mqtt_msg_new(FB_MQTT_MSG_TYPE_PUBCOMP, 0);
        fb_mqtt_msg_write_u16(nsg, mid); /* Message identifier */
        fb_mqtt_write(mqtt, nsg);
        fb_mqtt_msg_free(nsg);
        return;

    case FB_MQTT_MSG_TYPE_PINGRESP:
        fb_mqtt_ping(mqtt);
        return;

    case FB_MQTT_MSG_TYPE_PUBACK:
    case FB_MQTT_MSG_TYPE_PUBCOMP:
    case FB_MQTT_MSG_TYPE_SUBACK:
    case FB_MQTT_MSG_TYPE_UNSUBACK:
        return;

    default:
        fb_mqtt_error(mqtt, FB_MQTT_ERROR_GENERAL, "Unknown packet (%u)",
                      msg->type);
        return;
    }

    /* Since no case returned, there was a parse error. */
    fb_mqtt_error(mqtt, FB_MQTT_ERROR_GENERAL, "Failed to parse message");
}
Ejemplo n.º 13
0
/**
 * Implemented #b_event_handler for the read of #fb_mqtt->fd.
 *
 * @param data The user defined data, which is #fb_mqtt.
 * @param fd   The event file descriptor.
 * @param cond The #b_input_condition.
 *
 * @return TRUE for continued event handling, otherwise FALSE.
 **/
static gboolean fb_mqtt_cb_read(gpointer data, gint fd,
                                b_input_condition cond)
{
    fb_mqtt_t     *mqtt = data;
    fb_mqtt_msg_t *msg;
    gchar          buf[1024];
    guint8         byte;
    guint          mult;
    gssize         rize;
    gint           res;

    if (mqtt->remz < 1) {
        /* Reset the read buffer */
        g_byte_array_set_size(mqtt->rbuf, 0);

        res = ssl_read(mqtt->ssl, (gchar*) &byte, sizeof byte);
        g_byte_array_append(mqtt->rbuf, &byte, sizeof byte);

        if (res != sizeof byte)
            goto error;

        mult = 1;

        do {
            res = ssl_read(mqtt->ssl, (gchar*) &byte, sizeof byte);
            g_byte_array_append(mqtt->rbuf, &byte, sizeof byte);

            if (res != sizeof byte)
                goto error;

            mqtt->remz += (byte & 127) * mult;
            mult *= 128;
        } while ((byte & 128) != 0);
    }

    if (mqtt->remz > 0) {
        rize = ssl_read(mqtt->ssl, buf, MIN(mqtt->remz, sizeof buf));

        if (rize < 1)
            goto error;

        g_byte_array_append(mqtt->rbuf, (guint8*) buf, rize);
        mqtt->remz -= rize;
    }

    if (mqtt->remz < 1) {
        msg = fb_mqtt_msg_new_bytes(mqtt->rbuf);
        mqtt->remz = 0;

        if (G_UNLIKELY(msg == NULL))
            goto error;

        fb_mqtt_read(mqtt, msg);
        fb_mqtt_msg_free(msg);
    }

    return TRUE;

error:
    fb_mqtt_error(mqtt, FB_MQTT_ERROR_GENERAL, "Short read");
    return FALSE;
}