static int custom_update_thread(void* thread_data) { SDL_Event event; UpdateThreaData_t* data; Uint32 result; result = 0; data = (UpdateThreaData_t*)thread_data; init_thread_log("custom_update"); while (1) { CHECK_AND_LOCK_MUTEX(data->mutex); data->error = result; while (data->running == 1) { SDL_CondWait(data->condition, data->mutex); } if (data->running == 0) { CHECK_AND_UNLOCK_MUTEX(data->mutex); return 1; } data->error = 0; safe_snprintf(data->str, sizeof(data->str), "%s custom updates: %s", data->name, "started"); CHECK_AND_UNLOCK_MUTEX(data->mutex); result = custom_update_threaded(data->dir, data->zip, data); CHECK_AND_LOCK_MUTEX(data->mutex); if (data->running == 2) { data->running = 1; } LOG_INFO("%s", data->str); CHECK_AND_UNLOCK_MUTEX(data->mutex); // signal we are done event.type = SDL_USEREVENT; event.user.code = EVENT_CUSTOM_UPDATE_COMPLETE; event.user.data1 = 0; SDL_PushEvent(&event); } return 0; }
static el_file_ptr file_open(const char* file_name, const char* extra_path) { char str[1024]; el_zip_file_entry_t key; el_file_ptr result; Sint32 i, count; if (!file_name || !*file_name) return NULL; if (extra_path) { if (do_file_exists(file_name, extra_path, sizeof(str), str) == 1) { return xz_gz_file_open(str); } } if (do_file_exists(file_name, get_path_updates(), sizeof(str), str) == 1) { return xz_gz_file_open(str); } init_key(file_name, &key, sizeof(str), str); CHECK_AND_LOCK_MUTEX(zip_mutex); count = num_zip_files - 1; CHECK_AND_UNLOCK_MUTEX(zip_mutex); for (i = count; i >= 0; i--) { CHECK_AND_LOCK_MUTEX(zip_files[i].mutex); if (locate_in_zip(&zip_files[i], &key) == 1) { result = zip_file_open(zip_files[i].file); CHECK_AND_UNLOCK_MUTEX(zip_files[i].mutex); return result; } CHECK_AND_UNLOCK_MUTEX(zip_files[i].mutex); } if (do_file_exists(file_name, datadir, sizeof(str), str) == 1) { return xz_gz_file_open(str); } LOG_ERROR("Can't open file '%s'.", file_name); return NULL; }
static Uint32 file_exists_path(const char* file_name, const char* extra_path) { char str[1024]; el_zip_file_entry_t key; Sint32 i, count; if (file_name == 0) { return 0; } if (extra_path != 0) { if (do_file_exists(file_name, extra_path, sizeof(str), str) == 1) { return 1; } } if (do_file_exists(file_name, get_path_updates(), sizeof(str), str) == 1) { return 1; } init_key(file_name, &key, sizeof(str), str); CHECK_AND_LOCK_MUTEX(zip_mutex); count = num_zip_files - 1; CHECK_AND_UNLOCK_MUTEX(zip_mutex); for (i = count; i >= 0; i--) { CHECK_AND_LOCK_MUTEX(zip_files[i].mutex); if (find_in_zip(&zip_files[i], &key) == 1) { CHECK_AND_UNLOCK_MUTEX(zip_files[i].mutex); return 1; } CHECK_AND_UNLOCK_MUTEX(zip_files[i].mutex); } if (do_file_exists(file_name, datadir, sizeof(str), str) == 1) { return 1; } return 0; }
void unload_zip_archive(const char* file_name) { Uint32 i, count; if (file_name == 0) { LOG_ERROR("Invalid file name"); return; } ENTER_DEBUG_MARK("unload zip"); LOG_DEBUG("Unloading zip '%s'.", file_name); CHECK_AND_LOCK_MUTEX(zip_mutex); count = num_zip_files; CHECK_AND_UNLOCK_MUTEX(zip_mutex); LOG_DEBUG("Checking %d zip files", count); for (i = 0; i < count; i++) { CHECK_AND_LOCK_MUTEX(zip_files[i].mutex); LOG_DEBUG("Checking zip file '%s'", zip_files[i].file_name); if (zip_files[i].file_name != 0) { if (strcmp(zip_files[i].file_name, file_name) == 0) { clear_zip(&zip_files[i]); CHECK_AND_UNLOCK_MUTEX(zip_files[i].mutex); LEAVE_DEBUG_MARK("unload zip"); return; } } CHECK_AND_UNLOCK_MUTEX(zip_files[i].mutex); } LEAVE_DEBUG_MARK("unload zip"); }
void *queue_pop_blocking(queue_t *queue) { node_t *node; void *item; if (queue == 0) { return 0; } CHECK_AND_LOCK_MUTEX(queue->mutex); while (queue->front == queue->rear) { SDL_CondWait(queue->condition, queue->mutex); } node = queue->front->next; item = node->data; /* Check if removing the last node from the queue */ if (queue->front->next->next == 0) { queue->rear = queue->front; } else { queue->front->next = queue->front->next->next; } free(node); queue->nodes--; CHECK_AND_UNLOCK_MUTEX(queue->mutex); return item; }
int queue_push (queue_t *queue, void *item) { node_t *newnode; if (queue == 0) { LOG_ERROR("Null pointer for queue"); return 0; } newnode = malloc(sizeof(node_t)); if (newnode == 0) { LOG_ERROR("Failed to allocate memory for queue node"); return 0; } newnode->data = item; newnode->next = 0; /* Add to the end of the queue */ CHECK_AND_LOCK_MUTEX(queue->mutex); queue->rear->next = newnode; queue->rear = newnode; queue->nodes++; CHECK_AND_UNLOCK_MUTEX(queue->mutex); return 1; }
void *queue_pop (queue_t *queue) { node_t *oldnode; void *item; if (queue == NULL || queue_isempty(queue)) { return NULL; } else { CHECK_AND_LOCK_MUTEX(queue->mutex); oldnode = queue->front->next; item = oldnode->data; /* Check if removing the last node from the queue */ if (queue->front->next->next == NULL) { queue->rear = queue->front; } else { queue->front->next = queue->front->next->next; } free(oldnode); queue->nodes--; CHECK_AND_UNLOCK_MUTEX(queue->mutex); return item; } }
static Uint32 progress_function(const char* str, const Uint32 max, const Uint32 current, void* user_data) { UpdateThreaData_t* data; data = (UpdateThreaData_t*)user_data; CHECK_AND_LOCK_MUTEX(data->mutex); if (max > 0) { safe_snprintf(data->str, sizeof(data->str), "%s custom updates: %s %.2f%%", data->name, str, (current * 100.0f) / max); } else { safe_snprintf(data->str, sizeof(data->str), "%s custom updates: %s", data->name, str); } LOG_INFO("%s", data->str); if (data->running == 0) { CHECK_AND_UNLOCK_MUTEX(data->mutex); return 0; } CHECK_AND_UNLOCK_MUTEX(data->mutex); return 1; }
void queue_destroy (queue_t *queue) { void *tmp; if (queue != NULL) { //Tell our queue manager that we're done. stop_managing_queue(queue); CHECK_AND_LOCK_MUTEX(queue->mutex); while (!queue_isempty (queue)) { if ((tmp = queue_pop(queue)) == NULL) { break; } else { free(tmp); } } /* Free the dummy node too */ free(queue->front); CHECK_AND_UNLOCK_MUTEX(queue->mutex); SDL_DestroyMutex(queue->mutex); #ifdef NEW_TEXTURES SDL_DestroyCond(queue->condition); #endif /* NEW_TEXTURES */ free (queue); } }
int queue_isempty(const queue_t *queue) { int return_value; if (queue == NULL) { return_value = 1; } else { CHECK_AND_LOCK_MUTEX(queue->mutex); return_value = (queue->front == queue->rear); CHECK_AND_UNLOCK_MUTEX(queue->mutex); } return return_value; }
void *queue_delete_node(queue_t *queue, node_t *node) { if (queue == NULL || node == NULL || queue_isempty(queue)) { return NULL; } else { void *data = NULL; node_t *search_node; CHECK_AND_LOCK_MUTEX(queue->mutex); search_node = queue->front; /* Find the node in the queue */ /* Check if it's the first node. */ if (node == queue->front) { /* Shouldn't really happen */ return NULL; } else { while(search_node != NULL) { /* Check if the next node is what we're looking for */ if (search_node->next == node) { /* Point the node before our node's next pointer to the node after our node */ search_node->next = node->next; if (node == queue->rear) { queue->rear = search_node; } /* Make sure the data isn't lost when we free the node */ data = node->data; free(node); queue->nodes--; break; } search_node = search_node->next; } } CHECK_AND_UNLOCK_MUTEX(queue->mutex); return data; } }
void start_custom_update() { Uint32 i; for (i = 0; i < 2; i++) { CHECK_AND_LOCK_MUTEX(update_thread_data[i].mutex); if (update_thread_data[i].running == 1) { update_thread_data[i].running = 2; } CHECK_AND_UNLOCK_MUTEX(update_thread_data[i].mutex); SDL_CondSignal(update_thread_data[i].condition); } }
static void clear_zip(el_zip_file_t* zip) { Uint32 i; if (zip == 0) { LOG_ERROR("Invalid zip"); return; } CHECK_AND_LOCK_MUTEX(zip->mutex); LOG_DEBUG("Clearing zip file '%s'", zip->file_name); for (i = 0; i < zip->count; i++) { free(zip->files[i].file_name); } if (zip->files != 0) { free(zip->files); } if (zip->file_name != 0) { free(zip->file_name); } if (zip->file != 0) { unzClose(zip->file); } zip->file = 0; zip->count = 0; zip->files = 0; zip->file_name = 0; CHECK_AND_UNLOCK_MUTEX(zip->mutex); }
void add_to_download(const char *filename, const Uint8 *md5) { // lock the mutex CHECK_AND_LOCK_MUTEX(download_mutex); if(download_queue_size < MAX_UPDATE_QUEUE_SIZE){ // add the file to the list, and increase the count download_queue[download_queue_size]= strdup(filename); download_MD5s[download_queue_size]= calloc(1, 16); memcpy(download_MD5s[download_queue_size], md5, 16); download_queue_size++; // start a thread if one isn't running if(!download_cur_file){ char buffer[1024]; FILE *fp; safe_snprintf(download_temp_file, sizeof(download_temp_file), "tmp/temp%03d.dat", ++temp_counter); buffer[sizeof(buffer)-1]= '\0'; fp = open_file_config(download_temp_file, "wb+"); if(fp == NULL){ LOG_ERROR("%s: %s \"%s\": %s\n", reg_error_str, cant_open_file, download_temp_file, strerror(errno)); } else { // build the proper URL to download download_cur_file= download_queue[--download_queue_size]; download_cur_md5= download_MD5s[download_queue_size]; if(is_this_files_lst){ safe_snprintf(buffer, sizeof(buffer), "http://%s/updates%d%d%d/%s", update_server, VER_MAJOR, VER_MINOR, VER_RELEASE, download_cur_file); } else { safe_snprintf(buffer, sizeof(buffer), "http://%s/updates/%s", update_server, download_cur_file); } buffer[sizeof(buffer)-1]= '\0'; LOG_DEBUG("@@ %s %s",update_server,buffer); http_threaded_get_file(update_server, buffer, fp, download_cur_md5, EVENT_DOWNLOAD_COMPLETE); } } } // unlock the mutex CHECK_AND_UNLOCK_MUTEX(download_mutex); }
void stopp_custom_update() { Uint32 i; int result; for (i = 0; i < 2; i++) { CHECK_AND_LOCK_MUTEX(update_thread_data[i].mutex); update_thread_data[i].running = 0; CHECK_AND_UNLOCK_MUTEX(update_thread_data[i].mutex); SDL_CondSignal(update_thread_data[i].condition); SDL_WaitThread(update_thread_data[i].thread, &result); SDL_DestroyCond(update_thread_data[i].condition); SDL_DestroyMutex(update_thread_data[i].mutex); update_thread_data[i].mutex = 0; update_thread_data[i].thread = 0; } }
void clear_zip_archives() { Uint32 i; ENTER_DEBUG_MARK("unload zips"); CHECK_AND_LOCK_MUTEX(zip_mutex); for (i = 0; i < MAX_NUM_ZIP_FILES; i++) { clear_zip(&zip_files[i]); SDL_DestroyMutex(zip_files[i].mutex); } num_zip_files = 0; CHECK_AND_UNLOCK_MUTEX(zip_mutex); SDL_DestroyMutex(zip_mutex); LEAVE_DEBUG_MARK("unload zips"); }
int command_update_status(char *text, int len) { Uint32 i; if (custom_update == 0) { LOG_TO_CONSOLE(c_red1, "Custom updates disabled"); return 1; } for (i = 0; i < 2; i++) { CHECK_AND_LOCK_MUTEX(update_thread_data[i].mutex); switch (update_thread_data[i].error) { case 0: LOG_TO_CONSOLE(c_green1, update_thread_data[i].str); break; case 1: LOG_TO_CONSOLE(c_orange1, update_thread_data[i].str); break; default: LOG_TO_CONSOLE(c_red1, update_thread_data[i].str); break; } CHECK_AND_UNLOCK_MUTEX(update_thread_data[i].mutex); } return 1; }
static void wait_for_threads(download_files_thread_data_t *data, Uint32* error) { Sint32 result; Uint32 i; CHECK_AND_LOCK_MUTEX(data->mutex); if (*error == 0) { data->running = 2; } else { data->running = 0; } CHECK_AND_UNLOCK_MUTEX(data->mutex); for (i = 0; i < UPDATE_DOWNLOAD_THREAD_COUNT; i++) { SDL_CondBroadcast(data->condition); SDL_WaitThread(data->threads[i], &result); if (*error == 0) { *error = result; } } SDL_DestroyMutex(data->mutex); SDL_DestroyCond(data->condition); while (queue_pop(data->files) != 0); queue_destroy(data->files); }
int queue_push_signal(queue_t *queue, void *item) { node_t *node; if (queue == 0) { return 0; } node = malloc(sizeof(node_t)); if (node == 0) { CHECK_AND_UNLOCK_MUTEX(queue->mutex); LOG_ERROR("Failed to allocate memory for queue"); return 0; } node->data = item; node->next = 0; /* Add to the end of the queue */ CHECK_AND_LOCK_MUTEX(queue->mutex); queue->rear->next = node; queue->rear = node; queue->nodes++; CHECK_AND_UNLOCK_MUTEX(queue->mutex); SDL_CondSignal(queue->condition); return 1; }
void load_zip_archive(const char* file_name) { unzFile file; unz_file_info64 info; unz_global_info64 global_info; el_zip_file_entry_t* files; char* name; Uint32 i, count, size, index; if (file_name == 0) { LOG_ERROR("Empty zip file name", file_name); return; } if (num_zip_files >= MAX_NUM_ZIP_FILES) { LOG_ERROR("Can't add zip file %s", file_name); return; } file = unzOpen64(file_name); if (unzGetGlobalInfo64(file, &global_info) != UNZ_OK) { LOG_ERROR("Can't load zip file %s", file_name); unzClose(file); return; } count = global_info.number_entry; if (unzGoToFirstFile(file) != UNZ_OK) { LOG_ERROR("Can't load zip file %s", file_name); unzClose(file); return; } ENTER_DEBUG_MARK("load zip"); LOG_DEBUG("Loading zip file '%s' with %d files", file_name, count); files = malloc(count * sizeof(el_zip_file_entry_t)); for (i = 0; i < count; i++) { unzGetFilePos64(file, &files[i].position); unzGetCurrentFileInfo64(file, &info, 0, 0, 0, 0, 0, 0); size = info.size_filename; files[i].file_name = calloc(size + 1, 1); unzGetCurrentFileInfo64(file, 0, files[i].file_name, size, 0, 0, 0, 0); LOG_DEBUG("Loading file (%d) '%s' from zip file '%s'.", i, files[i].file_name, file_name); files[i].hash = mem_hash(files[i].file_name, size); unzGoToNextFile(file); } size = strlen(file_name); name = calloc(size + 1, 1); memcpy(name, file_name, size); LOG_DEBUG("Sorting files from zip file '%s'.", file_name); qsort(files, count, sizeof(el_zip_file_entry_t), compare_el_zip_file_entry); CHECK_AND_LOCK_MUTEX(zip_mutex); index = num_zip_files; for (i = 0; i < num_zip_files; i++) { if (zip_files[i].file_name == 0) { index = i; break; } } num_zip_files = max2u(num_zip_files, index + 1); CHECK_AND_LOCK_MUTEX(zip_files[index].mutex); CHECK_AND_UNLOCK_MUTEX(zip_mutex); LOG_DEBUG("Adding zip file '%s' at position %d.", file_name, index); zip_files[index].file_name = name; zip_files[index].file = file; zip_files[index].files = files; zip_files[index].count = count; CHECK_AND_UNLOCK_MUTEX(zip_files[index].mutex); LEAVE_DEBUG_MARK("load zip"); LOG_DEBUG("Loaded zip file '%s' with %d files", file_name, count); }
// finish up on one file that just downloaded void handle_file_download(struct http_get_struct *get) { int sts; if(!get){ // huh? what are you doing? return; } // lock the mutex CHECK_AND_LOCK_MUTEX(download_mutex); if(get->status == 0){ // replace the current file (creates all required directories) sts = move_file_to_updates(download_temp_file, download_cur_file, doing_custom); LOG_DEBUG("Moved \"%s\" to \"%s\"", download_temp_file, download_cur_file); // check for errors if(!sts){ // TODO: make the restart more intelligent if(allow_restart){ if(strstr(download_cur_file, "2dobjects/")==NULL && strstr(download_cur_file, "3dobjects/")==NULL && strstr(download_cur_file, "maps/")==NULL && strstr(download_cur_file, "music/")==NULL && strstr(download_cur_file, "textures/")==NULL && strstr(download_cur_file, ".menu")==NULL) restart_required++; if(strstr(download_cur_file, ".menu") > 0) reload_user_menus(); if(restart_required == 1) { LOG_TO_CONSOLE(c_red1, "Downloading Updates..."); } } } else { LOG_ERROR("Unable to finish processing of %s (%d)", download_cur_file, errno); // the final renamed failed, no restart permitted allow_restart= 0; restart_required= 0; } } else { // and make sure we can't restart since we had a total failure allow_restart= 0; restart_required= 0; } // wait for the just completed thread so we free it's resources assert(get->thread_index<MAX_THREADS); SDL_WaitThread(thread_list[get->thread_index], NULL); thread_list[get->thread_index] = NULL; // release the filename free(download_cur_file); free(download_cur_md5); download_cur_file= NULL; // unlock mutex CHECK_AND_UNLOCK_MUTEX(download_mutex); // now, release everything free(get); // lock the mutex CHECK_AND_LOCK_MUTEX(download_mutex); if(download_queue_size > 0 && !download_cur_file){ // start a thread if a file is waiting to download and no download active char buffer[512]; FILE *fp; safe_snprintf(download_temp_file, sizeof(download_temp_file), "tmp/temp%03d.dat", ++temp_counter); fp = open_file_config(download_temp_file, "wb+"); if(fp == NULL){ LOG_ERROR("%s: %s \"%s\": %s\n", reg_error_str, cant_open_file, download_temp_file, strerror(errno)); } else { // build the proper URL to download download_cur_file= download_queue[--download_queue_size]; download_cur_md5= download_MD5s[download_queue_size]; if(is_this_files_lst) { safe_snprintf(buffer, sizeof(buffer), "http://%s/updates%d%d%d/%s", update_server, VER_MAJOR, VER_MINOR, VER_RELEASE, download_cur_file); } else { safe_snprintf(buffer, sizeof(buffer), "http://%s/updates/%s", update_server, download_cur_file); } buffer[sizeof(buffer)-1]= '\0'; http_threaded_get_file(update_server, buffer, fp, download_cur_md5, EVENT_DOWNLOAD_COMPLETE); } } // check to see if this was the last file && a restart is required if(!update_busy && restart_required && allow_restart && download_queue_size <= 0 && !download_cur_file){ // yes, now trigger a restart LOG_INFO("Restart required because of update"); // Display something on the screen for a little bit before restarting if(autoupdate_delay >= 0) { int i; for (i=0; i < windows_list.num_windows;i++) { if(get_show_window(i)) break; } create_update_root_window (window_width, window_height, autoupdate_delay, i); show_window (update_root_win); } else { LOG_TO_CONSOLE(c_red2, "You need to restart the client to activate the updates!"); } } // unlock mutex CHECK_AND_UNLOCK_MUTEX(download_mutex); }
static int download_files_thread(void* _data) { char file_name[256]; char comment[64]; download_files_thread_data_t *data = NULL; update_info_t* info = NULL; char* download_buffer = NULL; void* file_buffer = NULL; FILE *file = NULL; Uint64 file_size, size; Uint32 i, len, result, error, count, index, running; Uint32 download_buffer_size; data = (download_files_thread_data_t*)_data; init_thread_log("download_files"); #ifdef WINDOWS file = my_tmpfile(); #else file = tmpfile(); #endif if (file == 0) { return 1; } error = 0; file_buffer = 0; download_buffer_size = 4096; download_buffer = calloc(download_buffer_size, sizeof(char)); count = data->count; while (1) { CHECK_AND_LOCK_MUTEX(data->mutex); do { info = queue_pop(data->files); running = data->running; if ((running == 1) && (info == 0)) { SDL_CondWait(data->condition, data->mutex); } } while ((data->running == 1) && (info == 0)); index = data->index; CHECK_AND_UNLOCK_MUTEX(data->mutex); if (info == 0) { break; } if (data->update_progress_function("Downloading files", count, index, data->user_data) != 1) { CHECK_AND_LOCK_MUTEX(data->mutex); data->running = 0; CHECK_AND_UNLOCK_MUTEX(data->mutex); error = 2; break; } for (i = 0; i < 5; i++) { fseek(file, 0, SEEK_SET); result = download_file(info->file_name, file, data->server, data->path, &size, download_buffer_size, download_buffer, 0, 0); if (result != 0) { LOG_ERROR("Download error %d while updating " "file '%s' from server '%s', retrying" " it", result, info->file_name, data->server); error = 3; continue; } if (file_read(file, size, &file_buffer, &file_size) != 0) { LOG_ERROR("Read error while updating file '%s' " "from server '%s', retrying it", info->file_name, data->server); error = 3; continue; } convert_md5_digest_to_comment_string(info->digest, sizeof(comment), comment); len = strlen(info->file_name); safe_snprintf(file_name, sizeof(file_name), "%s", info->file_name); if (has_suffix(file_name, len, ".xz", 3)) { file_name[len - 3] = 0; } CHECK_AND_LOCK_MUTEX(data->mutex); add_to_zip(file_name, file_size, file_buffer, data->dest, comment); data->index++; CHECK_AND_UNLOCK_MUTEX(data->mutex); free(file_buffer); error = 0; break; } if (error != 0) { break; } } free(download_buffer); fclose(file); return error; }
static Uint32 download_files(update_info_t* infos, const Uint32 count, const char* server, const char* path, const Uint32 source_count, unzFile* sources, zipFile dest, progress_fnc update_progress_function, void* user_data) { char file_name[256]; download_files_thread_data_t thread_data; FILE *file; Uint64 len; Uint32 i, j, download, error, index; #ifdef WINDOWS file = my_tmpfile(); #else file = tmpfile(); #endif if (file == 0) { return 1; } error = 0; init_threads(&thread_data, count, server, path, dest, update_progress_function, user_data); for (i = 0; i < count; i++) { CHECK_AND_LOCK_MUTEX(thread_data.mutex); index = thread_data.index; CHECK_AND_UNLOCK_MUTEX(thread_data.mutex); if (update_progress_function("Updating files", count, index, user_data) != 1) { error = 2; break; } download = 1; len = strlen(infos[i].file_name); safe_snprintf(file_name, sizeof(file_name), "%s", infos[i].file_name); if (has_suffix(file_name, len, ".xz", 3)) { file_name[len - 3] = 0; } for (j = 0; j < source_count; j++) { if (check_md5_from_zip(sources[j], file_name, infos[i].digest) == 0) { CHECK_AND_LOCK_MUTEX(thread_data.mutex); copy_from_zip(sources[j], dest); thread_data.index++; CHECK_AND_UNLOCK_MUTEX(thread_data.mutex); download = 0; break; } } if (download == 1) { queue_push(thread_data.files, &infos[i]); SDL_CondSignal(thread_data.condition); } } wait_for_threads(&thread_data, &error); fclose(file); return error; }