├── .gitignore ├── CMakeLists.txt ├── README.md ├── pubmain └── main.c ├── src ├── mqtt.c └── mqtt.h └── submain └── main.c /.gitignore: -------------------------------------------------------------------------------- 1 | /build/* 2 | .DS_Store 3 | /python/* 4 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #Specify the version being used as well as the language 2 | cmake_minimum_required(VERSION 2.6) 3 | #Name your project here 4 | project(mqttpub) 5 | project(mqttsub) 6 | 7 | #Sends the -std=c99 flag to the gcc compiler 8 | add_definitions(-std=c99) 9 | include_directories(src) 10 | 11 | #This tells CMake to main.c and name it mqttpub 12 | add_executable(mqttpub pubmain/main.c src/mqtt.c) 13 | add_executable(mqttsub submain/main.c src/mqtt.c) 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | MQTT-c-pub-sub 2 | ============== 3 | This projects builds a simple (QoS0) MQTT client and server process. 4 | The client will send messages to a MQTT broker (e.g. mosquito) and the server will display those messages. 5 | 6 | The build assumes you have CMake installed. 7 | 8 | to Build: 9 | cd build 10 | cmake .. 11 | make 12 | 13 | note on OSX need 14 | 15 | cmake -G "Unix Makefiles" .. 16 | 17 | -------------------------------------------------------------------------------- /pubmain/main.c: -------------------------------------------------------------------------------- 1 | // 2 | // main.c 3 | // mqtt_publisher 4 | // 5 | // Created by Niall Cooling on 23/12/2011. 6 | // Copyright 2012 Feabhas Limited. All rights reserved. 7 | // 8 | /* 9 | 10 | Redistribution and use in source and binary forms, with or without 11 | modification, are permitted provided that the following conditions are met: 12 | 13 | 1. Redistributions of source code must retain the above copyright notice, 14 | this list of conditions and the following disclaimer. 15 | 2. Redistributions in binary form must reproduce the above copyright 16 | notice, this list of conditions and the following disclaimer in the 17 | documentation and/or other materials provided with the distribution. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 23 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 | POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | // Current Assumes 33 | // QoS 0 34 | // All messages < 127 bytes 35 | // 36 | // ./mqttpub -c -i -p -t -n 37 | // 38 | // e.g. 39 | // ./mqttpub -i 192.168.1.38 -t mbed/fishtank -c MacBook -n 5 40 | // 41 | 42 | #include 43 | #include 44 | #include 45 | 46 | #include "mqtt.h" 47 | 48 | #include // for sleep function 49 | 50 | const char *client_name = "default_pub"; // -c 51 | const char *ip_addr = "127.0.0.1"; // -i 52 | uint32_t port = 1883; // -p 53 | const char *topic = "hello/world"; // -t 54 | uint32_t count = 10; // -n 55 | 56 | void parse_options(int argc, char** argv); 57 | 58 | int main (int argc, char** argv) 59 | { 60 | puts("MQTT PUB Test Code"); 61 | if(argc > 1) { 62 | parse_options(argc, argv); 63 | } 64 | 65 | // mqtt_broker_handle_t *broker = mqtt_connect("default_pub","127.0.0.1", 1883); 66 | mqtt_broker_handle_t *broker = mqtt_connect(client_name, ip_addr, port); 67 | 68 | 69 | if(broker == 0) { 70 | puts("Failed to connect"); 71 | exit(1); 72 | } 73 | 74 | char msg[128]; 75 | 76 | for(int i = 1; i <= count; ++i) { 77 | sprintf(msg, "Message number %d", i); 78 | if(mqtt_publish(broker, topic, msg, QoS1) == -1) { 79 | printf("publish failed\n"); 80 | } 81 | else { 82 | printf("Sent %d messages\n", i); 83 | } 84 | sleep(1); 85 | } 86 | mqtt_disconnect(broker); 87 | } 88 | 89 | void parse_options(int argc, char** argv) 90 | { 91 | for(int i = 1; i < argc; ++i) { 92 | if(strcmp("-c",argv[i]) == 0) { 93 | printf("client:%s ",argv[++i]); 94 | client_name = argv[i]; 95 | } 96 | if(strcmp("-i",argv[i]) == 0) { 97 | printf("ip:%s ",argv[++i]); 98 | ip_addr = argv[i]; 99 | } 100 | if(strcmp("-p",argv[i]) == 0) { 101 | printf("port:%s ", argv[++i]); 102 | port = atoi(argv[i]); 103 | } 104 | if(strcmp("-t",argv[i]) == 0) { 105 | printf("topic:%s ",argv[++i]); 106 | topic = argv[i]; 107 | } 108 | if(strcmp("-n",argv[i]) == 0) { 109 | printf("count:%s ",argv[++i]); 110 | count = atoi(argv[i]); 111 | } 112 | } 113 | puts(""); 114 | } 115 | 116 | -------------------------------------------------------------------------------- /src/mqtt.c: -------------------------------------------------------------------------------- 1 | // Created by Niall Cooling on 10/01/2012. 2 | // Copyright 2012 Feabhas Limited. All rights reserved. 3 | // 4 | /* 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, 10 | this list of conditions and the following disclaimer. 11 | 2. Redistributions in binary form must reproduce the above copyright 12 | notice, this list of conditions and the following disclaimer in the 13 | documentation and/or other materials provided with the distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | #include 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | 38 | #include 39 | #include 40 | 41 | /* For version 3 of the MQTT protocol */ 42 | #include "mqtt.h" 43 | 44 | #define PROTOCOL_NAME "MQIsdp" // 45 | #define PROTOCOL_VERSION 3U // version 3.0 of MQTT 46 | #define CLEAN_SESSION (1U<<1) 47 | #define KEEPALIVE 30U // specified in seconds 48 | #define MESSAGE_ID 1U // not used by QoS 0 - value must be > 0 49 | 50 | /* Macros for accessing the MSB and LSB of a uint16_t */ 51 | #define MSB(A) ((uint8_t)((A & 0xFF00) >> 8)) 52 | #define LSB(A) ((uint8_t)(A & 0x00FF)) 53 | 54 | 55 | #define SET_MESSAGE(M) ((uint8_t)(M << 4)) 56 | #define GET_MESSAGE(M) ((uint8_t)(M >> 4)) 57 | 58 | typedef enum { 59 | CONNECT = 1, 60 | CONNACK, 61 | PUBLISH, 62 | PUBACK, 63 | PUBREC, 64 | PUBREL, 65 | PUBCOMP, 66 | SUBSCRIBE, 67 | SUBACK, 68 | UNSUBSCRIBE, 69 | UNSUBACK, 70 | PINGREQ, 71 | PINGRESP, 72 | DISCONNECT 73 | } connect_msg_t; 74 | 75 | typedef enum { 76 | Connection_Accepted, 77 | Connection_Refused_unacceptable_protocol_version, 78 | Connection_Refused_identifier_rejected, 79 | Connection_Refused_server_unavailable, 80 | Connection_Refused_bad_username_or_password, 81 | Connection_Refused_not_authorized 82 | } connack_msg_t; 83 | 84 | 85 | struct mqtt_broker_handle 86 | { 87 | int socket; 88 | struct sockaddr_in socket_address; 89 | uint16_t port; 90 | char hostname[16]; // based on xxx.xxx.xxx.xxx format 91 | char clientid[24]; // max 23 charaters long 92 | bool connected; 93 | size_t topic; 94 | uint16_t pubMsgID; 95 | uint16_t subMsgID; 96 | }; 97 | 98 | typedef struct fixed_header_t 99 | { 100 | uint16_t retain : 1; 101 | uint16_t Qos : 2; 102 | uint16_t DUP : 1; 103 | uint16_t connect_msg_t : 4; 104 | uint16_t remaining_length : 8; 105 | }fixed_header_t; 106 | 107 | 108 | 109 | mqtt_broker_handle_t * mqtt_connect(const char* client, const char * server_ip, uint32_t port) 110 | { 111 | mqtt_broker_handle_t *broker = (mqtt_broker_handle_t *)calloc(sizeof(mqtt_broker_handle_t), 1) ; 112 | if(broker != 0) { 113 | // check connection strings are within bounds 114 | if ( (strlen(client)+1 > sizeof(broker->clientid)) || (strlen(server_ip)+1 > sizeof(broker->hostname))) { 115 | fprintf(stderr,"failed to connect: client or server exceed limits\n"); 116 | free(broker); 117 | return 0; // strings too large 118 | } 119 | 120 | broker->port = port; 121 | strcpy(broker->hostname, server_ip); 122 | strcpy(broker->clientid, client); 123 | 124 | if ((broker->socket = socket(PF_INET, SOCK_STREAM, 0)) < 0) { 125 | fprintf(stderr,"failed to connect: could not create socket\n"); 126 | free(broker); 127 | return 0; 128 | } 129 | 130 | // create the stuff we need to connect 131 | broker->connected = false; 132 | broker->socket_address.sin_family = AF_INET; 133 | broker->socket_address.sin_port = htons(broker->port); // converts the unsigned short from host byte order to network byte order 134 | broker->socket_address.sin_addr.s_addr = inet_addr(broker->hostname); 135 | 136 | // connect 137 | if ((connect(broker->socket, (struct sockaddr *)&broker->socket_address, sizeof(broker->socket_address))) < 0) { 138 | fprintf(stderr,"failed to connect: to server socket\n"); 139 | free(broker); 140 | return 0; 141 | } 142 | 143 | // variable header 144 | uint8_t var_header[] = { 145 | 0, // MSB(strlen(PROTOCOL_NAME)) but 0 as messages must be < 127 146 | strlen(PROTOCOL_NAME), // LSB(strlen(PROTOCOL_NAME)) is redundant 147 | 'M','Q','I','s','d','p', 148 | PROTOCOL_VERSION, 149 | CLEAN_SESSION, 150 | MSB(KEEPALIVE), 151 | LSB(KEEPALIVE) 152 | }; 153 | 154 | // set up payload for connect message 155 | uint8_t payload[2+strlen(broker->clientid)]; 156 | payload[0] = 0; 157 | payload[1] = strlen(broker->clientid); 158 | memcpy(&payload[2],broker->clientid,strlen(broker->clientid)); 159 | 160 | // fixed header: 2 bytes, big endian 161 | uint8_t fixed_header[] = { SET_MESSAGE(CONNECT), sizeof(var_header)+sizeof(payload) }; 162 | // fixed_header_t fixed_header = { .QoS = 0, .connect_msg_t = CONNECT, .remaining_length = sizeof(var_header)+strlen(broker->clientid) }; 163 | 164 | uint8_t packet[sizeof(fixed_header)+sizeof(var_header)+sizeof(payload)]; 165 | 166 | memset(packet,0,sizeof(packet)); 167 | memcpy(packet,fixed_header,sizeof(fixed_header)); 168 | memcpy(packet+sizeof(fixed_header),var_header,sizeof(var_header)); 169 | memcpy(packet+sizeof(fixed_header)+sizeof(var_header),payload,sizeof(payload)); 170 | 171 | // send Connect message 172 | if (send(broker->socket, packet, sizeof(packet), 0) < sizeof(packet)) { 173 | close(broker->socket); 174 | free(broker); 175 | return 0; 176 | } 177 | 178 | uint8_t buffer[4]; 179 | long sz = recv(broker->socket, buffer, sizeof(buffer), 0); // wait for CONNACK 180 | // printf("buffer size is %ld\n",sz); 181 | // printf("%2x:%2x:%2x:%2x\n",(uint8_t)buffer[0],(uint8_t)buffer[1],(uint8_t)buffer[2],(uint8_t)buffer[3]); 182 | if( (GET_MESSAGE(buffer[0]) == CONNACK) && ((sz-2)==buffer[1]) && (buffer[3] == Connection_Accepted) ) { 183 | printf("Connected to MQTT Server at %s:%4d\n",server_ip, port ); 184 | } 185 | else 186 | { 187 | fprintf(stderr,"failed to connect with error: %d\n", buffer[3]); 188 | close(broker->socket); 189 | free(broker); 190 | return 0; 191 | } 192 | 193 | // set connected flag 194 | broker->connected = true; 195 | 196 | } 197 | 198 | return broker; 199 | } 200 | 201 | 202 | 203 | 204 | int mqtt_subscribe(mqtt_broker_handle_t *broker, const char *topic, QoS qos) 205 | { 206 | if (!broker->connected) { 207 | return -1; 208 | } 209 | 210 | uint8_t var_header[] = { MSB(MESSAGE_ID), LSB(MESSAGE_ID) }; // appended to end of PUBLISH message 211 | 212 | // utf topic 213 | uint8_t utf_topic[2+strlen(topic)+1]; // 2 for message size + 1 for QoS 214 | 215 | // set up topic payload 216 | utf_topic[0] = 0; // MSB(strlen(topic)); 217 | utf_topic[1] = LSB(strlen(topic)); 218 | memcpy((char *)&utf_topic[2], topic, strlen(topic)); 219 | utf_topic[sizeof(utf_topic)-1] = qos; 220 | 221 | uint8_t fixed_header[] = { SET_MESSAGE(SUBSCRIBE), sizeof(var_header)+sizeof(utf_topic)}; 222 | // fixed_header_t fixed_header = { .QoS = 0, .connect_msg_t = SUBSCRIBE, .remaining_length = sizeof(var_header)+strlen(utf_topic) }; 223 | 224 | uint8_t packet[sizeof(fixed_header)+sizeof(var_header)+sizeof(utf_topic)]; 225 | 226 | memset(packet, 0, sizeof(packet)); 227 | memcpy(packet, &fixed_header, sizeof(fixed_header)); 228 | memcpy(packet+sizeof(fixed_header), var_header, sizeof(var_header)); 229 | memcpy(packet+sizeof(fixed_header)+sizeof(var_header), utf_topic, sizeof(utf_topic)); 230 | 231 | if (send(broker->socket, packet, sizeof(packet), 0) < sizeof(packet)) { 232 | puts("failed to send subscribe message"); 233 | return -1; 234 | } 235 | 236 | uint8_t buffer[5]; 237 | long sz = recv(broker->socket, buffer, sizeof(buffer), 0); // wait for SUBACK 238 | 239 | // printf("buffer size is %ld\n",sz); 240 | // printf("%2x:%2x:%2x:%2x:%2x\n",(uint8_t)buffer[0],(uint8_t)buffer[1],(uint8_t)buffer[2],(uint8_t)buffer[3],(uint8_t)buffer[4]); 241 | 242 | if((GET_MESSAGE(buffer[0]) == SUBACK) && ((sz-2) == buffer[1])&&(buffer[2] == MSB(MESSAGE_ID)) && (buffer[3] == LSB(MESSAGE_ID)) ) { 243 | printf("Subscribed to MQTT Service %s with QoS %d\n", topic, buffer[4]); 244 | } 245 | else 246 | { 247 | puts("failed to subscribe"); 248 | return -1; 249 | } 250 | broker->topic = strlen(topic); 251 | struct timeval tv; 252 | 253 | tv.tv_sec = 30; /* 30 Secs Timeout */ 254 | tv.tv_usec = 0; // Not init'ing this can cause strange errors 255 | 256 | setsockopt(broker->socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv,sizeof(struct timeval)); 257 | return 1; 258 | } 259 | 260 | int SetSocketTimeout(int connectSocket, int milliseconds) 261 | { 262 | struct timeval tv; 263 | 264 | tv.tv_sec = milliseconds / 1000 ; 265 | tv.tv_usec = ( milliseconds % 1000) * 1000 ; 266 | 267 | return setsockopt (connectSocket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof tv); 268 | } 269 | 270 | void mqtt_display_message(mqtt_broker_handle_t *broker, int (*print)(int)) 271 | { 272 | uint8_t buffer[128]; 273 | SetSocketTimeout(broker->socket, 30000); 274 | 275 | while(1) { 276 | // wait for next message 277 | long sz = recv(broker->socket, buffer, sizeof(buffer), 0); 278 | //printf("message size is %ld\n",sz); 279 | // if more than ack - i.e. data > 0 280 | if (sz == 0) 281 | { 282 | /* Socket has been disconnected */ 283 | printf("\nSocket EOF\n"); 284 | 285 | close(broker->socket); 286 | broker->socket = 0; 287 | return; 288 | } 289 | 290 | if(sz < 0) 291 | { 292 | printf("\nSocket recv returned %ld, errno %d %s\n",sz,errno, strerror(errno)); 293 | 294 | close(broker->socket); /* Close socket if we get an error */ 295 | broker->socket = 0; 296 | exit(0); 297 | } 298 | 299 | if(sz > 0) { 300 | //printf("message size is %ld\n",sz); 301 | if( GET_MESSAGE(buffer[0]) == PUBLISH) { 302 | //printf("Got PUBLISH message with size %d\n", (uint8_t)buffer[1]); 303 | uint32_t topicSize = (buffer[2]<<8) + buffer[3]; 304 | //printf("topic size is %d\n", topicSize); 305 | //for(int loop = 0; loop < topicSize; ++loop) { 306 | // putchar(buffer[4+loop]); 307 | //} 308 | //putchar('\n'); 309 | unsigned long i = 4+topicSize; 310 | if (((buffer[0]>>1) & 0x03) > QoS0) { 311 | uint32_t messageId = (buffer[4+topicSize] << 8) + buffer[4+topicSize+1]; 312 | //printf("Message ID is %d\n", messageId); 313 | i += 2; // 2 extra for msgID 314 | // if QoS1 the send PUBACK with message ID 315 | uint8_t puback[4] = { SET_MESSAGE(PUBACK), 2, buffer[4+topicSize], buffer[4+topicSize+1] }; 316 | if (send(broker->socket, puback, sizeof(puback), 0) < sizeof(puback)) { 317 | puts("failed to PUBACK"); 318 | return; 319 | } 320 | } 321 | for ( ; i < sz; ++i) { 322 | print(buffer[i]); 323 | } 324 | print('\n'); 325 | return; 326 | } 327 | } 328 | } 329 | 330 | } 331 | 332 | 333 | int mqtt_publish(mqtt_broker_handle_t *broker, const char *topic, const char *msg, QoS qos) 334 | { 335 | if (!broker->connected) { 336 | return -1; 337 | } 338 | if(qos > QoS2) { 339 | return -1; 340 | } 341 | 342 | if (qos == QoS0) { 343 | // utf topic 344 | uint8_t utf_topic[2+strlen(topic)]; // 2 for message size QoS-0 does not have msg ID 345 | 346 | // set up topic payload 347 | utf_topic[0] = 0; // MSB(strlen(topic)); 348 | utf_topic[1] = LSB(strlen(topic)); 349 | memcpy((char *)&utf_topic[2], topic, strlen(topic)); 350 | 351 | uint8_t fixed_header[] = { SET_MESSAGE(PUBLISH)|(qos << 1), sizeof(utf_topic)+strlen(msg)}; 352 | // fixed_header_t fixed_header = { .QoS = 0, .connect_msg_t = PUBLISH, .remaining_length = sizeof(utf_topic)+strlen(msg) }; 353 | 354 | uint8_t packet[sizeof(fixed_header)+sizeof(utf_topic)+strlen(msg)]; 355 | 356 | memset(packet, 0, sizeof(packet)); 357 | memcpy(packet, &fixed_header, sizeof(fixed_header)); 358 | memcpy(packet+sizeof(fixed_header), utf_topic, sizeof(utf_topic)); 359 | memcpy(packet+sizeof(fixed_header)+sizeof(utf_topic), msg, strlen(msg)); 360 | 361 | if (send(broker->socket, packet, sizeof(packet), 0) < sizeof(packet)) { 362 | return -1; 363 | } 364 | } 365 | else { 366 | broker->pubMsgID++; 367 | // utf topic 368 | uint8_t utf_topic[2+strlen(topic)+2]; // 2 extra for message size > QoS0 for msg ID 369 | 370 | // set up topic payload 371 | utf_topic[0] = 0; // MSB(strlen(topic)); 372 | utf_topic[1] = LSB(strlen(topic)); 373 | memcpy((char *)&utf_topic[2], topic, strlen(topic)); 374 | utf_topic[sizeof(utf_topic)-2] = MSB(broker->pubMsgID); 375 | utf_topic[sizeof(utf_topic)-1] = LSB(broker->pubMsgID); 376 | 377 | uint8_t fixed_header[] = { SET_MESSAGE(PUBLISH)|(qos << 1), sizeof(utf_topic)+strlen(msg)}; 378 | 379 | uint8_t packet[sizeof(fixed_header)+sizeof(utf_topic)+strlen(msg)]; 380 | 381 | memset(packet, 0, sizeof(packet)); 382 | memcpy(packet, &fixed_header, sizeof(fixed_header)); 383 | memcpy(packet+sizeof(fixed_header), utf_topic, sizeof(utf_topic)); 384 | memcpy(packet+sizeof(fixed_header)+sizeof(utf_topic), msg, strlen(msg)); 385 | 386 | if (send(broker->socket, packet, sizeof(packet), 0) < sizeof(packet)) { 387 | return -1; 388 | } 389 | if(qos == QoS1){ 390 | // expect PUBACK with MessageID 391 | uint8_t buffer[4]; 392 | long sz = recv(broker->socket, buffer, sizeof(buffer), 0); // wait for SUBACK 393 | 394 | // printf("buffer size is %ld\n",sz); 395 | // printf("%2x:%2x:%2x:%2x:%2x\n",(uint8_t)buffer[0],(uint8_t)buffer[1],(uint8_t)buffer[2],(uint8_t)buffer[3],(uint8_t)buffer[4]); 396 | 397 | if((GET_MESSAGE(buffer[0]) == PUBACK) && ((sz-2) == buffer[1]) && (buffer[2] == MSB(broker->pubMsgID)) && (buffer[3] == LSB(broker->pubMsgID)) ) { 398 | printf("Published to MQTT Service %s with QoS1\n", topic); 399 | } 400 | else 401 | { 402 | puts("failed to publisg at QoS1"); 403 | return -1; 404 | } 405 | } 406 | 407 | } 408 | 409 | return 1; 410 | } 411 | 412 | void mqtt_disconnect(mqtt_broker_handle_t *broker) 413 | { 414 | uint8_t fixed_header[] = { SET_MESSAGE(DISCONNECT), 0}; 415 | if (send(broker->socket, fixed_header, sizeof(fixed_header), 0)< sizeof(fixed_header)) { 416 | puts("failed to disconnect"); 417 | } 418 | } 419 | 420 | -------------------------------------------------------------------------------- /src/mqtt.h: -------------------------------------------------------------------------------- 1 | // 2 | // mqtt.h 3 | // 4 | // Created by Niall Cooling on 10/01/2012. 5 | // Copyright 2012 Feabhas Limited. All rights reserved. 6 | // 7 | /* 8 | 9 | Redistribution and use in source and binary forms, with or without 10 | modification, are permitted provided that the following conditions are met: 11 | 12 | 1. Redistributions of source code must retain the above copyright notice, 13 | this list of conditions and the following disclaimer. 14 | 2. Redistributions in binary form must reproduce the above copyright 15 | notice, this list of conditions and the following disclaimer in the 16 | documentation and/or other materials provided with the distribution. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef mqtt_h 32 | #define mqtt_h 33 | 34 | #include 35 | 36 | typedef struct mqtt_broker_handle mqtt_broker_handle_t; 37 | 38 | typedef enum {QoS0, QoS1, QoS2} QoS; 39 | 40 | mqtt_broker_handle_t * mqtt_connect(const char* client, const char * server_ip, uint32_t port); 41 | void mqtt_disconnect(mqtt_broker_handle_t *broker); 42 | 43 | int mqtt_publish(mqtt_broker_handle_t *broker, const char *topic, const char *msg, QoS qos); 44 | 45 | int mqtt_subscribe(mqtt_broker_handle_t *broker, const char *topic, QoS qos); 46 | void mqtt_display_message(mqtt_broker_handle_t *broker, int (*print)(int)); 47 | 48 | 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /submain/main.c: -------------------------------------------------------------------------------- 1 | // 2 | // main.c 3 | // mqtt_subscriber 4 | // 5 | // Created by Niall Cooling on 23/12/2011. 6 | // Copyright 2012 Feabhas Limited. All rights reserved. 7 | // 8 | /* 9 | 10 | Redistribution and use in source and binary forms, with or without 11 | modification, are permitted provided that the following conditions are met: 12 | 13 | 1. Redistributions of source code must retain the above copyright notice, 14 | this list of conditions and the following disclaimer. 15 | 2. Redistributions in binary form must reproduce the above copyright 16 | notice, this list of conditions and the following disclaimer in the 17 | documentation and/or other materials provided with the distribution. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 23 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 | POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | // Current Assumes 33 | // QoS 0 34 | // All messages < 127 bytes 35 | // 36 | // ./mqttsub -c -i -p -t 37 | // 38 | // e.g. 39 | // ./mqttsub -i 192.168.1.38 -t mbed/fishtank -c MacBook_sub 40 | // 41 | 42 | #include 43 | #include 44 | #include 45 | 46 | #include "mqtt.h" 47 | 48 | 49 | const char *client_name = "default_sub"; // -c 50 | const char *ip_addr = "127.0.0.1"; // -i 51 | uint32_t port = 1883; // -p 52 | const char *topic = "hello/world"; // -t 53 | 54 | void parse_options(int argc, char** argv); 55 | 56 | int main (int argc, char** argv) 57 | { 58 | puts("MQTT SUB Test Code"); 59 | 60 | if(argc > 1) { 61 | parse_options(argc, argv); 62 | } 63 | 64 | // mqtt_broker_handle_t *broker = mqtt_connect("default_sub","127.0.0.1", 1883); 65 | mqtt_broker_handle_t *broker = mqtt_connect(client_name, ip_addr, port); 66 | 67 | if(broker == 0) { 68 | puts("Failed to connect"); 69 | exit(1); 70 | } 71 | 72 | int result = mqtt_subscribe(broker, topic, QoS0); 73 | 74 | if(result != 1) { 75 | puts("failed to Subscribe"); 76 | exit(1); 77 | } 78 | 79 | while(1) 80 | { 81 | mqtt_display_message(broker, &putchar); 82 | } 83 | return 0; 84 | } 85 | 86 | void parse_options(int argc, char** argv) 87 | { 88 | for(int i = 1; i < argc; ++i) { 89 | if(strcmp("-c",argv[i]) == 0) { 90 | printf("client:%s ",argv[++i]); 91 | client_name = argv[i]; 92 | } 93 | if(strcmp("-i",argv[i]) == 0) { 94 | printf("ip:%s ",argv[++i]); 95 | ip_addr = argv[i]; 96 | } 97 | if(strcmp("-p",argv[i]) == 0) { 98 | printf("port:%s ", argv[++i]); 99 | port = atoi(argv[i]); 100 | } 101 | if(strcmp("-t",argv[i]) == 0) { 102 | printf("topic:%s ",argv[++i]); 103 | topic = argv[i]; 104 | } 105 | } 106 | puts(""); 107 | } 108 | 109 | 110 | --------------------------------------------------------------------------------