bool btif_config_set_bin(const char *section, const char *key, const uint8_t *value, size_t length) { const char *lookup = "0123456789abcdef"; assert(config != NULL); assert(section != NULL); assert(key != NULL); if (length > 0) assert(value != NULL); char *str = (char *)osi_calloc(length * 2 + 1); if (!str) return false; for (size_t i = 0; i < length; ++i) { str[(i * 2) + 0] = lookup[(value[i] >> 4) & 0x0F]; str[(i * 2) + 1] = lookup[value[i] & 0x0F]; } pthread_mutex_lock(&lock); config_set_string(config, section, key, str); pthread_mutex_unlock(&lock); osi_free(str); return true; }
socket_t *socket_new(void) { socket_t *ret = (socket_t *)osi_calloc(sizeof(socket_t)); if (!ret) { LOG_ERROR("%s unable to allocate memory for socket.", __func__); goto error; } ret->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (ret->fd == INVALID_FD) { LOG_ERROR("%s unable to create socket: %s", __func__, strerror(errno)); goto error; } int enable = 1; if (setsockopt(ret->fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable)) == -1) { LOG_ERROR("%s unable to set SO_REUSEADDR: %s", __func__, strerror(errno)); goto error; } return ret; error:; if (ret) close(ret->fd); osi_free(ret); return NULL; }
classic_peer_t *classic_peer_by_address(bt_bdaddr_t *address) { assert(initialized); assert(address != NULL); classic_peer_t *peer = hash_map_get(peers_by_address, address); if (!peer) { pthread_mutex_lock(&bag_of_peers_lock); // Make sure it didn't get added in the meantime peer = hash_map_get(peers_by_address, address); if (peer) goto done; // Splice in a new peer struct on behalf of the caller. peer = osi_calloc(sizeof(classic_peer_t)); peer->address = *address; hash_map_set(peers_by_address, &peer->address, peer); pthread_mutex_unlock(&bag_of_peers_lock); } done: return peer; }
data_dispatcher_t *data_dispatcher_new(const char *name) { assert(name != NULL); data_dispatcher_t *ret = osi_calloc(sizeof(data_dispatcher_t)); if (!ret) { LOG_ERROR(LOG_TAG, "%s unable to allocate memory for new data dispatcher.", __func__); goto error; } ret->dispatch_table = hash_map_new(DEFAULT_TABLE_BUCKETS, hash_function_naive, NULL, NULL, NULL); if (!ret->dispatch_table) { LOG_ERROR(LOG_TAG, "%s unable to create dispatch table.", __func__); goto error; } ret->name = osi_strdup(name); if (!ret->name) { LOG_ERROR(LOG_TAG, "%s unable to duplicate provided name.", __func__); goto error; } return ret; error:; data_dispatcher_free(ret); return NULL; }
static void accept_ready(socket_t *socket, UNUSED_ATTR void *context) { assert(socket != NULL); assert(socket == listen_socket); socket = socket_accept(socket); if (!socket) return; client_t *client = (client_t *)osi_calloc(sizeof(client_t)); if (!client) { LOG_ERROR(LOG_TAG, "%s unable to allocate memory for client.", __func__); socket_free(socket); return; } client->socket = socket; if (!list_append(clients, client)) { LOG_ERROR(LOG_TAG, "%s unable to add client to list.", __func__); client_free(client); return; } socket_register(socket, thread_get_reactor(thread), client, read_ready, NULL); }
static void transmit_command( BT_HDR *command, command_complete_cb complete_callback, command_status_cb status_callback, void *context) { uint8_t *stream; waiting_command_t *wait_entry = osi_calloc(sizeof(waiting_command_t)); if (!wait_entry) { LOG_ERROR("%s couldn't allocate space for wait entry.", __func__); return; } stream = command->data + command->offset; STREAM_TO_UINT16(wait_entry->opcode, stream); wait_entry->complete_callback = complete_callback; wait_entry->status_callback = status_callback; wait_entry->command = command; wait_entry->context = context; // Store the command message type in the event field // in case the upper layer didn't already command->event = MSG_STACK_TO_HC_HCI_CMD; LOG_DEBUG("HCI Enqueue Comamnd opcode=0x%x\n", wait_entry->opcode); BTTRC_DUMP_BUFFER(NULL, command->data + command->offset, command->len); fixed_queue_enqueue(hci_host_env.command_queue, wait_entry); hci_host_task_post(); }
eager_reader_t *eager_reader_new( int fd_to_read, const allocator_t *allocator, size_t buffer_size, size_t max_buffer_count, const char *thread_name) { assert(fd_to_read != INVALID_FD); assert(allocator != NULL); assert(buffer_size > 0); assert(max_buffer_count > 0); assert(thread_name != NULL && *thread_name != '\0'); eager_reader_t *ret = osi_calloc(sizeof(eager_reader_t)); if (!ret) { LOG_ERROR(LOG_TAG, "%s unable to allocate memory for new eager_reader.", __func__); goto error; } ret->allocator = allocator; ret->inbound_fd = fd_to_read; ret->bytes_available_fd = eventfd(0, 0); if (ret->bytes_available_fd == INVALID_FD) { LOG_ERROR(LOG_TAG, "%s unable to create output reading semaphore.", __func__); goto error; } ret->buffer_size = buffer_size; ret->buffers = fixed_queue_new(max_buffer_count); if (!ret->buffers) { LOG_ERROR(LOG_TAG, "%s unable to create buffers queue.", __func__); goto error; } ret->inbound_read_thread = thread_new(thread_name); if (!ret->inbound_read_thread) { LOG_ERROR(LOG_TAG, "%s unable to make reading thread.", __func__); goto error; } ret->inbound_read_object = reactor_register( thread_get_reactor(ret->inbound_read_thread), fd_to_read, ret, inbound_data_waiting, NULL ); return ret; error:; eager_reader_free(ret); return NULL; }
static void background_connection_add(bt_bdaddr_t *address) { assert(address); background_connections_lazy_init(); background_connection_t *connection = hash_map_get(background_connections, address); if (!connection) { connection = osi_calloc(sizeof(background_connection_t)); connection->address = *address; hash_map_set(background_connections, address, connection); } }
static entry_t *entry_new(const char *key, const char *value) { entry_t *entry = osi_calloc(sizeof(entry_t)); if (!entry) { return NULL; } entry->key = osi_strdup(key); entry->value = osi_strdup(value); return entry; }
static section_t *section_new(const char *name) { section_t *section = osi_calloc(sizeof(section_t)); if (!section) { return NULL; } section->name = osi_strdup(name); section->entries = list_new(entry_free); return section; }
// Hidden constructor, only to be used by the hash map for the allocation tracker. // Behaves the same as |list_new|, except you get to specify the allocator. list_t *list_new_internal(list_free_cb callback) { list_t *list = (list_t *) osi_calloc(sizeof(list_t)); if (!list) { return NULL; } list->head = list->tail = NULL; list->length = 0; list->free_cb = callback; return list; }
socket_t *socket_new_from_fd(int fd) { assert(fd != INVALID_FD); socket_t *ret = (socket_t *)osi_calloc(sizeof(socket_t)); if (!ret) { LOG_ERROR("%s unable to allocate memory for socket.", __func__); return NULL; } ret->fd = fd; return ret; }
void module_start_up_callbacked_wrapper( const module_t *module, thread_t *callback_thread, thread_fn callback) { callbacked_wrapper_t *wrapper = osi_calloc(sizeof(callbacked_wrapper_t)); wrapper->module = module; wrapper->lifecycle_thread = thread_new("module_wrapper"); wrapper->callback_thread = callback_thread; wrapper->callback = callback; // Run the actual module start up thread_post(wrapper->lifecycle_thread, run_wrapped_start_up, wrapper); }
buffer_t *buffer_new(size_t size) { assert(size > 0); buffer_t *buffer = osi_calloc(sizeof(buffer_t) + size); if (!buffer) { LOG_ERROR(LOG_TAG, "%s unable to allocate buffer of %zu bytes.", __func__, size); return NULL; } buffer->root = buffer; buffer->refcount = 1; buffer->length = size; return buffer; }
bool list_insert_after(list_t *list, list_node_t *prev_node, void *data) { assert(list != NULL); assert(prev_node != NULL); assert(data != NULL); list_node_t *node = (list_node_t *)osi_calloc(sizeof(list_node_t)); if (!node) { return false; } node->next = prev_node->next; node->data = data; prev_node->next = node; if (list->tail == prev_node) { list->tail = node; } ++list->length; return true; }
bool list_prepend(list_t *list, void *data) { assert(list != NULL); assert(data != NULL); list_node_t *node = (list_node_t *)osi_calloc(sizeof(list_node_t)); if (!node) { return false; } node->next = list->head; node->data = data; list->head = node; if (list->tail == NULL) { list->tail = list->head; } ++list->length; return true; }
static future_t *transmit_command_futured(BT_HDR *command) { waiting_command_t *wait_entry = osi_calloc(sizeof(waiting_command_t)); assert(wait_entry != NULL); future_t *future = future_new(); uint8_t *stream = command->data + command->offset; STREAM_TO_UINT16(wait_entry->opcode, stream); wait_entry->complete_future = future; wait_entry->command = command; // Store the command message type in the event field // in case the upper layer didn't already command->event = MSG_STACK_TO_HC_HCI_CMD; fixed_queue_enqueue(command_queue, wait_entry); return future; }
non_repeating_timer_t *non_repeating_timer_new(period_ms_t duration, alarm_callback_t cb, void *data) { assert(cb != NULL); non_repeating_timer_t *ret = osi_calloc(sizeof(non_repeating_timer_t)); ret->alarm = alarm_new(); if (!ret->alarm) goto error; ret->duration = duration; ret->callback = cb; ret->data = data; return ret; error:; non_repeating_timer_free(ret); return NULL; }
socket_t *socket_accept(const socket_t *socket) { assert(socket != NULL); int fd = accept(socket->fd, NULL, NULL); if (fd == INVALID_FD) { LOG_ERROR("%s unable to accept socket: %s", __func__, strerror(errno)); return NULL; } socket_t *ret = (socket_t *)osi_calloc(sizeof(socket_t)); if (!ret) { close(fd); LOG_ERROR("%s unable to allocate memory for socket.", __func__); return NULL; } ret->fd = fd; return ret; }
static int get_config_size_from_flash(nvs_handle fp) { assert(fp != 0); esp_err_t err; char *keyname = osi_calloc(sizeof(CONFIG_KEY) + 1); if (!keyname){ LOG_ERROR("%s, malloc error\n", __func__); return 0; } size_t length = CONFIG_FILE_DEFAULE_LENGTH; size_t total_length = 0; uint16_t i = 0; snprintf(keyname, sizeof(CONFIG_KEY) + 1, "%s%d", CONFIG_KEY, 0); err = nvs_get_blob(fp, keyname, NULL, &length); if (err == ESP_ERR_NVS_NOT_FOUND) { osi_free(keyname); return 0; } if (err != ESP_OK) { LOG_ERROR("%s, error %d\n", __func__, err); osi_free(keyname); return 0; } total_length += length; while (length == CONFIG_FILE_MAX_SIZE) { length = CONFIG_FILE_DEFAULE_LENGTH; snprintf(keyname, sizeof(CONFIG_KEY) + 1, "%s%d", CONFIG_KEY, ++i); err = nvs_get_blob(fp, keyname, NULL, &length); if (err == ESP_ERR_NVS_NOT_FOUND) { break; } if (err != ESP_OK) { LOG_ERROR("%s, error %d\n", __func__, err); osi_free(keyname); return 0; } total_length += length; } osi_free(keyname); return total_length; }
buffer_t *buffer_new_slice(const buffer_t *buf, size_t slice_size) { assert(buf != NULL); assert(slice_size > 0); assert(slice_size <= buf->length); buffer_t *ret = osi_calloc(sizeof(buffer_t)); if (!ret) { LOG_ERROR(LOG_TAG, "%s unable to allocate new buffer for slice of length %zu.", __func__, slice_size); return NULL; } ret->root = buf->root; ret->refcount = SIZE_MAX; ret->length = slice_size; ++buf->root->refcount; return ret; }
reactor_t *reactor_new(void) { reactor_t *ret = (reactor_t *)osi_calloc(sizeof(reactor_t)); if (!ret) return NULL; ret->epoll_fd = INVALID_FD; ret->event_fd = INVALID_FD; ret->epoll_fd = epoll_create(MAX_EVENTS); if (ret->epoll_fd == INVALID_FD) { LOG_ERROR("%s unable to create epoll instance: %s", __func__, strerror(errno)); goto error; } ret->event_fd = eventfd(0, 0); if (ret->event_fd == INVALID_FD) { LOG_ERROR("%s unable to create eventfd: %s", __func__, strerror(errno)); goto error; } pthread_mutex_init(&ret->list_lock, NULL); ret->invalidation_list = list_new(NULL); if (!ret->invalidation_list) { LOG_ERROR("%s unable to allocate object invalidation list.", __func__); goto error; } struct epoll_event event; memset(&event, 0, sizeof(event)); event.events = EPOLLIN; event.data.ptr = NULL; if (epoll_ctl(ret->epoll_fd, EPOLL_CTL_ADD, ret->event_fd, &event) == -1) { LOG_ERROR("%s unable to register eventfd with epoll set: %s", __func__, strerror(errno)); goto error; } return ret; error:; reactor_free(ret); return NULL; }
thread_t *thread_new_sized(const char *name, size_t work_queue_capacity) { assert(name != NULL); assert(work_queue_capacity != 0); thread_t *ret = osi_calloc(sizeof(thread_t)); if (!ret) goto error; ret->reactor = reactor_new(); if (!ret->reactor) goto error; ret->work_queue = fixed_queue_new(work_queue_capacity); if (!ret->work_queue) goto error; // Start is on the stack, but we use a semaphore, so it's safe struct start_arg start; start.start_sem = semaphore_new(0); if (!start.start_sem) goto error; strncpy(ret->name, name, THREAD_NAME_MAX); start.thread = ret; start.error = 0; pthread_create(&ret->pthread, NULL, run_thread, &start); semaphore_wait(start.start_sem); semaphore_free(start.start_sem); if (start.error) goto error; return ret; error:; if (ret) { fixed_queue_free(ret->work_queue, osi_free); reactor_free(ret->reactor); } osi_free(ret); return NULL; }
config_t *config_new_empty(void) { config_t *config = osi_calloc(sizeof(config_t)); if (!config) { LOG_ERROR("%s unable to allocate memory for config_t.\n", __func__); goto error; } config->sections = list_new(section_free); if (!config->sections) { LOG_ERROR("%s unable to allocate list for sections.\n", __func__); goto error; } return config; error:; config_free(config); return NULL; }
reactor_object_t *reactor_register(reactor_t *reactor, int fd, void *context, void (*read_ready)(void *context), void (*write_ready)(void *context)) { assert(reactor != NULL); assert(fd != INVALID_FD); reactor_object_t *object = (reactor_object_t *)osi_calloc(sizeof(reactor_object_t)); if (!object) { LOG_ERROR("%s unable to allocate reactor object: %s", __func__, strerror(errno)); return NULL; } object->reactor = reactor; object->fd = fd; object->context = context; object->read_ready = read_ready; object->write_ready = write_ready; pthread_mutex_init(&object->lock, NULL); struct epoll_event event; memset(&event, 0, sizeof(event)); if (read_ready) event.events |= (EPOLLIN | EPOLLRDHUP); if (write_ready) event.events |= EPOLLOUT; event.data.ptr = object; if (epoll_ctl(reactor->epoll_fd, EPOLL_CTL_ADD, fd, &event) == -1) { LOG_ERROR("%s unable to register fd %d to epoll set: %s", __func__, fd, strerror(errno)); pthread_mutex_destroy(&object->lock); osi_free(object); return NULL; } return object; }
static void transmit_command( BT_HDR *command, command_complete_cb complete_callback, command_status_cb status_callback, void *context) { waiting_command_t *wait_entry = osi_calloc(sizeof(waiting_command_t)); if (!wait_entry) { LOG_ERROR(LOG_TAG, "%s couldn't allocate space for wait entry.", __func__); return; } uint8_t *stream = command->data + command->offset; STREAM_TO_UINT16(wait_entry->opcode, stream); wait_entry->complete_callback = complete_callback; wait_entry->status_callback = status_callback; wait_entry->command = command; wait_entry->context = context; // Store the command message type in the event field // in case the upper layer didn't already command->event = MSG_STACK_TO_HC_HCI_CMD; fixed_queue_enqueue(command_queue, wait_entry); }
alarm_t *alarm_new(void) { // Make sure we have a list we can insert alarms into. if (!alarms && !lazy_initialize()) return NULL; pthread_mutexattr_t attr; pthread_mutexattr_init(&attr); alarm_t *ret = osi_calloc(sizeof(alarm_t)); if (!ret) { LOG_ERROR("%s unable to allocate memory for alarm.", __func__); goto error; } // Make this a recursive mutex to make it safe to call |alarm_cancel| from // within the callback function of the alarm. int error = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); if (error) { LOG_ERROR("%s unable to create a recursive mutex: %s", __func__, strerror(error)); goto error; } error = pthread_mutex_init(&ret->callback_lock, &attr); if (error) { LOG_ERROR("%s unable to initialize mutex: %s", __func__, strerror(error)); goto error; } pthread_mutexattr_destroy(&attr); return ret; error:; pthread_mutexattr_destroy(&attr); osi_free(ret); return NULL; }
static void config_parse(nvs_handle fp, config_t *config) { assert(fp != 0); assert(config != NULL); esp_err_t err; int line_num = 0; int err_code = 0; uint16_t i = 0; size_t length = CONFIG_FILE_DEFAULE_LENGTH; size_t total_length = 0; char *line = osi_calloc(1024); char *section = osi_calloc(1024); char *keyname = osi_calloc(sizeof(CONFIG_KEY) + 1); int buf_size = get_config_size_from_flash(fp); char *buf = osi_calloc(buf_size + 100); if (!line || !section || !buf || !keyname) { err_code |= 0x01; goto error; } snprintf(keyname, sizeof(CONFIG_KEY)+1, "%s%d", CONFIG_KEY, 0); err = nvs_get_blob(fp, keyname, buf, &length); if (err == ESP_ERR_NVS_NOT_FOUND) { goto error; } if (err != ESP_OK) { err_code |= 0x02; goto error; } total_length += length; while (length == CONFIG_FILE_MAX_SIZE) { length = CONFIG_FILE_DEFAULE_LENGTH; snprintf(keyname, sizeof(CONFIG_KEY) + 1, "%s%d", CONFIG_KEY, ++i); err = nvs_get_blob(fp, keyname, buf + CONFIG_FILE_MAX_SIZE * i, &length); if (err == ESP_ERR_NVS_NOT_FOUND) { break; } if (err != ESP_OK) { err_code |= 0x02; goto error; } total_length += length; } char *p_line_end; char *p_line_bgn = buf; strcpy(section, CONFIG_DEFAULT_SECTION); while ( (p_line_bgn < buf + total_length - 1) && (p_line_end = strchr(p_line_bgn, '\n'))) { // get one line int line_len = p_line_end - p_line_bgn; if (line_len > 1023) { LOG_WARN("%s exceed max line length on line %d.\n", __func__, line_num); break; } memcpy(line, p_line_bgn, line_len); line[line_len] = '\0'; p_line_bgn = p_line_end + 1; char *line_ptr = trim(line); ++line_num; // Skip blank and comment lines. if (*line_ptr == '\0' || *line_ptr == '#') { continue; } if (*line_ptr == '[') { size_t len = strlen(line_ptr); if (line_ptr[len - 1] != ']') { LOG_WARN("%s unterminated section name on line %d.\n", __func__, line_num); continue; } strncpy(section, line_ptr + 1, len - 2); section[len - 2] = '\0'; } else { char *split = strchr(line_ptr, '='); if (!split) { LOG_DEBUG("%s no key/value separator found on line %d.\n", __func__, line_num); continue; } *split = '\0'; config_set_string(config, section, trim(line_ptr), trim(split + 1), true); } } error: if (buf) { osi_free(buf); } if (line) { osi_free(line); } if (section) { osi_free(section); } if (keyname) { osi_free(keyname); } if (err_code) { LOG_ERROR("%s returned with err code: %d\n", __func__, err_code); } }
static sco_socket_t *sco_socket_new(void) { sco_socket_t *sco_socket = (sco_socket_t *)osi_calloc(sizeof(sco_socket_t)); if (sco_socket) sco_socket->sco_handle = BTM_INVALID_SCO_INDEX; return sco_socket; }
bool config_save(const config_t *config, const char *filename) { assert(config != NULL); assert(filename != NULL); assert(*filename != '\0'); esp_err_t err; int err_code = 0; nvs_handle fp; char *line = osi_calloc(1024); char *keyname = osi_calloc(sizeof(CONFIG_KEY) + 1); int config_size = get_config_size(config); char *buf = osi_calloc(config_size + 100); if (!line || !buf || !keyname) { err_code |= 0x01; goto error; } err = nvs_open(filename, NVS_READWRITE, &fp); if (err != ESP_OK) { if (err == ESP_ERR_NVS_NOT_INITIALIZED) { LOG_ERROR("%s: NVS not initialized. " "Call nvs_flash_init before initializing bluetooth.", __func__); } err_code |= 0x02; goto error; } int w_cnt, w_cnt_total = 0; for (const list_node_t *node = list_begin(config->sections); node != list_end(config->sections); node = list_next(node)) { const section_t *section = (const section_t *)list_node(node); w_cnt = snprintf(line, 1024, "[%s]\n", section->name); LOG_DEBUG("section name: %s, w_cnt + w_cnt_total = %d\n", section->name, w_cnt + w_cnt_total); memcpy(buf + w_cnt_total, line, w_cnt); w_cnt_total += w_cnt; for (const list_node_t *enode = list_begin(section->entries); enode != list_end(section->entries); enode = list_next(enode)) { const entry_t *entry = (const entry_t *)list_node(enode); LOG_DEBUG("(key, val): (%s, %s)\n", entry->key, entry->value); w_cnt = snprintf(line, 1024, "%s = %s\n", entry->key, entry->value); LOG_DEBUG("%s, w_cnt + w_cnt_total = %d", __func__, w_cnt + w_cnt_total); memcpy(buf + w_cnt_total, line, w_cnt); w_cnt_total += w_cnt; } // Only add a separating newline if there are more sections. if (list_next(node) != list_end(config->sections)) { buf[w_cnt_total] = '\n'; w_cnt_total += 1; } else { break; } } buf[w_cnt_total] = '\0'; if (w_cnt_total < CONFIG_FILE_MAX_SIZE) { snprintf(keyname, sizeof(CONFIG_KEY)+1, "%s%d", CONFIG_KEY, 0); err = nvs_set_blob(fp, keyname, buf, w_cnt_total); if (err != ESP_OK) { nvs_close(fp); err_code |= 0x04; goto error; } }else { uint count = (w_cnt_total / CONFIG_FILE_MAX_SIZE); for (int i = 0; i <= count; i++) { snprintf(keyname, sizeof(CONFIG_KEY)+1, "%s%d", CONFIG_KEY, i); if (i == count) { err = nvs_set_blob(fp, keyname, buf + i*CONFIG_FILE_MAX_SIZE, w_cnt_total - i*CONFIG_FILE_MAX_SIZE); LOG_DEBUG("save keyname = %s, i = %d, %d\n", keyname, i, w_cnt_total - i*CONFIG_FILE_MAX_SIZE); }else { err = nvs_set_blob(fp, keyname, buf + i*CONFIG_FILE_MAX_SIZE, CONFIG_FILE_MAX_SIZE); LOG_DEBUG("save keyname = %s, i = %d, %d\n", keyname, i, CONFIG_FILE_MAX_SIZE); } if (err != ESP_OK) { nvs_close(fp); err_code |= 0x04; goto error; } } } err = nvs_commit(fp); if (err != ESP_OK) { nvs_close(fp); err_code |= 0x08; goto error; } nvs_close(fp); osi_free(line); osi_free(buf); osi_free(keyname); return true; error: if (buf) { osi_free(buf); } if (line) { osi_free(line); } if (keyname) { osi_free(keyname); } if (err_code) { LOG_ERROR("%s, err_code: 0x%x\n", __func__, err_code); } return false; }