/** * @brief xor hash specified block * * @see * @note * @author auxten <*****@*****.**> * @date 2011-8-1 **/ unsigned xor_hash_block(s_job_t * jo, GKO_INT64 block_id, u_char * buf) { s_file_t * files = jo->files; s_block_t * blocks = jo->blocks; GKO_INT64 read_counter = 0; GKO_INT64 file_i = (blocks + block_id)->start_f; GKO_INT64 offset = 0; int fd; unsigned tmp_hash = 0; if (FAIL_CHECK(-1 == (fd = open((files + ((blocks + block_id)->start_f))->name, O_RDONLY | O_NOFOLLOW)))) { GKOLOG(WARNING, "file open() error!"); } memset(buf, 0, BLOCK_SIZE); offset = (blocks + block_id)->start_off; while (read_counter < (blocks + block_id)->size) { GKO_INT64 tmp = pread(fd, buf + read_counter, (blocks + block_id)->size - read_counter, offset); if (FAIL_CHECK(tmp < 0)) { GKOLOG(WARNING, "pread failed"); } if (LIKELY(tmp)) { ///printf("read: %ld\n", tmp); tmp_hash = xor_hash(buf + read_counter, (int) tmp, tmp_hash); read_counter += tmp; offset += tmp; } else { close(fd); ///if the next if a nonfile then next file_i = next_f(jo, file_i); if (FAIL_CHECK(-1 == (fd = open( (files + ((blocks + block_id)->start_f) + file_i)->name, O_RDONLY | O_NOFOLLOW)))) { fprintf(stderr, "filename: %s\n", (files + ((blocks + block_id)->start_f) + file_i)->name); GKOLOG(WARNING, "filename: %s", (files + ((blocks + block_id)->start_f) + file_i)->name); } offset = 0; } } (blocks + block_id)->digest = tmp_hash; /// printf("buf: %d\n", sizeof(buf)); /// memset(buf, 0, sizeof(buf)); /// printf("buf: %d\n", sizeof(buf)); close(fd); return tmp_hash; }
/** * @brief xor hash the file given * * @see * @note * @author auxten <*****@*****.**> * @date 2011-8-1 **/ unsigned xor_hash_file(unsigned value, FILE * fd, off_t * off, size_t * count, u_char * buf) { fseeko(fd, *off, SEEK_SET); if (FAIL_CHECK(*count != fread(buf, sizeof(char), *count, fd))) { GKOLOG(FATAL, "fread error"); } ///fprintf(stderr, "#######################buf: %s\n", buf); return xor_hash(buf, *count, value); }
/** * @brief gracefully close a socket, for client side * * @see * @note * @author auxten <*****@*****.**> <*****@*****.**> * @date 2011-8-1 **/ int close_socket(int sock) { /// if (shutdown(sock, 2)) { /// gko_log(WARNING, "shutdown sock error"); /// return -1; /// } // struct linger so_linger; // so_linger.l_onoff = 1; /// close right now, no time_wait at serv // so_linger.l_linger = 0; /// at most wait for 1s // if (FAIL_CHECK(setsockopt(sock, SOL_SOCKET, SO_LINGER, &so_linger, sizeof(so_linger)))) // { // gko_log(WARNING, "set so_linger failed"); // } if (FAIL_CHECK(close(sock))) { gko_log(WARNING, "close sock error"); return -1; } return 0; }
/** * @brief connect to a host * * @see * @note * h: pointer to s_host_t * recv_sec: receive timeout seconds, 0 for never timeout * return the socket when succ * return < 0 when error, specially HOST_DOWN_FAIL indicate host dead * @author auxten <*****@*****.**> <*****@*****.**> * @date 2011-8-1 **/ int connect_host(s_host_t * h, int recv_sec, int send_sec) { int sock = -1; int ret; int select_ret; int res; socklen_t res_size = sizeof res; struct sockaddr_in channel; in_addr_t host; int addr_len; struct timeval recv_timeout; struct timeval send_timeout; #if HAVE_POLL #else fd_set wset; #endif /* HAVE_POLL */ addr_len = getaddr_my(h->addr, &host); if (FAIL_CHECK(!addr_len)) { gko_log(WARNING, "gethostbyname %s error", h->addr); ret = -1; goto CONNECT_END; } sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (FAIL_CHECK(sock < 0)) { gko_log(WARNING, "get socket error"); ret = -1; goto CONNECT_END; } recv_timeout.tv_usec = 0; recv_timeout.tv_sec = recv_sec ? recv_sec : RCV_TIMEOUT; send_timeout.tv_usec = 0; send_timeout.tv_sec = send_sec ? send_sec : SND_TIMEOUT; memset(&channel, 0, sizeof(channel)); channel.sin_family = AF_INET; memcpy(&channel.sin_addr.s_addr, &host, addr_len); channel.sin_port = htons(h->port); /** set the connect non-blocking then blocking for add timeout on connect **/ if (FAIL_CHECK(setnonblock(sock) < 0)) { gko_log(WARNING, "set socket non-blocking error"); ret = -1; goto CONNECT_END; } /** connect and send the msg **/ if (FAIL_CHECK(connect(sock, (struct sockaddr *) &channel, sizeof(channel)) && errno != EINPROGRESS)) { gko_log(WARNING, "connect error"); ret = HOST_DOWN_FAIL; goto CONNECT_END; } /** Wait for write bit to be set **/ #if HAVE_POLL { struct pollfd pollfd; pollfd.fd = sock; pollfd.events = POLLOUT; /* send_sec is in seconds, timeout in ms */ select_ret = poll(&pollfd, 1, (int)(send_sec * 1000 + 1)); } #else { FD_ZERO(&wset); FD_SET(sock, &wset); select_ret = select(sock + 1, 0, &wset, 0, &send_timeout); } #endif /* HAVE_POLL */ if (select_ret < 0) { gko_log(WARNING, "select/poll error on connect"); ret = HOST_DOWN_FAIL; goto CONNECT_END; } if (!select_ret) { gko_log(WARNING, "connect timeout on connect"); ret = HOST_DOWN_FAIL; goto CONNECT_END; } /** * check if connection is RESETed, maybe this is the * best way to do that * SEE: http://cr.yp.to/docs/connect.html **/ (void) getsockopt(sock, SOL_SOCKET, SO_ERROR, &res, &res_size); if (CONNECT_DEST_DOWN(res)) { // gko_log(NOTICE, "connect dest is down errno: %d", res); ret = HOST_DOWN_FAIL; goto CONNECT_END; } ///gko_log(WARNING, "selected %d ret %d, time %d", sock, select_ret, send_timeout.tv_sec); /** set back blocking **/ if (FAIL_CHECK(setblock(sock) < 0)) { gko_log(WARNING, "set socket non-blocking error"); ret = -1; goto CONNECT_END; } /** set recv & send timeout **/ if (FAIL_CHECK(setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *) &recv_timeout, sizeof(struct timeval)))) { gko_log(WARNING, "setsockopt SO_RCVTIMEO error"); ret = -1; goto CONNECT_END; } if (FAIL_CHECK(setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char *) &send_timeout, sizeof(struct timeval)))) { gko_log(WARNING, "setsockopt SO_SNDTIMEO error"); ret = -1; goto CONNECT_END; } ret = sock; CONNECT_END: /// if (ret < 0 && sock >= 0) { close_socket(sock); } return ret; }
/** * @brief convert the remote path recv from JOIN to local path * * @see * @note * @author auxten <*****@*****.**> * @date 2011-8-1 **/ int process_path(s_job_t * jo) { char out_path[MAX_PATH_LEN] = {'\0'}; strncpy(out_path, jo->path, MAX_PATH_LEN); inplace_strip_tailing_slash(out_path); int out_type = path_type(out_path); if (out_type & GKO_NONE) {/** non-existed dest or dest is symlink to non-existed **/ if (out_type & GKO_LINK) {/** dest is symlink to non-existed **/ GKOLOG(FATAL, "destination: '%s' is a symlink to non-exist", out_path); return -1; } else if ((jo->file_count == 1 && jo->files->size >= 0) && (jo->path)[strlen(jo->path) - 1] == '/') {/** dest is a non existed dir path like './non/' but job is a singal file **/ GKOLOG(FATAL, "downloading a file to non existed path '%s'", jo->path); return -1; } else { /** non-existed dest **/ /** determine if the base dir is existed **/ char out_base_path[MAX_PATH_LEN]; //strncpy(out_base_path, out_path, MAX_PATH_LEN); cwd_path_to_abs_path(out_base_path, out_path); int base_idx = get_base_name_index(NULL, out_base_path); if (base_idx < 0) { GKOLOG(FATAL, "process_path failed"); return -1; } out_base_path[base_idx] = '\0'; int out_base_type = path_type(out_base_path); if (out_base_type & GKO_DIR) {/** out base path is a dir or symlink to dir **/ for (int i = 0; i < jo->file_count; i++) { if (FAIL_CHECK( change_to_local_path((jo->files + i)->name, jo->uri, out_path, 0))) { GKOLOG( FATAL, "change to local path error, name: '%s', uri: '%s', path: '%s'", (jo->files + i)->name, jo->uri, out_path); return -1; } //GKOLOG(NOTICE, "path: '%s'", (jo->files + i)->name); } return 0; } else {/** out base path is not dir, nor symlink to dir **/ GKOLOG(FATAL, "base path: '%s' is non-dir", out_base_path); return -1; } } } else {/** dest path existed **/ if (out_type & GKO_FILE) {/** dest path is file or symlink to file **/ if (jo->file_count == 1) { if ((jo->files)->size == -1) {/** dest path is dir **/ GKOLOG(FATAL, "can't overwrite dir: '%s' on file: '%s'", (jo->files)->name, out_path); return -1; } else if ((jo->files)->size == -2) {/** dest path is symlink **/ GKOLOG(FATAL, "can't overwrite symlink: '%s' on file: '%s'", (jo->files)->name, out_path); return -1; } else {/** dest path is file **/ strncpy((jo->files)->name, out_path, MAX_PATH_LEN); return 0; } } else { /** file count != 1, indicating that job is a dir, dest is a existed file **/ GKOLOG(FATAL, "can't overwrite dir: '%s' on file: '%s'", (jo->files)->name, out_path); return -1; } } else if (out_type & GKO_DIR) {/** dest is a existed dir **/ for (int i = 0; i < jo->file_count; i++) { if (FAIL_CHECK(change_to_local_path((jo->files + i)->name, jo->uri, out_path, 1))) { GKOLOG( FATAL, "change to local path error, name: '%s', uri: '%s', path: '%s'", (jo->files + i)->name, jo->uri, out_path); return -1; } } return 0; } else {/** dest is non-regular file or dir **/ GKOLOG(FATAL, "the dest: '%s' is non-regular file or dir", out_path); return -1; } } return 0; }