├── .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 | --------------------------------------------------------------------------------