📄 http.c
字号:
fprintf (stderr, "alloc memory failure.\n"); goto __FUNCTION__free_buffer; } } *(url + MAX_LEN_URL_HTTP + 8) = '\0'; if (-1 == get_redirect_url (buf, url, (MAX_LEN_URL_HTTP + 8))) { fprintf (stderr, "redirect error.\n"); goto __FUNCTION__close_fd_connect; } goto __FUNCTION__redirect; } else { p = strstr (buf, "\r\n"); *p = '\0'; fprintf (stderr, "%s.\n", buf); } __FUNCTION__close_fd_connect: close (fd_sock); __FUNCTION__free_buffer: free (buf); if (0 != redirect) free (url); __FUNCTION__return: return retval;}void *recv_response_get_file (void *const args){ int fd_epoll; struct epoll_event event; char *buffer_recv; const size_t size_buffer = 4096; struct file_range *fr; ssize_t nbytes_recv; char *file_name; int retval = -1; char *p; int fd; int fd_write; struct command cmd_thread_state; unsigned int connects_num = (unsigned int) args; /* create file. */ file_name = base_name (resource.path); if (-1 == (fd_write = open (file_name, O_CREAT | O_TRUNC | O_WRONLY , 0666))) { perror ("Error Create file"); goto __FUNCTION__exit; } /* alloc memory for receive data. */ if (NULL == (buffer_recv = calloc (size_buffer, 1))) { perror ("Error alloc memory"); goto __FUNCTION__close_fd_write; } /* create epoll file descriptor. */ if (-1 == (fd_epoll = epoll_create ((connects_num + 1)))) { perror ("Error create poll"); goto __FUNCTION__free_buffer_recv; } /* setup epoll event. */ if (-1 == epoll_add (fd_epoll, pipe_recv_send[0])) { perror ("Error poll file"); goto __FUNCTION__close_fd_epoll; } /* ready! */ cmd_thread_state.value = CMD_OK; send_cmd (&cmd_thread_state); /* print information of resource. */ print_resource_info (); /* receive data. */ while (1) { if (-1 == epoll_wait_restart (fd_epoll, &event, 1, -1)) { perror ("Error poll wait"); goto __FUNCTION__close_connects; } fd = event.data.fd; /* connection is readable. */ if (pipe_recv_send[0] != fd) { fr = fd_to_file_range (fd); if (1 != readable (&event)) { retry (fd_epoll, fr); continue; } /* read data. */ nbytes_recv = recv_restart (fd, (void *)buffer_recv, \ (size_buffer - 1), MSG_DONTWAIT); if ((-1 == nbytes_recv) || (0 == nbytes_recv)) { if (-1 == nbytes_recv) retry (fd_epoll, fr); continue; } /* adjust point to content. */ if (1 != (*fr).recv) { if ((0 != strncmp (buffer_recv, RES_RANGE_1_0, LEN_RES_RANGE)) &&\ (0 != strncmp (buffer_recv, RES_RANGE_1_1, LEN_RES_RANGE))) { fprintf (stderr, "Invalid response.\n"); goto __FUNCTION__close_connects; } *(buffer_recv + nbytes_recv) = '\0'; if (NULL == (p = strstr (buffer_recv, CONTENT_PFIX))) continue; p += LEN_CONTENT_PFIX; nbytes_recv -=(p - buffer_recv); (*fr).recv = 1; } else p = buffer_recv; /* write. */ lseek (fd_write, (*fr).offset, SEEK_SET); if (-1 == write_restart (fd_write, p, nbytes_recv)) { perror ("Error write file"); goto __FUNCTION__close_connects; } /* update file range. */ update_file_range (fr, nbytes_recv); if (0 == (*fr).nbytes) close_connect (fd_epoll, fr); /* display result. */ if (1 == print_result (nbytes_recv)) { retval = 0; goto __FUNCTION__close_connects; } } /* new connection. */ else { /* readable. */ if (1 != readable (&event)) { fprintf (stderr, "Error read pipe.\n"); goto __FUNCTION__close_connects; } /* get fd of new connection. */ if (NULL == (fr = get_new_connect (fd))) goto __FUNCTION__close_connects; /* add poll. */ if (-1 == epoll_add (fd_epoll, (*fr).fd)) goto __FUNCTION__close_connects; } } __FUNCTION__close_connects: close_connects (fd_epoll); __FUNCTION__close_fd_epoll: close_restart (fd_epoll); __FUNCTION__free_buffer_recv: free (buffer_recv); __FUNCTION__close_fd_write: if (0 != retval) remove (file_name); else fsync (fd_write); close_restart (fd_write); __FUNCTION__exit: cmd_thread_state.value = CMD_DONE; if (-1 == retval) cmd_thread_state.value = CMD_ERR; send_cmd (&cmd_thread_state); return (void *)retval;}int print_result (size_t nbytes_read){ static int count_read = 0; static size_t nbytes_done = 0; nbytes_done += nbytes_read; if (nbytes_done == resource.size) { fprintf (stdout, " 100%%\n"); fprintf (stdout, "Success download.\n"); return 1; } count_read++; if (COUNT_READ > count_read) { fprintf (stdout, " . "); fflush (stdout); fsync (STDOUT_FILENO); return 0; } fprintf (stdout, " %2d%% / ",((nbytes_done * 100) / resource.size)); print_size_human ((resource.size - nbytes_done)); fflush (stdout); fsync (STDOUT_FILENO); count_read = 0; return 0;}void print_size_human (size_t size){ if (size > MB) fprintf (stdout, "%.1f M\n", ((float) size / MB)); else if (size > KB) fprintf (stdout, "%.1f K\n", ((float) size / KB)); else fprintf (stdout, "%u b\n", size);}void print_resource_size (){ fprintf (stdout, "File size: "); print_size_human (resource.size);}void print_resource_info (){ /* resource name. */ fprintf (stdout, "File name: %s.\n", base_name (resource.path)); print_resource_size (); }struct file_range *get_new_connect (int fd){ struct file_range *fr = NULL; while ((-1 == read (fd, &fr, sizeof (struct file_range *))) && (EINTR == errno)); return fr;}inline int readable (struct epoll_event *event){ return (EPOLLIN & (*event).events);}/* define function for epoll.*/int epoll_add (int fd_epoll, int fd_add){ struct epoll_event event; int retval; bzero (&event, sizeof (struct epoll_event)); event.events |= EPOLLIN; event.data.fd = fd_add; retval = epoll_ctl (fd_epoll, EPOLL_CTL_ADD, fd_add, &event); if (-1 == retval) perror ("Error add poll file"); return retval;} void epoll_remove (int fd_epoll, int fd_remove){ epoll_ctl (fd_epoll, EPOLL_CTL_DEL, fd_remove, NULL);}/* define function to operate global struct command `cmd' */void clear_cmd (struct command *const p_cmd){ (*p_cmd).value = 0; (*p_cmd).opt = NULL;}void wait_cmd (struct command *const p_cmd){ pthread_mutex_lock (&mutex_cmd); if (0 == cmd.value) pthread_cond_wait (&cond_cmd_set, &mutex_cmd); *p_cmd = cmd; clear_cmd (&cmd); pthread_cond_signal (&cond_cmd_clear); pthread_mutex_unlock (&mutex_cmd);}void send_cmd (const struct command *p_cmd){ pthread_mutex_lock (&mutex_cmd); if (0 != cmd.value) pthread_cond_wait (&cond_cmd_set, &mutex_cmd); clear_cmd (&cmd); cmd = *p_cmd; pthread_cond_signal (&cond_cmd_set); pthread_mutex_unlock (&mutex_cmd);}void retry (int fd_epoll, struct file_range *const fr){ struct command cmd_retry; close_connect (fd_epoll, fr); cmd_retry.value = CMD_RETRY; cmd_retry.opt = (void *) fr; send_cmd (&cmd_retry);} void close_connects (int fd_epoll){ size_t i = 0; int fd; while (i < CONNECTS_NUM) { fd = (*(files_range + i)).fd; if (-1 != fd) close_connect (fd_epoll, (files_range + i)); i++; }}void close_connect (const int fd_epoll, struct file_range *const fr){ int fd; fd = (*fr).fd; epoll_remove (fd_epoll, fd); close_restart (fd); clear_file_range (fr);}void clear_file_range (struct file_range *fr){ bzero (fr, sizeof (struct file_range)); (*fr).fd = -1;} void update_file_range (struct file_range *fr, size_t nbytes){ (*fr).offset += nbytes; (*fr).nbytes -= nbytes;} struct file_range *fd_to_file_range (int fd){ int i = 0; struct file_range *fr = NULL; while (i < CONNECTS_NUM) { if (fd == (*(files_range + i)).fd) fr = (files_range + i); i++; } return fr;}extern void *send_request_get_file (void *const p_file_range){ int fd_sock; char range[64]; struct file_range *fr; int sockopt; size_t last; struct command cmd_retry; fr = (struct file_range *) p_file_range; bzero (range, sizeof (range)); last = (*fr).offset + (*fr).nbytes - 1; snprintf (range, (sizeof(range) - 1), "Range: bytes=%u-%u\r\n\r\n", \ (unsigned int) (*fr).offset, (unsigned int) last); if (-1 == (fd_sock = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP))) goto __FUNCTION__retry; if (-1 == connect (fd_sock, (struct sockaddr *) &resource.sockaddr, SIZE_SOCKADDR)) goto __FUNCTION__retry; if (-1 == send_restart (fd_sock, "GET ", strlen ("GET "), MSG_MORE)) goto __FUNCTION__retry; if (-1 == send_restart (fd_sock, (void *) resource.path, resource.len_path, MSG_MORE)) goto __FUNCTION__retry; if (-1 == send_restart (fd_sock, " HTTP/1.0\r\n", strlen (" HTTP/1.0\r\n"), MSG_MORE)) goto __FUNCTION__retry; if (-1 == send_restart (fd_sock, range, strlen(range), 0)) goto __FUNCTION__retry; sockopt = 1; setsockopt (fd_sock, SOL_SOCKET, TCP_NODELAY, (void *) &sockopt, SIZE_INT); (*fr).recv = 0; (*fr).fd = fd_sock; if (-1 == fd_sock) goto __FUNCTION__retry; while (-1 == write (pipe_recv_send[1], &fr, sizeof (struct file_range *))) { if (EINTR == errno) continue; else goto __FUNCTION__retry; } return NULL; __FUNCTION__retry: cmd_retry.value = CMD_RETRY; cmd_retry.opt = fr; send_cmd (&cmd_retry); return NULL;}size_t c_stolower (char *const s){ size_t len_s; len_s = strlen (s); return c_ntolower (s, len_s);}size_t c_ntolower (char *const s, size_t n){ size_t i; if (NULL == s) return 0; i = 0; do if ('\0' == c_tolower (s + i)) break; while (i++ < n); return i;}char c_tolower (char *const c){ return (C_ISUPPER (*c))? (*c = (*c | 32)): (*c);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -