/** * @brief mk_dirs It creates a multi-level directory like ./img/330/28/557. * * @param dir The path of a multi-level directory. * * @return 1 for success and -1 for fail. */ int mk_dirs(const char *dir) { char tmp[512]; char *p; if (strlen(dir) == 0 || dir == NULL) { LOG_PRINT(LOG_WARNING, "strlen(dir) is 0 or dir is NULL."); return -1; } memset(tmp, 0, sizeof(tmp)); strncpy(tmp, dir, strlen(dir)); if (tmp[0] == '/' && tmp[1]== '/') p = strchr(tmp + 2, '/'); else p = strchr(tmp, '/'); if (p) { *p = '\0'; mkdir(tmp,0777); chdir(tmp); } else { mkdir(tmp,0777); chdir(tmp); return 1; } mk_dirs(p + 1); return 1; }
/** * @brief main The entrance of zimg. * * @param argc Count of args. * @param argv Arg list. * * @return It returns a int to system. */ int main(int argc, char **argv) { /* Set signal handlers */ sigset_t sigset; sigemptyset(&sigset); struct sigaction siginfo = { .sa_sigaction = &sighandler, .sa_mask = sigset, .sa_flags = SA_RESTART, }; sigaction(SIGINT, &siginfo, NULL); sigaction(SIGTERM, &siginfo, NULL); if (argc < 2) { usage(argc, argv); return -1; } settings_init(); int i; for (i = 1; i < argc; i++) { if (strcmp(argv[i], "-d") == 0) { settings.is_daemon = 1; } else { conf_file = argv[i]; } } if (conf_file == NULL) { usage(argc, argv); return -1; } if (is_file(conf_file) == -1) { fprintf(stderr, "'%s' is not a file or not exists!\n", conf_file); return -1; } if (load_conf(conf_file) == -1) { fprintf(stderr, "'%s' load failed!\n", conf_file); return -1; } if (bind_check(settings.port) == -1) { fprintf(stderr, "Port %d bind failed!\n", settings.port); return -1; } if (settings.is_daemon == 1) { if (daemon(1, 1) < 0) { fprintf(stderr, "Create daemon failed!\n"); return -1; } else { fprintf(stdout, "zimg %s\n", settings.version); fprintf(stdout, "Copyright (c) 2013-2014 zimg.buaa.us\n"); fprintf(stderr, "\n"); } } //init the Path zimg need to use. //start log module... ./log/zimg.log if (mk_dirf(settings.log_name) != 1) { fprintf(stderr, "%s log path create failed!\n", settings.log_name); return -1; } log_init(); if (settings.script_name[0] != '\0') { if (is_file(settings.script_name) == -1) { fprintf(stderr, "%s open failed!\n", settings.script_name); return -1; } settings.script_on = 1; } if (is_dir(settings.img_path) != 1) { if (mk_dirs(settings.img_path) != 1) { LOG_PRINT(LOG_DEBUG, "img_path[%s] Create Failed!", settings.img_path); fprintf(stderr, "%s Create Failed!\n", settings.img_path); return -1; } } LOG_PRINT(LOG_DEBUG, "Paths Init Finished."); if (settings.mode == 2) { LOG_PRINT(LOG_DEBUG, "Begin to Test Memcached Connection..."); memcached_st *beans = memcached_create(NULL); char mserver[32]; snprintf(mserver, 32, "%s:%d", settings.beansdb_ip, settings.beansdb_port); memcached_server_st *servers = memcached_servers_parse(mserver); servers = memcached_servers_parse(mserver); memcached_server_push(beans, servers); memcached_server_list_free(servers); memcached_behavior_set(beans, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, 0); memcached_behavior_set(beans, MEMCACHED_BEHAVIOR_NO_BLOCK, 1); memcached_behavior_set(beans, MEMCACHED_BEHAVIOR_TCP_KEEPALIVE, 1); LOG_PRINT(LOG_DEBUG, "beansdb Connection Init Finished."); if (set_cache(beans, "zimg", "1") == -1) { LOG_PRINT(LOG_DEBUG, "Beansdb[%s] Connect Failed!", mserver); fprintf(stderr, "Beansdb[%s] Connect Failed!\n", mserver); memcached_free(beans); return -1; } else { LOG_PRINT(LOG_DEBUG, "beansdb connected to: %s", mserver); } memcached_free(beans); } else if (settings.mode == 3) { redisContext* c = redisConnect(settings.ssdb_ip, settings.ssdb_port); if (c->err) { redisFree(c); LOG_PRINT(LOG_DEBUG, "Connect to ssdb server faile"); fprintf(stderr, "SSDB[%s:%d] Connect Failed!\n", settings.ssdb_ip, settings.ssdb_port); return -1; } else { LOG_PRINT(LOG_DEBUG, "Connect to ssdb server Success"); } } //init magickwand MagickCoreGenesis((char *) NULL, MagickFalse); /* ExceptionInfo *exception=AcquireExceptionInfo(); MagickInfo *jpeg_info = (MagickInfo *)GetMagickInfo("JPEG", exception); if(jpeg_info->thread_support != MagickTrue) LOG_PRINT(LOG_DEBUG, "thread_support != MagickTrue"); jpeg_info->thread_support = MagickTrue; if(jpeg_info->thread_support != MagickTrue) LOG_PRINT(LOG_DEBUG, "thread_support != MagickTrue"); MagickInfo *jpg_info = (MagickInfo *)GetMagickInfo("JPG", exception); jpg_info->thread_support = MagickTrue; */ int result = pthread_key_create(&gLuaStateKey, thread_lua_dtor); if (result != 0) { LOG_PRINT(LOG_ERROR, "Could not allocate TLS key for lua_State."); } //begin to start httpd... LOG_PRINT(LOG_DEBUG, "Begin to Start Httpd Server..."); LOG_PRINT(LOG_INFO, "zimg started"); evbase = event_base_new(); evhtp_t *htp = evhtp_new(evbase, NULL); evhtp_set_cb(htp, "/dump", dump_request_cb, NULL); evhtp_set_cb(htp, "/upload", post_request_cb, NULL); evhtp_set_cb(htp, "/admin", admin_request_cb, NULL); evhtp_set_cb(htp, "/info", info_request_cb, NULL); evhtp_set_cb(htp, "/echo", echo_cb, NULL); evhtp_set_gencb(htp, get_request_cb, NULL); #ifndef EVHTP_DISABLE_EVTHR evhtp_use_threads(htp, init_thread, settings.num_threads, NULL); #endif evhtp_set_max_keepalive_requests(htp, settings.max_keepalives); evhtp_bind_socket(htp, settings.ip, settings.port, settings.backlog); event_base_loop(evbase, 0); evhtp_unbind_socket(htp); //evhtp_free(htp); event_base_free(evbase); free_headers_conf(settings.headers); free_access_conf(settings.up_access); free_access_conf(settings.down_access); free_access_conf(settings.admin_access); free(settings.mp_set); return 0; }
/** * @brief save_img Save buffer from POST requests * * @param thr_arg Thread arg struct. * @param buff The char * from POST request * @param len The length of buff * @param md5 Parsed md5 from url * * @return 1 for success and -1 for fail */ int save_img(thr_arg_t *thr_arg, const char *buff, const int len, char *md5) { int result = -1; LOG_PRINT(LOG_DEBUG, "Begin to Caculate MD5..."); md5_state_t mdctx; md5_byte_t md_value[16]; char md5sum[33]; int i; int h, l; md5_init(&mdctx); md5_append(&mdctx, (const unsigned char*)(buff), len); md5_finish(&mdctx, md_value); for(i=0; i<16; ++i) { h = md_value[i] & 0xf0; h >>= 4; l = md_value[i] & 0x0f; md5sum[i * 2] = (char)((h >= 0x0 && h <= 0x9) ? (h + 0x30) : (h + 0x57)); md5sum[i * 2 + 1] = (char)((l >= 0x0 && l <= 0x9) ? (l + 0x30) : (l + 0x57)); } md5sum[32] = '\0'; strcpy(md5, md5sum); LOG_PRINT(LOG_DEBUG, "md5: %s", md5sum); char cache_key[CACHE_KEY_SIZE]; char save_path[512]; char save_name[512]; gen_key(cache_key, md5sum, 0); if(exist_cache(thr_arg, cache_key) == 1) { LOG_PRINT(LOG_DEBUG, "File Exist, Needn't Save."); result = 1; goto done; } LOG_PRINT(LOG_DEBUG, "exist_cache not found. Begin to Save File."); if(settings.mode != 1) { if(save_img_db(thr_arg, cache_key, buff, len) == -1) { LOG_PRINT(LOG_DEBUG, "save_img_db failed."); goto done; } else { LOG_PRINT(LOG_DEBUG, "save_img_db succ."); result = 1; goto done; } } //caculate 2-level path int lvl1 = str_hash(md5sum); int lvl2 = str_hash(md5sum + 3); snprintf(save_path, 512, "%s/%d/%d/%s", settings.img_path, lvl1, lvl2, md5sum); LOG_PRINT(LOG_DEBUG, "save_path: %s", save_path); if(is_dir(save_path) == 1) { LOG_PRINT(LOG_DEBUG, "Check File Exist. Needn't Save."); goto cache; } if(mk_dirs(save_path) == -1) { LOG_PRINT(LOG_DEBUG, "save_path[%s] Create Failed!", save_path); goto done; } LOG_PRINT(LOG_DEBUG, "save_path[%s] Create Finish.", save_path); snprintf(save_name, 512, "%s/0*0", save_path); LOG_PRINT(LOG_DEBUG, "save_name-->: %s", save_name); if(new_img(buff, len, save_name) == -1) { LOG_PRINT(LOG_DEBUG, "Save Image[%s] Failed!", save_name); goto done; } cache: if(len < CACHE_MAX_SIZE) { gen_key(cache_key, md5sum, 0); set_cache_bin(thr_arg, cache_key, buff, len); } result = 1; done: return result; }
/** * @brief save_img Save buffer from POST requests * * @param buff The char * from POST request * @param len The length of buff * @param md5 Parsed md5 from url * * @return ZIMG_OK for success and ZIMG_ERR for fail */ int save_img(const char *buff, const int len, char *md5sum){ if(buff == NULL || md5sum == NULL || len <=0){ return ZIMG_ERR; } const char *image_format = get_img_format(buff); if(image_format == NULL){ return ZIMG_ERR; } calc_md5sum(buff,len,md5sum); char cache_key[45]; sprintf(cache_key, "img:%s:0:0:1:0", md5sum); if(exist_cache(cache_key) == 1){ LOG_PRINT(LOG_INFO, "File Exist, Needn't Save."); return ZIMG_OK; } LOG_PRINT(LOG_INFO, "exist_cache not found. Begin to Check File."); char *save_path = (char *)malloc(512); if(save_path == NULL){ return ZIMG_ERR; } //caculate 2-level path int lvl1 = str_hash(md5sum); int lvl2 = str_hash(md5sum + 3); sprintf(save_path, "%s/%d/%d/%s/0*0p", settings.img_path, lvl1, lvl2, md5sum); LOG_PRINT(LOG_INFO, "save_path: %s", save_path); if(is_file(save_path) == ZIMG_OK){ LOG_PRINT(LOG_INFO, "Check File Exist. Needn't Save."); //cache if(len < CACHE_MAX_SIZE) { // to gen cache_key like this: rsp_path-/926ee2f570dc50b2575e35a6712b08ce set_cache_bin(cache_key, buff, len); } free(save_path); return ZIMG_OK; }else{ char *p = strrchr(save_path,'/'); *p = '\0'; if(mk_dirs(save_path) == ZIMG_ERR){ LOG_PRINT(LOG_ERROR, "save_path[%s] Create Failed!", save_path); free(save_path); return ZIMG_ERR; } chdir(_init_path); LOG_PRINT(LOG_INFO, "save_path[%s] Create Finish.", save_path); *p = '/'; LOG_PRINT(LOG_INFO, "save_name-->: %s", save_path); if(new_img(buff, len, save_path) != ZIMG_OK){ LOG_PRINT(LOG_WARNING, "Save Image[%s] Failed!", save_path); free(save_path); return ZIMG_ERR; } //shrink as JPEG p = strrchr(save_path,'/'); memcpy(p+1,"0.jpg",5); *(p + 6) = '\0'; if(convert2jpg(buff,len,save_path) == ZIMG_OK){ LOG_PRINT(LOG_WARNING, "Convert Image to JPEG [%s] OK!", save_path); } free(save_path); return ZIMG_OK; } }