static int tear_down_index_buffer (SceneData* sceneData, SceneObject* so, SoData* soData) { Draw* method = so->draw; char bufferKey[KEYSIZE]; Attribute* indices = method->indices; GLuint bufferHandle; size_t bufferUsers; if ( indices && 1 == indices->useBuffer ) { snprintf (bufferKey, KEYSIZE, "%p", indices); bufferUsers = (size_t)hashmap_find ( bufferKey, sceneData->countBufferUsers ); bufferUsers--; if ( 0 == bufferUsers ) { bufferHandle = (GLuint)hashmap_find ( bufferKey, sceneData->mapBuffer2Handle ); glDeleteBuffers ( 1, &bufferHandle ); hashmap_delete ( bufferKey, sceneData->mapBuffer2Handle ); hashmap_delete ( bufferKey, sceneData->countBufferUsers ); list_remove_elem ( (void*)bufferHandle, sceneData->listBuffers ); } else { hashmap_insert ( bufferKey, (void*)bufferUsers, sceneData->countBufferUsers ); } } return 0; }
static void free_config (struct config_s *conf) { safefree (conf->config_file); safefree (conf->logf_name); safefree (conf->stathost); safefree (conf->user); safefree (conf->group); /*Added to enable POST data recovery to output directory*/ safefree (conf->output_dir); safefree (conf->ipAddr); #ifdef FILTER_ENABLE safefree (conf->filter); #endif /* FILTER_ENABLE */ #ifdef REVERSE_SUPPORT free_reversepath_list(conf->reversepath_list); safefree (conf->reversebaseurl); #endif #ifdef UPSTREAM_SUPPORT free_upstream_list (conf->upstream_list); #endif /* UPSTREAM_SUPPORT */ safefree (conf->pidpath); safefree (conf->bind_address); safefree (conf->via_proxy_name); hashmap_delete (conf->errorpages); free_added_headers (conf->add_headers); safefree (conf->errorpage_undef); safefree (conf->statpage); flush_access_list (conf->access_list); free_connect_ports_list (conf->connect_ports); hashmap_delete (conf->anonymous_map); memset (conf, 0, sizeof(*conf)); }
static int tear_down_textures (SceneData* sceneData, SceneObject* so, SoData* soData) { Uniform* uniform; char uniKey[KEYSIZE]; GLuint textureHandle; size_t textureUsers; int i; for ( i = 0; i < list_size ( soData->textures ); i++) { uniform = list_get( i, soData->textures); snprintf ( uniKey, KEYSIZE, "%p", uniform ); textureHandle = (GLuint)hashmap_find ( uniKey, sceneData->mapTexture2Handle ); textureUsers = (size_t)hashmap_find ( uniKey, sceneData->countTextureUsers ); textureUsers--; if ( 0 == textureUsers ) { glDeleteTextures( 1, &textureHandle ); hashmap_delete ( uniKey, sceneData->mapTexture2Handle ); hashmap_delete ( uniKey, sceneData->countTextureUsers ); list_remove_elem ( (void*)textureHandle, sceneData->listTextures ); } else { hashmap_insert ( uniKey, (void*)textureUsers, sceneData->countTextureUsers ); } } return 0; }
int main(int argc, char **argv) { int i, key, inmap, insert, data; void *datap; struct hashmap_t *map = hashmap_new(5); srandom(0); for (i=0; i<10000; i++) { key = rand()%DATASET_SIZE; insert = rand()%2; inmap = test_status[key]; data = test_data[key]; if (inmap && insert) { /* update */ data++; hashmap_upsert(map, &key, sizeof(int), INT2PTR(data), &datap); assert((intptr_t)datap == (intptr_t)test_data[key]); test_data[key] = data; } else if ( !inmap && insert) { /* insert */ hashmap_upsert(map, &key, sizeof(int), INT2PTR(data), &datap); assert( (intptr_t)datap == 0); test_status[key] = 1; } else if (inmap && !insert) { /* delete */ hashmap_delete(map, &key, sizeof(int), &datap); assert((intptr_t)datap == (intptr_t)test_data[key]); test_status[key] = 0; } else if (!inmap && !insert) { /* nothing to be deleted */ hashmap_delete(map, &key, sizeof(int), &datap); assert((intptr_t)datap == 0); } } return 0; }
static int tear_down_program(SceneData* sceneData, SceneObject* so, SoData* soData) { tear_down_shaders ( sceneData, so, soData ); char progKey[KEYSIZE]; snprintf (progKey, KEYSIZE, "%p,%p", &so->vShader, &so->fShader); GLuint program = (GLuint)hashmap_find(progKey, sceneData->mapShaderShader2Handle); size_t programUsers = (size_t)hashmap_find ( progKey, sceneData->countProgramUsers ); programUsers--; if ( 0 == programUsers ) { glDeleteProgram ( program ); hashmap_delete ( progKey, sceneData->mapShaderShader2Handle ); hashmap_delete ( progKey, sceneData->countProgramUsers ); list_remove_elem ( (void*)program, sceneData->listPrograms ); } else { hashmap_insert ( progKey, (void*)programUsers, sceneData->countProgramUsers ); } return 0; }
END_TEST START_TEST(test_map_put_delete_get) { hashmap *map; int res = hashmap_init(0, &map); fail_unless(res == 0); char buf[100]; void *out; for (int i=0; i<100;i++) { snprintf((char*)&buf, 100, "test%d", i); out = 0 & i; fail_unless(hashmap_put(map, (char*)buf, out) == 1); } for (int i=0; i<100;i++) { snprintf((char*)&buf, 100, "test%d", i); fail_unless(hashmap_delete(map, (char*)buf) == 0); } for (int i=0; i<100;i++) { snprintf((char*)&buf, 100, "test%d", i); fail_unless(hashmap_get(map, (char*)buf, &out) == -1); } res = hashmap_destroy(map); fail_unless(res == 0); }
END_TEST START_TEST(test_map_put_delete) { hashmap *map; int res = hashmap_init(0, &map); fail_unless(res == 0); char buf[100]; void *out; int j; for (int i=0; i<100;i++) { snprintf((char*)&buf, 100, "test%d", i); j = 0 & i; out = (void *)&j; fail_unless(hashmap_put(map, (char*)buf, out) == 1); } fail_unless(hashmap_size(map) == 100); for (int i=0; i<100;i++) { snprintf((char*)&buf, 100, "test%d", i); fail_unless(hashmap_delete(map, (char*)buf) == 0); fail_unless(hashmap_size(map) == (100-i-1)); } fail_unless(hashmap_size(map) == 0); res = hashmap_destroy(map); fail_unless(res == 0); }
static int tear_down_shaders (SceneData* sceneData, SceneObject* so, SoData* soData) { char shaderKey[KEYSIZE]; snprintf ( shaderKey, KEYSIZE, "%p", &so->vShader ); GLuint handle = (GLuint)hashmap_find ( shaderKey, sceneData->mapVShader2Handle ); size_t shaderUsers = (size_t)hashmap_find ( shaderKey, sceneData->countVShaderUsers ); shaderUsers--; if ( 0 == shaderUsers ) { glDeleteShader ( handle ); list_remove_elem ( (void*)handle, sceneData->listVShaders ); hashmap_delete ( shaderKey, sceneData->mapVShader2Handle ); hashmap_delete ( shaderKey, sceneData->countVShaderUsers ); } else { hashmap_insert ( shaderKey, (void*)shaderUsers, sceneData->countVShaderUsers ); } snprintf ( shaderKey, KEYSIZE, "%p", &so->fShader ); handle = (GLuint)hashmap_find ( shaderKey, sceneData->mapFShader2Handle ); shaderUsers = (GLuint)hashmap_find ( shaderKey, sceneData->countFShaderUsers ); shaderUsers--; if ( 0 == shaderUsers ) { glDeleteShader ( handle ); list_remove_elem ( (void*)handle, sceneData->listFShaders ); hashmap_delete ( shaderKey, sceneData->mapFShader2Handle ); hashmap_delete ( shaderKey, sceneData->countFShaderUsers ); } else { hashmap_insert ( shaderKey, (void*)shaderUsers, sceneData->countFShaderUsers ); } return 0; }
void global_term(void){ self.exit = 1; emc_thread_join(self.treconnect); #if defined (EMC_WINDOWS) WSACleanup(); #endif hashmap_delete(self.devices); self.devices = NULL; hashmap_delete(self.plugs); self.plugs = NULL; unpack_delete(self.upk); self.upk = NULL; delete_nqueue(self.id_allocator); self.id_allocator = NULL; delete_sendqueue(self.sq); self.sq = NULL; delete_map(self.rcmq); self.rcmq = NULL; }
void tcache_tick() { iterator it; hashmap_iter_begin(&cache->entries, &it); hashmap_pair *pair; while((pair = iter_next(&it)) != NULL) { tcache_entry_value *entry = pair->val; entry->age++; if(entry->age > CACHE_LIFETIME) { SDL_DestroyTexture(entry->tex); hashmap_delete(&cache->entries, &it); cache->old_frees++; } } }
/* Prune entries older than 3 seconds from the route cache */ void prune_route_cache(void* arg) { // This will store the next item in the linked list of hashmap entries hashmap_item_t next_item; // This will store a pointer to the route data struct route_data_t route_data; hashmap_item_t item; // Get the first item in the hashmap (first in the chronological sense) semaphore_P(route_cache_sem); item = hashmap_get_first(route_cache); // Go through all the items until we arrive at one that isn't ready for deletion while (item != NULL) { // Get the next item ahead of time, in case we delete this item next_item = hashmap_get_next(item); // Get the value of the hashmap, which is a route_data struct route_data = (route_data_t) hashmap_item_get_value(item); // Check if the entry is more than 3 seconds old if ((ticks - route_data->time_found) * PERIOD/MILLISECOND > 3000) { //printf("Deleting key %d\n", hashmap_item_get_key(item)); // Delete the route data struct delete_route_data(route_data); // Run hashmap delete, which will delete the hashmap_item struct (i.e. "item") hashmap_delete(route_cache, hashmap_item_get_key(item)); } else { // If the entry wasn't ready for deletion, then we can end (since the // linked list is maintained in chronological order of insertion) break; } // If we deleted the item, move to the next one item = next_item; } semaphore_V(route_cache_sem); // Once we're done, register the alarm to run again in 3 seconds register_alarm(3000, &prune_route_cache, NULL); }
static int tear_down_attributes (SceneData* sceneData, SceneObject* so, SoData* soData) { Attribute* attribute; char bufferKey[KEYSIZE]; size_t bufferUsers; GLuint bufferHandle; int i; for (i = 0; i < list_size(soData->attributes); i++) { attribute = list_get ( i, soData->attributes ); if ( 1 != attribute->useBuffer ) continue; snprintf (bufferKey, KEYSIZE, "%p", attribute); bufferHandle = (GLuint)hashmap_find ( bufferKey, sceneData->mapBuffer2Handle ); bufferUsers = (size_t)hashmap_find ( bufferKey, sceneData->countBufferUsers ); bufferUsers--; if ( 0 == bufferUsers) { // free resources glDeleteBuffers (1, &bufferHandle); list_remove_elem ( (void*)bufferHandle, sceneData->listBuffers ); hashmap_delete ( bufferKey, sceneData->mapBuffer2Handle ); hashmap_delete ( bufferKey, sceneData->countBufferUsers ); } else { hashmap_insert ( bufferKey, (void*)bufferUsers, sceneData->countBufferUsers ); } } return 0; }
// moves entry li to the front and sets // its id to id. static inline void move_to_front(cache_t* c, long li, cache_id_t id) { cache_id_t to_free = NULL; cache_list_entry_t* le; cache_list_entry_t* prev = NULL; cache_list_entry_t* next = NULL; cache_list_entry_t* head = NULL; hm_entry_t entry; assert( li >= 0 ); le = & c->list[li]; if( li != c->head ) { if( le->prev != -1 ) prev = & c->list[le->prev]; if( le->next != -1 ) next = & c->list[le->next]; // remove the element from the list if( prev ) prev->next = le->next; else c->head = le->next; if( next ) next->prev = le->prev; else c->tail = le->prev; // now place it at the beginning of the list. head = &c->list[c->head]; le->next = c->head; le->prev = -1; head->prev = li; c->head = li; } // update the IDs. if( le->id ) { // remove the old entry entry.key = le->id; entry.value = NULL; hashmap_delete(&c->mapping, &entry); to_free = le->id; } le->id = c->copy_id(id); if( to_free ) c->free_id(to_free); entry.key = le->id; entry.value = (void*) li; hashmap_insert(&c->mapping, &entry); }
/* Must be called by a thread that called _retrieve_block_id() when they're * done with it. * * Will free the block struct if possible. */ int _release_block(block_t block) { // todo: ensure not superblock // If it's a block, we're not deleting it / adding it to free blocks, just saying we dont need it in mem right now minifile_t inode; // Block isn't opened if (block->num_open == 0) { return 0; } // Decrement the open counter block->num_open--; if (block->is_dirty == 1) { block->is_dirty = 0; _commit_block(block); } // Check if the block is no longer in use if (block->num_open == 0) { if ((block->block_type == BLOCK_TYPE_FILE || block->block_type == BLOCK_TYPE_DIRECTORY) && block->is_deleted == 1) { _delete_inode((minifile_t) block); } else { // Delete the block from the stored hashmap - just deletes the inode struct, doesnt destroy the inode block itself if ( block->block_type == BLOCK_TYPE_FILE || block->block_type == BLOCK_TYPE_DIRECTORY) { inode = (minifile_t) block; semaphore_destroy(inode->u.data.mutex); } hashmap_delete(retrieved_blocks, block->block_id); } // free(block); hashmap_delete() does this... but it probably shouldn't... } return 0; }
END_TEST START_TEST(test_map_delete_no_keys) { hashmap *map; int res = hashmap_init(0, &map); fail_unless(res == 0); fail_unless(hashmap_size(map) == 0); char buf[100]; for (int i=0; i<100;i++) { snprintf((char*)&buf, 100, "test%d", i); fail_unless(hashmap_delete(map, (char*)buf) == -1); } res = hashmap_destroy(map); fail_unless(res == 0); }
static int internal_release_fd(int fd) { struct poll_note *notep; void *task = (void*)task_current(); notep = hashmap_get(g_fd_map, &fd, sizeof(int)); if (!notep) { return -1; //not exist; } if (notep->reader == task) { notep->reader = NULL; } if (notep->writer == task) { notep->writer = NULL; } if (notep->reader == NULL && notep->writer == NULL) { hashmap_delete(g_fd_map, (void*)&fd, sizeof(int), (void*)¬ep); cs_free(notep); cs_poll_del(g_poll_fd, fd); return 0; // a normal close } return 1; //remain reference; }
static int tear_down_so (SceneData* sceneData, SceneObject* so) { SoData* soData = find_so_data ( sceneData, so ); if ( !soData ) return -1; tear_down_index_buffer ( sceneData, so, soData ); tear_down_textures ( sceneData, so, soData ); tear_down_attributes ( sceneData, so, soData ); tear_down_program ( sceneData, so, soData ); list_free ( soData->attributes ); list_free ( soData->textures ); char soKey[KEYSIZE]; snprintf ( soKey, KEYSIZE, "%p", so ); hashmap_delete ( soKey, sceneData->mapSo2SoData ) ; free ( soData ); return 0; }
/** * hashmap_new: * returns a new hashmap of size ``max_size'' which keys can be compared/hashed * using ``compare_fun''/``hash_fun'' functions. * NOTE: if such functions are undefined, the hashmap defaults to the ``char*'' * implementation for strings (assumes ``any_key_t'' is ``char''). */ hashmap_ptr hashmap_new(const size_t max_size, hashmap_key_compare compare_fun, hashmap_key_hash hash_fun) { /* alloc hashmap */ hashmap_map* map = (hashmap_map*) calloc(1, sizeof(hashmap_map)); if (!map) goto error; /* check input parameters */ if (max_size <= 0) { map->_max_size = HASHMAP_DEFAULT_SIZE; } else { map->_max_size = max_size; } /* alloc support memory */ map->_buckets = (hashmap_bucket*) calloc(map->_max_size, sizeof(hashmap_bucket)); if (!map->_buckets) goto error; /* initialize fields */ map->_keys = NULL; map->_compare = (compare_fun ? compare_fun : (hashmap_key_compare) hashmap_key_compare_str); map->_hash = (hash_fun ? hash_fun : (hashmap_key_hash) hashmap_key_hash_str); map->_cur_size = 0; map->_changed = 1; return (hashmap_ptr) map; error: hashmap_delete(map); return NULL; }
int room_leave(struct room *r, struct client *c) { if (r && c) { return hashmap_delete(r->clients, (void *) c); } return -1; }
/* This will be used when deleting files and directories. * * This frees the inode and adds it back to the free inode list. It does not check * if it's in use, as that is the responsibility of the caller. * * This will free all data and indirection blocks, as they can't be in use if * this is being called, as the caller will ensure no other thread has it open or * can open it during the duration of this call. */ void _delete_inode(minifile_t inode) { block_t indir_block; block_t data_block; int indir_block_id = inode->u.data.indir_block_id; int tmp_indir_block_id; int i; int delete_ret = 0; int tmp_block_num; int ret = 0; // Delete the data blocks by either adding them to free list or telling // _release_block() to do so when all threads close it for (i = 0; i < inode->u.data.num_data_blocks; i++) { tmp_block_num = _inode_get_data_block_id(inode, i); data_block = _retrieve_block(tmp_block_num); data_block->block_id = tmp_block_num; data_block->is_deleted = 0; // took an hour... _commit_block((block_t) data_block); // to find this bug... _push_free_data_block(data_block); // Don't bother with release_block if it functions like ths, just free it (todo) hashmap_delete(retrieved_blocks, indir_block); if (ret == -1) free(data_block); } // Delete all indirection blocks in a similar manner while (indir_block_id != 0) { indir_block = _retrieve_block(indir_block_id); tmp_indir_block_id = indir_block->type.indir_block.entries[MAX_INDIR_BLOCK_ENTRIES]; indir_block->block_id = indir_block_id; indir_block->is_deleted = 0; _commit_block((block_t) indir_block); // took an hour to find this bug... _push_free_data_block(indir_block); indir_block_id = tmp_indir_block_id; // Just free it for now, make it correct later (todo) hashmap_delete(retrieved_blocks, indir_block); if (ret == -1) free(indir_block); } // Add this inode to the list of free inode blocks for (i = 0; i < 11; i++) { inode->u.data.data_block_ids[i] = 0; } _commit_block((block_t) inode); _push_free_inode(inode); // Free the inode semaphore if (inode->u.data.block_type == BLOCK_TYPE_FREE_INODE || inode->u.data.block_type == BLOCK_TYPE_FILE || inode->u.data.block_type == BLOCK_TYPE_DIRECTORY) { semaphore_destroy(inode->u.data.mutex); } // Delete the block from the stored hashmap, as well as the struct delete_ret = hashmap_delete(retrieved_blocks, inode->u.data.block_id); if (delete_ret == -1) { free(inode); } }
static void free_scene_data (Scene* scene) { char sdkey[KEYSIZE]; snprintf (sdkey, KEYSIZE, "%p", scene); SceneData* sceneData = hashmap_find (sdkey, mapSceneData); if (sceneData) { GLuint handle; int k; for (k = 0; k < list_size(sceneData->listBuffers); k++) { handle = (GLuint)list_get(k, sceneData->listBuffers); glDeleteBuffers (1, &handle); } for ( k = 0; k < list_size(sceneData->listPrograms); k++) { handle = (GLuint)list_get(k, sceneData->listPrograms); glDeleteProgram ( handle ); } for ( k = 0; k < list_size(sceneData->listVShaders); k++) { handle = (GLuint)list_get(k, sceneData->listVShaders); glDeleteShader ( handle ); } for ( k = 0; k < list_size(sceneData->listFShaders); k++) { handle = (GLuint)list_get(k, sceneData->listFShaders); glDeleteShader ( handle ); } for ( k = 0; k < list_size(sceneData->listTextures); k++) { handle = (GLuint)list_get(k, sceneData->listTextures); glDeleteTextures ( 1, &handle ); } list_free (sceneData->listPrograms); list_free (sceneData->listVShaders); list_free (sceneData->listFShaders); list_free (sceneData->listBuffers); list_free (sceneData->listTextures); hashmap_free (sceneData->mapVShader2Handle); hashmap_free (sceneData->mapFShader2Handle); hashmap_free (sceneData->mapShaderShader2Handle); hashmap_free (sceneData->mapBuffer2Handle); hashmap_free (sceneData->mapTexture2Handle); hashmap_free (sceneData->countBufferUsers); hashmap_free (sceneData->countVShaderUsers); hashmap_free (sceneData->countFShaderUsers); hashmap_free (sceneData->countProgramUsers); hashmap_free (sceneData->countTextureUsers); hashmap_free (sceneData->mapSo2SoData); list_free (sceneData->stageGbuffer); list_free (sceneData->stageLight); list_free (sceneData->stageGeometry); list_free (sceneData->stageParticle); list_free (sceneData->stageOverlay); hashmap_delete (sdkey, mapSceneData); } }
/* * This is the main drive for each connection. As you can tell, for the * first few steps we are using a blocking socket. If you remember the * older tinyproxy code, this use to be a very confusing state machine. * Well, no more! :) The sockets are only switched into nonblocking mode * when we start the relay portion. This makes most of the original * tinyproxy code, which was confusing, redundant. Hail progress. * - rjkaes */ void handle_connection(int fd) { struct conn_s *connptr; struct request_s *request = NULL; hashmap_t hashofheaders = NULL; char peer_ipaddr[PEER_IP_LENGTH]; char peer_string[PEER_STRING_LENGTH]; getpeer_information(fd, peer_ipaddr, peer_string); log_message(LOG_CONN, "Connect (file descriptor %d): %s [%s]", fd, peer_string, peer_ipaddr); connptr = initialize_conn(fd, peer_ipaddr, peer_string); if (!connptr) { close(fd); return; } if (check_acl(fd, peer_ipaddr, peer_string) <= 0) { update_stats(STAT_DENIED); indicate_http_error(connptr, 403, "Access denied", "detail", "The administrator of this proxy has not configured it to service requests from your host.", NULL); send_http_error_message(connptr); destroy_conn(connptr); return; } if (read_request_line(connptr) < 0) { update_stats(STAT_BADCONN); indicate_http_error(connptr, 408, "Timeout", "detail", "Server timeout waiting for the HTTP request from the client.", NULL); send_http_error_message(connptr); destroy_conn(connptr); return; } /* * The "hashofheaders" store the client's headers. */ if (!(hashofheaders = hashmap_create(HEADER_BUCKETS))) { update_stats(STAT_BADCONN); indicate_http_error(connptr, 503, "Internal error", "detail", "An internal server error occurred while processing your request. Please contact the administrator.", NULL); send_http_error_message(connptr); destroy_conn(connptr); return; } /* * Get all the headers from the client in a big hash. */ if (get_all_headers(connptr->client_fd, hashofheaders) < 0) { log_message(LOG_WARNING, "Could not retrieve all the headers from the client"); hashmap_delete(hashofheaders); update_stats(STAT_BADCONN); destroy_conn(connptr); return; } request = process_request(connptr, hashofheaders); if (!request) { if (!connptr->error_variables && !connptr->show_stats) { update_stats(STAT_BADCONN); destroy_conn(connptr); hashmap_delete(hashofheaders); return; } goto send_error; } connptr->upstream_proxy = UPSTREAM_HOST(request->host); if (connptr->upstream_proxy != NULL) { if (connect_to_upstream(connptr, request) < 0) { goto send_error; } } else { connptr->server_fd = opensock(request->host, request->port); if (connptr->server_fd < 0) { indicate_http_error(connptr, 500, "Unable to connect", "detail", PACKAGE " was unable to connect to the remote web server.", "error", strerror(errno), NULL); goto send_error; } log_message(LOG_CONN, "Established connection to host \"%s\" using file descriptor %d.", request->host, connptr->server_fd); if (!connptr->connect_method) establish_http_connection(connptr, request); } send_error: free_request_struct(request); if (process_client_headers(connptr, hashofheaders) < 0) { update_stats(STAT_BADCONN); if (!connptr->error_variables) { hashmap_delete(hashofheaders); destroy_conn(connptr); return; } } hashmap_delete(hashofheaders); if (connptr->error_variables) { send_http_error_message(connptr); destroy_conn(connptr); return; } else if (connptr->show_stats) { showstats(connptr); destroy_conn(connptr); return; } if (!connptr->connect_method || (connptr->upstream_proxy != NULL)) { if (process_server_headers(connptr) < 0) { if (connptr->error_variables) send_http_error_message(connptr); update_stats(STAT_BADCONN); destroy_conn(connptr); return; } } else { if (send_ssl_response(connptr) < 0) { log_message(LOG_ERR, "handle_connection: Could not send SSL greeting to client."); update_stats(STAT_BADCONN); destroy_conn(connptr); return; } } relay_connection(connptr); log_message(LOG_INFO, "Closed connection between local client (fd:%d) and remote client (fd:%d)", connptr->client_fd, connptr->server_fd); /* * All done... close everything and go home... :) */ destroy_conn(connptr); return; }
/* * Loop through all the headers (including the response code) from the * server. */ static int process_server_headers(struct conn_s *connptr) { static char *skipheaders[] = { "keep-alive", "proxy-authenticate", "proxy-authorization", "proxy-connection", "transfer-encoding", }; char *response_line; hashmap_t hashofheaders; hashmap_iter iter; char *data, *header; ssize_t len; int i; int ret; /* FIXME: Remember to handle a "simple_req" type */ /* Get the response line from the remote server. */ retry: len = readline(connptr->server_fd, &response_line); if (len <= 0) return -1; /* * Strip the new line and character return from the string. */ if (chomp(response_line, len) == len) { /* * If the number of characters removed is the same as the * length then it was a blank line. Free the buffer and * try again (since we're looking for a request line.) */ safefree(response_line); goto retry; } hashofheaders = hashmap_create(HEADER_BUCKETS); if (!hashofheaders) { safefree(response_line); return -1; } /* * Get all the headers from the remote server in a big hash */ if (get_all_headers(connptr->server_fd, hashofheaders) < 0) { log_message(LOG_WARNING, "Could not retrieve all the headers from the remote server."); hashmap_delete(hashofheaders); safefree(response_line); indicate_http_error(connptr, 503, "Could not retrieve all the headers", "detail", PACKAGE " was unable to retrieve and process headers from the remote web server.", NULL); return -1; } /* Send the saved response line first */ ret = write_message(connptr->client_fd, "%s\r\n", response_line); safefree(response_line); if (ret < 0) goto ERROR_EXIT; /* * If there is a "Content-Length" header, retrieve the information * from it for later use. */ connptr->content_length.server = get_content_length(hashofheaders); /* * See if there is a connection header. If so, we need to to a bit of * processing. */ remove_connection_headers(hashofheaders); /* * Delete the headers listed in the skipheaders list */ for (i = 0; i != (sizeof(skipheaders) / sizeof(char *)); i++) { hashmap_remove(hashofheaders, skipheaders[i]); } /* Send, or add the Via header */ ret = write_via_header(connptr->client_fd, hashofheaders, connptr->protocol.major, connptr->protocol.minor); if (ret < 0) goto ERROR_EXIT; /* * All right, output all the remaining headers to the client. */ iter = hashmap_first(hashofheaders); if (iter >= 0) { for ( ; !hashmap_is_end(hashofheaders, iter); ++iter) { hashmap_return_entry(hashofheaders, iter, &data, (void **)&header); ret = write_message(connptr->client_fd, "%s: %s\r\n", data, header); if (ret < 0) goto ERROR_EXIT; } } hashmap_delete(hashofheaders); /* Write the final blank line to signify the end of the headers */ if (safe_write(connptr->client_fd, "\r\n", 2) < 0) return -1; return 0; ERROR_EXIT: hashmap_delete(hashofheaders); return -1; }
error_t cache_get(cache_t* c, cache_id_t id, void** ret_data) { cache_list_entry_t* le; void* data; error_t err; hm_entry_t entry; long idx; int data_number; entry.key = id; entry.value = NULL; // first, check the mapping. if( hashmap_retrieve(&c->mapping, &entry) ) { idx = (long) entry.value; if( 0 == c->mapping.cmp(id, c->list[idx].id ) ) { // it's a valid mapping. // move it to the front of the list. //printf("Cache before mtf; id=%p\n", c->list[idx].id); move_to_front(c, idx, c->list[idx].id); data_number = idx; data = ((unsigned char*) c->data) + data_number * c->data_size; *ret_data = data; return ERR_NOERR; } } // if it's not an valid mapping, we'll evict the data // item pointed to by the last list element, then // load the new item, and finally move it to the front // of the list. // find a home for the new data item. // does the tail item in the list already have a data item? le = & c->list[c->tail]; data_number = c->tail; data = ((unsigned char*) c->data) + data_number * c->data_size; if( le->id && c->evict ) { c->evict(le->id, c->data_size, data, c->context); } // load the new item. //printf("Cache before fault; id=%p\n", id); err = c->fault(id, c->data_size, data, c->context); if( err ) { if( le->id ) { // remove the old entry entry.key = le->id; entry.value = NULL; hashmap_delete(&c->mapping, &entry); c->free_id(le->id); le->id = NULL; } return err; } //printf("Cache after fault; id=%p\n", id); // move the tail element to the front of the list. move_to_front(c, c->tail, id); *ret_data = data; return ERR_NOERR; }
/* sends a miniroute packet, automatically discovering the path if necessary. See description in the * .h file. */ int miniroute_send_pkt(network_address_t dest_address, int hdr_len, char* hdr, int data_len, char* data) { // This will store the route request struct, which is a structure related to the // search for a path to the host route_request_t route_request; // Store the routing header routing_header_t routing_header; // Store the route to the host, which is an array of addresses network_address_t* route; // Store the route data struct, which holds the route and some metadata route_data_t route_data; // Store my address network_address_t my_addr; // Used to synchronize access with structures the network handler touches interrupt_level_t prev_level; // This will store the combined routing + normal headers char* full_header; network_address_t dest_address2; // These will store data related to the routes int time_route_found; int route_len; int route_valid = 1; // Used to get data from the header containing the paht routing_header_t tmp_routing_header; // Used to just check the IP of senders; combats UDP port issues w/ simulated broadcasts unsigned int dest_address_ip = dest_address[0]; // Loop + tmp variables int current_req_id; int success = 0; int alarm_id; int x; int i; if (hdr_len == 0 || hdr == NULL || data_len == 0 || data == NULL) return -1; // Get the route item, which is a hashmap_item_t, from the hashmap for this addr semaphore_P(route_cache_sem); route_data = (route_data_t) hashmap_get(route_cache, hash_address(dest_address)); // If it's not NULL, extract the data from the item if (route_data != NULL) { time_route_found = route_data->time_found; route_len = route_data->route_len; // caveat: the cleanup thread may delete the route data, so we need to // save it in a separate variable, just incase. route = (network_address_t*) malloc(sizeof(network_address_t) * route_len); if (route == NULL) { semaphore_V(route_cache_sem); return -1; } memcpy(route, route_data->route, sizeof(network_address_t) * route_len); } else { route_valid = 0; } semaphore_V(route_cache_sem); // Check, if the route isn't NULL, if it's expired if (route_valid == 1 && (ticks - time_route_found) * PERIOD/MILLISECOND > 3000) { route_valid = 0; } // If the route is invalid (either not in the cache or expired)... if (route_valid == 0) { // We won't be needing that previous route variable if (route_data != NULL) { // But, just in case someone is still using it, use the route cache semaphore semaphore_P(route_cache_sem); free(route); semaphore_V(route_cache_sem); } // Check if someone else already initiated this route discovery request prev_level = set_interrupt_level(DISABLED); route_request = (route_request_t) hashmap_get(current_discovery_requests, dest_address_ip); set_interrupt_level(prev_level); // If so, we can just wait for their result if (route_request != NULL) { // Wait for the other thread to get the path // The threads waiting variable needs to be synchronized. We decided // to reuse the route cache sem, as there will not be much lock // contention semaphore_P(route_cache_sem); route_request->threads_waiting++; semaphore_V(route_cache_sem); semaphore_P(route_request->waiting_sem); // Get the route from the hashmap semaphore_P(route_cache_sem); route_data = (route_data_t) hashmap_get(route_cache, hash_address(dest_address)); // If the other thread didn't get the route, return an error if (route_data == NULL) { // Return failure... semaphore_V(route_cache_sem); return -1; } else { time_route_found = route_data->time_found; route_len = route_data->route_len; if ((ticks - time_route_found) * PERIOD/MILLISECOND > 3000) { // This could have been a left-over expired cache entry that we haven't // deleted yet. semaphore_V(route_cache_sem); return -1; } // Save the route in a separate variable in case the route gets cleaned up // while we're using it route = (network_address_t*) malloc(sizeof(network_address_t) * route_len); if (route == NULL) { semaphore_V(route_cache_sem); return -1; } memcpy(route, route_data->route, sizeof(network_address_t) * route_len); semaphore_V(route_cache_sem); } } else { // Otherwise, we have to do the route discovery process // Create a new route request struct route_request = create_route_request(); if (route_request == NULL) { return -1; } // Add the route request to the current discovery requests prev_level = set_interrupt_level(DISABLED); hashmap_insert(current_discovery_requests, dest_address_ip, route_request); set_interrupt_level(prev_level); // We'll try the route discovery process three times for (i = 0; i < 3; i++) { // Register an alarm to wake this thread up as it waits for a response alarm_id = register_alarm(12000, &alarm_wakeup_sem, (void*) route_request->initiator_sem); // Increment the request ID - must be synchronized, obviously semaphore_P(request_id_sem); current_req_id = route_request_id++; semaphore_V(request_id_sem); // We need to make a header for the discovery request, but the path // needs to have our address in it, so the reply can be forwarded back // to us network_get_my_address(my_addr); // Passing in the address of this local variable will suffice, as the // value is immediately copied into the header and then not used again // Create a routing header for the route discovery request routing_header = create_miniroute_header(ROUTING_ROUTE_DISCOVERY, dest_address, current_req_id, MAX_ROUTE_LENGTH, 1, &my_addr); if (routing_header == NULL) { return -1; } // Combine it with the given header full_header = merge_headers(routing_header, hdr, hdr_len); if (full_header == NULL) { free(routing_header); return -1; } // Send out the route discovery request network_bcast_pkt(sizeof(struct routing_header)+hdr_len, (char*) full_header, data_len, data); // Wait for a reply (which will be signalled by the network handler) prev_level = set_interrupt_level(DISABLED); semaphore_P(route_request->initiator_sem); set_interrupt_level(prev_level); // Check if we got a successful response if (route_request->interrupt_arg != NULL) { // Deregister the alarm before it tries to wake us up // Needs to be synchronized, as the IH touches it and we destroy it here prev_level = set_interrupt_level(alarm_id); deregister_alarm(alarm_id); set_interrupt_level(alarm_id); // Get the header tmp_routing_header = (routing_header_t) route_request->interrupt_arg->buffer; route_len = unpack_unsigned_int(tmp_routing_header->path_len); // Then the path, for our own use later in this function // We'll also create one copy and put it in the route data struct route = miniroute_reverse_raw_path(tmp_routing_header, route_len); if (route == NULL) { free(routing_header); free(full_header); return -1; } // Create a route data struct - with a different route (as it will be deleted by a diff thread) route_data = create_route_data(miniroute_reverse_raw_path(tmp_routing_header, route_len), route_len, ticks); if (route_data == NULL) { free(routing_header); free(full_header); return -1; } // add it to the cache hashmap semaphore_P(route_cache_sem); hashmap_insert(route_cache, hash_address(dest_address), route_data); semaphore_V(route_cache_sem); // Wake up the other threads waiting for (x = 0; x < route_request->threads_waiting; x++) { semaphore_V(route_request->waiting_sem); } // Clean up the route request struct, then delete it from the hashmap // DELETE ROUTE REQUEST WILL FREE THE NETWORK INTERRUPT ARG! prev_level = set_interrupt_level(DISABLED); delete_route_request(route_request); hashmap_delete(current_discovery_requests, dest_address_ip); set_interrupt_level(prev_level); // We don't need to actually get any of the routing stuff from the // route_ite, as this process also sent the data packet // Free the headers free(routing_header); free(full_header); // Return the total bytes sent, not including the routing header success = 1; break; } } // If we didn't get a successful response after 3 tries... if (success == 0) { // Wake up the other threads waiting so they can see we failed for (x = 0; x < route_request->threads_waiting; x++) { semaphore_V(route_request->waiting_sem); } // clean up the route request struct, then delete it from the hashmap prev_level = set_interrupt_level(DISABLED); delete_route_request(route_request); hashmap_delete(current_discovery_requests, dest_address_ip); set_interrupt_level(prev_level); // Free the headers free(routing_header); free(full_header); // Return failure... return -1; } } } // If we're here, we either found the route in the cache or waited for another // thread to finish getting the route (and it did so successfully) network_address_copy(route[route_len-1], dest_address2); // Need to update the dst address to deal with UDP port issues // This again is due to UDP port issues... pack_address(((mini_header_t) hdr)->destination_address, dest_address2); // Create a routing header for the data packet routing_header = create_miniroute_header(ROUTING_DATA, dest_address2, 0, MAX_ROUTE_LENGTH, route_len, route); if (routing_header == NULL) { return -1; } // Combine it with the given header full_header = merge_headers(routing_header, hdr, hdr_len); if (full_header == NULL) { free(routing_header); } // Set the right destination address network_address_copy(route[1], dest_address2); // Send the packet network_send_pkt(dest_address2, sizeof(struct routing_header) + hdr_len, full_header, data_len, data); // Free the route + headers free(route); free(routing_header); free(full_header); // Return the total data sent return hdr_len + data_len; }