/* * Use the sendfile systemcall to move size bytes data from * source to dest. This works only if source is a regular * file and dest is a socket. If size is -1 data will be * moved until the end of source is reached. Source and dest * must be given as Integer. */ VALUE t_sendfile(VALUE self, VALUE in, VALUE out, VALUE size) { int s, d; int si; s= NUM2INT(in); d= NUM2INT(out); si= NUM2INT(size); //deactivate O_NONBLOCK int flags_s= fcntl(s, F_GETFL); int flags_d= fcntl(d, F_GETFL); fcntl(s, F_SETFL, 0); fcntl(d, F_SETFL, 0); size_t last; size_t send= 0; if (size == -1) { // send everything while ((last= do_sendfile(d, s, SENDFILE_MAX)) < 0) send+= last; } else { // send only the bytes requested while (si > 0) { last= do_sendfile(d, s, min(si, SENDFILE_MAX)); send+= last; if (last == 0) // the end of the file break; } } fcntl(s, F_SETFL, flags_s); fcntl(d, F_SETFL, flags_d); return INT2NUM(send); }
asmlinkage ssize_t sys_sendfile64(int out_fd, int in_fd, loff_t __user *offset, size_t count) { loff_t pos; ssize_t ret; if (offset) { if (unlikely(copy_from_user(&pos, offset, sizeof(loff_t)))) return -EFAULT; ret = do_sendfile(out_fd, in_fd, &pos, count, 0); if (unlikely(put_user(pos, offset))) return -EFAULT; return ret; } return do_sendfile(out_fd, in_fd, NULL, count, 0); }
SYSCALL_DEFINE4(sendfile64, int, out_fd, int, in_fd, loff_t __user *, offset, size_t, count) { loff_t pos; ssize_t ret; if (offset) { if (unlikely(copy_from_user(&pos, offset, sizeof(loff_t)))) return -EFAULT; ret = do_sendfile(out_fd, in_fd, &pos, count, 0); if (unlikely(put_user(pos, offset))) return -EFAULT; return ret; } return do_sendfile(out_fd, in_fd, NULL, count, 0); }
int main(int ac, char **av) { int i; int lc; char *msg; /* parse_opts() return message */ if ((msg = parse_opts(ac, av, NULL, NULL)) != NULL) { tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg); } #ifdef UCLINUX argv0 = av[0]; maybe_run_child(&do_child, ""); #endif setup(); /* * The following loop checks looping state if -c option given */ for (lc = 0; TEST_LOOPING(lc); lc++) { tst_count = 0; for (i = 0; i < TST_TOTAL; ++i) { do_sendfile(testcases[i].protection, testcases[i].pass_unmapped_buffer); } } cleanup(); tst_exit(); }
int main(int ac, char **av) { int i; int lc; /* loop counter */ char *msg; /* parse_opts() return message */ if ((msg = parse_opts(ac, av, (option_t *) NULL, NULL)) != (char *)NULL) { tst_brkm(TBROK, tst_exit, "OPTION PARSING ERROR - %s", msg); /*NOTREACHED*/} #ifdef UCLINUX argv0 = av[0]; maybe_run_child(&do_child, ""); #endif setup(); /* * The following loop checks looping state if -c option given */ for (lc = 0; TEST_LOOPING(lc); lc++) { Tst_count = 0; for (i = 0; i < TST_TOTAL; ++i) { do_sendfile(testcases[i].offset, i); } } cleanup(); /*NOTREACHED*/ return 0; }
int main(int ac, char **av) { int lc; char *msg; /* parse_opts() return message */ if ((msg = parse_opts(ac, av, NULL, NULL)) != NULL) { tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg); } #ifdef UCLINUX argv0 = av[0]; maybe_run_child(&do_child, ""); #endif setup(); /* * The following loop checks looping state if -c option given */ for (lc = 0; TEST_LOOPING(lc); lc++) { tst_count = 0; do_sendfile(); } cleanup(); tst_exit(); }
int main(int ac, char **av) { int i; int lc; tst_parse_opts(ac, av, NULL, NULL); #ifdef UCLINUX argv0 = av[0]; maybe_run_child(&do_child, ""); #endif setup(); /* * The following loop checks looping state if -c option given */ for (lc = 0; TEST_LOOPING(lc); lc++) { tst_count = 0; for (i = 0; i < TST_TOTAL; ++i) { do_sendfile(testcases[i].protection, testcases[i].pass_unmapped_buffer); } } cleanup(); tst_exit(); }
static write_state on_write_sendfile(struct ev_loop* mainloop, Request* request) { /* A sendfile response is split into two phases: * Phase A) sending HTTP headers * Phase B) sending the actual file contents */ if(request->current_chunk) { /* Phase A) -- current_chunk contains the HTTP headers */ if (do_send_chunk(request)) { // data left to send in the current chunk return not_yet_done; } else { assert(request->current_chunk == NULL); assert(request->current_chunk_p == 0); /* Transition to Phase B) -- abuse current_chunk_p to store the file fd */ request->current_chunk_p = PyObject_AsFileDescriptor(request->iterable); // don't stop yet, Phase B is still missing return not_yet_done; } } else { /* Phase B) -- current_chunk_p contains file fd */ if (do_sendfile(request)) { // Haven't reached the end of file yet return not_yet_done; } else { // Done with the file return done; } } }
asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t __user *offset, size_t count) { loff_t pos; off_t off; ssize_t ret; if (offset) { if (unlikely(get_user(off, offset))) return -EFAULT; pos = off; ret = do_sendfile(out_fd, in_fd, &pos, count, MAX_NON_LFS); if (unlikely(put_user(pos, offset))) return -EFAULT; return ret; } return do_sendfile(out_fd, in_fd, NULL, count, 0); }
SYSCALL_DEFINE4(sendfile, int, out_fd, int, in_fd, off_t __user *, offset, size_t, count) { loff_t pos; off_t off; ssize_t ret; if (offset) { if (unlikely(get_user(off, offset))) return -EFAULT; pos = off; ret = do_sendfile(out_fd, in_fd, &pos, count, MAX_NON_LFS); if (unlikely(put_user(pos, offset))) return -EFAULT; return ret; } return do_sendfile(out_fd, in_fd, NULL, count, 0); }
SYSCALL_DEFINE4(sendfile2, int, out_fd, int, in_fd, off_t __user *, offset, size_t, count) { loff_t pos; off_t off; ssize_t ret; struct fd in; in = fdget(in_fd); if(!in.file) return -EFAULT; in.file->f_flags |= O_SENDFILE2; if (offset) { if (unlikely(get_user(off, offset))) return -EFAULT; pos = off; ret = do_sendfile(out_fd, in_fd, &pos, count, MAX_NON_LFS); if (unlikely(put_user(pos, offset))) return -EFAULT; return ret; } return do_sendfile(out_fd, in_fd, NULL, count, 0); }
SYSCALL_DEFINE4(sendfile, int, out_fd, int, in_fd, off_t __user *, offset, size_t, count) { loff_t pos; off_t off; ssize_t ret; if (offset) { if (unlikely(get_user(off, offset))) return -EFAULT; pos = off; /* modified start pling 12/04/2009 */ #ifdef SAMBA_ENABLE ret = do_sendfile(out_fd, in_fd, &pos, count, (loff_t)0xFFFFFFFFUL); #else ret = do_sendfile(out_fd, in_fd, &pos, count, MAX_NON_LFS); #endif /* modified end pling 12/04/2009 */ if (unlikely(put_user(pos, offset))) return -EFAULT; return ret; } return do_sendfile(out_fd, in_fd, NULL, count, 0); }
int main(void) { struct stat stat; int fd,size; int client_sock; fd=open("./data",O_RDONLY); if (fstat(fd, &stat)) { perror("fstat\n"); exit(1); } size = stat.st_size; printf("file size = %d\n", size); client_sock = socket_create(); do_sendfile(client_sock, fd, 0, FILE_SIZE); close(client_sock); close(fd); return 0; }
int vsf_sysutil_sendfile(const int out_fd, const int in_fd, filesize_t* p_offset, filesize_t num_send, unsigned int max_chunk) { /* Grr - why is off_t signed? */ if (*p_offset < 0 || num_send < 0) { die("invalid offset or send count in vsf_sysutil_sendfile"); } if (max_chunk == 0) { max_chunk = INT_MAX; } while (num_send > 0) { int retval; unsigned int send_this_time; if (num_send > max_chunk) { send_this_time = max_chunk; } else { send_this_time = (unsigned int) num_send; } /* Keep input file position in line with sendfile() calls */ vsf_sysutil_lseek_to(in_fd, *p_offset); retval = do_sendfile(out_fd, in_fd, send_this_time, *p_offset); if (vsf_sysutil_retval_is_error(retval) || retval == 0) { return retval; } num_send -= retval; *p_offset += retval; } return 0; }
/* XXX too many gotos */ static void ev_io_on_write(struct ev_loop* mainloop, ev_io* watcher, const int events) { Request* request = REQUEST_FROM_WATCHER(watcher); GIL_LOCK(0); if(request->state.use_sendfile) { /* sendfile */ if(request->current_chunk) { /* current_chunk contains the HTTP headers */ if(send_chunk(request)) goto out; assert(!request->current_chunk_p); /* abuse current_chunk_p to store the file fd */ request->current_chunk_p = PyObject_AsFileDescriptor(request->iterable); goto out; } if(do_sendfile(request)) goto out; } else { /* iterable */ if(send_chunk(request)) goto out; if(request->iterator) { PyObject* next_chunk; next_chunk = wsgi_iterable_get_next_chunk(request); if(next_chunk) { if(request->state.chunked_response) { request->current_chunk = wrap_http_chunk_cruft_around(next_chunk); Py_DECREF(next_chunk); } else { request->current_chunk = next_chunk; } assert(request->current_chunk_p == 0); goto out; } else { if(PyErr_Occurred()) { PyErr_Print(); /* We can't do anything graceful here because at least one * chunk is already sent... just close the connection */ DBG_REQ(request, "Exception in iterator, can not recover"); ev_io_stop(mainloop, &request->ev_watcher); close(request->client_fd); Request_free(request); goto out; } Py_CLEAR(request->iterator); } } if(request->state.chunked_response) { /* We have to send a terminating empty chunk + \r\n */ request->current_chunk = PyString_FromString("0\r\n\r\n"); assert(request->current_chunk_p == 0); request->state.chunked_response = false; goto out; } } ev_io_stop(mainloop, &request->ev_watcher); if(request->state.keep_alive) { DBG_REQ(request, "done, keep-alive"); Request_clean(request); Request_reset(request); ev_io_init(&request->ev_watcher, &ev_io_on_read, request->client_fd, EV_READ); ev_io_start(mainloop, &request->ev_watcher); } else { DBG_REQ(request, "done, close"); close(request->client_fd); Request_free(request); } out: GIL_UNLOCK(0); }
static void io_write(Request* request) { //GIL_LOCK(0); if(request->state.use_sendfile) { dprint("发送文件给客户端"); /* sendfile */ if(request->current_chunk && send_chunk(request)) goto out; /* abuse current_chunk_p to store the file fd */ request->current_chunk_p = PyObject_AsFileDescriptor(request->iterable); if(do_sendfile(request)) goto out; } else { dprint("发送字符"); /* iterable */ if(send_chunk(request)){ dprint("一次发送即完成"); //uv_close((uv_handle_t*) &request->ev_watcher, _http_uv__on_close__cb); goto out; } if(request->iterator) { PyObject* next_chunk; dprint("request迭代"); next_chunk = wsgi_iterable_get_next_chunk(request); if(next_chunk) { dprint("下一块chunk发送"); if(request->state.chunked_response) { request->current_chunk = wrap_http_chunk_cruft_around(next_chunk); Py_DECREF(next_chunk); } else { request->current_chunk = next_chunk; } assert(request->current_chunk_p == 0); //io_write(request); goto out; } else { if(PyErr_Occurred()) { uv_err_t err; dprint("迭代出错"); PyErr_Print(); DBG_REQ(request, "Exception in iterator, can not recover"); uv_close((uv_handle_t*) request->ev_watcher, on_close); Request_free(request); err = uv_last_error(loop); UVERR(err, "uv_write error on next chunk"); ASSERT(0); goto out; } dprint("没有下一块chunk"); Py_CLEAR(request->iterator); } } if(request->state.chunked_response) { dprint("如果是chunked_response 发送收尾数据,并置空chunked_response"); /* We have to send a terminating empty chunk + \r\n */ request->current_chunk = PyString_FromString("0\r\n\r\n"); assert(request->current_chunk_p == 0); //io_write(request); request->state.chunked_response = false; goto out; } } dprint("响应完成"); if(request->state.keep_alive) { DBG_REQ(request, "done, keep-alive"); Request_clean(request); Request_reset(request); } else { dprint("done not keep alive"); uv_close((uv_handle_t*) request->ev_watcher, on_close); Request_free(request); } out: dprint("本次字符发送结束"); //GIL_UNLOCK(0); return; }