mqtt_message_t* mqtt_msg_publish(mqtt_connection_t* connection, const char* topic, const char* data, int data_length, int qos, int retain, uint16_t* message_id) { init_message(connection); if (topic == NULL || topic[0] == '\0') return fail_message(connection); if (append_string(connection, topic, strlen(topic)) < 0) return fail_message(connection); if (qos > 0) { if ((*message_id = append_message_id(connection, 0)) == 0) return fail_message(connection); } else *message_id = 0; if (connection->message.length + data_length > connection->buffer_length) { // Not enough size in buffer -> fragment this message connection->message.fragmented_msg_data_offset = connection->message.length; memcpy(connection->buffer + connection->message.length, data, connection->buffer_length - connection->message.length); connection->message.length = connection->buffer_length; connection->message.fragmented_msg_total_length = data_length + connection->message.fragmented_msg_data_offset; } else { memcpy(connection->buffer + connection->message.length, data, data_length); connection->message.length += data_length; connection->message.fragmented_msg_total_length = 0; } return fini_message(connection, MQTT_MSG_TYPE_PUBLISH, 0, qos, retain); }
mqtt_message_t* mqtt_msg_publish(mqtt_connection_t* connection, const char* topic, const char* data, int data_length, int qos, int retain, uint16_t* message_id) { init_message(connection); if(topic == NULL || topic[0] == '\0') return fail_message(connection); if(append_string(connection, topic, c_strlen(topic)) < 0) return fail_message(connection); if(qos > 0) { if((*message_id = append_message_id(connection, 0)) == 0) return fail_message(connection); } else *message_id = 0; if(connection->message.length + data_length > connection->buffer_length) return fail_message(connection); c_memcpy(connection->buffer + connection->message.length, data, data_length); connection->message.length += data_length; return fini_message(connection, MQTT_MSG_TYPE_PUBLISH, 0, qos, retain); }
mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pubcomp(mqtt_connection_t* connection, uint16_t message_id) { if (init_message(connection) == 0) { return fail_message(connection); } if (append_message_id(connection, message_id) == 0) return fail_message(connection); return fini_message(connection, MQTT_MSG_TYPE_PUBCOMP, 0, 0, 0); }
void file_sync_service(int fd, void *cookie) { syncmsg msg; char name[1025]; unsigned namelen; char *buffer = malloc(SYNC_DATA_MAX); if(buffer == 0) goto fail; for(;;) { D("sync: waiting for command\n"); if(readx(fd, &msg.req, sizeof(msg.req))) { fail_message(fd, "command read failure"); break; } namelen = ltohl(msg.req.namelen); if(namelen > 1024) { fail_message(fd, "invalid namelen"); break; } if(readx(fd, name, namelen)) { fail_message(fd, "filename read failure"); break; } name[namelen] = 0; msg.req.namelen = 0; D("sync: '%s' '%s'\n", (char*) &msg.req, name); switch(msg.req.id) { case ID_STAT: if(do_stat(fd, name)) goto fail; break; case ID_LIST: if(do_list(fd, name)) goto fail; break; case ID_SEND: if(do_send(fd, name, buffer)) goto fail; break; case ID_RECV: if(do_recv(fd, name, buffer)) goto fail; break; case ID_QUIT: goto fail; default: fail_message(fd, "unknown command"); goto fail; } } fail: if(buffer != 0) free(buffer); D("sync: done\n"); adb_close(fd); }
mqtt_message_t* mqtt_msg_unsubscribe_topic(mqtt_connection_t* connection, const char* topic) { if(topic == NULL || topic[0] == '\0') return fail_message(connection); if(append_string(connection, topic, c_strlen(topic)) < 0) return fail_message(connection); return &connection->message; }
static int handle_send_link(int s, char *path, char *buffer) { syncmsg msg; unsigned int len; int ret; if(readx(s, &msg.data, sizeof(msg.data))) return -1; if(msg.data.id != ID_DATA) { fail_message(s, "invalid data message: expected ID_DATA"); return -1; } len = ltohl(msg.data.size); if(len > SYNC_DATA_MAX) { fail_message(s, "oversize data message"); return -1; } if(readx(s, buffer, len)) return -1; ret = symlink(buffer, path); if(ret && errno == ENOENT) { if(mkdirs(path) != 0) { fail_errno(s); return -1; } ret = symlink(buffer, path); } if(ret) { fail_errno(s); return -1; } if(readx(s, &msg.data, sizeof(msg.data))) return -1; if(msg.data.id == ID_DONE) { msg.status.id = ID_OKAY; msg.status.msglen = 0; if(writex(s, &msg.status, sizeof(msg.status))) return -1; } else { fail_message(s, "invalid data message: expected ID_DONE"); return -1; } return 0; }
mqtt_message_t* mqtt_msg_subscribe_topic(mqtt_connection_t* connection, const char* topic, int qos) { if(topic == NULL || topic[0] == '\0') return fail_message(connection); if(append_string(connection, topic, c_strlen(topic)) < 0) return fail_message(connection); if(connection->message.length + 1 > connection->buffer_length) return fail_message(connection); connection->buffer[connection->message.length++] = qos; return &connection->message; }
mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_unsubscribe(mqtt_connection_t* connection, const char* topic, uint16_t* message_id) { init_message(connection); if(topic == NULL || topic[0] == '\0') return fail_message(connection); if((*message_id = append_message_id(connection, 0)) == 0) return fail_message(connection); if(append_string(connection, topic, strlen(topic)) < 0) return fail_message(connection); return fini_message(connection, MQTT_MSG_TYPE_UNSUBSCRIBE, 0, 1, 0); }
mqtt_message_t* mqtt_msg_pubcomp(mqtt_connection_t* connection, uint16_t message_id) { init_message(connection); if(append_message_id(connection, message_id) == 0) return fail_message(connection); return fini_message(connection, MQTT_MSG_TYPE_PUBCOMP, 0, 0, 0); }
mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pubrel(mqtt_connection_t* connection, uint16_t message_id) { init_message(connection); if(append_message_id(connection, message_id) == 0) return fail_message(connection); return fini_message(connection, MQTT_MSG_TYPE_PUBREL, 0, 1, 0); }
mqtt_message_t* mqtt_msg_subscribe_init(mqtt_connection_t* connection, uint16_t *message_id) { init_message(connection); if((*message_id = append_message_id(connection, 0)) == 0) return fail_message(connection); return &connection->message; }
mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_subscribe(mqtt_connection_t* connection, const char* topic, int qos, uint16_t* message_id) { init_message(connection); if(topic == NULL || topic[0] == '\0') return fail_message(connection); if((*message_id = append_message_id(connection, 0)) == 0) return fail_message(connection); if(append_string(connection, topic, strlen(topic)) < 0) return fail_message(connection); if(connection->message.length + 1 > connection->buffer_length) return fail_message(connection); connection->buffer[connection->message.length++] = qos; return fini_message(connection, MQTT_MSG_TYPE_SUBSCRIBE, 0, 1, 0); }
static mqtt_message_t* fini_message(mqtt_connection_t* connection, int type, int dup, int qos, int retain) { int message_length = connection->message.length - MQTT_MAX_FIXED_HEADER_SIZE; int total_length = message_length; int encoded_length = 0; uint8_t encoded_lens[4] = {0}; // Check if we have fragmented message and update total_len if (connection->message.fragmented_msg_total_length) { total_length = connection->message.fragmented_msg_total_length - MQTT_MAX_FIXED_HEADER_SIZE; } // Encode MQTT message length int len_bytes = 0; // size of encoded message length do { encoded_length = total_length % 128; total_length /= 128; if (total_length > 0) { encoded_length |= 0x80; } encoded_lens[len_bytes] = encoded_length; len_bytes++; } while (total_length > 0); // Sanity check for MQTT header if (len_bytes + 1 > MQTT_MAX_FIXED_HEADER_SIZE) { return fail_message(connection); } // Save the header bytes connection->message.length = message_length + len_bytes + 1; // msg len + encoded_size len + type (1 byte) int offs = MQTT_MAX_FIXED_HEADER_SIZE - 1 - len_bytes; connection->message.data = connection->buffer + offs; connection->message.fragmented_msg_data_offset -= offs; // type byte connection->buffer[offs++] = ((type & 0x0f) << 4) | ((dup & 1) << 3) | ((qos & 3) << 1) | (retain & 1); // length bytes for (int j = 0; j<len_bytes; j++) { connection->buffer[offs++] = encoded_lens[j]; } return &connection->message; }
mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_disconnect(mqtt_connection_t* connection) { if (init_message(connection) == 0) { return fail_message(connection); } return fini_message(connection, MQTT_MSG_TYPE_DISCONNECT, 0, 0, 0); }
mqtt_message_t* mqtt_msg_connect(mqtt_connection_t* connection, mqtt_connect_info_t* info) { struct mqtt_connect_variable_header* variable_header; init_message(connection); if(connection->message.length + sizeof(*variable_header) > connection->buffer_length) return fail_message(connection); variable_header = (void*)(connection->buffer + connection->message.length); connection->message.length += sizeof(*variable_header); variable_header->lengthMsb = 0; variable_header->lengthLsb = 4; c_memcpy(variable_header->magic, "MQTT", 4); variable_header->version = 4; variable_header->flags = 0; variable_header->keepaliveMsb = info->keepalive >> 8; variable_header->keepaliveLsb = info->keepalive & 0xff; if(info->clean_session) variable_header->flags |= MQTT_CONNECT_FLAG_CLEAN_SESSION; if(info->client_id != NULL && info->client_id[0] != '\0') { if(append_string(connection, info->client_id, c_strlen(info->client_id)) < 0) return fail_message(connection); } else return fail_message(connection); if(info->will_topic != NULL && info->will_topic[0] != '\0') { if(append_string(connection, info->will_topic, c_strlen(info->will_topic)) < 0) return fail_message(connection); if(append_string(connection, info->will_message, c_strlen(info->will_message)) < 0) return fail_message(connection); variable_header->flags |= MQTT_CONNECT_FLAG_WILL; if(info->will_retain) variable_header->flags |= MQTT_CONNECT_FLAG_WILL_RETAIN; variable_header->flags |= (info->will_qos & 3) << 3; } if(info->username != NULL && info->username[0] != '\0') { if(append_string(connection, info->username, c_strlen(info->username)) < 0) return fail_message(connection); variable_header->flags |= MQTT_CONNECT_FLAG_USERNAME; } if(info->password != NULL && info->password[0] != '\0') { if(append_string(connection, info->password, c_strlen(info->password)) < 0) return fail_message(connection); variable_header->flags |= MQTT_CONNECT_FLAG_PASSWORD; } return fini_message(connection, MQTT_MSG_TYPE_CONNECT, 0, 0, 0); }
mqtt_message_t* ICACHE_FLASH_ATTR mqtt_msg_pingresp(mqtt_connection_t* connection) { if (init_message(connection) == 0) { return fail_message(connection); } return fini_message(connection, MQTT_MSG_TYPE_PINGRESP, 0, 0, 0); }
static int handle_send_file(int s, char *path, uid_t uid, gid_t gid, mode_t mode, char *buffer, bool do_unlink) { syncmsg msg; unsigned int timestamp = 0; int fd; fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode); if(fd < 0 && errno == ENOENT) { if(mkdirs(path) != 0) { if(fail_errno(s)) return -1; fd = -1; } else { fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode); } } if(fd < 0 && errno == EEXIST) { fd = adb_open_mode(path, O_WRONLY | O_CLOEXEC, mode); } if(fd < 0) { if(fail_errno(s)) return -1; fd = -1; } else { if(fchown(fd, uid, gid) != 0) { fail_errno(s); errno = 0; } /* * fchown clears the setuid bit - restore it if present. * Ignore the result of calling fchmod. It's not supported * by all filesystems. b/12441485 */ fchmod(fd, mode); } for(;;) { unsigned int len; if(readx(s, &msg.data, sizeof(msg.data))) goto fail; if(msg.data.id != ID_DATA) { if(msg.data.id == ID_DONE) { timestamp = ltohl(msg.data.size); break; } fail_message(s, "invalid data message"); goto fail; } len = ltohl(msg.data.size); if(syc_size_enabled == 1) { if(len > SYNC_DATA_MAX) { fail_message(s, "oversize data message"); goto fail; } else { unsigned int total = 0; while (total < len) { int count = len - total; if (count > SYNC_DATA_MAX_CUSTOMIZE) { count = SYNC_DATA_MAX_CUSTOMIZE; } if(readx(s, buffer, count)) goto fail; if(fd < 0) continue; if(writex(fd, buffer, count)) { int saved_errno = errno; adb_close(fd); if (do_unlink) adb_unlink(path); fd = -1; errno = saved_errno; if(fail_errno(s)) return -1; } total += count; } } }else { if(len > SYNC_DATA_MAX) { fail_message(s, "oversize data message"); goto fail; } if(readx(s, buffer, len)) goto fail; if(fd < 0) continue; if(writex(fd, buffer, len)) { int saved_errno = errno; adb_close(fd); if (do_unlink) adb_unlink(path); fd = -1; errno = saved_errno; if(fail_errno(s)) return -1; } } } if(fd >= 0) { struct utimbuf u; adb_close(fd); selinux_android_restorecon(path, 0); u.actime = timestamp; u.modtime = timestamp; utime(path, &u); msg.status.id = ID_OKAY; msg.status.msglen = 0; if(writex(s, &msg.status, sizeof(msg.status))) return -1; } return 0; fail: if(fd >= 0) adb_close(fd); if (do_unlink) adb_unlink(path); return -1; }
static int fail_errno(int s) { return fail_message(s, strerror(errno)); }
static int handle_send_file(int s, char *path, mode_t mode, char *buffer) { syncmsg msg; unsigned int timestamp = 0; int fd; fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL, mode); if(fd < 0 && errno == ENOENT) { mkdirs(path); fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL, mode); } if(fd < 0 && errno == EEXIST) { fd = adb_open_mode(path, O_WRONLY, mode); } if(fd < 0) { if(fail_errno(s)) return -1; fd = -1; } for(;;) { unsigned int len; if(readx(s, &msg.data, sizeof(msg.data))) goto fail; if(msg.data.id != ID_DATA) { if(msg.data.id == ID_DONE) { timestamp = ltohl(msg.data.size); break; } fail_message(s, "invalid data message"); goto fail; } len = ltohl(msg.data.size); if(len > SYNC_DATA_MAX) { fail_message(s, "oversize data message"); goto fail; } if(readx(s, buffer, len)) goto fail; if(fd < 0) continue; if(writex(fd, buffer, len)) { int saved_errno = errno; adb_close(fd); adb_unlink(path); fd = -1; errno = saved_errno; if(fail_errno(s)) return -1; } } if(fd >= 0) { struct utimbuf u; adb_close(fd); u.actime = timestamp; u.modtime = timestamp; utime(path, &u); msg.status.id = ID_OKAY; msg.status.msglen = 0; if(writex(s, &msg.status, sizeof(msg.status))) return -1; } return 0; fail: if(fd >= 0) adb_close(fd); adb_unlink(path); return -1; }