├── .gitignore
├── Android.mk
├── LICENSE
├── Makefile
├── README.markdown
├── TODO.markdown
├── client
├── pub.c
├── pub.py
├── sub.c
└── sub.py
├── include
└── libemqtt.h
└── src
├── libemqtt.c
└── python
├── python-libemqtt.c
├── python-mqtt.c
├── python-mqtt.h
├── python-mqtt_packet.c
└── python-mqtt_packet.h
/.gitignore:
--------------------------------------------------------------------------------
1 | *.o
2 | *.a
3 | *.so
4 |
--------------------------------------------------------------------------------
/Android.mk:
--------------------------------------------------------------------------------
1 | LOCAL_PATH:= $(call my-dir)
2 |
3 | include $(CLEAR_VARS)
4 | LOCAL_MODULE:= mqttpub
5 |
6 | LOCAL_SRC_FILES:= \
7 | client/pub.c \
8 |
9 | LOCAL_LDLIBS += -llog -lz -ldl -landroid
10 | LOCAL_CFLAGS += -Wall \
11 | -O3
12 |
13 | LOCAL_C_INCLUDES += \
14 | $(LOCAL_PATH) \
15 | $(LOCAL_PATH)/include
16 | LOCAL_STATIC_LIBRARIES := libemqtt
17 |
18 | include $(BUILD_SHARED_LIBRARY)
19 |
20 | include $(CLEAR_VARS)
21 | LOCAL_MODULE:= mqttsub
22 |
23 | LOCAL_SRC_FILES:= \
24 | client/sub.c \
25 |
26 | LOCAL_LDLIBS += -llog -lz -ldl -landroid
27 | LOCAL_CFLAGS += -Wall \
28 | -O3
29 |
30 | LOCAL_C_INCLUDES += \
31 | $(LOCAL_PATH) \
32 | $(LOCAL_PATH)/include
33 | LOCAL_STATIC_LIBRARIES := libemqtt
34 |
35 | include $(BUILD_SHARED_LIBRARY)
36 |
37 |
38 | # Define vars for library that will be build statically.
39 | include $(CLEAR_VARS)
40 | LOCAL_MODULE := libemqtt
41 | LOCAL_C_INCLUDES += \
42 | $(LOCAL_PATH) \
43 | $(LOCAL_PATH)/include
44 | LOCAL_SRC_FILES := \
45 | src/libemqtt.c
46 | # Optional compiler flags.
47 | LOCAL_LDLIBS += -llog -lz -ldl -landroid
48 | LOCAL_CFLAGS += -Wall \
49 | -O3
50 | include $(BUILD_STATIC_LIBRARY)
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | This program is free software: you can redistribute it and/or modify
2 | it under the terms of the GNU Lesser General Public License as published by
3 | the Free Software Foundation, either version 3 of the License, or
4 | (at your option) any later version.
5 |
6 | This program is distributed in the hope that it will be useful,
7 | but WITHOUT ANY WARRANTY; without even the implied warranty of
8 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 | GNU General Public License for more details.
10 |
11 | You should have received a copy of the GNU General Public License
12 | along with this program. If not, see .
13 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | SRC=src
2 | INC=include
3 | LIB=.
4 | CLIENT=client
5 |
6 | CC=gcc
7 | CCFLAGS=-I$(INC) -Wall -O
8 | LDFLAGS=-L$(LIB) -lemqtt
9 | AR=ar
10 |
11 | PYTHON_VER=2.7
12 | PYTHON_SRC=src/python
13 | PYTHON_CCFLAGS=-I$(INC) -I$(PYTHON_SRC) -I/usr/include/python$(PYTHON_VER) -Wall -O -fPIC
14 | PYTHON_LDFLAGS=-shared
15 |
16 |
17 |
18 | c: $(CLIENT)/pub $(CLIENT)/sub
19 |
20 | $(CLIENT)/pub: libemqtt.a pub.o
21 | $(CC) pub.o -o $(CLIENT)/pub $(LDFLAGS)
22 |
23 | pub.o: $(CLIENT)/pub.c $(INC)/libemqtt.h
24 | $(CC) $(CCFLAGS) -c $(CLIENT)/pub.c -o pub.o
25 |
26 | $(CLIENT)/sub: libemqtt.a sub.o
27 | $(CC) sub.o -o $(CLIENT)/sub $(LDFLAGS)
28 |
29 | sub.o: $(CLIENT)/sub.c $(INC)/libemqtt.h
30 | $(CC) $(CCFLAGS) -c $(CLIENT)/sub.c -o sub.o
31 |
32 |
33 |
34 |
35 |
36 | python: python-libemqtt.o python-mqtt.o python-mqtt_packet.o libemqtt-python.o
37 | $(CC) $(PYTHON_LDFLAGS) python-libemqtt.o python-mqtt.o python-mqtt_packet.o libemqtt-python.o -o $(CLIENT)/libemqtt.so
38 |
39 | python-libemqtt.o: $(PYTHON_SRC)/python-libemqtt.c $(INC)/libemqtt.h $(PYTHON_SRC)/python-mqtt.h $(PYTHON_SRC)/python-mqtt_packet.h
40 | $(CC) $(PYTHON_CCFLAGS) -c $(PYTHON_SRC)/python-libemqtt.c -o python-libemqtt.o
41 |
42 | python-mqtt.o: $(PYTHON_SRC)/python-mqtt.c $(INC)/libemqtt.h $(PYTHON_SRC)/python-mqtt.h
43 | $(CC) $(PYTHON_CCFLAGS) -c $(PYTHON_SRC)/python-mqtt.c -o python-mqtt.o
44 |
45 | python-mqtt_packet.o: $(PYTHON_SRC)/python-mqtt_packet.c $(INC)/libemqtt.h $(PYTHON_SRC)/python-mqtt_packet.h
46 | $(CC) $(PYTHON_CCFLAGS) -c $(PYTHON_SRC)/python-mqtt_packet.c -o python-mqtt_packet.o
47 |
48 | libemqtt-python.o: $(SRC)/libemqtt.c $(INC)/libemqtt.h
49 | $(CC) $(PYTHON_CCFLAGS) -c $(SRC)/libemqtt.c -o libemqtt-python.o
50 |
51 |
52 | python3:
53 | @echo "Not yet available. Sorry!"
54 |
55 |
56 |
57 |
58 |
59 | libemqtt.a: libemqtt.o
60 | $(AR) rcs libemqtt.a libemqtt.o
61 |
62 | libemqtt.o: $(SRC)/libemqtt.c $(INC)/libemqtt.h
63 | $(CC) $(CCFLAGS) -c $(SRC)/libemqtt.c -o libemqtt.o
64 |
65 |
66 |
67 |
68 |
69 | all: c python
70 |
71 |
72 |
73 |
74 |
75 | clean:
76 | rm -f *.o libemqtt.a
77 |
78 | dist-clean: clean
79 | rm -f $(CLIENT)/pub $(CLIENT)/sub $(CLIENT)/libemqtt.so
80 |
--------------------------------------------------------------------------------
/README.markdown:
--------------------------------------------------------------------------------
1 | # Libemqtt
2 |
3 | This program is a fork of liblwmqtt developed by Filipe Varela.
4 | You can find the original project on .
5 |
6 | libemqtt aims to be an embedded C client library for the MQTT protocol. It also
7 | provides a binding for Python.
8 |
9 | ## Status
10 |
11 | Under development. DO NOT USE in a serious development. API is not closed, so it
12 | could be changed.
13 |
14 | I hope to release the first version in April.
15 |
16 |
17 | ## Compile
18 |
19 | ### C Library
20 |
21 | > $ make
22 |
23 | ### Python binding
24 |
25 | > $ make python
26 |
27 |
28 | ## Install
29 |
30 | ### C Library
31 |
32 | ### Python binding
33 |
34 | > $ sudo ln -fs /home/user/libemqtt/client/libemqtt.so /usr/lib/python2.7/emqtt/libemqtt.so
35 |
36 |
37 |
38 | # Limitations
39 |
40 | * Can not subscribe to multiple topics in the same MQTT message.
41 |
42 |
43 |
44 | # Additional
45 |
46 | For debugging MQTT development it's possible to use
47 | Wireshark-MQTT (https://github.com/menudoproblema/Wireshark-MQTT)
48 |
--------------------------------------------------------------------------------
/TODO.markdown:
--------------------------------------------------------------------------------
1 | # C Library
2 | * Remaining Length can be multibyte field
3 | * Subscribe
4 | - QoS for topic
5 | * Will
6 | * Use of DUP flag
7 | * Clean session
8 |
9 | # Python binding
10 |
11 | * Remaining Length from C Library
12 | * Python 3 support
13 |
--------------------------------------------------------------------------------
/client/pub.c:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of libemqtt.
3 | *
4 | * libemqtt is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU Lesser General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * libemqtt is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 |
14 | * You should have received a copy of the GNU General Public License
15 | * along with libemqtt. If not, see .
16 | */
17 |
18 | /*
19 | *
20 | * Created by Vicente Ruiz Rodríguez
21 | * Copyright 2012 Vicente Ruiz Rodríguez . All rights reserved.
22 | *
23 | */
24 |
25 | #include
26 |
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include
32 |
33 |
34 | #define RCVBUFSIZE 1024
35 | uint8_t packet_buffer[RCVBUFSIZE];
36 |
37 | int socket_id;
38 |
39 |
40 |
41 |
42 | int send_packet(void* socket_info, const void* buf, unsigned int count)
43 | {
44 | int fd = *((int*)socket_info);
45 | return send(fd, buf, count, 0);
46 | }
47 |
48 | int init_socket(mqtt_broker_handle_t* broker, const char* hostname, short port)
49 | {
50 | int flag = 1;
51 | int keepalive = 3; // Seconds
52 |
53 | // Create the socket
54 | if((socket_id = socket(PF_INET, SOCK_STREAM, 0)) < 0)
55 | return -1;
56 |
57 | // Disable Nagle Algorithm
58 | if (setsockopt(socket_id, IPPROTO_TCP, TCP_NODELAY, (char*)&flag, sizeof(flag)) < 0)
59 | return -2;
60 |
61 | struct sockaddr_in socket_address;
62 | // Create the stuff we need to connect
63 | socket_address.sin_family = AF_INET;
64 | socket_address.sin_port = htons(port);
65 | socket_address.sin_addr.s_addr = inet_addr(hostname);
66 |
67 | // Connect the socket
68 | if((connect(socket_id, (struct sockaddr*)&socket_address, sizeof(socket_address))) < 0)
69 | return -1;
70 |
71 | // MQTT stuffs
72 | mqtt_set_alive(broker, keepalive);
73 | broker->socket_info = (void*)&socket_id;
74 | broker->send = send_packet;
75 |
76 | return 0;
77 | }
78 |
79 | int close_socket(mqtt_broker_handle_t* broker)
80 | {
81 | int fd = *((int*)broker->socket_info);
82 | return close(fd);
83 | }
84 |
85 |
86 |
87 |
88 | int read_packet(int timeout)
89 | {
90 | if(timeout > 0)
91 | {
92 | fd_set readfds;
93 | struct timeval tmv;
94 |
95 | // Initialize the file descriptor set
96 | FD_ZERO (&readfds);
97 | FD_SET (socket_id, &readfds);
98 |
99 | // Initialize the timeout data structure
100 | tmv.tv_sec = timeout;
101 | tmv.tv_usec = 0;
102 |
103 | // select returns 0 if timeout, 1 if input available, -1 if error
104 | if(select(1, &readfds, NULL, NULL, &tmv))
105 | return -2;
106 | }
107 |
108 | int total_bytes = 0, bytes_rcvd, packet_length;
109 | memset(packet_buffer, 0, sizeof(packet_buffer));
110 |
111 | while(total_bytes < 2) // Reading fixed header
112 | {
113 | if((bytes_rcvd = recv(socket_id, (packet_buffer+total_bytes), RCVBUFSIZE, 0)) <= 0)
114 | return -1;
115 | total_bytes += bytes_rcvd; // Keep tally of total bytes
116 | }
117 |
118 | packet_length = packet_buffer[1] + 2; // Remaining length + fixed header length
119 |
120 | while(total_bytes < packet_length) // Reading the packet
121 | {
122 | if((bytes_rcvd = recv(socket_id, (packet_buffer+total_bytes), RCVBUFSIZE, 0)) <= 0)
123 | return -1;
124 | total_bytes += bytes_rcvd; // Keep tally of total bytes
125 | }
126 |
127 | return packet_length;
128 | }
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 | int main(int argc, char* argv[])
137 | {
138 | int packet_length;
139 | uint16_t msg_id, msg_id_rcv;
140 | mqtt_broker_handle_t broker;
141 |
142 | mqtt_init(&broker, "avengalvon");
143 | mqtt_init_auth(&broker, "cid", "campeador");
144 | init_socket(&broker, "127.0.0.1", 1883);
145 |
146 | // >>>>> CONNECT
147 | mqtt_connect(&broker);
148 | // <<<<< CONNACK
149 | packet_length = read_packet(1);
150 | if(packet_length < 0)
151 | {
152 | fprintf(stderr, "Error(%d) on read packet!\n", packet_length);
153 | return -1;
154 | }
155 |
156 | if(MQTTParseMessageType(packet_buffer) != MQTT_MSG_CONNACK)
157 | {
158 | fprintf(stderr, "CONNACK expected!\n");
159 | return -2;
160 | }
161 |
162 | if(packet_buffer[3] != 0x00)
163 | {
164 | fprintf(stderr, "CONNACK failed!\n");
165 | return -2;
166 | }
167 |
168 | // >>>>> PUBLISH QoS 0
169 | printf("Publish: QoS 0\n");
170 | mqtt_publish(&broker, "hello/emqtt", "Example: QoS 0", 0);
171 |
172 | // >>>>> PUBLISH QoS 1
173 | printf("Publish: QoS 1\n");
174 | mqtt_publish_with_qos(&broker, "hello/emqtt", "Example: QoS 1", 0, 1, &msg_id);
175 | // <<<<< PUBACK
176 | packet_length = read_packet(1);
177 | if(packet_length < 0)
178 | {
179 | fprintf(stderr, "Error(%d) on read packet!\n", packet_length);
180 | return -1;
181 | }
182 |
183 | if(MQTTParseMessageType(packet_buffer) != MQTT_MSG_PUBACK)
184 | {
185 | fprintf(stderr, "PUBACK expected!\n");
186 | return -2;
187 | }
188 |
189 | msg_id_rcv = mqtt_parse_msg_id(packet_buffer);
190 | if(msg_id != msg_id_rcv)
191 | {
192 | fprintf(stderr, "%d message id was expected, but %d message id was found!\n", msg_id, msg_id_rcv);
193 | return -3;
194 | }
195 |
196 | // >>>>> PUBLISH QoS 2
197 | printf("Publish: QoS 2\n");
198 | mqtt_publish_with_qos(&broker, "hello/emqtt", "Example: QoS 2", 1, 2, &msg_id); // Retain
199 | // <<<<< PUBREC
200 | packet_length = read_packet(1);
201 | if(packet_length < 0)
202 | {
203 | fprintf(stderr, "Error(%d) on read packet!\n", packet_length);
204 | return -1;
205 | }
206 |
207 | if(MQTTParseMessageType(packet_buffer) != MQTT_MSG_PUBREC)
208 | {
209 | fprintf(stderr, "PUBREC expected!\n");
210 | return -2;
211 | }
212 |
213 | msg_id_rcv = mqtt_parse_msg_id(packet_buffer);
214 | if(msg_id != msg_id_rcv)
215 | {
216 | fprintf(stderr, "%d message id was expected, but %d message id was found!\n", msg_id, msg_id_rcv);
217 | return -3;
218 | }
219 |
220 | // >>>>> PUBREL
221 | mqtt_pubrel(&broker, msg_id);
222 | // <<<<< PUBCOMP
223 | packet_length = read_packet(1);
224 | if(packet_length < 0)
225 | {
226 | fprintf(stderr, "Error(%d) on read packet!\n", packet_length);
227 | return -1;
228 | }
229 |
230 | if(MQTTParseMessageType(packet_buffer) != MQTT_MSG_PUBCOMP)
231 | {
232 | fprintf(stderr, "PUBCOMP expected!\n");
233 | return -2;
234 | }
235 |
236 | msg_id_rcv = mqtt_parse_msg_id(packet_buffer);
237 | if(msg_id != msg_id_rcv)
238 | {
239 | fprintf(stderr, "%d message id was expected, but %d message id was found!\n", msg_id, msg_id_rcv);
240 | return -3;
241 | }
242 |
243 | // >>>>> DISCONNECT
244 | mqtt_disconnect(&broker);
245 | close_socket(&broker);
246 | return 0;
247 | }
248 |
249 |
--------------------------------------------------------------------------------
/client/pub.py:
--------------------------------------------------------------------------------
1 | #
2 | # This file is part of python-emqtt.
3 | #
4 | # python-emqtt is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU Lesser General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # python-emqtt is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with python-emqtt. If not, see .
16 | #
17 | #
18 | # Copyright 2012 Vicente Ruiz Rodríguez . All rights reserved.
19 | #
20 |
21 | from __future__ import print_function
22 |
23 | import select
24 | import signal
25 | import socket
26 | import sys
27 |
28 | import libemqtt
29 |
30 |
31 | def read(sck, timeout=None):
32 | try:
33 | inputready, outputready, exceptready = select.select([sck], [], [], timeout)
34 | except:
35 | return None
36 |
37 | if sck in inputready:
38 | fix_header = sck.recv(2)
39 | remain = ord(fix_header[1])
40 |
41 | data = sck.recv(remain)
42 |
43 | return libemqtt.MqttPacket(fix_header + data)
44 | return None
45 |
46 |
47 | HOST = '192.168.10.40'
48 | PORT = 1883
49 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
50 | s.connect((HOST, PORT))
51 |
52 | client = libemqtt.Mqtt(s, clientid='avengalvon', username='cid', password='campeador', keepalive=5)
53 |
54 | def alive_callback(client):
55 | def alive(signum, frame):
56 | print('Timeout! Sending ping...')
57 | client.ping()
58 | signal.alarm(client.keepalive)
59 |
60 | return alive
61 |
62 | signal.signal(signal.SIGALRM, alive_callback(client))
63 | signal.alarm(client.keepalive)
64 |
65 | # >>>>> CONNECT
66 | client.connect()
67 | # <<<<< CONNACK
68 | packet = read(s)
69 | if not packet:
70 | print('Error on read packet!', file=sys.stderr)
71 | sys.exit(-1)
72 |
73 | if packet.type != libemqtt.CONNACK:
74 | print('CONNACK expected!', file=sys.stderr)
75 | sys.exit(-2)
76 |
77 | if packet.index(3) != 0x00:
78 | print('CONNACK failed!', file=sys.stderr)
79 | sys.exit(-2)
80 |
81 | # >>>>> PUBLISH QoS 0
82 | print('Publish: QoS 0')
83 | client.publish('hello/emqtt', 'Example: QoS 0')
84 |
85 | # >>>>> PUBLISH QoS 1
86 | print('Publish: Example: QoS 1')
87 | msgid = client.publish('hello/emqtt', 'Example: QoS 1', qos=1)
88 | # <<<<< PUBACK
89 | packet = read(s)
90 | if not packet:
91 | print('Error on read packet!', file=sys.stderr)
92 | sys.exit(-1)
93 |
94 | if packet.type != libemqtt.PUBACK:
95 | print('PUBACK expected!', file=sys.stderr)
96 | sys.exit(-2)
97 |
98 | if msgid != packet.message_id:
99 | print('%d message id was expected, but %d message id was found!' % (msgid, packet.message_id), file=sys.stderr)
100 | sys.exit(-2)
101 |
102 | # >>>>> PUBLISH QoS 2
103 | print('Publish: Example: QoS 2')
104 | msgid = client.publish('hello/emqtt', 'Example: QoS 2', qos=2, retain=1)
105 | # <<<<< PUBREC
106 | packet = read(s)
107 | if not packet:
108 | print('Error on read packet!', file=sys.stderr)
109 | sys.exit(-1)
110 |
111 | if packet.type != libemqtt.PUBREC:
112 | print('PUBREC expected!', file=sys.stderr)
113 | sys.exit(-2)
114 |
115 | if msgid != packet.message_id:
116 | print('%d message id was expected, but %d message id was found!' % (msgid, packet.message_id), file=sys.stderr)
117 | sys.exit(-2)
118 |
119 | # >>>>> PUBREL
120 | client.pubrel(msgid)
121 | # <<<<< PUBCOMP
122 | packet = read(s)
123 | if not packet:
124 | print('Error on read packet!', file=sys.stderr)
125 | sys.exit(-1)
126 |
127 | if packet.type != libemqtt.PUBCOMP:
128 | print('PUBCOMP expected!', file=sys.stderr)
129 | sys.exit(-2)
130 |
131 | if msgid != packet.message_id:
132 | print('%d message id was expected, but %d message id was found!' % (msgid, packet.message_id), file=sys.stderr)
133 | sys.exit(-2)
134 |
135 |
136 | # >>>>> DISCONNECT
137 | client.disconnect()
138 |
139 | s.close()
140 |
--------------------------------------------------------------------------------
/client/sub.c:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of libemqtt.
3 | *
4 | * libemqtt is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU Lesser General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * libemqtt is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 |
14 | * You should have received a copy of the GNU General Public License
15 | * along with libemqtt. If not, see .
16 | */
17 |
18 | /*
19 | *
20 | * Created by Vicente Ruiz Rodríguez
21 | * Copyright 2012 Vicente Ruiz Rodríguez . All rights reserved.
22 | *
23 | */
24 |
25 | /* sub.c */
26 |
27 | /*
28 | * This file was forked from libemqtt,
29 | * developed by Vicente Ruiz Rodríguez.
30 | * https://github.com/menudoproblema/libemqtt
31 | *
32 | */
33 |
34 | #include
35 |
36 | #include
37 | #include
38 | #include
39 | #include
40 | #include
41 | #include
42 | #include
43 |
44 |
45 | #define RCVBUFSIZE 1024
46 | uint8_t packet_buffer[RCVBUFSIZE];
47 |
48 | int keepalive = 30;
49 | mqtt_broker_handle_t broker;
50 |
51 | int socket_id;
52 |
53 |
54 | int send_packet(void* socket_info, const void* buf, unsigned int count)
55 | {
56 | int fd = *((int*)socket_info);
57 | return send(fd, buf, count, 0);
58 | }
59 |
60 | int init_socket(mqtt_broker_handle_t* broker, const char* hostname, short port, int keepalive)
61 | {
62 | int flag = 1;
63 |
64 | // Create the socket
65 | if((socket_id = socket(PF_INET, SOCK_STREAM, 0)) < 0)
66 | return -1;
67 |
68 | // Disable Nagle Algorithm
69 | if (setsockopt(socket_id, IPPROTO_TCP, TCP_NODELAY, (char*)&flag, sizeof(flag)) < 0)
70 | return -2;
71 |
72 | struct sockaddr_in socket_address;
73 | // Create the stuff we need to connect
74 | socket_address.sin_family = AF_INET;
75 | socket_address.sin_port = htons(port);
76 | socket_address.sin_addr.s_addr = inet_addr(hostname);
77 |
78 | // Connect the socket
79 | if((connect(socket_id, (struct sockaddr*)&socket_address, sizeof(socket_address))) < 0)
80 | return -1;
81 |
82 | // MQTT stuffs
83 | mqtt_set_alive(broker, keepalive);
84 | broker->socket_info = (void*)&socket_id;
85 | broker->send = send_packet;
86 |
87 | return 0;
88 | }
89 |
90 | int close_socket(mqtt_broker_handle_t* broker)
91 | {
92 | int fd = *((int*)broker->socket_info);
93 | return close(fd);
94 | }
95 |
96 | int read_packet(int timeout)
97 | {
98 | if(timeout > 0)
99 | {
100 | fd_set readfds;
101 | struct timeval tmv;
102 |
103 | // Initialize the file descriptor set
104 | FD_ZERO (&readfds);
105 | FD_SET (socket_id, &readfds);
106 |
107 | // Initialize the timeout data structure
108 | tmv.tv_sec = timeout;
109 | tmv.tv_usec = 0;
110 |
111 | // select returns 0 if timeout, 1 if input available, -1 if error
112 | if(select(1, &readfds, NULL, NULL, &tmv))
113 | return -2;
114 | }
115 |
116 | int total_bytes = 0, bytes_rcvd, packet_length;
117 | memset(packet_buffer, 0, sizeof(packet_buffer));
118 |
119 | if((bytes_rcvd = recv(socket_id, (packet_buffer+total_bytes), RCVBUFSIZE, 0)) <= 0) {
120 | return -1;
121 | }
122 |
123 | total_bytes += bytes_rcvd; // Keep tally of total bytes
124 | if (total_bytes < 2)
125 | return -1;
126 |
127 | // now we have the full fixed header in packet_buffer
128 | // parse it for remaining length and number of bytes
129 | uint16_t rem_len = mqtt_parse_rem_len(packet_buffer);
130 | uint8_t rem_len_bytes = mqtt_num_rem_len_bytes(packet_buffer);
131 |
132 | //packet_length = packet_buffer[1] + 2; // Remaining length + fixed header length
133 | // total packet length = remaining length + byte 1 of fixed header + remaning length part of fixed header
134 | packet_length = rem_len + rem_len_bytes + 1;
135 |
136 | while(total_bytes < packet_length) // Reading the packet
137 | {
138 | if((bytes_rcvd = recv(socket_id, (packet_buffer+total_bytes), RCVBUFSIZE, 0)) <= 0)
139 | return -1;
140 | total_bytes += bytes_rcvd; // Keep tally of total bytes
141 | }
142 |
143 | return packet_length;
144 | }
145 |
146 | void alive(int sig)
147 | {
148 | printf("Timeout! Sending ping...\n");
149 | mqtt_ping(&broker);
150 |
151 | alarm(keepalive);
152 | }
153 |
154 | void term(int sig)
155 | {
156 | printf("Goodbye!\n");
157 | // >>>>> DISCONNECT
158 | mqtt_disconnect(&broker);
159 | close_socket(&broker);
160 |
161 | exit(0);
162 | }
163 |
164 | /**
165 | * Main routine
166 | *
167 | */
168 | int main()
169 | {
170 | int packet_length;
171 | uint16_t msg_id, msg_id_rcv;
172 |
173 | mqtt_init(&broker, "client-id");
174 | //mqtt_init_auth(&broker, "quijote", "rocinante");
175 | init_socket(&broker, "127.0.0.1", 1883, keepalive);
176 |
177 | // >>>>> CONNECT
178 | mqtt_connect(&broker);
179 | // <<<<< CONNACK
180 | packet_length = read_packet(1);
181 | if(packet_length < 0)
182 | {
183 | fprintf(stderr, "Error(%d) on read packet!\n", packet_length);
184 | return -1;
185 | }
186 |
187 | if(MQTTParseMessageType(packet_buffer) != MQTT_MSG_CONNACK)
188 | {
189 | fprintf(stderr, "CONNACK expected!\n");
190 | return -2;
191 | }
192 |
193 | if(packet_buffer[3] != 0x00)
194 | {
195 | fprintf(stderr, "CONNACK failed!\n");
196 | return -2;
197 | }
198 |
199 | // Signals after connect MQTT
200 | signal(SIGALRM, alive);
201 | alarm(keepalive);
202 | signal(SIGINT, term);
203 |
204 | // >>>>> SUBSCRIBE
205 | mqtt_subscribe(&broker, "public/test/topic", &msg_id);
206 | // <<<<< SUBACK
207 | packet_length = read_packet(1);
208 | if(packet_length < 0)
209 | {
210 | fprintf(stderr, "Error(%d) on read packet!\n", packet_length);
211 | return -1;
212 | }
213 |
214 | if(MQTTParseMessageType(packet_buffer) != MQTT_MSG_SUBACK)
215 | {
216 | fprintf(stderr, "SUBACK expected!\n");
217 | return -2;
218 | }
219 |
220 | msg_id_rcv = mqtt_parse_msg_id(packet_buffer);
221 | if(msg_id != msg_id_rcv)
222 | {
223 | fprintf(stderr, "%d message id was expected, but %d message id was found!\n", msg_id, msg_id_rcv);
224 | return -3;
225 | }
226 |
227 | while(1)
228 | {
229 | // <<<<<
230 | packet_length = read_packet(0);
231 | if(packet_length == -1)
232 | {
233 | fprintf(stderr, "Error(%d) on read packet!\n", packet_length);
234 | return -1;
235 | }
236 | else if(packet_length > 0)
237 | {
238 | printf("Packet Header: 0x%x...\n", packet_buffer[0]);
239 | if(MQTTParseMessageType(packet_buffer) == MQTT_MSG_PUBLISH)
240 | {
241 | uint8_t topic[255], msg[1000];
242 | uint16_t len;
243 | len = mqtt_parse_pub_topic(packet_buffer, topic);
244 | topic[len] = '\0'; // for printf
245 | len = mqtt_parse_publish_msg(packet_buffer, msg);
246 | msg[len] = '\0'; // for printf
247 | printf("%s %s\n", topic, msg);
248 | }
249 | }
250 |
251 | }
252 | return 0;
253 | }
254 |
--------------------------------------------------------------------------------
/client/sub.py:
--------------------------------------------------------------------------------
1 | #
2 | # This file is part of python-emqtt.
3 | #
4 | # python-emqtt is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU Lesser General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # python-emqtt is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with python-emqtt. If not, see .
16 | #
17 | #
18 | # Copyright 2012 Vicente Ruiz Rodríguez . All rights reserved.
19 | #
20 |
21 | from __future__ import print_function
22 |
23 | import select
24 | import signal
25 | import socket
26 | import sys
27 |
28 | import libemqtt
29 |
30 |
31 | def read(sck, timeout=None):
32 | try:
33 | inputready, outputready, exceptready = select.select([sck], [], [], timeout)
34 | except:
35 | return None
36 |
37 | if sck in inputready:
38 | fix_header = sck.recv(2)
39 | if len(fix_header):
40 | remain = ord(fix_header[1])
41 |
42 | data = sck.recv(remain)
43 |
44 | return libemqtt.MqttPacket(fix_header + data)
45 | return None
46 |
47 |
48 | HOST = '192.168.10.40'
49 | PORT = 1883
50 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
51 | s.connect((HOST, PORT))
52 |
53 | client = libemqtt.Mqtt(s, clientid='sancho', username='quijote', password='rocinante', keepalive=5)
54 |
55 | def alive_callback(client):
56 | def alive(signum, frame):
57 | print('Timeout! Sending ping...')
58 | client.ping()
59 | signal.alarm(client.keepalive)
60 |
61 | return alive
62 |
63 | signal.signal(signal.SIGALRM, alive_callback(client))
64 | signal.alarm(client.keepalive)
65 |
66 | # >>>>> CONNECT
67 | client.connect()
68 | # <<<<< CONNACK
69 | packet = read(s)
70 | if not packet:
71 | print('Error on read packet!', file=sys.stderr)
72 | sys.exit(-1)
73 |
74 | if packet.type != libemqtt.CONNACK:
75 | print('CONNACK expected!', file=sys.stderr)
76 | sys.exit(-2)
77 |
78 | if packet.index(3) != 0x00:
79 | print('CONNACK failed!', file=sys.stderr)
80 | sys.exit(-2)
81 |
82 | # >>>>> SUBSCRIBE
83 | msgid = client.subscribe("hello/emqtt")
84 | # <<<<< SUBACK
85 | packet = read(s)
86 | if not packet:
87 | print('Error on read packet!', file=sys.stderr)
88 | sys.exit(-1)
89 |
90 | if packet.type != libemqtt.SUBACK:
91 | print('SUBACK expected!', file=sys.stderr)
92 | sys.exit(-2)
93 |
94 | if msgid != packet.message_id:
95 | print('%d message id was expected, but %d message id was found!' % (msgid, packet.message_id), file=sys.stderr)
96 | sys.exit(-2)
97 |
98 | try:
99 | while True:
100 | # <<<<<
101 | packet = read(s)
102 | if packet:
103 | print('Packet Header: 0x%x' % packet.index(0))
104 | if packet.type == libemqtt.PUBLISH:
105 | print(packet.get_topic(), packet.get_message())
106 | except KeyboardInterrupt:
107 | print('Goodbye!')
108 |
109 |
110 | client.disconnect()
111 |
112 | s.close()
113 |
--------------------------------------------------------------------------------
/include/libemqtt.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of libemqtt.
3 | *
4 | * libemqtt is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU Lesser General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * libemqtt is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with libemqtt. If not, see .
16 | */
17 |
18 | /*
19 | *
20 | * Created by Filipe Varela on 09/10/16.
21 | * Copyright 2009 Caixa Mágica Software. All rights reserved.
22 | *
23 | * Fork developed by Vicente Ruiz Rodríguez
24 | * Copyright 2012 Vicente Ruiz Rodríguez . All rights reserved.
25 | *
26 | */
27 |
28 | #ifndef __LIBEMQTT_H__
29 | #define __LIBEMQTT_H__
30 |
31 | #include
32 |
33 | #ifndef MQTT_CONF_USERNAME_LENGTH
34 | #define MQTT_CONF_USERNAME_LENGTH 13 // Recommended by MQTT Specification (12 + '\0')
35 | #endif
36 |
37 | #ifndef MQTT_CONF_PASSWORD_LENGTH
38 | #define MQTT_CONF_PASSWORD_LENGTH 13 // Recommended by MQTT Specification (12 + '\0')
39 | #endif
40 |
41 |
42 | #define MQTT_MSG_CONNECT 1<<4
43 | #define MQTT_MSG_CONNACK 2<<4
44 | #define MQTT_MSG_PUBLISH 3<<4
45 | #define MQTT_MSG_PUBACK 4<<4
46 | #define MQTT_MSG_PUBREC 5<<4
47 | #define MQTT_MSG_PUBREL 6<<4
48 | #define MQTT_MSG_PUBCOMP 7<<4
49 | #define MQTT_MSG_SUBSCRIBE 8<<4
50 | #define MQTT_MSG_SUBACK 9<<4
51 | #define MQTT_MSG_UNSUBSCRIBE 10<<4
52 | #define MQTT_MSG_UNSUBACK 11<<4
53 | #define MQTT_MSG_PINGREQ 12<<4
54 | #define MQTT_MSG_PINGRESP 13<<4
55 | #define MQTT_MSG_DISCONNECT 14<<4
56 |
57 |
58 | /** Extract the message type from buffer.
59 | * @param buffer Pointer to the packet.
60 | *
61 | * @return Message Type byte.
62 | */
63 | #define MQTTParseMessageType(buffer) ( *buffer & 0xF0 )
64 |
65 | /** Indicate if it is a duplicate packet.
66 | * @param buffer Pointer to the packet.
67 | *
68 | * @retval 0 Not duplicate.
69 | * @retval !=0 Duplicate.
70 | */
71 | #define MQTTParseMessageDuplicate(buffer) ( *buffer & 0x08 )
72 |
73 | /** Extract the message QoS level.
74 | * @param buffer Pointer to the packet.
75 | *
76 | * @return QoS Level (0, 1 or 2).
77 | */
78 | #define MQTTParseMessageQos(buffer) ( (*buffer & 0x06) >> 1 )
79 |
80 | /** Indicate if this packet has a retain flag.
81 | * @param buffer Pointer to the packet.
82 | *
83 | * @retval 0 Not duplicate.
84 | * @retval !=0 Duplicate.
85 | */
86 | #define MQTTParseMessageRetain(buffer) ( *buffer & 0x01 )
87 |
88 |
89 | /** Parse packet buffer for number of bytes in remaining length field.
90 | *
91 | * Given a packet, return number of bytes in remaining length
92 | * field in MQTT fixed header. Can be from 1 - 4 bytes depending
93 | * on length of message.
94 | *
95 | * @param buf Pointer to the packet.
96 | *
97 | * @retval number of bytes
98 | */
99 | uint8_t mqtt_num_rem_len_bytes(const uint8_t* buf);
100 |
101 | /** Parse packet buffer for remaning length value.
102 | *
103 | * Given a packet, return remaining length value (in fixed header).
104 | *
105 | * @param buf Pointer to the packet.
106 | *
107 | * @retval remaining length
108 | */
109 | uint16_t mqtt_parse_rem_len(const uint8_t* buf);
110 |
111 | /** Parse packet buffer for message id.
112 | *
113 | * @param buf Pointer to the packet.
114 | *
115 | * @retval message id
116 | */
117 | uint8_t mqtt_parse_msg_id(const uint8_t* buf);
118 |
119 | /** Parse a packet buffer for the publish topic.
120 | *
121 | * Given a packet containing an MQTT publish message,
122 | * return the message topic.
123 | *
124 | * @param buf Pointer to the packet.
125 | * @param topic Pointer destination buffer for topic
126 | *
127 | * @retval size in bytes of topic (0 = no publish message in buffer)
128 | */
129 | uint16_t mqtt_parse_pub_topic(const uint8_t* buf, uint8_t* topic);
130 |
131 | /** Parse a packet buffer for a pointer to the publish topic.
132 | *
133 | * Not called directly - called by mqtt_parse_pub_topic
134 | */
135 | uint16_t mqtt_parse_pub_topic_ptr(const uint8_t* buf, const uint8_t** topic_ptr);
136 |
137 | /** Parse a packet buffer for the publish message.
138 | *
139 | * Given a packet containing an MQTT publish message,
140 | * return the message.
141 | *
142 | * @param buf Pointer to the packet.
143 | * @param msg Pointer destination buffer for message
144 | *
145 | * @retval size in bytes of topic (0 = no publish message in buffer)
146 | */
147 | uint16_t mqtt_parse_publish_msg(const uint8_t* buf, uint8_t* msg);
148 |
149 | /** Parse a packet buffer for a pointer to the publish message.
150 | *
151 | * Not called directly - called by mqtt_parse_pub_msg
152 | */
153 | uint16_t mqtt_parse_pub_msg_ptr(const uint8_t* buf, const uint8_t** msg_ptr);
154 |
155 |
156 | typedef struct {
157 | void* socket_info;
158 | int (*send)(void* socket_info, const void* buf, unsigned int count);
159 | // Connection info
160 | char clientid[50];
161 | // Auth fields
162 | char username[MQTT_CONF_USERNAME_LENGTH];
163 | char password[MQTT_CONF_PASSWORD_LENGTH];
164 | // Will topic
165 | uint8_t will_retain;
166 | uint8_t will_qos;
167 | uint8_t clean_session;
168 | // Management fields
169 | uint16_t seq;
170 | uint16_t alive;
171 | } mqtt_broker_handle_t;
172 |
173 |
174 | /** Initialize the information to connect to the broker.
175 | * @param broker Data structure that contains the connection information with the broker.
176 | * @param clientid A string that identifies the client id.
177 | *
178 | * @note Only has effect before to call mqtt_connect
179 | */
180 | void mqtt_init(mqtt_broker_handle_t* broker, const char* clientid);
181 |
182 | /** Enable the authentication to connect to the broker.
183 | * @param broker Data structure that contains the connection information with the broker.
184 | * @param username A string that contains the username.
185 | * @param password A string that contains the password.
186 | *
187 | * @note Only has effect before to call mqtt_connect
188 | */
189 | void mqtt_init_auth(mqtt_broker_handle_t* broker, const char* username, const char* password);
190 |
191 | /** Set the keep alive timer.
192 | * @param broker Data structure that contains the connection information with the broker.
193 | * @param alive Keep aliver timer value (in seconds).
194 | *
195 | * @note Only has effect before to call mqtt_connect
196 | */
197 | void mqtt_set_alive(mqtt_broker_handle_t* broker, uint16_t alive);
198 |
199 | /** Connect to the broker.
200 | * @param broker Data structure that contains the connection information with the broker.
201 | *
202 | * @retval 1 On success.
203 | * @retval 0 On connection error.
204 | * @retval -1 On IO error.
205 | */
206 | int mqtt_connect(mqtt_broker_handle_t* broker);
207 |
208 | /** Disconnect to the broker.
209 | * @param broker Data structure that contains the connection information with the broker.
210 | *
211 | * @note The socket must also be closed.
212 | *
213 | * @retval 1 On success.
214 | * @retval 0 On connection error.
215 | * @retval -1 On IO error.
216 | */
217 | int mqtt_disconnect(mqtt_broker_handle_t* broker);
218 |
219 | /** Publish a message on a topic. This message will be published with 0 Qos level.
220 | * @param broker Data structure that contains the connection information with the broker.
221 | * @param topic The topic name.
222 | * @param msg The message.
223 | * @param retain Enable or disable the Retain flag (values: 0 or 1).
224 | *
225 | * @retval 1 On success.
226 | * @retval 0 On connection error.
227 | * @retval -1 On IO error.
228 | */
229 | int mqtt_publish(mqtt_broker_handle_t* broker, const char* topic, const char* msg, uint8_t retain);
230 |
231 | /** Publish a message on a topic.
232 | * @param broker Data structure that contains the connection information with the broker.
233 | * @param topic The topic name.
234 | * @param msg The message.
235 | * @param retain Enable or disable the Retain flag (values: 0 or 1).
236 | * @param qos Quality of Service (values: 0, 1 or 2)
237 | * @param message_id Variable that will store the Message ID, if the pointer is not NULL.
238 | *
239 | * @retval 1 On success.
240 | * @retval 0 On connection error.
241 | * @retval -1 On IO error.
242 | */
243 | int mqtt_publish_with_qos(mqtt_broker_handle_t* broker, const char* topic, const char* msg, uint8_t retain, uint8_t qos, uint16_t* message_id);
244 |
245 | /** Send a PUBREL message. It's used for PUBLISH message with 2 QoS level.
246 | * @param broker Data structure that contains the connection information with the broker.
247 | * @param message_id Message ID
248 | *
249 | * @retval 1 On success.
250 | * @retval 0 On connection error.
251 | * @retval -1 On IO error.
252 | */
253 | int mqtt_pubrel(mqtt_broker_handle_t* broker, uint16_t message_id);
254 |
255 | /** Subscribe to a topic.
256 | * @param broker Data structure that contains the connection information with the broker.
257 | * @param topic The topic name.
258 | * @param message_id Variable that will store the Message ID, if the pointer is not NULL.
259 | *
260 | * @retval 1 On success.
261 | * @retval 0 On connection error.
262 | * @retval -1 On IO error.
263 | */
264 | int mqtt_subscribe(mqtt_broker_handle_t* broker, const char* topic, uint16_t* message_id);
265 |
266 | /** Unsubscribe from a topic.
267 | * @param broker Data structure that contains the connection information with the broker.
268 | * @param topic The topic name.
269 | * @param message_id Variable that will store the Message ID, if the pointer is not NULL.
270 | *
271 | * @retval 1 On success.
272 | * @retval 0 On connection error.
273 | * @retval -1 On IO error.
274 | */
275 | int mqtt_unsubscribe(mqtt_broker_handle_t* broker, const char* topic, uint16_t* message_id);
276 |
277 | /** Make a ping.
278 | * @param broker Data structure that contains the connection information with the broker.
279 | *
280 | * @retval 1 On success.
281 | * @retval 0 On connection error.
282 | * @retval -1 On IO error.
283 | */
284 | int mqtt_ping(mqtt_broker_handle_t* broker);
285 |
286 |
287 | #endif // __LIBEMQTT_H__
288 |
--------------------------------------------------------------------------------
/src/libemqtt.c:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of libemqtt.
3 | *
4 | * libemqtt is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU Lesser General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * libemqtt is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with libemqtt. If not, see .
16 | */
17 |
18 | /*
19 | *
20 | * Created by Filipe Varela on 09/10/16.
21 | * Copyright 2009 Caixa Mágica Software. All rights reserved.
22 | *
23 | * Fork developed by Vicente Ruiz Rodríguez
24 | * Copyright 2012 Vicente Ruiz Rodríguez . All rights reserved.
25 | *
26 | */
27 |
28 | #include
29 | #include
30 |
31 | #define MQTT_DUP_FLAG 1<<3
32 | #define MQTT_QOS0_FLAG 0<<1
33 | #define MQTT_QOS1_FLAG 1<<1
34 | #define MQTT_QOS2_FLAG 2<<1
35 |
36 | #define MQTT_RETAIN_FLAG 1
37 |
38 | #define MQTT_CLEAN_SESSION 1<<1
39 | #define MQTT_WILL_FLAG 1<<2
40 | #define MQTT_WILL_RETAIN 1<<5
41 | #define MQTT_USERNAME_FLAG 1<<7
42 | #define MQTT_PASSWORD_FLAG 1<<6
43 |
44 |
45 | uint8_t mqtt_num_rem_len_bytes(const uint8_t* buf) {
46 | uint8_t num_bytes = 1;
47 |
48 | //printf("mqtt_num_rem_len_bytes\n");
49 |
50 | if ((buf[1] & 0x80) == 0x80) {
51 | num_bytes++;
52 | if ((buf[2] & 0x80) == 0x80) {
53 | num_bytes ++;
54 | if ((buf[3] & 0x80) == 0x80) {
55 | num_bytes ++;
56 | }
57 | }
58 | }
59 | return num_bytes;
60 | }
61 |
62 | uint16_t mqtt_parse_rem_len(const uint8_t* buf) {
63 | uint16_t multiplier = 1;
64 | uint16_t value = 0;
65 | uint8_t digit;
66 |
67 | //printf("mqtt_parse_rem_len\n");
68 |
69 | buf++; // skip "flags" byte in fixed header
70 |
71 | do {
72 | digit = *buf;
73 | value += (digit & 127) * multiplier;
74 | multiplier *= 128;
75 | buf++;
76 | } while ((digit & 128) != 0);
77 |
78 | return value;
79 | }
80 |
81 | uint16_t mqtt_parse_msg_id(const uint8_t* buf) {
82 | uint8_t type = MQTTParseMessageType(buf);
83 | uint8_t qos = MQTTParseMessageQos(buf);
84 | uint16_t id = 0;
85 |
86 | //printf("mqtt_parse_msg_id\n");
87 |
88 | if(type >= MQTT_MSG_PUBLISH && type <= MQTT_MSG_UNSUBACK) {
89 | if(type == MQTT_MSG_PUBLISH) {
90 | if(qos != 0) {
91 | // fixed header length + Topic (UTF encoded)
92 | // = 1 for "flags" byte + rlb for length bytes + topic size
93 | uint8_t rlb = mqtt_num_rem_len_bytes(buf);
94 | uint8_t offset = *(buf+1+rlb)<<8; // topic UTF MSB
95 | offset |= *(buf+1+rlb+1); // topic UTF LSB
96 | offset += (1+rlb+2); // fixed header + topic size
97 | id = *(buf+offset)<<8; // id MSB
98 | id |= *(buf+offset+1); // id LSB
99 | }
100 | } else {
101 | // fixed header length
102 | // 1 for "flags" byte + rlb for length bytes
103 | uint8_t rlb = mqtt_num_rem_len_bytes(buf);
104 | id = *(buf+1+rlb)<<8; // id MSB
105 | id |= *(buf+1+rlb+1); // id LSB
106 | }
107 | }
108 | return id;
109 | }
110 |
111 | uint16_t mqtt_parse_pub_topic(const uint8_t* buf, uint8_t* topic) {
112 | const uint8_t* ptr;
113 | uint16_t topic_len = mqtt_parse_pub_topic_ptr(buf, &ptr);
114 |
115 | //printf("mqtt_parse_pub_topic\n");
116 |
117 | if(topic_len != 0 && ptr != NULL) {
118 | memcpy(topic, ptr, topic_len);
119 | }
120 |
121 | return topic_len;
122 | }
123 |
124 | uint16_t mqtt_parse_pub_topic_ptr(const uint8_t* buf, const uint8_t **topic_ptr) {
125 | uint16_t len = 0;
126 |
127 | //printf("mqtt_parse_pub_topic_ptr\n");
128 |
129 | if(MQTTParseMessageType(buf) == MQTT_MSG_PUBLISH) {
130 | // fixed header length = 1 for "flags" byte + rlb for length bytes
131 | uint8_t rlb = mqtt_num_rem_len_bytes(buf);
132 | len = *(buf+1+rlb)<<8; // MSB of topic UTF
133 | len |= *(buf+1+rlb+1); // LSB of topic UTF
134 | // start of topic = add 1 for "flags", rlb for remaining length, 2 for UTF
135 | *topic_ptr = (buf + (1+rlb+2));
136 | } else {
137 | *topic_ptr = NULL;
138 | }
139 | return len;
140 | }
141 |
142 | uint16_t mqtt_parse_publish_msg(const uint8_t* buf, uint8_t* msg) {
143 | const uint8_t* ptr;
144 |
145 | //printf("mqtt_parse_publish_msg\n");
146 |
147 | uint16_t msg_len = mqtt_parse_pub_msg_ptr(buf, &ptr);
148 |
149 | if(msg_len != 0 && ptr != NULL) {
150 | memcpy(msg, ptr, msg_len);
151 | }
152 |
153 | return msg_len;
154 | }
155 |
156 | uint16_t mqtt_parse_pub_msg_ptr(const uint8_t* buf, const uint8_t **msg_ptr) {
157 | uint16_t len = 0;
158 |
159 | //printf("mqtt_parse_pub_msg_ptr\n");
160 |
161 | if(MQTTParseMessageType(buf) == MQTT_MSG_PUBLISH) {
162 | // message starts at
163 | // fixed header length + Topic (UTF encoded) + msg id (if QoS>0)
164 | uint8_t rlb = mqtt_num_rem_len_bytes(buf);
165 | uint8_t offset = (*(buf+1+rlb))<<8; // topic UTF MSB
166 | offset |= *(buf+1+rlb+1); // topic UTF LSB
167 | offset += (1+rlb+2); // fixed header + topic size
168 |
169 | if(MQTTParseMessageQos(buf)) {
170 | offset += 2; // add two bytes of msg id
171 | }
172 |
173 | *msg_ptr = (buf + offset);
174 |
175 | // offset is now pointing to start of message
176 | // length of the message is remaining length - variable header
177 | // variable header is offset - fixed header
178 | // fixed header is 1 + rlb
179 | // so, lom = remlen - (offset - (1+rlb))
180 | len = mqtt_parse_rem_len(buf) - (offset-(rlb+1));
181 | } else {
182 | *msg_ptr = NULL;
183 | }
184 | return len;
185 | }
186 |
187 | void mqtt_init(mqtt_broker_handle_t* broker, const char* clientid) {
188 | // Connection options
189 | broker->alive = 300; // 300 seconds = 5 minutes
190 | broker->seq = 1; // Sequency for message indetifiers
191 | // Client options
192 | memset(broker->clientid, 0, sizeof(broker->clientid));
193 | memset(broker->username, 0, sizeof(broker->username));
194 | memset(broker->password, 0, sizeof(broker->password));
195 | if(clientid) {
196 | strncpy(broker->clientid, clientid, sizeof(broker->clientid));
197 | } else {
198 | strcpy(broker->clientid, "emqtt");
199 | }
200 | // Will topic
201 | broker->clean_session = 1;
202 | }
203 |
204 | void mqtt_init_auth(mqtt_broker_handle_t* broker, const char* username, const char* password) {
205 | if(username && username[0] != '\0')
206 | strncpy(broker->username, username, sizeof(broker->username)-1);
207 | if(password && password[0] != '\0')
208 | strncpy(broker->password, password, sizeof(broker->password)-1);
209 | }
210 |
211 | void mqtt_set_alive(mqtt_broker_handle_t* broker, uint16_t alive) {
212 | broker->alive = alive;
213 | }
214 |
215 | int mqtt_connect(mqtt_broker_handle_t* broker)
216 | {
217 | uint8_t flags = 0x00;
218 |
219 | uint16_t clientidlen = strlen(broker->clientid);
220 | uint16_t usernamelen = strlen(broker->username);
221 | uint16_t passwordlen = strlen(broker->password);
222 | uint16_t payload_len = clientidlen + 2;
223 |
224 | // Preparing the flags
225 | if(usernamelen) {
226 | payload_len += usernamelen + 2;
227 | flags |= MQTT_USERNAME_FLAG;
228 | }
229 | if(passwordlen) {
230 | payload_len += passwordlen + 2;
231 | flags |= MQTT_PASSWORD_FLAG;
232 | }
233 | if(broker->clean_session) {
234 | flags |= MQTT_CLEAN_SESSION;
235 | }
236 |
237 | // Variable header
238 | uint8_t var_header[] = {
239 | 0x00,0x06,0x4d,0x51,0x49,0x73,0x64,0x70, // Protocol name: MQIsdp
240 | 0x03, // Protocol version
241 | flags, // Connect flags
242 | broker->alive>>8, broker->alive&0xFF, // Keep alive
243 | };
244 |
245 |
246 | // Fixed header
247 | uint8_t fixedHeaderSize = 2; // Default size = one byte Message Type + one byte Remaining Length
248 | uint8_t remainLen = sizeof(var_header)+payload_len;
249 | if (remainLen > 127) {
250 | fixedHeaderSize++; // add an additional byte for Remaining Length
251 | }
252 | uint8_t fixed_header[fixedHeaderSize];
253 |
254 | // Message Type
255 | fixed_header[0] = MQTT_MSG_CONNECT;
256 |
257 | // Remaining Length
258 | if (remainLen <= 127) {
259 | fixed_header[1] = remainLen;
260 | } else {
261 | // first byte is remainder (mod) of 128, then set the MSB to indicate more bytes
262 | fixed_header[1] = remainLen % 128;
263 | fixed_header[1] = fixed_header[1] | 0x80;
264 | // second byte is number of 128s
265 | fixed_header[2] = remainLen / 128;
266 | }
267 |
268 | uint16_t offset = 0;
269 | uint8_t packet[sizeof(fixed_header)+sizeof(var_header)+payload_len];
270 | memset(packet, 0, sizeof(packet));
271 | memcpy(packet, fixed_header, sizeof(fixed_header));
272 | offset += sizeof(fixed_header);
273 | memcpy(packet+offset, var_header, sizeof(var_header));
274 | offset += sizeof(var_header);
275 | // Client ID - UTF encoded
276 | packet[offset++] = clientidlen>>8;
277 | packet[offset++] = clientidlen&0xFF;
278 | memcpy(packet+offset, broker->clientid, clientidlen);
279 | offset += clientidlen;
280 |
281 | if(usernamelen) {
282 | // Username - UTF encoded
283 | packet[offset++] = usernamelen>>8;
284 | packet[offset++] = usernamelen&0xFF;
285 | memcpy(packet+offset, broker->username, usernamelen);
286 | offset += usernamelen;
287 | }
288 |
289 | if(passwordlen) {
290 | // Password - UTF encoded
291 | packet[offset++] = passwordlen>>8;
292 | packet[offset++] = passwordlen&0xFF;
293 | memcpy(packet+offset, broker->password, passwordlen);
294 | offset += passwordlen;
295 | }
296 |
297 | // Send the packet
298 | if(broker->send(broker->socket_info, packet, sizeof(packet)) < sizeof(packet)) {
299 | return -1;
300 | }
301 |
302 | return 1;
303 | }
304 |
305 | int mqtt_disconnect(mqtt_broker_handle_t* broker) {
306 | uint8_t packet[] = {
307 | MQTT_MSG_DISCONNECT, // Message Type, DUP flag, QoS level, Retain
308 | 0x00 // Remaining length
309 | };
310 |
311 | // Send the packet
312 | if(broker->send(broker->socket_info, packet, sizeof(packet)) < sizeof(packet)) {
313 | return -1;
314 | }
315 |
316 | return 1;
317 | }
318 |
319 | int mqtt_ping(mqtt_broker_handle_t* broker) {
320 | uint8_t packet[] = {
321 | MQTT_MSG_PINGREQ, // Message Type, DUP flag, QoS level, Retain
322 | 0x00 // Remaining length
323 | };
324 |
325 | // Send the packet
326 | if(broker->send(broker->socket_info, packet, sizeof(packet)) < sizeof(packet)) {
327 | return -1;
328 | }
329 |
330 | return 1;
331 | }
332 |
333 | int mqtt_publish(mqtt_broker_handle_t* broker, const char* topic, const char* msg, uint8_t retain) {
334 | return mqtt_publish_with_qos(broker, topic, msg, retain, 0, NULL);
335 | }
336 |
337 | int mqtt_publish_with_qos(mqtt_broker_handle_t* broker, const char* topic, const char* msg, uint8_t retain, uint8_t qos, uint16_t* message_id) {
338 | uint16_t topiclen = strlen(topic);
339 | uint16_t msglen = strlen(msg);
340 |
341 | uint8_t qos_flag = MQTT_QOS0_FLAG;
342 | uint8_t qos_size = 0; // No QoS included
343 | if(qos == 1) {
344 | qos_size = 2; // 2 bytes for QoS
345 | qos_flag = MQTT_QOS1_FLAG;
346 | }
347 | else if(qos == 2) {
348 | qos_size = 2; // 2 bytes for QoS
349 | qos_flag = MQTT_QOS2_FLAG;
350 | }
351 |
352 | // Variable header
353 | uint8_t var_header[topiclen+2+qos_size]; // Topic size (2 bytes), utf-encoded topic
354 | memset(var_header, 0, sizeof(var_header));
355 | var_header[0] = topiclen>>8;
356 | var_header[1] = topiclen&0xFF;
357 | memcpy(var_header+2, topic, topiclen);
358 | if(qos_size) {
359 | var_header[topiclen+2] = broker->seq>>8;
360 | var_header[topiclen+3] = broker->seq&0xFF;
361 | if(message_id) { // Returning message id
362 | *message_id = broker->seq;
363 | }
364 | broker->seq++;
365 | }
366 |
367 | // Fixed header
368 | // the remaining length is one byte for messages up to 127 bytes, then two bytes after that
369 | // actually, it can be up to 4 bytes but I'm making the assumption the embedded device will only
370 | // need up to two bytes of length (handles up to 16,383 (almost 16k) sized message)
371 | uint8_t fixedHeaderSize = 2; // Default size = one byte Message Type + one byte Remaining Length
372 | uint16_t remainLen = sizeof(var_header)+msglen;
373 | if (remainLen > 127) {
374 | fixedHeaderSize++; // add an additional byte for Remaining Length
375 | }
376 | uint8_t fixed_header[fixedHeaderSize];
377 |
378 | // Message Type, DUP flag, QoS level, Retain
379 | fixed_header[0] = MQTT_MSG_PUBLISH | qos_flag;
380 | if(retain) {
381 | fixed_header[0] |= MQTT_RETAIN_FLAG;
382 | }
383 | // Remaining Length
384 | if (remainLen <= 127) {
385 | fixed_header[1] = remainLen;
386 | } else {
387 | // first byte is remainder (mod) of 128, then set the MSB to indicate more bytes
388 | fixed_header[1] = remainLen % 128;
389 | fixed_header[1] = fixed_header[1] | 0x80;
390 | // second byte is number of 128s
391 | fixed_header[2] = remainLen / 128;
392 | }
393 |
394 | uint8_t packet[sizeof(fixed_header)+sizeof(var_header)+msglen];
395 | memset(packet, 0, sizeof(packet));
396 | memcpy(packet, fixed_header, sizeof(fixed_header));
397 | memcpy(packet+sizeof(fixed_header), var_header, sizeof(var_header));
398 | memcpy(packet+sizeof(fixed_header)+sizeof(var_header), msg, msglen);
399 |
400 | // Send the packet
401 | if(broker->send(broker->socket_info, packet, sizeof(packet)) < sizeof(packet)) {
402 | return -1;
403 | }
404 |
405 | return 1;
406 | }
407 |
408 | int mqtt_pubrel(mqtt_broker_handle_t* broker, uint16_t message_id) {
409 | uint8_t packet[] = {
410 | MQTT_MSG_PUBREL | MQTT_QOS1_FLAG, // Message Type, DUP flag, QoS level, Retain
411 | 0x02, // Remaining length
412 | message_id>>8,
413 | message_id&0xFF
414 | };
415 |
416 | // Send the packet
417 | if(broker->send(broker->socket_info, packet, sizeof(packet)) < sizeof(packet)) {
418 | return -1;
419 | }
420 |
421 | return 1;
422 | }
423 |
424 | int mqtt_subscribe(mqtt_broker_handle_t* broker, const char* topic, uint16_t* message_id) {
425 | uint16_t topiclen = strlen(topic);
426 |
427 | // Variable header
428 | uint8_t var_header[2]; // Message ID
429 | var_header[0] = broker->seq>>8;
430 | var_header[1] = broker->seq&0xFF;
431 | if(message_id) { // Returning message id
432 | *message_id = broker->seq;
433 | }
434 | broker->seq++;
435 |
436 | // utf topic
437 | uint8_t utf_topic[topiclen+3]; // Topic size (2 bytes), utf-encoded topic, QoS byte
438 | memset(utf_topic, 0, sizeof(utf_topic));
439 | utf_topic[0] = topiclen>>8;
440 | utf_topic[1] = topiclen&0xFF;
441 | memcpy(utf_topic+2, topic, topiclen);
442 |
443 | // Fixed header
444 | uint8_t fixed_header[] = {
445 | MQTT_MSG_SUBSCRIBE | MQTT_QOS1_FLAG, // Message Type, DUP flag, QoS level, Retain
446 | sizeof(var_header)+sizeof(utf_topic)
447 | };
448 |
449 | uint8_t packet[sizeof(var_header)+sizeof(fixed_header)+sizeof(utf_topic)];
450 | memset(packet, 0, sizeof(packet));
451 | memcpy(packet, fixed_header, sizeof(fixed_header));
452 | memcpy(packet+sizeof(fixed_header), var_header, sizeof(var_header));
453 | memcpy(packet+sizeof(fixed_header)+sizeof(var_header), utf_topic, sizeof(utf_topic));
454 |
455 | // Send the packet
456 | if(broker->send(broker->socket_info, packet, sizeof(packet)) < sizeof(packet)) {
457 | return -1;
458 | }
459 |
460 | return 1;
461 | }
462 |
463 | int mqtt_unsubscribe(mqtt_broker_handle_t* broker, const char* topic, uint16_t* message_id) {
464 | uint16_t topiclen = strlen(topic);
465 |
466 | // Variable header
467 | uint8_t var_header[2]; // Message ID
468 | var_header[0] = broker->seq>>8;
469 | var_header[1] = broker->seq&0xFF;
470 | if(message_id) { // Returning message id
471 | *message_id = broker->seq;
472 | }
473 | broker->seq++;
474 |
475 | // utf topic
476 | uint8_t utf_topic[topiclen+2]; // Topic size (2 bytes), utf-encoded topic
477 | memset(utf_topic, 0, sizeof(utf_topic));
478 | utf_topic[0] = topiclen>>8;
479 | utf_topic[1] = topiclen&0xFF;
480 | memcpy(utf_topic+2, topic, topiclen);
481 |
482 | // Fixed header
483 | uint8_t fixed_header[] = {
484 | MQTT_MSG_UNSUBSCRIBE | MQTT_QOS1_FLAG, // Message Type, DUP flag, QoS level, Retain
485 | sizeof(var_header)+sizeof(utf_topic)
486 | };
487 |
488 | uint8_t packet[sizeof(var_header)+sizeof(fixed_header)+sizeof(utf_topic)];
489 | memset(packet, 0, sizeof(packet));
490 | memcpy(packet, fixed_header, sizeof(fixed_header));
491 | memcpy(packet+sizeof(fixed_header), var_header, sizeof(var_header));
492 | memcpy(packet+sizeof(fixed_header)+sizeof(var_header), utf_topic, sizeof(utf_topic));
493 |
494 | // Send the packet
495 | if(broker->send(broker->socket_info, packet, sizeof(packet)) < sizeof(packet)) {
496 | return -1;
497 | }
498 |
499 | return 1;
500 | }
--------------------------------------------------------------------------------
/src/python/python-libemqtt.c:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of python-emqtt.
3 | *
4 | * python-emqtt is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU Lesser General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * python-emqtt is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with python-emqtt. If not, see .
16 | *
17 | *
18 | * Copyright 2012 Vicente Ruiz Rodríguez . All rights reserved.
19 | *
20 | */
21 |
22 | #include
23 | #include
24 | #include
25 |
26 |
27 | // Module definition
28 | #ifndef PyMODINIT_FUNC /* declarations for DLL import/export */
29 | #define PyMODINIT_FUNC void
30 | #endif
31 |
32 | PyMODINIT_FUNC initlibemqtt(void)
33 | {
34 | PyObject* m;
35 |
36 | MqttType.tp_new = PyType_GenericNew;
37 | if(PyType_Ready(&MqttType) < 0)
38 | return;
39 |
40 | MqttPacketType.tp_new = PyType_GenericNew;
41 | if(PyType_Ready(&MqttPacketType) < 0)
42 | return;
43 |
44 | m = Py_InitModule3("libemqtt", NULL, "Embedded MQTT library.");
45 |
46 | Py_INCREF(&MqttType);
47 | PyModule_AddObject(m, "Mqtt", (PyObject*)&MqttType);
48 |
49 | Py_INCREF(&MqttPacketType);
50 | PyModule_AddObject(m, "MqttPacket", (PyObject*)&MqttPacketType);
51 |
52 | PyModule_AddIntConstant(m, "CONNECT", MQTT_MSG_CONNECT);
53 | PyModule_AddIntConstant(m, "CONNACK", MQTT_MSG_CONNACK);
54 | PyModule_AddIntConstant(m, "PUBLISH", MQTT_MSG_PUBLISH);
55 | PyModule_AddIntConstant(m, "PUBACK", MQTT_MSG_PUBACK);
56 | PyModule_AddIntConstant(m, "PUBREC", MQTT_MSG_PUBREC);
57 | PyModule_AddIntConstant(m, "PUBREL", MQTT_MSG_PUBREL);
58 | PyModule_AddIntConstant(m, "PUBCOMP", MQTT_MSG_PUBCOMP);
59 | PyModule_AddIntConstant(m, "SUBSCRIBE", MQTT_MSG_SUBSCRIBE);
60 | PyModule_AddIntConstant(m, "SUBACK", MQTT_MSG_SUBACK);
61 | PyModule_AddIntConstant(m, "UNSUBSCRIBE", MQTT_MSG_UNSUBSCRIBE);
62 | PyModule_AddIntConstant(m, "UNSUBACK", MQTT_MSG_UNSUBACK);
63 | PyModule_AddIntConstant(m, "PINGREQ", MQTT_MSG_PINGREQ);
64 | PyModule_AddIntConstant(m, "PINGRESP", MQTT_MSG_PINGRESP);
65 | PyModule_AddIntConstant(m, "DISCONNECT", MQTT_MSG_DISCONNECT);
66 |
67 | ConnectionError = PyErr_NewException("libemqtt.ConnectionError", NULL, NULL);
68 | Py_INCREF(ConnectionError);
69 | PyModule_AddObject(m, "ConnectionError", ConnectionError);
70 | }
71 |
72 | /*
73 | static PyModuleDef moduledef = {
74 | PyModuleDef_HEAD_INIT,
75 | "emqtt",
76 | "python-emqtt",
77 | -1,
78 | NULL, // methods
79 | NULL,
80 | NULL, // traverse
81 | NULL, // clear
82 | NULL
83 | };
84 |
85 |
86 | PyInit_emqtt(void)
87 | {
88 | PyObject* mod; = (PyModule_Create(&moduledef);
89 | if (mod == NULL) {
90 | return NULL;
91 | }
92 |
93 | MqttType.tp_new = PyType_GenericNew;
94 | if (PyType_Ready(&MqttType) < 0) {
95 | Py_DECREF(mod);
96 | return NULL;
97 | }
98 |
99 | Py_INCREF(&MqttType);
100 | PyModule_AddObject(mod, "Mqtt", (PyObject*)&MqttType);
101 |
102 | return mod;
103 | }
104 | */
105 |
--------------------------------------------------------------------------------
/src/python/python-mqtt.c:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of python-emqtt.
3 | *
4 | * python-emqtt is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU Lesser General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * python-emqtt is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with python-emqtt. If not, see .
16 | *
17 | *
18 | * Copyright 2012 Vicente Ruiz Rodríguez . All rights reserved.
19 | *
20 | */
21 |
22 | #include
23 | #include
24 |
25 |
26 | PyObject *ConnectionError;
27 |
28 |
29 | int send_packet(void* socket_info, const void* buf, unsigned int count)
30 | {
31 | Mqtt* self = (Mqtt *)socket_info;
32 | PyObject* packet = PyString_FromStringAndSize(buf, count);
33 | PyObject* result = PyObject_CallMethod(self->socket, "send", "S", packet);
34 | int bytes = PyInt_AsLong(result);
35 | Py_DECREF(packet);
36 | return bytes;
37 | }
38 |
39 |
40 |
41 | static PyObject*
42 | Mqtt_init(Mqtt* self, PyObject* args, PyObject* kwargs)
43 | {
44 | static char* kwlist[] = {"socket", "clientid", "username", "password", "keepalive", NULL};
45 |
46 | char* clientid = "python-emqtt";
47 | char* username = NULL;
48 | char* password = NULL;
49 | int keepalive = 300; // By default
50 |
51 | if(!PyArg_ParseTupleAndKeywords(args, kwargs, "O|sssi", kwlist, &self->socket, &clientid, &username, &password, &keepalive))
52 | {
53 | return NULL;
54 | }
55 |
56 | // TODO: check the first argument. It must be a socket
57 |
58 | mqtt_init(&self->broker, clientid);
59 | mqtt_init_auth(&self->broker, username, password);
60 | mqtt_set_alive(&self->broker, keepalive);
61 |
62 | self->broker.socket_info = (void*)self;
63 | self->broker.send = send_packet;
64 |
65 | self->connected = 0;
66 | self->keepalive = keepalive;
67 |
68 | Py_RETURN_NONE;
69 | }
70 |
71 | static PyObject*
72 | Mqtt_connect(Mqtt* self)
73 | {
74 | if(self->connected <= 0) // Prevent reconnect
75 | {
76 | self->connected = mqtt_connect(&self->broker);
77 | return Py_BuildValue("b", self->connected);
78 | }
79 | Py_RETURN_FALSE;
80 | }
81 |
82 | static PyObject*
83 | Mqtt_disconnect(Mqtt* self)
84 | {
85 | if(self->connected > 0)
86 | {
87 | int result = mqtt_disconnect(&self->broker);
88 | self->connected = 0;
89 | return Py_BuildValue("i", result);
90 | }
91 | Py_RETURN_NONE;
92 | }
93 |
94 | static PyObject*
95 | Mqtt_ping(Mqtt* self)
96 | {
97 | if(self->connected <= 0) // Not connected
98 | {
99 | PyErr_SetString(ConnectionError, "Not connected");
100 | return NULL;
101 | }
102 |
103 | return Py_BuildValue("i", mqtt_ping(&self->broker));
104 | }
105 |
106 | static PyObject*
107 | Mqtt_publish(Mqtt* self, PyObject* args, PyObject* kwargs)
108 | {
109 | static char* kwlist[] = {"topic", "message", "retain", "qos", NULL};
110 |
111 | char* topic = NULL; // Required
112 | char* message = NULL; // Required
113 | PyObject* retain = Py_False; // By default
114 | int qos = 0; // By default
115 | uint16_t message_id;
116 |
117 | int result;
118 |
119 | if(!PyArg_ParseTupleAndKeywords(args, kwargs, "ss|Oi", kwlist, &topic, &message, &retain, &qos))
120 | {
121 | return NULL;
122 | }
123 |
124 | if(self->connected <= 0) // Not connected
125 | {
126 | PyErr_SetString(ConnectionError, "Not connected");
127 | return NULL;
128 | }
129 |
130 | if(!PyBool_Check(retain) && !PyInt_Check(retain))
131 | {
132 | PyErr_SetString(PyExc_TypeError, "Retain must be bool or integer");
133 | return NULL;
134 | }
135 |
136 | if(qos < 0 || qos > 2)
137 | {
138 | PyErr_SetString(PyExc_TypeError, "QoS out of range");
139 | return NULL;
140 | }
141 |
142 | result = mqtt_publish_with_qos(&self->broker, topic, message, PyInt_AsLong(retain), qos, &message_id);
143 | if(result > 0)
144 | result = message_id;
145 |
146 | return Py_BuildValue("i", result);
147 | }
148 |
149 | static PyObject*
150 | Mqtt_pubrel(Mqtt* self, PyObject* args, PyObject* kwargs)
151 | {
152 | static char* kwlist[] = {"msgid", NULL};
153 |
154 | int message_id;
155 |
156 | if(!PyArg_ParseTupleAndKeywords(args, kwargs, "i", kwlist, &message_id))
157 | {
158 | return NULL;
159 | }
160 |
161 | if(self->connected <= 0) // Not connected
162 | {
163 | PyErr_SetString(ConnectionError, "Not connected");
164 | return NULL;
165 | }
166 |
167 | return Py_BuildValue("i", mqtt_pubrel(&self->broker, message_id));
168 | }
169 |
170 | static PyObject*
171 | Mqtt_subscribe(Mqtt* self, PyObject* args, PyObject* kwargs)
172 | {
173 | static char* kwlist[] = {"topic", NULL};
174 |
175 | int result;
176 | char* topic = NULL;
177 | uint16_t msg_id;
178 |
179 | if(!PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist, &topic))
180 | {
181 | return NULL;
182 | }
183 |
184 | if(self->connected <= 0) // Not connected
185 | {
186 | PyErr_SetString(ConnectionError, "Not connected");
187 | return NULL;
188 | }
189 |
190 | result = mqtt_subscribe(&self->broker, topic, &msg_id);
191 | if(result > 0)
192 | result = msg_id;
193 |
194 | return Py_BuildValue("i", result);
195 | }
196 |
197 | static PyObject*
198 | Mqtt_unsubscribe(Mqtt* self, PyObject* args, PyObject* kwargs)
199 | {
200 | static char* kwlist[] = {"topic", NULL};
201 |
202 | int result;
203 | char* topic = NULL;
204 | uint16_t msg_id;
205 |
206 | if(!PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist, &topic))
207 | {
208 | return NULL;
209 | }
210 |
211 | if(self->connected <= 0) // Not connected
212 | {
213 | PyErr_SetString(ConnectionError, "Not connected");
214 | return NULL;
215 | }
216 |
217 | result = mqtt_unsubscribe(&self->broker, topic, &msg_id);
218 | if(result > 0)
219 | result = msg_id;
220 |
221 | return Py_BuildValue("i", result);
222 | }
223 |
224 | static void
225 | Mqtt_dealloc(Mqtt* self)
226 | {
227 | if(self->connected > 0)
228 | {
229 | Mqtt_disconnect(self);
230 | }
231 | Py_XDECREF(self->socket);
232 | self->ob_type->tp_free((PyObject*)self);
233 | }
234 |
235 | static PyMemberDef Mqtt_members[] = {
236 | {"keepalive", T_INT, offsetof(Mqtt, keepalive), 0, "Keep alive timer."},
237 |
238 | { NULL }
239 | };
240 |
241 | static PyMethodDef Mqtt_methods[] = {
242 | { "connect", (PyCFunction) Mqtt_connect, METH_NOARGS, "MQTT connect." },
243 | { "disconnect", (PyCFunction) Mqtt_disconnect, METH_NOARGS, "MQTT disconnect." },
244 | { "ping", (PyCFunction) Mqtt_ping, METH_NOARGS, "MQTT ping." },
245 | { "publish", (PyCFunction) Mqtt_publish, METH_KEYWORDS, "MQTT publish." },
246 | { "pubrel", (PyCFunction) Mqtt_pubrel, METH_KEYWORDS, "MQTT pubrel." },
247 | { "subscribe", (PyCFunction) Mqtt_subscribe, METH_KEYWORDS, "MQTT subscribe." },
248 | { "unsubscribe", (PyCFunction) Mqtt_unsubscribe, METH_KEYWORDS, "MQTT unsubscribe." },
249 |
250 | { NULL }
251 | };
252 |
253 | PyTypeObject MqttType = {
254 | PyObject_HEAD_INIT(NULL)
255 | 0, /* ob_size */
256 | "libemqtt.Mqtt", /* tp_name */
257 | sizeof(Mqtt), /* tp_basicsize */
258 | 0, /* tp_itemsize */
259 | (destructor)Mqtt_dealloc, /* tp_dealloc */
260 | 0, /* tp_print*/
261 | 0, /* tp_getattr */
262 | 0, /* tp_setattr */
263 | 0, /* tp_compare */
264 | 0, /* tp_repr */
265 | 0, /* tp_as_number */
266 | 0, /* tp_as_sequence */
267 | 0, /* tp_as_mapping */
268 | 0, /* tp_hash */
269 | 0, /* tp_call */
270 | 0, /* tp_str */
271 | 0, /* tp_getattro */
272 | 0, /* tp_setattro */
273 | 0, /* tp_as_buffer */
274 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags*/
275 | "Mqtt objects", /* tp_doc */
276 | 0, /* tp_traverse */
277 | 0, /* tp_clear */
278 | 0, /* tp_richcompare */
279 | 0, /* tp_weaklistoffset */
280 | 0, /* tp_iter */
281 | 0, /* tp_iternext */
282 | Mqtt_methods, /* tp_methods */
283 | Mqtt_members, /* tp_members */
284 | 0, /* tp_getset */
285 | 0, /* tp_base */
286 | 0, /* tp_dict */
287 | 0, /* tp_descr_get */
288 | 0, /* tp_descr_set */
289 | 0, /* tp_dictoffset */
290 | (initproc)Mqtt_init, /* tp_init */
291 | 0, /* tp_alloc */
292 | 0, /* tp_new */
293 | };
294 |
--------------------------------------------------------------------------------
/src/python/python-mqtt.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of python-emqtt.
3 | *
4 | * python-emqtt is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU Lesser General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * python-emqtt is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with python-emqtt. If not, see .
16 | *
17 | *
18 | * Copyright 2012 Vicente Ruiz Rodríguez . All rights reserved.
19 | *
20 | */
21 |
22 | #ifndef __LIBEMQTT_PYTHON_MQTT_H__
23 | #define __LIBEMQTT_PYTHON_MQTT_H__
24 |
25 | #include
26 | #include
27 | #include
28 |
29 | typedef struct {
30 | PyObject_HEAD
31 | PyObject* socket;
32 | short connected; // < 1 means not connected
33 | int keepalive;
34 | mqtt_broker_handle_t broker;
35 | } Mqtt;
36 |
37 | extern PyObject *ConnectionError;
38 | extern PyTypeObject MqttType;
39 |
40 | #endif // __LIBEMQTT_PYTHON_MQTT_H__
41 |
--------------------------------------------------------------------------------
/src/python/python-mqtt_packet.c:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of python-emqtt.
3 | *
4 | * python-emqtt is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU Lesser General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * python-emqtt is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with python-emqtt. If not, see .
16 | *
17 | *
18 | * Copyright 2012 Vicente Ruiz Rodríguez . All rights reserved.
19 | *
20 | */
21 |
22 | #include
23 | #include
24 | #include
25 |
26 |
27 | static PyObject*
28 | MqttPacket_init(MqttPacket* self, PyObject* args, PyObject* kwargs)
29 | {
30 | static char* kwlist[] = {"data", NULL};
31 |
32 | if(!PyArg_ParseTupleAndKeywords(args, kwargs, "S", kwlist, &self->data))
33 | {
34 | return NULL;
35 | }
36 | const char* data = PyString_AS_STRING(self->data);
37 | self->type = MQTTParseMessageType(data);
38 | self->qos = MQTTParseMessageQos(data);
39 | self->duplicate = Py_False;
40 | if(MQTTParseMessageDuplicate(data))
41 | self->duplicate = Py_True;
42 | self->retain = Py_False;
43 | if(MQTTParseMessageRetain(data))
44 | self->retain = Py_True;
45 | MQTTParseMessageId(data, self->message_id);
46 |
47 | Py_RETURN_NONE;
48 | }
49 |
50 | static PyObject*
51 | MqttPacket_index(MqttPacket* self, PyObject* args)
52 | {
53 | int index;
54 |
55 | if(!PyArg_ParseTuple(args, "i", &index))
56 | {
57 | return NULL;
58 | }
59 |
60 | if(index < 0 || index >= PyString_Size(self->data))
61 | {
62 | PyErr_SetString(PyExc_IndexError, "index out of range");
63 | return NULL;
64 | }
65 |
66 | char* data = PyString_AS_STRING(self->data);
67 |
68 | return Py_BuildValue("i", (uint8_t)data[index]);
69 | }
70 |
71 | static PyObject*
72 | MqttPacket_get_topic(MqttPacket* self)
73 | {
74 | int len;
75 | char* ptr;
76 | char* data = PyString_AS_STRING(self->data);
77 |
78 | MQTTParsePublishTopicPtr(data, ptr, len);
79 | if(ptr == NULL)
80 | {
81 | Py_RETURN_NONE;
82 | }
83 |
84 | PyObject* message = PyString_FromStringAndSize(ptr, len); // New reference
85 | if(message == NULL)
86 | {
87 | return NULL;
88 | }
89 |
90 | return message;
91 | }
92 |
93 | static PyObject*
94 | MqttPacket_get_message(MqttPacket* self)
95 | {
96 | int len;
97 | char* ptr;
98 | char* data = PyString_AS_STRING(self->data);
99 |
100 | MQTTParsePublishMessagePtr(data, ptr, len);
101 | if(ptr == NULL)
102 | {
103 | Py_RETURN_NONE;
104 | }
105 |
106 | PyObject* message = PyString_FromStringAndSize(ptr, len); // New reference
107 | if(message == NULL)
108 | {
109 | return NULL;
110 | }
111 |
112 | return message;
113 | }
114 |
115 | static void
116 | MqttPacket_dealloc(MqttPacket* self)
117 | {
118 | self->ob_type->tp_free((PyObject*)self);
119 | }
120 |
121 | static PyMemberDef MqttPacket_members[] = {
122 | {"type", T_INT, offsetof(MqttPacket, type), 0, "Packet type."},
123 | {"qos", T_INT, offsetof(MqttPacket, qos), 0, "Quality of Service."},
124 | {"duplicate", T_OBJECT_EX, offsetof(MqttPacket, duplicate), 0, "Duplicate flag."},
125 | {"retain", T_OBJECT_EX, offsetof(MqttPacket, retain), 0, "Retain flag."},
126 | {"message_id", T_INT, offsetof(MqttPacket, message_id), 0, "Message ID."},
127 |
128 | { NULL }
129 | };
130 |
131 | static PyMethodDef MqttPacket_methods[] = {
132 | { "index", (PyCFunction) MqttPacket_index, METH_VARARGS, "Get a byte from the packet." },
133 | { "get_topic", (PyCFunction) MqttPacket_get_topic, METH_NOARGS, "Get the topic from a publish packet." },
134 | { "get_message", (PyCFunction) MqttPacket_get_message, METH_NOARGS, "Get the message from a publish packet." },
135 |
136 | { NULL }
137 | };
138 |
139 | PyTypeObject MqttPacketType = {
140 | PyObject_HEAD_INIT(NULL)
141 | 0, /* ob_size */
142 | "libemqtt.MqttPacket", /* tp_name */
143 | sizeof(MqttPacket), /* tp_basicsize */
144 | 0, /* tp_itemsize */
145 | (destructor)MqttPacket_dealloc, /* tp_dealloc */
146 | 0, /* tp_print*/
147 | 0, /* tp_getattr */
148 | 0, /* tp_setattr */
149 | 0, /* tp_compare */
150 | 0, /* tp_repr */
151 | 0, /* tp_as_number */
152 | 0, /* tp_as_sequence */
153 | 0, /* tp_as_mapping */
154 | 0, /* tp_hash */
155 | 0, /* tp_call */
156 | 0, /* tp_str */
157 | 0, /* tp_getattro */
158 | 0, /* tp_setattro */
159 | 0, /* tp_as_buffer */
160 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags*/
161 | "MqttPacket objects", /* tp_doc */
162 | 0, /* tp_traverse */
163 | 0, /* tp_clear */
164 | 0, /* tp_richcompare */
165 | 0, /* tp_weaklistoffset */
166 | 0, /* tp_iter */
167 | 0, /* tp_iternext */
168 | MqttPacket_methods, /* tp_methods */
169 | MqttPacket_members, /* tp_members */
170 | 0, /* tp_getset */
171 | 0, /* tp_base */
172 | 0, /* tp_dict */
173 | 0, /* tp_descr_get */
174 | 0, /* tp_descr_set */
175 | 0, /* tp_dictoffset */
176 | (initproc)MqttPacket_init, /* tp_init */
177 | 0, /* tp_alloc */
178 | 0, /* tp_new */
179 | };
180 |
--------------------------------------------------------------------------------
/src/python/python-mqtt_packet.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of python-emqtt.
3 | *
4 | * python-emqtt is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU Lesser General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * python-emqtt is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with python-emqtt. If not, see .
16 | *
17 | *
18 | * Copyright 2012 Vicente Ruiz Rodríguez . All rights reserved.
19 | *
20 | */
21 |
22 | #ifndef __LIBEMQTT_PYTHON_MQTT_PACKET_H__
23 | #define __LIBEMQTT_PYTHON_MQTT_PACKET_H__
24 |
25 | #include
26 | #include
27 |
28 | typedef struct {
29 | PyObject_HEAD
30 | PyObject* data;
31 | uint16_t type;
32 | int qos;
33 | PyObject* duplicate;
34 | PyObject* retain;
35 | uint16_t message_id;
36 | } MqttPacket;
37 |
38 | extern PyTypeObject MqttPacketType;
39 |
40 | #endif // __LIBEMQTT_PYTHON_MQTT_PACKET_H__
41 |
--------------------------------------------------------------------------------