/* * directory.c * * Code controlling sending, receiving, storage and retrieval of directory * information * * Copyright (c) 2004 Todd MacDermid * */ #include #include #include int directory_reply_pack(cutlass_t *cut_handle, uint8_t *buffer, int buf_size, struct cutlass_dir_info *reply_arr, int num_replies) { int i; int bytes_remaining; uint8_t *cur_loc; uint16_t tmp_port; cutlass_capability_t tmp_capabilities; struct cutlass_dir_info *dir_entry; cur_loc = buffer; bytes_remaining = buf_size; for(i = 0; i < num_replies; i++) { dir_entry = &(reply_arr[i]); bytes_remaining -= sizeof(struct cutlass_dir_info); if(bytes_remaining < 0) { cutlass_sysmsg(cut_handle, CUT_INFO, "directory_reply_pack: Ran out of buffer space\n"); return(-1); } *cur_loc = dir_entry->addr_type; cur_loc++; memcpy(cur_loc, dir_entry->remote_addr, CUT_ADDR_MAX); cur_loc += CUT_ADDR_MAX; tmp_port = htons(dir_entry->port); memcpy(cur_loc, &tmp_port, sizeof(uint16_t)); cur_loc += sizeof(uint16_t); memcpy(cur_loc, dir_entry->conn_name, CUTLASS_NAME_LEN); cur_loc += CUTLASS_NAME_LEN; memcpy(cur_loc, dir_entry->fingerprint, CUT_ID_LEN); cur_loc += CUT_ID_LEN; tmp_capabilities = htonl(dir_entry->capabilities); memcpy(cur_loc, &tmp_capabilities, sizeof(cutlass_capability_t)); cur_loc += sizeof(cutlass_capability_t); } return(0); } int directory_reply_unpack(cutlass_t *cut_handle, uint8_t *buffer, int buf_size, struct cutlass_dir_info *reply_arr, int max_replies) { int i; int bytes_remaining; int8_t *cur_loc; uint16_t tmp_port; cutlass_capability_t tmp_capabilities; struct cutlass_dir_info *dir_entry; cur_loc = buffer; bytes_remaining = buf_size; for(i = 0; (i < max_replies) && (bytes_remaining >= (sizeof(struct cutlass_dir_info))); i++) { dir_entry = &(reply_arr[i]); bytes_remaining -= sizeof(struct cutlass_dir_info); dir_entry->addr_type = *cur_loc; cur_loc++; memcpy(dir_entry->remote_addr, cur_loc, CUT_ADDR_MAX); cur_loc += CUT_ADDR_MAX; memcpy(&tmp_port, cur_loc, sizeof(uint16_t)); dir_entry->port = ntohs(tmp_port); memcpy(dir_entry->conn_name, cur_loc, CUTLASS_NAME_LEN); cur_loc += CUTLASS_NAME_LEN; memcpy(dir_entry->fingerprint, cur_loc, CUT_ID_LEN); cur_loc += CUT_ID_LEN; memcpy(&tmp_capabilities, cur_loc, sizeof(cutlass_capability_t)); dir_entry->capabilities = htonl(tmp_capabilities); cur_loc += sizeof(cutlass_capability_t); (dir_entry->conn_name)[CUTLASS_NAME_LEN - 1] = 0; } if(bytes_remaining > 0) { cutlass_sysmsg(cut_handle, CUT_INFO, "directory_reply_unpack: Ran out of buffer space\n"); return(1); } return(0); } int dir_response_send(cutlass_t *cut_handle, conn_t *conn, int num_response, struct cutlass_dir_info *response_arr, request_t *original_request) { struct channel *transport_info; struct timespec now; uint8_t buffer[CUT_MSG_LEN_MAX]; uint8_t new_channel; if(directory_reply_pack(cut_handle, buffer, CUT_MSG_LEN_MAX, response_arr, num_response) < 0) { cutlass_sysmsg(cut_handle, CUT_ERROR, "dir_response_send: directory_reply_pack failed\n"); return(-1); } new_channel = new_cut_channel_out(cut_handle, conn, CHANNEL_DIR_INFO, num_response * sizeof(struct cutlass_dir_info), NULL, buffer, original_request->request_id); if(new_channel == 0) { cutlass_sysmsg(cut_handle, CUT_ERROR, "dir_response_send: error allocating channel\n"); return(-1); } transport_info = &(conn->out_channels[new_channel]); cutlass_time(&now); cutlass_transport_init_send(cut_handle, conn, transport_info, &now); return(0); } static conn_t * dir_server_check(cutlass_t *cut_handle, uint8_t *dir_fprint) { conn_t *conn; conn = hashtable_fingerprint_find(cut_handle, dir_fprint); if(NULL == conn) { cutlass_sysmsg(cut_handle, CUT_ERROR, "dir_server_check: Could not find fingerprint\n"); return(NULL); } if(!(conn->capabilities & CAN_SERVE_DIR)) { cutlass_sysmsg(cut_handle, CUT_ERROR, "dir_server_check: " "Selected connection is not a directory server\n"); pthread_mutex_unlock(&conn->conn_mutex); return(NULL); } if(CUTSTATE_ACTIVE != conn->conn_state) { cutlass_sysmsg(cut_handle, CUT_INFO, "dir_server_check: " "Attempted to send on non-active state: %d\n", conn->conn_state); pthread_mutex_unlock(&conn->conn_mutex); return(NULL); } return(conn); } int cutlass_directory_request_process(cutlass_t *cut_handle, conn_t *conn, request_t *dir_request) { struct cutlass_dir_info *dir_replies; struct cutlass_dir_info *current_info; uint8_t *fingerprint_key; if(cutlass_check_auth(cut_handle, conn, CUT_SERVE_DIRECTORY) != PERMITTED) { cutlass_sysmsg(cut_handle, CUT_ERROR, "cutlass_directory_request_process: " "Permission for use as directory server denied\n"); return(-1); } pthread_mutex_lock(&cut_handle->directory_mutex); switch(dir_request->request_type) { case REQ_DIR_ADVERTISE: if(hfind(cut_handle->directory, conn->fingerprint, CUT_ID_LEN) == TRUE) { current_info = hstuff(cut_handle->directory); } else { current_info = calloc(1, sizeof(struct cutlass_dir_info)); if(NULL == current_info) { cutlass_sysmsg(cut_handle, CUT_ERROR, "directory_respond: Error allocating memory\n"); goto fail; } fingerprint_key = calloc(1, CUT_ID_LEN); if(NULL == fingerprint_key) { cutlass_sysmsg(cut_handle, CUT_ERROR, "directory_respond: Error allocating memory\n"); goto fail2; } memcpy(fingerprint_key, conn->fingerprint, CUT_ID_LEN); if(hadd(cut_handle->directory, fingerprint_key, CUT_ID_LEN, current_info) == FALSE) { cutlass_sysmsg(cut_handle, CUT_ERROR, "directory_respond: Error adding directory entry\n"); goto fail3; } } current_info->addr_type = CUT_IPV4; memcpy(current_info->remote_addr, &(conn->remote_addr.sin_addr), 4); current_info->port = ntohs(conn->remote_addr.sin_port); memcpy(current_info->conn_name, conn->conn_name, CUTLASS_NAME_LEN); memcpy(current_info->fingerprint, conn->fingerprint, CUT_ID_LEN); current_info->capabilities = conn->capabilities; break; case REQ_DIR_UNADVERTISE: if(hfind(cut_handle->directory, conn->fingerprint, CUT_ID_LEN) == TRUE) { current_info = hstuff(cut_handle->directory); free(hkey(cut_handle->directory)); free(hstuff(cut_handle->directory)); hdel(cut_handle->directory); } break; case REQ_DIR_LOOKUP_PRINT: if(hfind(cut_handle->directory, dir_request->request_data, CUT_ID_LEN) == TRUE) { current_info = hstuff(cut_handle->directory); dir_replies = calloc(1, sizeof(struct cutlass_dir_info)); if(NULL == dir_replies) { cutlass_sysmsg(cut_handle, CUT_ERROR, "directory_respond: Error allocating memory\n"); goto fail; } if(dir_response_send(cut_handle, conn, 1, current_info, dir_request) < 0) { cutlass_sysmsg(cut_handle, CUT_ERROR, "directory_respond: Error sending response\n"); goto fail; } } else { if(dir_response_send(cut_handle, conn, 0, NULL, dir_request) < 0) { cutlass_sysmsg(cut_handle, CUT_ERROR, "directory_respond: Error sending response\n"); goto fail; } } /* directory_reply_pack(cut_handle, response_buf, CUT_MSG_LEN_MAX, dir_replies, */ break; case REQ_DIR_LOOKUP_REGEX: cutlass_sysmsg(cut_handle, CUT_ERROR, "directory_respond: Don't yet support regex\n"); goto fail; break; case REQ_DIR_SUBSCRIBE: cutlass_sysmsg(cut_handle, CUT_ERROR, "directory_respond: Don't yet support subscribe\n"); break; default: cutlass_sysmsg(cut_handle, CUT_ERROR, "directory_respond: Uknown request type: %d\n", dir_request->request_type); goto fail; } pthread_mutex_unlock(&cut_handle->directory_mutex); return(0); fail3: free(fingerprint_key); fail2: free(current_info); fail: pthread_mutex_unlock(&cut_handle->directory_mutex); return(-1); } int cutlass_dir_info_process(cutlass_t *cut_handle, conn_t *conn, uint8_t *buffer, int buf_size) { struct cutlass_dir_info dir_entry; if(directory_reply_unpack(cut_handle, buffer, buf_size, &dir_entry, 1) < 0) { cutlass_sysmsg(cut_handle, CUT_ERROR, "cutlass_dir_info_process: Error unpacking reply\n"); return(-1); } printf("TEST: addr_type: %d\n remote_addr %s\nport %d\nname %s\n", dir_entry.addr_type, dir_entry.remote_addr, dir_entry.port, dir_entry.conn_name); return(0); } int cutlass_directory_advertise(cutlass_t *cut_handle, uint8_t *dir_fprint) { request_t dir_request; conn_t *conn; if((NULL == dir_fprint) || (NULL == cut_handle)) { cutlass_sysmsg(cut_handle, CUT_ERROR, "cutlass_directory_advertise: Passed a NULL pointer\n"); return(-1); } cutlass_sysmsg(cut_handle, CUT_DEBUG, "cutlass_directory_advertise: Looking up dir server\n"); if((conn = dir_server_check(cut_handle, dir_fprint)) == NULL) { cutlass_sysmsg(cut_handle, CUT_ERROR, "cutlass_directory_advertise: " "Requested fingerprint not an active directory server\n"); return(-1); } memset(&dir_request, 0, sizeof(request_t)); dir_request.request_type = REQ_DIR_ADVERTISE; dir_request.request_len = CUTLASS_REQ_LEN_MIN; cutlass_sysmsg(cut_handle, CUT_DEBUG, "cutlass_directory_advertise: Sending request\n"); if(cutlass_request_new(cut_handle, conn, &dir_request) < 0) { cutlass_sysmsg(cut_handle, CUT_ERROR, "cutlass_directory_advertise: " "cutlass_request_new failed\n"); pthread_mutex_unlock(&conn->conn_mutex); return(-1); } cutlass_sysmsg(cut_handle, CUT_DEBUG, "cutlass_directory_advertise: Unlocking dir server conn\n"); pthread_mutex_unlock(&conn->conn_mutex); return(0); } int cutlass_directory_unadvertise(cutlass_t *cut_handle, uint8_t *dir_fprint) { request_t dir_request; conn_t *conn; if((NULL == dir_fprint) || (NULL == cut_handle)) { cutlass_sysmsg(cut_handle, CUT_ERROR, "cutlass_directory_advertise: Passed a NULL pointer\n"); return(-1); } if((conn = dir_server_check(cut_handle, dir_fprint)) == NULL) { cutlass_sysmsg(cut_handle, CUT_INFO, "cutlass_directory_unadvertise: " "Requested fingerprint not an active directory server\n"); return(-1); } memset(&dir_request, 0, sizeof(request_t)); dir_request.request_type = REQ_DIR_UNADVERTISE; dir_request.request_len = CUTLASS_REQ_LEN_MIN; if(cutlass_request_new(cut_handle, conn, &dir_request) < 0) { cutlass_sysmsg(cut_handle, CUT_ERROR, "cutlass_directory_unadvertise: " "cutlass_request_new failed\n"); pthread_mutex_unlock(&conn->conn_mutex); return(-1); } pthread_mutex_unlock(&conn->conn_mutex); return(0); } int cutlass_directory_lookup_print(cutlass_t *cut_handle, uint8_t *dir_fprint, uint8_t *lookup_fprint) { request_t dir_request; conn_t *conn; if((NULL == dir_fprint) || (NULL == cut_handle) || (NULL == lookup_fprint)) { cutlass_sysmsg(cut_handle, CUT_ERROR, "cutlass_directory_lookup_print: Passed a NULL pointer\n"); return(-1); } if((conn = dir_server_check(cut_handle, dir_fprint)) == NULL) { cutlass_sysmsg(cut_handle, CUT_INFO, "cutlass_directory_lookup_print: " "Requested fingerprint not an active directory server\n"); return(-1); } memset(&dir_request, 0, sizeof(request_t)); dir_request.request_type = REQ_DIR_LOOKUP_PRINT; memcpy(dir_request.request_data, lookup_fprint, CUT_ID_LEN); dir_request.max_responses = CUTLASS_DEFAULT_DIRENT; dir_request.request_len = CUTLASS_REQ_LEN_MIN + CUT_ID_LEN; if(cutlass_request_new(cut_handle, conn, &dir_request) < 0) { cutlass_sysmsg(cut_handle, CUT_ERROR, "cutlass_directory_lookup_print: " "cutlass_request_new failed\n"); pthread_mutex_unlock(&conn->conn_mutex); return(-1); } pthread_mutex_unlock(&conn->conn_mutex); return(0); } int cutlass_directory_lookup_regex(cutlass_t *cut_handle, uint8_t *dir_fprint, char *lookup_regex) { request_t dir_request; conn_t *conn; if((NULL == dir_fprint) || (NULL == cut_handle) || (NULL == lookup_regex)) { cutlass_sysmsg(cut_handle, CUT_ERROR, "cutlass_directory_lookup_regex: Passed a NULL pointer\n"); return(-1); } if((conn = dir_server_check(cut_handle, dir_fprint)) == NULL) { cutlass_sysmsg(cut_handle, CUT_INFO, "cutlass_directory_lookup_regex: " "Requested fingerprint not an active directory server\n"); return(-1); } memset(&dir_request, 0, sizeof(request_t)); dir_request.request_type = REQ_DIR_LOOKUP_REGEX; strncpy(dir_request.request_data, lookup_regex, CUTLASS_REQ_DATA_MAX - 1); dir_request.max_responses = CUTLASS_DEFAULT_DIRENT; dir_request.request_len = CUTLASS_REQ_LEN_MIN + strlen(dir_request.request_data); if(cutlass_request_new(cut_handle, conn, &dir_request) < 0) { cutlass_sysmsg(cut_handle, CUT_ERROR, "cutlass_directory_lookup_regex: " "cutlass_request_new failed\n"); pthread_mutex_unlock(&conn->conn_mutex); return(-1); } pthread_mutex_unlock(&conn->conn_mutex); return(0); } int cutlass_directory_subscribe(cutlass_t *cut_handle, uint8_t *dir_fprint, uint8_t *lookup_fprint) { request_t dir_request; conn_t *conn; if((NULL == dir_fprint) || (NULL == cut_handle) || (NULL == lookup_fprint)) { cutlass_sysmsg(cut_handle, CUT_ERROR, "cutlass_directory_subscribe: Passed a NULL pointer\n"); return(-1); } if((conn = dir_server_check(cut_handle, dir_fprint)) == NULL) { cutlass_sysmsg(cut_handle, CUT_INFO, "cutlass_directory_subscribe: " "Requested fingerprint not an active directory server\n"); return(-1); } memset(&dir_request, 0, sizeof(request_t)); dir_request.request_type = REQ_DIR_SUBSCRIBE; memcpy(dir_request.request_data, lookup_fprint, CUT_ID_LEN); dir_request.request_len = CUTLASS_REQ_LEN_MIN + CUT_ID_LEN; if(cutlass_request_new(cut_handle, conn, &dir_request) < 0) { cutlass_sysmsg(cut_handle, CUT_ERROR, "cutlass_directory_lookup_print: " "cutlass_request_new failed\n"); pthread_mutex_unlock(&conn->conn_mutex); return(-1); } pthread_mutex_unlock(&conn->conn_mutex); return(0); } int cutlass_directory_dump(cutlass_t *cut_handle) { int i; int more = 1; struct cutlass_dir_info *dir_entry; uint8_t *fingerprint_key; pthread_mutex_lock(&cut_handle->directory_mutex); if(hfirst(cut_handle->directory) == TRUE) { while(more == 1) { fingerprint_key = hkey(cut_handle->directory); printf("KEY: "); for(i = 0; i < CUT_ID_LEN; i++) { printf("%02x", fingerprint_key[i]); } printf("\n"); dir_entry = hstuff(cut_handle->directory); printf("addr_type: %d\n", dir_entry->addr_type); printf("addr: "); for(i = 0; i < CUT_ADDR_MAX; i++) { printf("%02x", dir_entry->remote_addr[i]); } printf("\n"); printf("port: %d\n", dir_entry->port); printf("conn_name %s\n", dir_entry->conn_name); printf("fingerprint: "); for(i = 0; i < CUT_ID_LEN; i++) { printf("%02x", dir_entry->fingerprint[i]); } printf("\n"); if(hnext(cut_handle->directory)== FALSE) { more = 0; } } } else { printf("No dir entries\n"); } pthread_mutex_unlock(&cut_handle->directory_mutex); return(0); }