void* client_func(void* p) { pthread_mutex_lock(&mutex); int* arguments = (int*) p; int client_sd = arguments[0]; busy = FALSE; pthread_cond_signal(&thread_ready); pthread_mutex_unlock(&mutex); struct sockaddr_in client_addr; socklen_t addr_len = sizeof(client_addr); getpeername(client_sd, (struct sockaddr*) &client_addr, &addr_len); printf("s> accept %s:%d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); char bytes[MSG_BUFFER]; ssize_t bytes_read, bytes_written; while(TRUE) { if((bytes_read = read(client_sd, bytes, MSG_BUFFER)) == -1) { perror("s> Could not receive data from client.\n"); break; } else if(bytes_read == 0) { printf("s> %s:%d quit\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); close(client_sd); pthread_exit(EXIT_SUCCESS); } if(bytes[0] == PUT_CODE) { struct put *petition = (struct put *) &bytes; // Create file from received data // receive size char size[10]; ssize_t bytes_read; if((bytes_read = read(client_sd, size, 10)) == -1) { perror("c> Error receiving data from client.\n"); break; } else if(bytes_read == 0) { printf("c> Client has closed the connection.\n"); close(client_sd); break; } int filesize = atoi(size); printf("c> File size - %d\n", filesize); //receive actual file data char file_data[filesize]; if((bytes_read = read(client_sd, file_data, filesize)) == -1) { perror("c> Error receiving data from client.\n"); break; } else if(bytes_read == 0) { printf("c> Client has closed the connection.\n"); close(client_sd); break; } //create file FILE *file = fopen(petition->src, "wb"); fwrite(file_data, filesize, 1, file); fclose(file); // Create graphic generate_graphics(petition->title, petition->xLabel, petition->yLabel, petition->style, petition->src); printf("s> %s:%d OK gnuplot %s\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port), petition->title); // Send ACK to client. char byte[1]; byte[0] = PUT_CODE; if((bytes_written = write(client_sd, byte, 1)) == -1) { perror("s> Could not send data to client.\n"); break; } } else if (bytes[0] == GET_CODE) { struct get *petition = (struct get *) &bytes; printf("s> %s:%d init get graphic %s\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port), petition->file); //Open file FILE *file; char *file_data; if ((file = fopen(petition->file, "rb")) != 0){ fseek(file, 0L, SEEK_END); int size = ftell(file); fseek(file, 0L, SEEK_SET); //Allocate memory file_data=(char *)malloc(size+1); //Read file contents into buffer fread(file_data, size, 1, file); fclose(file); char filesize[10]; sprintf(filesize, "%d", size); // SEND size if((bytes_written = send(client_sd, filesize, 10, 0)) == -1) { perror("s> Could not send file size to client.\n"); break; } //SEND file if((bytes_written = sendfile(client_sd, open(petition->file, 0), 0, size)) == -1) { perror("s> Could not send data to client.\n"); break; } printf("s> %s:%d end get graphic %s\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port), petition->file); } else { printf("s> %s:%d error sending file %s\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port), petition->file); } } memset(bytes, 0, sizeof(bytes)); } close(client_sd); pthread_exit(0); }
static int do_sendfile(const int out_fd, const int in_fd, unsigned int num_send, filesize_t start_pos) { /* Probably should one day be shared with instance in ftpdataio.c */ static char* p_recvbuf; unsigned int total_written = 0; int retval; enum EVSFSysUtilError error; (void) start_pos; (void) error; #if defined(VSF_SYSDEP_HAVE_LINUX_SENDFILE) || \ defined(VSF_SYSDEP_HAVE_FREEBSD_SENDFILE) || \ defined(VSF_SYSDEP_HAVE_HPUX_SENDFILE) || \ defined(VSF_SYSDEP_HAVE_AIX_SENDFILE) || \ defined(VSF_SYSDEP_HAVE_SOLARIS_SENDFILE) if (tunable_use_sendfile) { static int s_sendfile_checked; static int s_runtime_sendfile_works; if (!s_sendfile_checked || s_runtime_sendfile_works) { do { #ifdef VSF_SYSDEP_HAVE_LINUX_SENDFILE retval = sendfile(out_fd, in_fd, NULL, num_send); #elif defined(VSF_SYSDEP_HAVE_FREEBSD_SENDFILE) { /* XXX - start_pos will truncate on 32-bit machines - can we * say "start from current pos"? */ off_t written = 0; retval = sendfile(in_fd, out_fd, start_pos, num_send, NULL, &written, 0); /* Translate to Linux-like retval */ if (written > 0) { retval = (int) written; } } #elif defined(VSF_SYSDEP_HAVE_SOLARIS_SENDFILE) { size_t written = 0; struct sendfilevec the_vec; vsf_sysutil_memclr(&the_vec, sizeof(the_vec)); the_vec.sfv_fd = in_fd; the_vec.sfv_off = start_pos; the_vec.sfv_len = num_send; retval = sendfilev(out_fd, &the_vec, 1, &written); /* Translate to Linux-like retval */ if (written > 0) { retval = (int) written; } } #elif defined(VSF_SYSDEP_HAVE_AIX_SENDFILE) { struct sf_parms sf_iobuf; vsf_sysutil_memclr(&sf_iobuf, sizeof(sf_iobuf)); sf_iobuf.header_data = NULL; sf_iobuf.header_length = 0; sf_iobuf.trailer_data = NULL; sf_iobuf.trailer_length = 0; sf_iobuf.file_descriptor = in_fd; sf_iobuf.file_offset = start_pos; sf_iobuf.file_bytes = num_send; retval = send_file((int*)&out_fd, &sf_iobuf, 0); if (retval >= 0) { retval = sf_iobuf.bytes_sent; } } #else /* must be VSF_SYSDEP_HAVE_HPUX_SENDFILE */ { retval = sendfile(out_fd, in_fd, start_pos, num_send, NULL, 0); } #endif /* VSF_SYSDEP_HAVE_LINUX_SENDFILE */ error = vsf_sysutil_get_error(); vsf_sysutil_check_pending_actions(kVSFSysUtilIO, retval, out_fd); } while (vsf_sysutil_retval_is_error(retval) && error == kVSFSysUtilErrINTR); if (!s_sendfile_checked) { s_sendfile_checked = 1; if (!vsf_sysutil_retval_is_error(retval) || error != kVSFSysUtilErrNOSYS) { s_runtime_sendfile_works = 1; } } if (!vsf_sysutil_retval_is_error(retval)) { return retval; } if (s_runtime_sendfile_works && error != kVSFSysUtilErrINVAL && error != kVSFSysUtilErrOPNOTSUPP) { return retval; } /* Fall thru to normal implementation. We won't check again. NOTE - * also falls through if sendfile() is OK but it returns EINVAL. For * Linux this means the file was not page cache backed. Original * complaint was trying to serve files from an NTFS filesystem! */ } } #endif /* VSF_SYSDEP_HAVE_LINUX_SENDFILE || VSF_SYSDEP_HAVE_FREEBSD_SENDFILE */ if (p_recvbuf == 0) { vsf_secbuf_alloc(&p_recvbuf, VSFTP_DATA_BUFSIZE); } while (1) { unsigned int num_read; unsigned int num_written; unsigned int num_read_this_time = VSFTP_DATA_BUFSIZE; if (num_read_this_time > num_send) { num_read_this_time = num_send; } retval = vsf_sysutil_read(in_fd, p_recvbuf, num_read_this_time); if (retval < 0) { return retval; } else if (retval == 0) { return -1; } num_read = (unsigned int) retval; retval = vsf_sysutil_write_loop(out_fd, p_recvbuf, num_read); if (retval < 0) { return retval; } num_written = (unsigned int) retval; total_written += num_written; if (num_written != num_read) { return num_written; } if (num_written > num_send) { bug("num_written bigger than num_send in do_sendfile"); } num_send -= num_written; if (num_send == 0) { /* Bingo! */ return total_written; } } }
//response static resource void http_response_static_proc( httpHeader* reqHeader ) { int len, cllen , ctlen ; char path[1024] = {0}; header_out_t header_out; memset( &header_out , 0 , sizeof( header_out )); header_out.req = reqHeader; get_file_path( reqHeader->uri , path ); struct stat stat_file; int ret = stat( path , &stat_file ); if ( ret < 0 ) { //printf( "not found page=%s \n" , path ); resp_error_page( &header_out , 404 ); return; } create_common_header( &header_out , 200 ); header_append_length( &header_out , stat_file.st_size ); resp_append_header( &header_out , HEADER_END_LINE ); int nwritten = write( reqHeader->connfd , header_out.data , header_out.length ); if (nwritten <= 0) { printf( "I/O error writing to client connfd=%d,len=%d: %s \n", reqHeader->connfd , header_out.length , strerror(errno)); return; } int fd = open( path , O_RDONLY ); if ( fd < 0 ) { printf( "Open file Error:%s,errno=%d \n" , strerror(errno) , errno ); return; } //优化 //setsockopt (fd, SOL_TCP, TCP_CORK, &on, sizeof (on)); off_t offset = 0; int force_close = 0; while ( offset < stat_file.st_size ) { int sendn = sendfile( reqHeader->connfd , fd , &offset , stat_file.st_size - offset ); if ( sendn < 0 ) { //如果socket缓冲区不可用,则挂起等待可用 if (errno == EAGAIN || errno == EINTR ) { if( anetHandup( reqHeader->connfd , 1000 , AE_WRITABLE ) < 0 ) { //如果超时,退出 printf( "Sendfile anetHandup timeout.......\n" ); force_close = 1; break; } else { //否则继续发送 continue; } } else { break; } } //printf( "Response uri=%s, connfd=%d,len=%d,send=%d \n", reqHeader->uri , reqHeader->connfd ,stat_file.st_size , sendn ); } close( fd ); http_close( reqHeader , force_close ); }
ret_t cherokee_socket_sendfile (cherokee_socket_t *socket, int fd, size_t size, off_t *offset, ssize_t *sent) { static cherokee_boolean_t no_sys = false; #if DARWIN_SENDFILE_API || FREEBSD_SENDFILE_API int re; #endif #if DARWIN_SENDFILE_API off_t _sent = size; #endif /* Exit if there is no sendfile() function in the system */ if (unlikely (no_sys)) return ret_no_sys; /* If there is nothing to send then return now, this may be * needed in some systems (i.e. *BSD) because value 0 may have * special meanings or trigger occasional hidden bugs. */ if (unlikely (size == 0)) return ret_ok; /* Limit size of data that has to be sent. */ if (size > MAX_SF_BLK_SIZE2) size = MAX_SF_BLK_SIZE; #if defined(LINUX_BROKEN_SENDFILE_API) UNUSED(socket); UNUSED(fd); UNUSED(offset); UNUSED(sent); /* Large file support is set but native Linux 2.2 or 2.4 sendfile() * does not support _FILE_OFFSET_BITS 64 */ return ret_no_sys; #elif defined(LINUX_SENDFILE_API) /* Linux sendfile * * ssize_t * sendfile (int out_fd, int in_fd, off_t *offset, size_t *count); * * ssize_t * sendfile64 (int out_fd, int in_fd, off64_t *offset, size_t *count); */ *sent = sendfile (SOCKET_FD(socket), /* int out_fd */ fd, /* int in_fd */ offset, /* off_t *offset */ size); /* size_t count */ if (*sent < 0) { switch (errno) { case EINTR: case EAGAIN: #if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN) case EWOULDBLOCK: #endif return ret_eagain; case EINVAL: /* maybe sendfile is not supported by this FS (no mmap available), * since more than one FS can be used (ext2, ext3, ntfs, etc.) * we should retry with emulated sendfile (read+write). */ return ret_no_sys; case ENOSYS: /* This kernel does not support sendfile at all. */ no_sys = true; return ret_no_sys; } return ret_error; } else if (*sent == 0) { /* It isn't an error, but it wrote nothing */ return ret_error; } #elif DARWIN_SENDFILE_API /* MacOS X: BSD-like System Call * * int * sendfile (int fd, int s, off_t offset, off_t *len, * struct sf_hdtr *hdtr, int flags); */ re = sendfile (fd, /* int fd */ SOCKET_FD(socket), /* int s */ *offset, /* off_t offset */ &_sent, /* off_t *len */ NULL, /* struct sf_hdtr *hdtr */ 0); /* int flags */ if (re == -1) { switch (errno) { case EINTR: case EAGAIN: /* It might have sent some information */ if (_sent <= 0) return ret_eagain; break; case ENOSYS: no_sys = true; return ret_no_sys; default: return ret_error; } } else if (_sent == 0) { /* It wrote nothing. Most likely the file was * truncated and the fd offset is off-limits. */ return ret_error; } *sent = _sent; *offset = *offset + _sent; #elif SOLARIS_SENDFILE_API *sent = sendfile (SOCKET_FD(socket), /* int out_fd */ fd, /* int in_fd */ offset, /* off_t *off */ size); /* size_t len */ if (*sent < 0) { switch (errno) { case EINTR: case EAGAIN: #if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN) case EWOULDBLOCK: #endif return ret_eagain; case ENOSYS: /* This kernel does not support sendfile at all. */ no_sys = true; return ret_no_sys; case EAFNOSUPPORT: return ret_no_sys; } return ret_error; } else if (*sent == 0) { /* It isn't an error, but it wrote nothing */ return ret_error; } #elif FREEBSD_SENDFILE_API struct sf_hdtr hdr; struct iovec hdtrl; hdr.headers = &hdtrl; hdr.hdr_cnt = 1; hdr.trailers = NULL; hdr.trl_cnt = 0; hdtrl.iov_base = NULL; hdtrl.iov_len = 0; *sent = 0; /* FreeBSD sendfile: in_fd and out_fd are reversed * * int * sendfile (int fd, int s, off_t offset, size_t nbytes, * struct sf_hdtr *hdtr, off_t *sbytes, int flags); */ re = sendfile (fd, /* int fd */ SOCKET_FD(socket), /* int s */ *offset, /* off_t offset */ size, /* size_t nbytes */ &hdr, /* struct sf_hdtr *hdtr */ sent, /* off_t *sbytes */ 0); /* int flags */ if (re == -1) { switch (errno) { case EINTR: case EAGAIN: #if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN) case EWOULDBLOCK: #endif if (*sent < 1) return ret_eagain; /* else it's ok, something has been sent. */ break; case ENOSYS: no_sys = true; return ret_no_sys; default: return ret_error; } } else if (*sent == 0) { /* It isn't an error, but it wrote nothing */ return ret_error; } *offset = *offset + *sent; #elif HPUX_SENDFILE_API /* HP-UX: * * sbsize_t sendfile(int s, int fd, off_t offset, bsize_t nbytes, * const struct iovec *hdtrl, int flags); * * HPUX guarantees that if any data was written before * a signal interrupt then sendfile returns the number of * bytes written (which may be less than requested) not -1. * nwritten includes the header data sent. */ *sent = sendfile (SOCKET_FD(socket), /* socket */ fd, /* fd to send */ *offset, /* where to start */ size, /* bytes to send */ NULL, /* Headers/footers */ 0); /* flags */ if (*sent < 0) { switch (errno) { case EINTR: case EAGAIN: #if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN) case EWOULDBLOCK: #endif return ret_eagain; case ENOSYS: no_sys = true; return ret_no_sys; } return ret_error; } else if (*sent == 0) { /* It isn't an error, but it wrote nothing */ return ret_error; } *offset = *offset + *sent; #else UNUSED(socket); UNUSED(fd); UNUSED(offset); UNUSED(sent); SHOULDNT_HAPPEN; return ret_error; #endif return ret_ok; }
static void* cacheopen(char const* url) { const char* basename = strrchr(url,'/'); assert(basename); static char dest[508]; snprintf(dest,508,"%s/%s",cacheDir,basename); bool didtemp = false; int doopen(void) { int result = open(dest,O_RDONLY); if(result<0) { char temp[512]; snprintf(temp,512,"%s.temp",dest); if(xmlIOHTTPMatch(url)) { void* ctx = NULL; #if W3_ARE_NOT_MORONS ctx = xmlNanoHTTPOpen(url, NULL); if(xmlNanoHTTPReturnCode(ctx) != 200) #else if(true) #endif { // XXX: it always is... w3.org dies on HTTP/1.0 #if W3_ARE_NOT_MORONS xmlNanoHTTPClose(ctx); #endif fprintf(stderr,"Curl fallback for %s\n",url); int pid = fork(); if(pid == 0) { execlp("curl","curl","-o",temp,url,NULL); abort(); } int status = 0; waitpid(pid,&status,0); if(!(WIFEXITED(status) && (0 == WEXITSTATUS(status)))) { fprintf(stderr,"CUrl failed! %x %d\n",status,WEXITSTATUS(status)); abort(); } } else { assert(0==xmlNanoHTTPSave(ctx,temp)); } } else if(xmlIOFTPMatch(url)) { void* ftp = xmlNanoFTPOpen(url); int out = open(temp,O_WRONLY|O_TRUNC|O_CREAT,0644); assert(out>0); char buf[0x1000]; for(;;) { int amt = xmlNanoFTPRead(ftp, buf, 0x1000); if(amt==0) break; assert(amt>0); write(out,buf,amt); } close(out); } else { FILE* fp = xmlFileOpen(url); struct stat fpstat; if(!fp) { fprintf(stderr,"No idea what to do with url %s\n",url); abort(); } int inp = fileno(fp); assert(0==fstat(inp,&fpstat)); off_t left = fpstat.st_size; int out = open(temp,O_WRONLY|O_TRUNC|O_CREAT,0644); assert(out>0); do { ssize_t amt = sendfile(out,inp,NULL,left); if(amt<0) { perror(url); } assert(amt>=0); left -= amt; } while(left > 0); fclose(fp); close(out); } rename(temp,dest); // doesn't matter if fails unlink(temp); // in case it failed return doopen(); } return result; }
ssize_t sendfile_full(int out_fd, const char *fn) { _cleanup_fclose_ FILE *f; struct stat st; int r; ssize_t s; size_t n, l; _cleanup_free_ char *buf = NULL; assert(out_fd > 0); assert(fn); f = fopen(fn, "re"); if (!f) return -errno; r = fstat(fileno(f), &st); if (r < 0) return -errno; s = sendfile(out_fd, fileno(f), NULL, st.st_size); if (s < 0) if (errno == EINVAL || errno == ENOSYS) { /* continue below */ } else return -errno; else return s; /* sendfile() failed, fall back to read/write */ /* Safety check */ if (st.st_size > 4*1024*1024) return -E2BIG; n = st.st_size > 0 ? st.st_size : LINE_MAX; l = 0; while (true) { char *t; size_t k; t = realloc(buf, n); if (!t) return -ENOMEM; buf = t; k = fread(buf + l, 1, n - l, f); if (k <= 0) { if (ferror(f)) return -errno; break; } l += k; n *= 2; /* Safety check */ if (n > 4*1024*1024) return -E2BIG; } r = write(out_fd, buf, l); if (r < 0) return -errno; return (ssize_t) l; }
bool client_test(int argc, char **argv) { FILE *out = NULL; FILE *err = NULL; char *ack = NULL; const char *filename = NULL; const char *host = NULL; const char *port = NULL; off_t offset = 0; bool check = false; int sockfd, tmperr, write_count, fdin, size, wait_for_ack, req, next_opt; const char *short_opt = "no:"; const struct option long_opt[] = { {"no-ack", 0, NULL, 'n'}, {"output", 1, NULL, 'o'}, {NULL, 0, NULL, 0}, }; /* Just in case we want to redirect stderr later on. */ err = stderr; out = stdout; wait_for_ack = 1; do { next_opt = getopt_long(argc, argv, short_opt, long_opt, NULL); switch(next_opt) { case 'o': /* -o or --output ... optional */ out = redirect(optarg, "a", stdout); break; case 'n': /* -n or --no-ack ... optional */ wait_for_ack = 0; break; case '?': /* invalid option */ usage(err, EXIT_FAILURE); break; /* End of options */ case -1: break; /* If we get here, something went very wrong. */ default: abort(); break; } } while(next_opt != -1); argv += optind; argc -= optind; if(argc != 3) usage(err, EXIT_FAILURE); host = argv[0]; port = argv[1]; filename = argv[2]; if(filename == NULL) die(err, EINVAL, "%s: HL7 filename required.\n", program); if(host == NULL) die(err, EDESTADDRREQ, "%s: Destination host required.\n", program); if(port == NULL) die(err, EINVAL, "%s: Destination port required.\n", program); fdin = sockfd = -1; write_count = 0; size = getsize(filename); /* Save errno, as writing to a stream can change it in the * interim. */ tmperr = errno; if(size <= 0) { switch(size) { case 0: die(err, EXIT_FAILURE, "%s: %s: Cowardly refusing to send an empty file!\n", program, filename); break; case -1: die(err, tmperr, "%s: Could not open \"%s\": %s\n", program, filename, strerror(errno)); break; default: die(err, EXIT_FAILURE, "%s: Could not open \"%s\"\n", program, filename); break; } } if(!tcp_connect(host, atoi(port), &sockfd)) { tmperr = errno; switch(sockfd) { case -1: die(err, EXIT_FAILURE, "Error opening socket.\n"); break; case -2: die(err, EXIT_FAILURE, "%s: Hostname lookup failure: %s\n", program, host); break; case -3: die(err, tmperr, "%s: error connecting to %s, port %s.\n", program, host, port); break; default: /* If we get here, the API is busted. */ die(err, EXIT_FAILURE, "%s: Unknown error!\n", program); break; } } /* Read file and send to server */ if((fdin = open(filename, O_RDONLY)) == -1) { die(err, errno, "%s: couldn't open %s for reading: %s\n", program, filename, strerror(errno)); } else { /* Toss file to server. Linux syscall, but its fast. :D*/ sendfile(sockfd, fdin, &offset, size); if(wait_for_ack) { ack = tcp_recv(sockfd, 5000, MAX_READ, &req); if(ack==NULL) return false; if((ack!=NULL) && (strlen(ack) > 0)) { fprintf(stderr, "%s\n", ack); check = parse(ack); } free(ack); ack = NULL; close(sockfd); return check; } /* if waiting for ack ... */ close(sockfd); } /* if able to open filestream... */ return true; }
void do_sendfile(OFF_T offset, int i) { int in_fd; struct stat sb; int wait_status; int wait_stat; off_t before_pos, after_pos; out_fd = create_server(); if ((in_fd = open(in_file, O_RDONLY)) < 0) { tst_brkm(TBROK, cleanup, "open failed: %d", errno); /*NOTREACHED*/} if (stat(in_file, &sb) < 0) { tst_brkm(TBROK, cleanup, "stat failed: %d", errno); /*NOTREACHED*/} if ((before_pos = lseek(in_fd, 0, SEEK_CUR)) < 0) { tst_brkm(TBROK, cleanup, "lseek before invoking sendfile failed: %d", errno); /*NOTREACHED*/} TEST(sendfile(out_fd, in_fd, &offset, sb.st_size - offset)); if ((after_pos = lseek(in_fd, 0, SEEK_CUR)) < 0) { tst_brkm(TBROK, cleanup, "lseek after invoking sendfile failed: %d", errno); /*NOTREACHED*/} if (STD_FUNCTIONAL_TEST) { /* Close the sockets */ shutdown(sockfd, SHUT_RDWR); shutdown(s, SHUT_RDWR); if (TEST_RETURN != testcases[i].exp_retval) { tst_resm(TFAIL, "sendfile(2) failed to return " "expected value, expected: %d, " "got: %ld", testcases[i].exp_retval, TEST_RETURN); kill(child_pid, SIGKILL); } else if (offset != testcases[i].exp_updated_offset) { tst_resm(TFAIL, "sendfile(2) failed to update " "OFFSET parameter to expected value, " "expected: %d, got: %"PRId64, testcases[i].exp_updated_offset, (int64_t)offset); } else if (before_pos != after_pos) { tst_resm(TFAIL, "sendfile(2) updated the file position " " of in_fd unexpectedly, expected file position: %"PRId64", " " actual file position %"PRId64, (int64_t)before_pos, (int64_t)after_pos); } else { tst_resm(TPASS, "functionality of sendfile() is " "correct"); wait_status = waitpid(-1, &wait_stat, 0); } } else { tst_resm(TPASS, "call succeeded"); /* Close the sockets */ shutdown(sockfd, SHUT_RDWR); shutdown(s, SHUT_RDWR); if (TEST_RETURN != testcases[i].exp_retval) { kill(child_pid, SIGKILL); } else { wait_status = waitpid(-1, &wait_stat, 0); } } close(in_fd); }
int network_write_chunkqueue_linuxsendfile(server *srv, connection *con, int fd, chunkqueue *cq, off_t max_bytes) { chunk *c; for(c = cq->first; (max_bytes > 0) && (NULL != c); c = c->next) { int chunk_finished = 0; switch(c->type) { case MEM_CHUNK: { char * offset; off_t toSend; ssize_t r; size_t num_chunks, i; struct iovec chunks[UIO_MAXIOV]; chunk *tc; size_t num_bytes = 0; /* build writev list * * 1. limit: num_chunks < UIO_MAXIOV * 2. limit: num_bytes < max_bytes */ for (num_chunks = 0, tc = c; tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV; tc = tc->next, num_chunks++); for (tc = c, i = 0; i < num_chunks; tc = tc->next, i++) { if (buffer_string_is_empty(tc->mem)) { chunks[i].iov_base = tc->mem->ptr; chunks[i].iov_len = 0; } else { offset = tc->mem->ptr + tc->offset; toSend = buffer_string_length(tc->mem) - tc->offset; chunks[i].iov_base = offset; /* protect the return value of writev() */ if (toSend > max_bytes || (off_t) num_bytes + toSend > max_bytes) { chunks[i].iov_len = max_bytes - num_bytes; num_chunks = i + 1; break; } else { chunks[i].iov_len = toSend; } num_bytes += toSend; } } if ((r = writev(fd, chunks, num_chunks)) < 0) { switch (errno) { case EAGAIN: case EINTR: r = 0; break; case EPIPE: case ECONNRESET: return -2; default: log_error_write(srv, __FILE__, __LINE__, "ssd", "writev failed:", strerror(errno), fd); return -1; } } /* check which chunks have been written */ cq->bytes_out += r; max_bytes -= r; for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) { if (r >= (ssize_t)chunks[i].iov_len) { /* written */ r -= chunks[i].iov_len; tc->offset += chunks[i].iov_len; if (chunk_finished) { /* skip the chunks from further touches */ c = c->next; } else { /* chunks_written + c = c->next is done in the for()*/ chunk_finished = 1; } } else { /* partially written */ tc->offset += r; chunk_finished = 0; break; } } break; } case FILE_CHUNK: { ssize_t r; off_t offset; off_t toSend; stat_cache_entry *sce = NULL; offset = c->file.start + c->offset; toSend = c->file.length - c->offset; if (toSend > max_bytes) toSend = max_bytes; /* open file if not already opened */ if (-1 == c->file.fd) { if (-1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) { log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno)); return -1; } fd_close_on_exec(c->file.fd); #ifdef HAVE_POSIX_FADVISE /* tell the kernel that we want to stream the file */ if (-1 == posix_fadvise(c->file.fd, 0, 0, POSIX_FADV_SEQUENTIAL)) { if (ENOSYS != errno) { log_error_write(srv, __FILE__, __LINE__, "ssd", "posix_fadvise failed:", strerror(errno), c->file.fd); } } #endif } if (-1 == (r = sendfile(fd, c->file.fd, &offset, toSend))) { switch (errno) { case EAGAIN: case EINTR: /* ok, we can't send more, let's try later again */ r = 0; break; case EPIPE: case ECONNRESET: return -2; default: log_error_write(srv, __FILE__, __LINE__, "ssd", "sendfile failed:", strerror(errno), fd); return -1; } } else if (r == 0) { int oerrno = errno; /* We got an event to write but we wrote nothing * * - the file shrinked -> error * - the remote side closed inbetween -> remote-close */ if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) { /* file is gone ? */ return -1; } if (offset > sce->st.st_size) { /* file shrinked, close the connection */ errno = oerrno; return -1; } errno = oerrno; return -2; } #ifdef HAVE_POSIX_FADVISE #if 0 #define K * 1024 #define M * 1024 K #define READ_AHEAD 4 M /* check if we need a new chunk */ if ((c->offset & ~(READ_AHEAD - 1)) != ((c->offset + r) & ~(READ_AHEAD - 1))) { /* tell the kernel that we want to stream the file */ if (-1 == posix_fadvise(c->file.fd, (c->offset + r) & ~(READ_AHEAD - 1), READ_AHEAD, POSIX_FADV_NOREUSE)) { log_error_write(srv, __FILE__, __LINE__, "ssd", "posix_fadvise failed:", strerror(errno), c->file.fd); } } #endif #endif c->offset += r; cq->bytes_out += r; max_bytes -= r; if (c->offset == c->file.length) { chunk_finished = 1; /* chunk_free() / chunk_reset() will cleanup for us but it is a ok to be faster :) */ if (c->file.fd != -1) { close(c->file.fd); c->file.fd = -1; } } break; } default: log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known"); return -1; } if (!chunk_finished) { /* not finished yet */ break; } } return 0; }
ssize_t portable_sendfile(int out_fd, int in_fd) { off_t len = SENDFILE_CHUNK_SIZE; if(sendfile(in_fd, out_fd, 0, &len, NULL, 0) == -1) return -1; return len; }
ssize_t portable_sendfile(int out_fd, int in_fd) { return sendfile(out_fd, in_fd, NULL, SENDFILE_CHUNK_SIZE); }
int main(int argc, char *argv[]){ int listenfd,connfd,n; int epoll_fd,cur_fd,newfd,number,stop; struct epoll_event ev; struct epoll_event events[size]; struct sockaddr_in server_address,client_address; struct stat stat_buf; const char* file_name=argv[1]; char buffer[BUF]; int file_ptr=open(file_name,O_RDONLY); fstat(file_ptr,&stat_buf); close(file_ptr); bzero(&server_address,sizeof(server_address)); server_address.sin_family=AF_INET; server_address.sin_addr.s_addr=htonl(INADDR_ANY); server_address.sin_port=htons(PORT); if((listenfd=socket(AF_INET,SOCK_STREAM,0))==-1){ exit(0); } setnonblocking(listenfd); int opt=1; setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt)); if(bind(listenfd,(struct sockaddr*)&server_address,sizeof(server_address))==-1){ exit(0); } if(listen(listenfd,BACKLOG)==-1){ exit(0); } epoll_fd=epoll_create(10); ev.data.fd=listenfd; ev.events=EPOLLIN | EPOLLET; epoll_ctl(epoll_fd,EPOLL_CTL_ADD,listenfd,&ev); cur_fd=1;stop=FALSE; socklen_t len=sizeof(struct sockaddr_in); while(!stop){ number=epoll_wait(epoll_fd,events,cur_fd,-1); assert(number!=-1); for(n=0;n<number;n++){ connfd=events[n].data.fd; if(connfd==listenfd){ while((newfd=accept(listenfd,(struct sockaddr*)&client_address,&len))>0){ printf("connect with %s ,socket index %d\n",\ inet_ntoa(client_address.sin_addr),newfd); setnonblocking(newfd); ev.data.fd=newfd; ev.events=EPOLLIN|EPOLLET|EPOLLHUP; if(epoll_ctl(epoll_fd,EPOLL_CTL_ADD,newfd,&ev)==-1){ perror("epoll_ctl:add"); stop=TRUE; } cur_fd++; } if(newfd==-1){ if(errno!=EAGAIN&&errno!=ECONNABORTED\ &&errno!=EPROTO&&errno!=EINTR){ perror("accept"); } } continue; }else if(events[n].events & EPOLLOUT){ printf("start to sendfile !\n"); int ret=0,left=stat_buf.st_size; file_ptr=open(file_name,O_RDONLY); while(left>0){ ret=sendfile(connfd,file_ptr,NULL,BUF); if(ret<0 && errno==EAGAIN){ continue; }else if(ret==0){ break; }else{ left-=ret; } } printf("sendfile over !\n"); close(file_ptr); ev.data.fd=connfd; epoll_ctl(epoll_fd,EPOLL_CTL_DEL,connfd,&ev); cur_fd--; close(connfd); }else if(events[n].events & EPOLLIN){ char msg[100]; memset(msg,'\0',100); int ret=recv(connfd,msg,100,0); if(ret<=0){ close(connfd); } printf("recv from client : %s\n",msg); ev.data.fd=connfd; ev.events=EPOLLOUT|EPOLLET|EPOLLHUP; epoll_ctl(epoll_fd,EPOLL_CTL_MOD,connfd,&ev); } } } close(listenfd); close(epoll_fd); return 0; }
static int spamdscan_socket(const char *file, const struct spamd_server *srv, struct config_file *cfg, rspamd_result_t *res) { #ifdef HAVE_PATH_MAX char buf[PATH_MAX + 10]; #elif defined(HAVE_MAXPATHLEN) char buf[MAXPATHLEN + 10]; #else #error "neither PATH_MAX nor MAXPATHEN defined" #endif char *c, *err; struct sockaddr_un server_un; struct sockaddr_in server_in; int s, r, fd, ofl, size = 0; struct stat sb; struct rspamd_metric_result *cur = NULL; struct rspamd_symbol *cur_symbol; /* somebody doesn't need reply... */ if (!srv) return 0; if (srv->sock_type == AF_LOCAL) { memset(&server_un, 0, sizeof(server_un)); server_un.sun_family = AF_UNIX; strncpy(server_un.sun_path, srv->sock.unix_path, sizeof(server_un.sun_path)); if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { msg_warn("spamd: socket %s, %s", srv->sock.unix_path, strerror (errno)); return -1; } if (connect_t(s, (struct sockaddr *) & server_un, sizeof(server_un), cfg->spamd_connect_timeout) < 0) { msg_warn("spamd: connect %s, %s", srv->sock.unix_path, strerror (errno)); close(s); return -1; } } else { /* inet hostname, send stream over tcp/ip */ memset(&server_in, 0, sizeof(server_in)); server_in.sin_family = AF_INET; server_in.sin_port = srv->sock.inet.port; memcpy((char *)&server_in.sin_addr, &srv->sock.inet.addr, sizeof(struct in_addr)); if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0) { msg_warn("spamd: socket %s", strerror (errno)); return -1; } if (connect_t(s, (struct sockaddr *) & server_in, sizeof(server_in), cfg->spamd_connect_timeout) < 0) { msg_warn("spamd: connect %s, %s", srv->name, strerror (errno)); close(s); return -1; } } /* Get file size */ fd = open(file, O_RDONLY); if (fstat (fd, &sb) == -1) { msg_warn ("spamd: stat failed: %s", strerror (errno)); close(s); return -1; } if (poll_fd(s, cfg->spamd_connect_timeout, POLLOUT) < 1) { msg_warn ("spamd: timeout waiting writing, %s", srv->name); close (s); return -1; } /* Set blocking again */ ofl = fcntl(s, F_GETFL, 0); fcntl(s, F_SETFL, ofl & (~O_NONBLOCK)); r = snprintf (buf, sizeof (buf), "SYMBOLS SPAMC/1.2\r\nContent-length: %ld\r\n\r\n", (long int)sb.st_size); if (write (s, buf, r) == -1) { msg_warn("spamd: write (%s), %s", srv->name, strerror (errno)); close(fd); close(s); return -1; } #ifdef HAVE_SENDFILE #if defined(FREEBSD) if (sendfile(fd, s, 0, 0, 0, 0, 0) != 0) { msg_warn("spamd: sendfile (%s), %s", srv->name, strerror (errno)); close(fd); close(s); return -1; } #elif defined(LINUX) off_t off = 0; if (sendfile(s, fd, &off, sb.st_size) == -1) { msg_warn("spamd: sendfile (%s), %s", srv->name, strerror (errno)); close(fd); close(s); return -1; } #endif #else while ((r = read (fd, buf, sizeof (buf))) > 0) { write (s, buf, r); } #endif fcntl(s, F_SETFL, ofl); close(fd); /* wait for reply */ if (poll_fd(s, cfg->spamd_results_timeout, POLLIN) < 1) { msg_warn("spamd: timeout waiting results %s", srv->name); close(s); return -1; } /* * read results */ buf[0] = 0; while ((r = read(s, buf + size, sizeof (buf) - size - 1)) > 0 && size < sizeof (buf) - 1) { size += r; } buf[size] = 0; if (r < 0) { msg_warn("spamd: read, %s, %s", srv->name, strerror (errno)); close(s); return -1; } close(s); /* * ok, we got result; test what we got */ if ((c = strstr(buf, "Spam: ")) == NULL) { msg_warn("spamd: unexpected result on file (%s) %s, %s", srv->name, file, buf); return -2; } else { cur = malloc (sizeof (struct rspamd_metric_result)); if (cur == NULL) { msg_err ("malloc falied: %s", strerror (errno)); return -1; } bzero (cur, sizeof (struct rspamd_metric_result)); /* Find mark */ c = strchr (c, ';'); if (c != NULL && *c != '\0') { cur->score = strtod (c + 1, &err); if (*err == ' ' && *(err + 1) == '/') { cur->required_score = strtod (err + 3, NULL); } else { cur->score = 0; } } else { cur->score = 0; cur->required_score = 0; } } /* Skip empty lines */ while (*c && *c++ != '\n'); while (*c++ && (*c == '\r' || *c == '\n')); /* Write symbols */ if (*c != '\0') { err = strchr (c, '\r'); if (err != NULL) { *err = '\0'; } cur_symbol = malloc (sizeof (struct rspamd_symbol)); cur_symbol->symbol = strdup (c); TAILQ_INSERT_HEAD(&cur->symbols, cur_symbol, entry); } if (strstr(buf, "True") != NULL) { cur->action = METRIC_ACTION_REJECT; return 1; } return 0; }
static int rspamdscan_socket(SMFICTX *ctx, struct mlfi_priv *priv, const struct spamd_server *srv, struct config_file *cfg, rspamd_result_t *res, char **mid) { char buf[16384]; char *c, *p, *err_str; struct sockaddr_un server_un; struct sockaddr_in server_in; int s, r, fd, ofl, size = 0, to_write, written, state, next_state, toklen; int remain; struct stat sb; struct rspamd_metric_result *cur = NULL; struct rcpt *rcpt; struct rspamd_symbol *cur_symbol; /* somebody doesn't need reply... */ if (!srv) return 0; if (srv->sock_type == AF_LOCAL) { memset(&server_un, 0, sizeof(server_un)); server_un.sun_family = AF_UNIX; strncpy(server_un.sun_path, srv->sock.unix_path, sizeof(server_un.sun_path)); if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { msg_warn("rspamd: socket %s, %s", srv->sock.unix_path, strerror (errno)); return -1; } if (connect_t(s, (struct sockaddr *) & server_un, sizeof(server_un), cfg->spamd_connect_timeout) < 0) { msg_warn("rspamd: connect %s, %s", srv->sock.unix_path, strerror (errno)); close(s); return -1; } } else { /* inet hostname, send stream over tcp/ip */ memset(&server_in, 0, sizeof(server_in)); server_in.sin_family = AF_INET; server_in.sin_port = srv->sock.inet.port; memcpy((char *)&server_in.sin_addr, &srv->sock.inet.addr, sizeof(struct in_addr)); if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0) { msg_warn("rspamd: socket %s", strerror (errno)); return -1; } if (connect_t(s, (struct sockaddr *) & server_in, sizeof(server_in), cfg->spamd_connect_timeout) < 0) { msg_warn("rspamd: connect %s: %s", srv->name, strerror (errno)); close(s); return -1; } } /* Get file size */ fd = open(priv->file, O_RDONLY); if (fstat (fd, &sb) == -1) { msg_warn ("rspamd: stat failed: %s", strerror (errno)); close(s); return -1; } if (poll_fd(s, cfg->spamd_connect_timeout, POLLOUT) < 1) { msg_warn ("rspamd: timeout waiting writing, %s", srv->name); close (s); return -1; } /* Set blocking again */ ofl = fcntl(s, F_GETFL, 0); fcntl(s, F_SETFL, ofl & (~O_NONBLOCK)); r = 0; to_write = sizeof (buf) - r; written = snprintf (buf + r, to_write, "SYMBOLS RSPAMC/1.2\r\nContent-length: %ld\r\n", (long int)sb.st_size); if (written > to_write) { msg_warn("rspamd: buffer overflow while filling buffer (%s)", srv->name); close(fd); close(s); return -1; } r += written; for (rcpt = priv->rcpts.lh_first; rcpt != NULL; rcpt = rcpt->r_list.le_next) { to_write = sizeof (buf) - r; written = snprintf (buf + r, to_write, "Rcpt: %s\r\n", rcpt->r_addr); if (written > to_write) { msg_warn("rspamd: buffer overflow while filling buffer (%s)", srv->name); close(fd); close(s); return -1; } r += written; } if (priv->priv_from[0] != '\0') { to_write = sizeof (buf) - r; written = snprintf (buf + r, to_write, "From: %s\r\n", priv->priv_from); if (written > to_write) { msg_warn("rspamd: buffer overflow while filling buffer (%s)", srv->name); close(fd); close(s); return -1; } r += written; } if (priv->priv_helo[0] != '\0') { to_write = sizeof (buf) - r; written = snprintf (buf + r, to_write, "Helo: %s\r\n", priv->priv_helo); if (written > to_write) { msg_warn("rspamd: buffer overflow while filling buffer (%s)", srv->name); close(fd); close(s); return -1; } r += written; } if (priv->priv_hostname[0] != '\0' && memcmp (priv->priv_hostname, "unknown", 8) != 0) { to_write = sizeof (buf) - r; written = snprintf (buf + r, to_write, "Hostname: %s\r\n", priv->priv_hostname); if (written > to_write) { msg_warn("rspamd: buffer overflow while filling buffer (%s)", srv->name); close(fd); close(s); return -1; } r += written; } if (priv->priv_ip[0] != '\0') { to_write = sizeof (buf) - r; written = snprintf (buf + r, to_write, "IP: %s\r\n", priv->priv_ip); if (written > to_write) { msg_warn("rspamd: buffer overflow while filling buffer (%s)", srv->name); close(fd); close(s); return -1; } r += written; } if (priv->priv_user[0] != '\0') { to_write = sizeof (buf) - r; written = snprintf (buf + r, to_write, "User: %s\r\n", priv->priv_user); if (written > to_write) { msg_warn("rspamd: buffer overflow while filling buffer (%s)", srv->name); close(fd); close(s); return -1; } r += written; } to_write = sizeof (buf) - r; written = snprintf (buf + r, to_write, "Queue-ID: %s\r\n\r\n", priv->mlfi_id); if (written > to_write) { msg_warn("rspamd: buffer overflow while filling buffer (%s)", srv->name); close(fd); close(s); return -1; } r += written; if (write (s, buf, r) == -1) { msg_warn("rspamd: write (%s), %s", srv->name, strerror (errno)); close(fd); close(s); return -1; } #ifdef HAVE_SENDFILE #if defined(FREEBSD) if (sendfile(fd, s, 0, 0, 0, 0, 0) != 0) { msg_warn("rspamd: sendfile (%s), %s", srv->name, strerror (errno)); close(fd); close(s); return -1; } #elif defined(LINUX) off_t off = 0; if (sendfile(s, fd, &off, sb.st_size) == -1) { msg_warn("rspamd: sendfile (%s), %s", srv->name, strerror (errno)); close(fd); close(s); return -1; } #endif #else while ((r = read (fd, buf, sizeof (buf))) > 0) { write (s, buf, r); } #endif fcntl(s, F_SETFL, ofl); close(fd); /* wait for reply */ if (poll_fd(s, cfg->spamd_results_timeout, POLLIN) < 1) { msg_warn("rspamd: timeout waiting results %s", srv->name); close(s); return -1; } /* * read results */ buf[0] = 0; size = 0; /* XXX: in fact here should be some FSM to parse reply and this one just skip long replies */ while ((r = read(s, buf + size, sizeof (buf) - size - 1)) > 0 && size < sizeof (buf) - 1) { size += r; } if (r < 0) { msg_warn("rspamd: read, %s, %s", srv->name, strerror (errno)); close(s); return -1; } buf[size] = '\0'; close(s); #define TEST_WORD(x) \ do { \ if (remain < sizeof ((x)) - 1 || memcmp (p, (x), sizeof ((x)) - 1) != 0) { \ msg_warn ("invalid reply from server %s at state %d, expected: %s, got %*s", srv->name, state, ((x)), (int)sizeof((x)), p); \ return -1; \ } \ p += sizeof((x)) - 1; \ remain -= sizeof((x)) - 1; \ } while (0) c = buf; p = buf; remain = size - 1; state = 0; next_state = 100; while (remain > 0) { switch (state) { case 0: /* * Expect first reply line: * RSPAMD/{VERSION} {ERROR_CODE} {DESCR} CRLF */ TEST_WORD("RSPAMD/"); if ((c = strchr (p, ' ')) == NULL) { msg_warn ("invalid reply from server %s on state %d", srv->name, state); return -1; } /* Well now in c we have space symbol, skip all */ while (remain > 0 && isspace (*c)) { c ++; } /* Now check code */ if (*c != '0') { msg_warn ("invalid reply from server %s on state %d, code: %c", srv->name, state, *c); return -1; } /* Now skip everything till \n */ if ((c = strchr (c, '\n')) == NULL) { msg_warn ("invalid reply from server %s on state %d", srv->name, state); return -1; } c ++; remain -= c - p; p = c; next_state = 2; state = 99; break; case 2: /* * In this state we compare begin of line with Metric: */ TEST_WORD("Metric:"); cur = malloc (sizeof (struct rspamd_metric_result)); if (cur == NULL) { msg_err ("malloc failed: %s", strerror (errno)); return -1; } cur->subject = NULL; TAILQ_INIT(&cur->symbols); next_state = 3; state = 99; break; case 3: /* * In this state we parse metric line * Typical line looks as name; result; score1 / score2[ / score3] and we are interested in: * name, result, score1 and score2 */ if ((c = strchr (p, ';')) == NULL) { msg_warn ("invalid reply from server %s on state %d, at position: %s", srv->name, state, p); return -1; } /* Now in c we have end of name and in p - begin of name, so copy this data to temp buffer */ cur->metric_name = malloc (c - p + 1); if (cur->metric_name == NULL) { msg_err ("malloc failed: %s", strerror (errno)); return -1; } rmilter_strlcpy (cur->metric_name, p, c - p + 1); remain -= c - p + 1; p = c + 1; /* Now skip result from rspamd, just extract 2 numbers */ if ((c = strchr (p, ';')) == NULL) { msg_warn ("invalid reply from server %s on state %d, at position: %s", srv->name, state, p); return -1; } remain -= c - p + 1; p = c + 1; /* Now skip spaces */ while (isspace (*p) && remain > 0) { p ++; remain --; } /* Try to read first mark */ cur->score = strtod (p, &err_str); if (err_str != NULL && (*err_str != ' ' && *err_str != '/')) { msg_warn ("invalid reply from server %s on state %d, error converting score number: %s", srv->name, state, err_str); return -1; } remain -= err_str - p; p = err_str; while (remain > 0 && (*p == ' ' || *p == '/')) { remain --; p ++; } /* Try to read second mark */ cur->required_score = strtod (p, &err_str); if (err_str != NULL && (*err_str != ' ' && *err_str != '/' && *err_str != '\r')) { msg_warn ("invalid reply from server %s on state %d, error converting required score number: %s", srv->name, state, err_str); return -1; } remain -= err_str - p; p = err_str; while (remain > 0 && *p != '\n') { remain --; p ++; } state = 99; next_state = 4; break; case 4: /* Symbol/Action */ if (remain >= sizeof ("Symbol:") && memcmp (p, "Symbol:", sizeof ("Symbol:") - 1) == 0) { state = 99; next_state = 5; p += sizeof("Symbol:") - 1; \ remain -= sizeof("Symbol:") - 1; } else if (remain >= sizeof ("Action:") && memcmp (p, "Action:", sizeof ("Action:") - 1) == 0) { state = 99; next_state = 6; p += sizeof("Action:") - 1; \ remain -= sizeof("Action:") - 1; } else if (remain >= sizeof ("Metric:") && memcmp (p, "Metric:", sizeof ("Metric:") - 1) == 0) { state = 99; next_state = 3; p += sizeof("Metric:") - 1; \ remain -= sizeof("Metric:") - 1; TAILQ_INSERT_HEAD(res, cur, entry); cur = malloc (sizeof (struct rspamd_metric_result)); if (cur == NULL) { msg_err ("malloc failed: %s", strerror (errno)); return -1; } TAILQ_INIT(&cur->symbols); } else if (remain >= sizeof ("Message-ID:") && memcmp (p, "Message-ID:", sizeof ("Message-ID:") - 1) == 0) { state = 99; next_state = 7; p += sizeof("Message-ID:") - 1; \ remain -= sizeof("Message-ID:") - 1; } else if (remain >= sizeof ("Subject:") && memcmp (p, "Subject:", sizeof ("Subject:") - 1) == 0) { state = 99; next_state = 8; p += sizeof("Subject:") - 1; \ remain -= sizeof("Subject:") - 1; } else { toklen = strcspn (p, "\r\n"); if (toklen > remain) { msg_info ("bad symbol name detected"); return -1; } remain -= toklen; p += toklen; next_state = 4; state = 99; } break; case 5: /* Parse symbol line */ toklen = strcspn (p, ";\r\n"); if (toklen == 0 || toklen > remain) { /* Bad symbol name */ msg_info ("bad symbol name detected"); return -1; } cur_symbol = malloc (sizeof (struct rspamd_symbol)); if (cur_symbol == NULL) { msg_err ("malloc failed: %s", strerror (errno)); return -1; } cur_symbol->symbol = malloc (toklen + 1); if (cur_symbol->symbol == NULL) { msg_err ("malloc failed: %s", strerror (errno)); return -1; } rmilter_strlcpy (cur_symbol->symbol, p, toklen + 1); TAILQ_INSERT_HEAD (&cur->symbols, cur_symbol, entry); /* Skip to the end of line */ toklen = strcspn (p, "\r\n"); if (toklen > remain) { msg_info ("bad symbol name detected"); return -1; } remain -= toklen; p += toklen; next_state = 4; state = 99; break; case 6: /* Parse action */ if (memcmp (p, "reject", sizeof ("reject") - 1) == 0) { cur->action = METRIC_ACTION_REJECT; } else if (memcmp (p, "greylist", sizeof ("greylist") - 1) == 0) { cur->action = METRIC_ACTION_GREYLIST; } else if (memcmp (p, "add header", sizeof ("add header") - 1) == 0) { cur->action = METRIC_ACTION_ADD_HEADER; } else if (memcmp (p, "rewrite subject", sizeof ("rewrite subject") - 1) == 0) { cur->action = METRIC_ACTION_REWRITE_SUBJECT; } else { cur->action = METRIC_ACTION_NOACTION; } /* Skip to the end of line */ toklen = strcspn (p, "\r\n"); if (toklen > remain) { msg_info ("bad symbol name detected"); return -1; } remain -= toklen; p += toklen; next_state = 4; state = 99; break; case 7: /* Parse message id */ toklen = strcspn (p, "\r\n"); *mid = malloc (toklen + 1); rmilter_strlcpy (*mid, p, toklen + 1); remain -= toklen; p += toklen; next_state = 4; state = 99; break; case 8: /* Parse subject line */ toklen = strcspn (p, "\r\n"); if (cur) { cur->subject = malloc (toklen + 1); rmilter_strlcpy (cur->subject, p, toklen + 1); } remain -= toklen; p += toklen; next_state = 4; state = 99; break; case 99: /* Skip spaces */ if (isspace (*p)) { p ++; remain --; } else { state = next_state; } break; default: msg_err ("state machine breakage detected, state = %d, p = %s", state, p); return -1; } } if (cur != NULL) { TAILQ_INSERT_HEAD(res, cur, entry); } return 0; }
static void file_read_checks(const char *path) { char buf1[16],buf2[8],buf3[32]; struct iovec vec[3]; int rc, f, cnt; off_t i; mlog("+open"); f = open(path, O_RDONLY); if (f < 0) return; // first look at the file's attributes mlog("+fstat"); rc = fstat(f, &sbuf); #ifdef CHECK_XATTR mlog("+flistxattr"); flistxattr(f, lbuf, MAXLISTBUF); mlog("+fgetxattr"); fgetxattr(f, "selinux", lbuf, MAXLISTBUF); #endif // readahead(f, NULL // Check reading mlog("+read"); cnt = 0; while((read(f, buf3, sizeof(buf3)) > 0) && cnt < 1000) cnt++; // lseek around mlog("+lseek"); if (rc == 0) lseek(f, sbuf.st_size, SEEK_SET); lseek(f, 100000, SEEK_SET); lseek(f, 0, SEEK_SET); // vectored reads vec[0].iov_base = (void*)&buf1; vec[0].iov_len = sizeof(buf1); vec[1].iov_base = (void*)&buf2; vec[1].iov_len = sizeof(buf2); vec[2].iov_base = (void*)&buf3; vec[2].iov_len = sizeof(buf3); mlog("+readv"); cnt = 0; while((readv(f, vec, 3) > 0) && cnt < 1000) cnt++; // check out pread syscall i = 0; mlog("+pread"); cnt = 0; while ((pread(f, buf1, sizeof(buf1), i) > 0) && cnt < 1000) { i += sizeof(buf1)*2; cnt++; } // flock mlog("+flock"); flock(f, LOCK_SH|LOCK_NB); flock(f, LOCK_UN); // fcntl ? // sendfile to localhost:discard #if defined(__linux__) setup_socket(); if (sfd >= 0) { mlog("+sendfile"); lseek(f, 0, SEEK_SET); sendfile(sfd, f, NULL, rc ? 100000 : sbuf.st_size); close(sfd); sfd = -1; } #endif // mmap each file if (rc == 0) { char *src; mlog("+mmap"); src = mmap(0, sbuf.st_size, PROT_READ, MAP_FILE | MAP_SHARED, f, 0); if (src != (char *)-1) { // Don't touch memory...or Mr. SIGBUS will visit you mlog("+munmap"); munmap(src, sbuf.st_size); } } close(f); }
static void do_retr(session_t *sess) { if(get_transfer_fd(sess) == 0) return; int fd = open(sess->arg, O_RDONLY); if(fd == -1) { ftp_reply(sess, FTP_FILEFAIL, "1Failed to open file."); return; } int ret; ret = lock_file_read(fd); if(ret == -1) { ftp_reply(sess, FTP_FILEFAIL, "Failed to open file."); return; } //device file can not be downloaded struct stat sbuf; ret = fstat(fd, &sbuf); if(!S_ISREG(sbuf.st_mode)) { ftp_reply(sess, FTP_FILEFAIL, "Failed to open file."); return; } long long offset = sess->restart_pos; sess->restart_pos = 0; if(offset != 0) { ret = lseek(fd, offset, SEEK_SET); if(ret == -1) { ftp_reply(sess, FTP_FILEFAIL, "Failed to open file."); return; } } char text[1024] = {0}; if(sess->is_ascii) { sprintf(text, "Opening ASCII mode data conection for %s (%lld bytes).", sess->arg, (long long)sbuf.st_size); } else { sprintf(text, "Opening BINARY mode data conection for %s (%lld bytes).", sess->arg, (long long)sbuf.st_size); } ftp_reply(sess, FTP_DATACONN, text); int flag = 0; long long bytes_to_send = sbuf.st_size; if(offset > bytes_to_send) bytes_to_send = 0; else bytes_to_send -= offset; sess->bw_transfer_start_sec = get_time_sec(); sess->bw_transfer_start_usec = get_time_usec(); while(bytes_to_send) { int num_this_time = bytes_to_send > 65536 ? 65536 : bytes_to_send; ret = sendfile(sess->data_fd, fd, NULL, num_this_time); if(ret == -1) { flag = 2; break; } limit_rate(sess, ret, 0); if(sess->abor_received) { flag = 2; break; } bytes_to_send -= ret; } close(sess->data_fd); sess->data_fd = -1; close(fd); if(flag == 0) ftp_reply(sess, FTP_TRANSFEROK, "Transfer complete."); else if(flag == 1) ftp_reply(sess, FTP_BADSENDFILE, "Failure reading from local file."); else if(flag == 2) ftp_reply(sess, FTP_BADSENDNET, "Failure writing to network stream."); check_abor(sess); start_cmdio_alarm(); }
int tcpsendfile_ex(int sock, const char *filename, const int64_t file_offset, \ const int64_t file_bytes, const int timeout, int64_t *total_send_bytes) { int fd; int64_t send_bytes; int result; int flags; #ifdef USE_SENDFILE #if defined(OS_FREEBSD) || defined(OS_LINUX) off_t offset; #ifdef OS_LINUX int64_t remain_bytes; #endif #endif #else int64_t remain_bytes; #endif fd = open(filename, O_RDONLY); if (fd < 0) { *total_send_bytes = 0; return errno != 0 ? errno : EACCES; } flags = fcntl(sock, F_GETFL, 0); if (flags < 0) { *total_send_bytes = 0; return errno != 0 ? errno : EACCES; } #ifdef USE_SENDFILE if (flags & O_NONBLOCK) { if (fcntl(sock, F_SETFL, flags & ~O_NONBLOCK) == -1) { *total_send_bytes = 0; return errno != 0 ? errno : EACCES; } } #ifdef OS_LINUX /* result = 1; if (setsockopt(sock, SOL_TCP, TCP_CORK, &result, sizeof(int)) < 0) { logError("file: "__FILE__", line: %d, " \ "setsockopt failed, errno: %d, error info: %s.", \ __LINE__, errno, STRERROR(errno)); close(fd); *total_send_bytes = 0; return errno != 0 ? errno : EIO; } */ #define FILE_1G_SIZE (1 * 1024 * 1024 * 1024) result = 0; offset = file_offset; remain_bytes = file_bytes; while (remain_bytes > 0) { if (remain_bytes > FILE_1G_SIZE) { send_bytes = sendfile(sock, fd, &offset, FILE_1G_SIZE); } else { send_bytes = sendfile(sock, fd, &offset, remain_bytes); } if (send_bytes <= 0) { result = errno != 0 ? errno : EIO; break; } remain_bytes -= send_bytes; } *total_send_bytes = file_bytes - remain_bytes; #else #ifdef OS_FREEBSD offset = file_offset; if (sendfile(fd, sock, offset, file_bytes, NULL, NULL, 0) != 0) { *total_send_bytes = 0; result = errno != 0 ? errno : EIO; } else { *total_send_bytes = file_bytes; result = 0; } #endif #endif if (flags & O_NONBLOCK) //restore { if (fcntl(sock, F_SETFL, flags) == -1) { result = errno != 0 ? errno : EACCES; } } #ifdef OS_LINUX close(fd); return result; #endif #ifdef OS_FREEBSD close(fd); return result; #endif #endif { char buff[FDFS_WRITE_BUFF_SIZE]; int64_t remain_bytes; tcpsenddatafunc send_func; if (file_offset > 0 && lseek(fd, file_offset, SEEK_SET) < 0) { result = errno != 0 ? errno : EIO; close(fd); *total_send_bytes = 0; return result; } if (flags & O_NONBLOCK) { send_func = tcpsenddata_nb; } else { send_func = tcpsenddata; } result = 0; remain_bytes = file_bytes; while (remain_bytes > 0) { if (remain_bytes > sizeof(buff)) { send_bytes = sizeof(buff); } else { send_bytes = remain_bytes; } if (read(fd, buff, send_bytes) != send_bytes) { result = errno != 0 ? errno : EIO; break; } if ((result=send_func(sock, buff, send_bytes, \ timeout)) != 0) { break; } remain_bytes -= send_bytes; } *total_send_bytes = file_bytes - remain_bytes; } close(fd); return result; }
void main(int argc,char *argv[]) { int going=TRUE,forsok=2,car=1,x,connectbps, i, tmp; struct NodeType *nt; char *tmppscreen,commandstring[100], configname[50] = "NiKom:DatoCfg/SerNode.cfg"; FILE *fil; if(argc>1) for(x=1; x<argc; x++) { if(argv[x][0]=='-') { if(argv[x][1]=='G') getty=TRUE; else if(argv[x][1]=='B') gettybps=atoi(&argv[x][2]); else if(argv[x][1]=='C') connectbps = atoi(&argv[x][2]); } else strcpy(configname,argv[x]); } if(!(IntuitionBase=(struct IntuitionBase *)OpenLibrary("intuition.library",0))) cleanup(ERROR,"Kunde inte öppna intuition.library\n"); if(!(UtilityBase=OpenLibrary("utility.library",37L))) cleanup(ERROR,"Kunde inte öppna utility.library\n"); if(!(NiKomBase=OpenLibrary("nikom.library",0L))) cleanup(ERROR,"Kunde inte öppna nikom.library\n"); if(!initnode(NODSER)) cleanup(ERROR,"Kunde inte registrera noden i Servern\n"); if(!(nikomnodeport = CreateMsgPort())) cleanup(ERROR,"Kunde inte skapa NiKomNode-porten"); sprintf(nikomnodeportnamn,"NiKomNode%d",nodnr); nikomnodeport->mp_Node.ln_Name = nikomnodeportnamn; nikomnodeport->mp_Node.ln_Pri = 1; AddPort(nikomnodeport); sprintf(rexxportnamn,"NiKomPreRexx%d",nodnr); if(!(rexxport=(struct MsgPort *)CreateMsgPort())) cleanup(ERROR,"Kunde inte öppna RexxPort\n"); rexxport->mp_Node.ln_Name=rexxportnamn; rexxport->mp_Node.ln_Pri=50; AddPort(rexxport); if(!(RexxSysBase=(struct RsxLib *)OpenLibrary("rexxsyslib.library",0L))) cleanup(ERROR,"Kunde inte öppna rexxsyslib.library\n"); getnodeconfig(configname); if(pubscreen[0]=='-') tmppscreen=NULL; else tmppscreen=pubscreen; if(!(NiKwind=openmywindow(tmppscreen))) cleanup(ERROR,"Kunde inte öppna fönstret\n"); if(getty) dtespeed = gettybps; else dtespeed = highbaud; if(!OpenIO(NiKwind)) cleanup(ERROR,"Couldn't setup IO"); strcpy(Servermem->nodid[nodnr],nodid); conreqtkn(); serreqtkn(); Delay(50); for(;;) { inloggad=-1; Servermem->idletime[nodnr] = time(NULL); Servermem->inloggad[nodnr]=-1; if(getty) Servermem->connectbps[nodnr] = connectbps; else waitconnect(); Servermem->idletime[nodnr] = time(NULL); Servermem->inloggad[nodnr]=-2; /* Sätt till <Uppringd> för att även hantera -getty-fallet */ reloginspec: updateinactive(); Servermem->inne[nodnr].flaggor = Servermem->cfg.defaultflags; if(!getty) Delay(100); Servermem->inne[nodnr].rader=0; Servermem->inne[nodnr].chrset = CHRS_LATIN1; sendfile("NiKom:Texter/Inlogg.txt"); if(Servermem->cfg.ar.preinlogg) sendrexx(Servermem->cfg.ar.preinlogg); car=TRUE; Servermem->inne[nodnr].chrset = 0; memset(commandhistory,0,1000); going=1; while(going && going<=Servermem->cfg.logintries) { putstring("\r\nNamn: ",-1,0); if(getstring(EKO,40,NULL)) { car=FALSE; break; } if(!stricmp(inmat,Servermem->cfg.ny) && !(Servermem->cfg.cfgflags & NICFG_CLOSEDBBS)) { tmp = RegisterNewUser(); if(tmp == 2) { goto panik; } car = tmp ? 0 : 1; going=FALSE; } else if((inloggad=parsenamn(inmat))>=0) { if(readuser(inloggad,&Servermem->inne[nodnr])) { puttekn("Error reading user data.\r\n", -1); goto panik; } // TODO: Extract password loop. Should be identical to in NiKomCon.c forsok=2; while(forsok) { puttekn("\r\nLösen: ",-1); if(Servermem->inne[nodnr].flaggor & STAREKOFLAG) { if(getstring(STAREKO,15,NULL)) { car=FALSE; break; } } else { if(getstring(EJEKO,15,NULL)) { car=FALSE; break; } } if(CheckPassword(inmat, Servermem->inne[nodnr].losen)) { forsok=FALSE; going=FALSE; } else forsok--; } if(going && (Servermem->cfg.logmask & LOG_FAILINLOGG)) { LogEvent(USAGE_LOG, WARN, "Nod %d, %s angivet som namn, fel lösen.", nodnr, getusername(inloggad)); } if(going) going++; } else if(inloggad==-1) puttekn("\r\nHittar ej namnet\r\n",-1); } if(!car) { if(getty) cleanup(OK,""); disconnect(); continue; } if(going) { putstring("\n\n\rTyvärr. Du har försökt maximalt antal gånger att logga in. Kopplar ned.\n\r",-1,0); goto panik; /* Urrk vad fult. :-) */ } Servermem->inloggad[nodnr]=inloggad; Servermem->idletime[nodnr] = time(NULL); if((nt = selectNodeType()) == NULL) { goto panik; } abortinactive(); abortserial(); sprintf(commandstring,"%s -N%d -B%d %s",nt->path,nodnr,dtespeed,configname); CloseConsole(); CloseWindow(NiKwind); NiKwind = NULL; RemPort(nikomnodeport); i = 0; if(Servermem->connectbps[nodnr] > 0) { while(Servermem->info.bps[i] != Servermem->connectbps[nodnr] && Servermem->info.bps[i] > 0 && i<49) i++; if(i<49) { if(Servermem->info.bps[i] == Servermem->connectbps[nodnr]) Servermem->info.antbps[i]++; else { Servermem->info.bps[i] = Servermem->connectbps[nodnr]; Servermem->info.antbps[i]++; } } if(!(fil = fopen("NiKom:datocfg/sysinfo.dat","w"))) { /* putstring("Kunde inte spara nya sysinfo.dat..\n",-1,0); */ } if(fwrite((void *)&Servermem->info,sizeof(Servermem->info),1,fil) != 1) { /* putstring("Kunde inte skriva till nya sysinfo.dat....\n",-1,0); */ } fclose(fil); } nodestate = SystemTags(commandstring, SYS_UserShell, TRUE, TAG_DONE); AddPort(nikomnodeport); if(!getty || (nodestate & NIKSTATE_RELOGIN)) { if(!(NiKwind = openmywindow(tmppscreen))) cleanup(ERROR,"Kunde inte öppna fönstret\n"); OpenConsole(NiKwind); } serreqtkn(); if(nodestate & NIKSTATE_RELOGIN) goto reloginspec; panik: Delay(hangupdelay); if(getty) cleanup(OK,""); disconnect(); } }
int network_write_file_chunk_sendfile(server *srv, connection *con, int fd, chunkqueue *cq, off_t *p_max_bytes) { chunk* const c = cq->first; ssize_t r; off_t offset; off_t toSend; force_assert(NULL != c); force_assert(FILE_CHUNK == c->type); force_assert(c->offset >= 0 && c->offset <= c->file.length); offset = c->file.start + c->offset; toSend = c->file.length - c->offset; if (toSend > *p_max_bytes) toSend = *p_max_bytes; if (0 == toSend) { chunkqueue_remove_finished_chunks(cq); return 0; } if (0 != network_open_file_chunk(srv, con, cq)) return -1; if (-1 == (r = sendfile(fd, c->file.fd, &offset, toSend))) { switch (errno) { case EAGAIN: case EINTR: break; case EPIPE: case ECONNRESET: return -2; case EINVAL: case ENOSYS: #if defined(ENOTSUP) \ && (!defined(EOPNOTSUPP) || EOPNOTSUPP != ENOTSUP) case ENOTSUP: #endif #ifdef EOPNOTSUPP case EOPNOTSUPP: #endif #ifdef ESOCKTNOSUPPORT case ESOCKTNOSUPPORT: #endif #ifdef EAFNOSUPPORT case EAFNOSUPPORT: #endif #ifdef USE_MMAP return network_write_file_chunk_mmap(srv, con, fd, cq, p_max_bytes); #else return network_write_file_chunk_no_mmap(srv, con, fd, cq, p_max_bytes); #endif default: log_error_write(srv, __FILE__, __LINE__, "ssd", "sendfile failed:", strerror(errno), fd); return -1; } } if (r >= 0) { chunkqueue_mark_written(cq, r); *p_max_bytes -= r; } return (r > 0 && r == toSend) ? 0 : -3; }
/** * @function net.sendfile * * ### Synopsis * * net.sendFile(sock, path); * net.sendFile(sock, path, offset); * net.sendFile(sock, path, offset, size); * * This function calls the OS sendfile() function to send a complete or partial file to the network entirely within kernel space. It is a HUGE speed win for HTTP and FTP type servers. * * @param {int} sock - file descriptor of socket to send the file to. * @param {string} path - file system path to file to send. * @param {int} offset - offset from beginning of file to send (for partial). If omitted, the entire file is sent. * @param {int} size - number of bytes of the file to send. If omitted, the remainder of the file is sent (or all of it). * * ### Exceptions * An exception is thrown if the file cannot be opened or if there is a sendfile(2) OS call error. */ static JSVAL net_sendfile (JSARGS args) { HandleScope handle_scope; int sock = args[0]->IntegerValue(); String::AsciiValue filename(args[1]); off_t offset = 0; if (args.Length() > 2) { offset = args[2]->IntegerValue(); } size_t size; if (args.Length() > 3) { size = args[3]->IntegerValue(); } else { struct stat buf; if (stat(*filename, &buf)) { printf("%s\n", *filename); perror("SendFile stat"); { FILE* fp=fopen("c:\\error.txt", "a+b"); fprintf(fp, "%d", __LINE__); fclose(fp); } return handle_scope.Close(False()); } size = buf.st_size - offset; } #ifdef WIN32 HANDLE fd = CreateFile(*filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN | FILE_ATTRIBUTE_NORMAL, NULL); if (fd == INVALID_HANDLE_VALUE) { #else int fd = open(*filename, O_RDONLY); if (fd < 0) { #endif return ThrowException(String::Concat(String::New("sendFile open Error: "), String::New(strerror(errno)))); } while (size > 0) { #ifdef __APPLE__ off_t count = size; if (sendfile(fd, sock, offset, &count, NULL, 0) == -1) { close(fd); return ThrowException(String::Concat(String::New("sendFile Error: "), String::New(strerror(errno)))); } #else #ifdef WIN32 SetFilePointer(fd, offset, NULL, FILE_BEGIN); TransmitFile(sock, fd, size, 0, NULL, NULL,0); ssize_t count = size; if (count == -1) { CloseHandle(fd); return ThrowException(String::Concat(String::New("sendFile Error: "), String::New(strerror(errno)))); } #else ssize_t count = sendfile(sock, fd, &offset, size); if (count == -1) { close(fd); return ThrowException(String::Concat(String::New("sendFile Error: "), String::New(strerror(errno)))); } #endif #endif size -= count; offset += count; } #ifdef WIN32 CloseHandle(fd); int flag = 0; setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char*)&flag, sizeof (flag)); flag = 1; setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char*)&flag, sizeof (flag)); #else close(fd); int flag = 0; setsockopt(fd, IPPROTO_TCP, TCP_CORK, &flag, sizeof (flag)); flag = 1; setsockopt(fd, IPPROTO_TCP, TCP_CORK, &flag, sizeof (flag)); #endif return Undefined(); } void init_net_object () { HandleScope scope; Handle<ObjectTemplate>net = ObjectTemplate::New(); net->Set(String::New("connect"), FunctionTemplate::New(net_connect)); net->Set(String::New("listen"), FunctionTemplate::New(net_listen)); net->Set(String::New("accept"), FunctionTemplate::New(net_accept)); net->Set(String::New("remote_addr"), FunctionTemplate::New(net_remote_addr)); net->Set(String::New("cork"), FunctionTemplate::New(net_cork)); net->Set(String::New("close"), FunctionTemplate::New(net_close)); net->Set(String::New("read"), FunctionTemplate::New(net_read)); net->Set(String::New("write"), FunctionTemplate::New(net_write)); net->Set(String::New("writeBuffer"), FunctionTemplate::New(net_writebuffer)); net->Set(String::New("sendFile"), FunctionTemplate::New(net_sendfile)); net->Set(String::New("duplicateSocket"), FunctionTemplate::New(net_duplicateSocket)); net->Set(String::New("getSocketDescriptor"), FunctionTemplate::New(net_getSocketDescriptor)); builtinObject->Set(String::New("net"), net); }
int main (int argc, char **argv) { struct sockaddr_un sin1; int server_sockfd, client_sockfd; int server_len, client_len; ssize_t bytes, res=0; ssize_t rtotal = 0; FILE *stream; int in_fd; struct stat buf; off_t off = 0; unlink ("server_socket"); unlink ("src_sendfile_save"); stream = fopen ("src_sendfile_save", "w"); if (!stream) { perror ("fopen"); exit (EXIT_FAILURE); } fclose (stream); if ((in_fd = open ("src", O_RDONLY)) < 0) { printf ("Can't open 'src' file"); exit (EXIT_FAILURE); } if (fstat (in_fd, &buf) == -1) { printf ("Can't stat 'src' file\n"); exit (EXIT_FAILURE); } printf ("Get file size are %u bytes\n", buf.st_size); server_sockfd = socket (AF_UNIX, SOCK_STREAM, 0); if (server_sockfd < 0) { perror ("socket"); exit (EXIT_FAILURE); } sin1.sun_family = AF_UNIX; strcpy (sin1.sun_path, "server_socket"); server_len = sizeof (sin1); if (bind (server_sockfd, (struct sockaddr *)&sin1, server_len) < 0) { perror ("bind"); exit (EXIT_FAILURE); } if (listen (server_sockfd, 5) < 0) { perror ("listen"); exit (EXIT_FAILURE); } printf ("The server is waiting for client connect...\n"); client_sockfd = accept (server_sockfd, (struct sockaddr *)&sin1, (socklen_t *)&client_len); if (client_sockfd == -1 ) { perror ("accept"); exit (EXIT_FAILURE); } while (off < buf.st_size) { if ((res = sendfile (client_sockfd, in_fd, &off, buf.st_size)) < 0 ) { printf ("sendfile failed\n"); exit (EXIT_FAILURE); } else { rtotal += res; } } printf ("server sendfile total %u bytes\n", rtotal); close (client_sockfd); unlink ("server_socket"); return (0); }
static int send_test(int connect_socket, struct sendfile_test test) { struct test_header th; struct sf_hdtr hdtr, *hdtrp; struct iovec headers; char *header; ssize_t len; int length; off_t off; len = lseek(file_fd, 0, SEEK_SET); if (len != 0) FAIL_ERR("lseek") if (test.length == 0) { struct stat st; if (fstat(file_fd, &st) < 0) FAIL_ERR("fstat") length = st.st_size - test.offset; } else { length = test.length; } init_th(&th, test.hdr_length, test.offset, length); len = write(connect_socket, &th, sizeof(th)); if (len != sizeof(th)) return (-1); if (test.hdr_length != 0) { header = malloc(test.hdr_length); if (header == NULL) FAIL_ERR("malloc") hdtrp = &hdtr; bzero(&headers, sizeof(headers)); headers.iov_base = header; headers.iov_len = test.hdr_length; bzero(&hdtr, sizeof(hdtr)); hdtr.headers = &headers; hdtr.hdr_cnt = 1; hdtr.trailers = NULL; hdtr.trl_cnt = 0; } else { hdtrp = NULL; header = NULL; } if (sendfile(file_fd, connect_socket, test.offset, test.length, hdtrp, &off, 0) < 0) { if (header != NULL) free(header); FAIL_ERR("sendfile") } if (length == 0) { struct stat sb; if (fstat(file_fd, &sb) == 0) length = sb.st_size - test.offset; } if (header != NULL) free(header); if (off != length) FAIL("offset != length") return (0); }
bool proxy_connection::loop(unsigned fd) { size_t total = 0; size_t count; int error; bool ret; do { logger::instance().log(logger::LOG_DEBUG, "[proxy_connection::loop] (fd %d) State = %s.", fd, state_to_string(_M_state)); switch (_M_state) { case CONNECTING_STATE: if (!_M_client) { return false; } if ((!socket_wrapper::get_socket_error(fd, error)) || (error)) { logger::instance().log(logger::LOG_WARNING, "(fd %d) Connection to backend failed with error: %d.", fd, error); #if !PROXY _M_client->_M_rule->backends.connection_failed(fd); #endif _M_client->_M_error = http_error::GATEWAY_TIMEOUT; _M_state = PREPARING_ERROR_PAGE_STATE; } else { if (!_M_client->_M_payload_in_memory) { socket_wrapper::cork(fd); } _M_state = SENDING_HEADERS_STATE; } break; case SENDING_HEADERS_STATE: if (!_M_writable) { return true; } if ((!_M_client->_M_payload_in_memory) || (_M_client->_M_request_body_size == 0)) { count = _M_out.count(); ret = write(fd, total); } else { socket_wrapper::io_vector io_vector[2]; io_vector[0].iov_base = _M_out.data(); io_vector[0].iov_len = _M_out.count(); io_vector[1].iov_base = _M_client->_M_in.data() + _M_client->_M_request_header_size; io_vector[1].iov_len = _M_client->_M_request_body_size; count = io_vector[0].iov_len + io_vector[1].iov_len; ret = writev(fd, io_vector, 2, total); } if (!ret) { _M_client->_M_error = http_error::GATEWAY_TIMEOUT; _M_state = PREPARING_ERROR_PAGE_STATE; } else { _M_client->_M_timestamp = now::_M_time; if (_M_outp == (off_t) count) { if (_M_client->_M_payload_in_memory) { if (!modify(fd, tcp_server::READ)) { _M_client->_M_error = http_error::INTERNAL_SERVER_ERROR; _M_state = PREPARING_ERROR_PAGE_STATE; } else { _M_client->_M_body.reset(); _M_state = READING_STATUS_LINE_STATE; } } else { _M_outp = 0; _M_state = SENDING_BODY_STATE; } } } break; case SENDING_BODY_STATE: if (!_M_writable) { return true; } if (!sendfile(fd, _M_client->_M_tmpfile, _M_client->_M_request_body_size, total)) { _M_client->_M_error = http_error::GATEWAY_TIMEOUT; _M_state = PREPARING_ERROR_PAGE_STATE; } else { _M_client->_M_timestamp = now::_M_time; if (_M_outp == (off_t) _M_client->_M_request_body_size) { // We don't need the client's temporary file anymore. static_cast<http_server*>(_M_server)->_M_tmpfiles.close(_M_client->_M_tmpfile); _M_client->_M_tmpfile = -1; socket_wrapper::uncork(fd); if (!modify(fd, tcp_server::READ)) { _M_client->_M_error = http_error::INTERNAL_SERVER_ERROR; _M_state = PREPARING_ERROR_PAGE_STATE; } else { _M_client->_M_body.reset(); _M_state = READING_STATUS_LINE_STATE; } } } break; case READING_STATUS_LINE_STATE: if (!_M_readable) { return true; } if (!read_status_line(fd, total)) { _M_state = PREPARING_ERROR_PAGE_STATE; } break; case READING_HEADERS_STATE: if (!_M_readable) { return true; } if (!read_headers(fd, total)) { _M_state = PREPARING_ERROR_PAGE_STATE; } break; case PROCESSING_RESPONSE_STATE: if (!process_response(fd)) { _M_state = PREPARING_ERROR_PAGE_STATE; } break; case READING_BODY_STATE: if (!_M_readable) { return true; } if (!read_body(fd, total)) { _M_state = PREPARING_ERROR_PAGE_STATE; } break; case READING_CHUNKED_BODY_STATE: if (!_M_readable) { return true; } if (!read_chunked_body(fd, total)) { _M_state = PREPARING_ERROR_PAGE_STATE; } break; case READING_UNKNOWN_SIZE_BODY_STATE: if (!_M_readable) { return true; } if (!read_unknown_size_body(fd, total)) { _M_state = PREPARING_ERROR_PAGE_STATE; } break; case PREPARING_ERROR_PAGE_STATE: if (!http_error::build_page(_M_client)) { return false; } _M_client->_M_response_header_size = _M_client->_M_out.count(); if ((_M_client->_M_method == http_method::HEAD) || (_M_client->_M_bodyp->count() == 0)) { _M_client->_M_filesize = 0; } else { _M_client->_M_filesize = _M_client->_M_bodyp->count(); } _M_client->_M_payload_in_memory = 1; _M_client->_M_in_ready_list = 1; _M_client->_M_state = http_connection::SENDING_BACKEND_HEADERS_STATE; return false; case RESPONSE_COMPLETED_STATE: if (!prepare_http_response(fd)) { _M_client->_M_error = http_error::INTERNAL_SERVER_ERROR; _M_state = PREPARING_ERROR_PAGE_STATE; } else { _M_client->_M_in_ready_list = 1; _M_client->_M_tmpfile = _M_tmpfile; _M_tmpfile = -1; _M_client->_M_state = http_connection::SENDING_BACKEND_HEADERS_STATE; if (!_M_client->_M_payload_in_memory) { socket_wrapper::cork(_M_fd); } return false; } break; } } while (!_M_in_ready_list); return true; }
ngx_chain_t * ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) { int rc, flags; off_t send, prev_send, sent; size_t file_size; ssize_t n; ngx_uint_t eintr, eagain; ngx_err_t err; ngx_buf_t *file; ngx_event_t *wev; ngx_chain_t *cl; ngx_iovec_t header, trailer; struct sf_hdtr hdtr; struct iovec headers[NGX_IOVS_PREALLOCATE]; struct iovec trailers[NGX_IOVS_PREALLOCATE]; wev = c->write; if (!wev->ready) { return in; } #if (NGX_HAVE_KQUEUE) if ((ngx_event_flags & NGX_USE_KQUEUE_EVENT) && wev->pending_eof) { (void) ngx_connection_error(c, wev->kq_errno, "kevent() reported about an closed connection"); wev->error = 1; return NGX_CHAIN_ERROR; } #endif /* the maximum limit size is the maximum size_t value - the page size */ if (limit == 0 || limit > (off_t) (NGX_MAX_SIZE_T_VALUE - ngx_pagesize)) { limit = NGX_MAX_SIZE_T_VALUE - ngx_pagesize; } send = 0; eagain = 0; flags = 0; header.iovs = headers; header.nalloc = NGX_IOVS_PREALLOCATE; trailer.iovs = trailers; trailer.nalloc = NGX_IOVS_PREALLOCATE; for ( ;; ) { eintr = 0; prev_send = send; /* create the header iovec and coalesce the neighbouring bufs */ cl = ngx_output_chain_to_iovec(&header, in, limit - send, c->log); if (cl == NGX_CHAIN_ERROR) { return NGX_CHAIN_ERROR; } send += header.size; if (cl && cl->buf->in_file && send < limit) { file = cl->buf; /* coalesce the neighbouring file bufs */ file_size = (size_t) ngx_chain_coalesce_file(&cl, limit - send); send += file_size; /* create the trailer iovec and coalesce the neighbouring bufs */ cl = ngx_output_chain_to_iovec(&trailer, cl, limit - send, c->log); if (cl == NGX_CHAIN_ERROR) { return NGX_CHAIN_ERROR; } send += trailer.size; if (ngx_freebsd_use_tcp_nopush && c->tcp_nopush == NGX_TCP_NOPUSH_UNSET) { if (ngx_tcp_nopush(c->fd) == NGX_ERROR) { err = ngx_socket_errno; /* * there is a tiny chance to be interrupted, however, * we continue a processing without the TCP_NOPUSH */ if (err != NGX_EINTR) { wev->error = 1; (void) ngx_connection_error(c, err, ngx_tcp_nopush_n " failed"); return NGX_CHAIN_ERROR; } } else { c->tcp_nopush = NGX_TCP_NOPUSH_SET; ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "tcp_nopush"); } } /* * sendfile() does unneeded work if sf_hdtr's count is 0, * but corresponding pointer is not NULL */ hdtr.headers = header.count ? header.iovs : NULL; hdtr.hdr_cnt = header.count; hdtr.trailers = trailer.count ? trailer.iovs : NULL; hdtr.trl_cnt = trailer.count; /* * the "nbytes bug" of the old sendfile() syscall: * http://bugs.freebsd.org/33771 */ if (!ngx_freebsd_sendfile_nbytes_bug) { header.size = 0; } sent = 0; #if (NGX_HAVE_AIO_SENDFILE) flags = c->aio_sendfile ? SF_NODISKIO : 0; #endif rc = sendfile(file->file->fd, c->fd, file->file_pos, file_size + header.size, &hdtr, &sent, flags); if (rc == -1) { err = ngx_errno; switch (err) { case NGX_EAGAIN: eagain = 1; break; case NGX_EINTR: eintr = 1; break; #if (NGX_HAVE_AIO_SENDFILE) case NGX_EBUSY: c->busy_sendfile = file; break; #endif default: wev->error = 1; (void) ngx_connection_error(c, err, "sendfile() failed"); return NGX_CHAIN_ERROR; } ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, err, "sendfile() sent only %O bytes", sent); /* * sendfile() in FreeBSD 3.x-4.x may return value >= 0 * on success, although only 0 is documented */ } else if (rc >= 0 && sent == 0) { /* * if rc is OK and sent equal to zero, then someone * has truncated the file, so the offset became beyond * the end of the file */ ngx_log_error(NGX_LOG_ALERT, c->log, 0, "sendfile() reported that \"%s\" was truncated at %O", file->file->name.data, file->file_pos); return NGX_CHAIN_ERROR; } ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, "sendfile: %d, @%O %O:%uz", rc, file->file_pos, sent, file_size + header.size); } else { n = ngx_writev(c, &header); if (n == NGX_ERROR) { return NGX_CHAIN_ERROR; } sent = (n == NGX_AGAIN) ? 0 : n; } c->sent += sent; in = ngx_chain_update_sent(in, sent); #if (NGX_HAVE_AIO_SENDFILE) if (c->busy_sendfile) { return in; } #endif if (eagain) { /* * sendfile() may return EAGAIN, even if it has sent a whole file * part, it indicates that the successive sendfile() call would * return EAGAIN right away and would not send anything. * We use it as a hint. */ wev->ready = 0; return in; } if (eintr) { send = prev_send + sent; continue; } if (send - prev_send != sent) { wev->ready = 0; return in; } if (send >= limit || in == NULL) { return in; } } }
void httpResponseStaticProc( httpHeader *req_header ) { int len,cllen,ctlen; char path[1024] = {0}; headerOut header_out; memset( &header_out , 0 , sizeof( header_out ) ); header_out.req = req_header; getFilePath( req_header->uri , path ); struct stat stat_file; int ret = stat( path , &stat_file ); if (ret < 0) { respErrorPage( &header_out , 404 ); return; } createCommonHeader( &header_out , 200 ); headerAppendLength( &header_out , stat_file.st_size ); appendRespHeader( &header_out , HEADER_END_LINE ); int nwritten = write( req_header->connfd , header_out.data , header_out.length ); if (nwritten <= 0) { printf( "I/O error writing to client connfd=%d,len=%d: %s \n" , req_header->connfd , header_out.length , strerror( errno ) ); return; } if (req_header->nobody == AE_TRUE) { httpClose( req_header , 1 ); return; } int fd = open( path , O_RDONLY ); if (fd < 0) { printf( "Open file Error:%s,errno=%d \n" , strerror( errno ) , errno ); return; } // setsockopt (fd, SOL_TCP, TCP_CORK, &on, sizeof (on)); off_t offset = 0; int force_close = 0; while (offset < stat_file.st_size) { int sendn = sendfile( req_header->connfd , fd , &offset , stat_file.st_size - offset ); if (sendn < 0) { //如果socket缓冲区不可用,则挂起等待可用 if (errno == EAGAIN || errno == EINTR) { if (anetHandup( req_header->connfd , 5000 , AE_WRITABLE ) < 0) { //如果超时,退出 printf( "Sendfile anetHandup timeout.......\n" ); force_close = 1; break; } else { //否则继续发送 continue; } } else { break; } } } close( fd ); httpClose( req_header , force_close ); }
int main(int argc, char ** argv) { int port; struct stat obj; int sock = -1; struct sockaddr_in address; struct hostent * host; int choice; char buf[100], command[5], filename[20], *f; int k, size, status; int filehandle; int len; /* checking commandline parameter */ if (argc != 4) { printf("usage: %s <hostname> <port> <name>\n", argv[0]); return -1; } /* obtain port number */ if (sscanf(argv[2], "%d", &port) <= 0) { fprintf(stderr, "%s: error: wrong parameter: port\n", argv[0]); return -2; } /* create socket */ sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (sock <= 0) { fprintf(stderr, "%s: error: cannot create socket\n", argv[0]); return -3; } /* connect to server */ address.sin_family = AF_INET; address.sin_port = htons(port); host = gethostbyname(argv[1]); if (!host) { fprintf(stderr, "%s: error: unknown host %s\n", argv[0], argv[1]); return -4; } memcpy(&address.sin_addr, host->h_addr_list[0], host->h_length); if (connect(sock, (struct sockaddr *)&address, sizeof(address))) { fprintf(stderr, "%s: error: cannot connect to host %s\n", argv[0], argv[1]); return -5; } int i = 1; signal(SIGINT,sigproc); /* call signal function */ while(1) { printf("\n***Welcome to C# File Repository System***\n"); printf("\nMain Menu:\n1- Download\n2- Upload\n3- Current Path\n4- List\n5- Change Path\n6- Register\n7- Quit\n"); printf("Enter a choice:"); scanf("%d", &choice); switch(choice) { case 1: printf("\n***Download File***\n"); printf("Enter filename to Download: "); scanf("%s", filename); strcpy(buf, "get "); strcat(buf, filename); send(sock, buf, 100, 0); recv(sock, &size, sizeof(int), 0); if(!size) { printf("No such file on the remote directory\n\n"); break; } f = malloc(size); recv(sock, f, size, 0); printf("Downloading....\n\n"); while(1) { filehandle = open(filename, O_CREAT | O_EXCL | O_WRONLY, 0666); if(filehandle == -1) { sprintf(filename + strlen(filename), "%d", i);//needed only if same directory is used for both server and client } else break; } write(filehandle, f, size); close(filehandle); printf("Download completed\n\n"); break; case 2: printf("\n***Upload File***\n"); printf("Enter filename to put to server: "); scanf("%s", filename); filehandle = open(filename, O_RDONLY); if(filehandle == -1) { printf("No such file on the local directory\n\n"); break; } printf("Uploading....\n\n"); strcpy(buf, "put "); strcat(buf, filename); send(sock, buf, 100, 0); stat(filename, &obj); size = obj.st_size; send(sock, &size, sizeof(int), 0); sendfile(sock, filehandle, NULL, size); recv(sock, &status, sizeof(int), 0); if(status) printf("File stored successfully\n"); else printf("File failed to be stored to remote machine\n"); break; case 3: strcpy(buf, "pwd"); send(sock, buf, 100, 0); recv(sock, buf, 100, 0); printf("\n***Current Path***\n"); printf("Path: %s\n", buf); break; case 4: printf("\n***List of Current Directory***\n"); strcpy(buf, "ls"); send(sock, buf, 100, 0); recv(sock, &size, sizeof(int), 0); f = malloc(size); recv(sock, f, size, 0); filehandle = creat("temp.txt", O_WRONLY); system("chmod 666 temp.txt"); write(filehandle, f, size); close(filehandle); printf("The remote directory listing is as follows:\n"); printf("-------------------------------------------\n"); system("cat temp.txt"); printf("-------------------------------------------\n"); break; case 5: strcpy(buf, "cd "); printf("\n***Change Path***\n"); printf("Enter the path to change the remote directory: "); scanf("%s", buf + 3); send(sock, buf, 100, 0); recv(sock, &status, sizeof(int), 0); if(status) printf("Remote directory successfully changed\n"); else printf("Remote directory failed to change\n"); break; case 6: strcpy(buf, "register"); send(sock, buf, 100, 0); char username[BUFSIZ], password1[BUFSIZ], /* Buffers for user input and comparison */ password2[BUFSIZ], *pbuf; /* Get the username */ printf("Username: "******"%s", username); strcpy(buf, username); strcat(buf, ":"); do { /* Get the password */ pbuf = getpass("Password: "******"stable" pointer */ sprintf(password1, "%s", pbuf); /* Get the password */ pbuf = getpass("Enter Again: "); /* Copy to a "stable" pointer */ sprintf(password2, "%s", pbuf); /* See if the passwords are the same */ if(strcmp(password1, password2) != 0) printf("\nPasswords do not match!\nTry again.\n\n"); } while(strcmp(password1, password2) != 0); strcat(buf, password2); send(sock, buf, 100, 0); recv(sock, &status, sizeof(int), 0); if(status) printf("User successfully registered\n"); else printf("Error. Registration failed.\n"); break; case 7: strcpy(buf, "quit"); send(sock, buf, 100, 0); len = strlen(argv[3]); write(sock, &len, sizeof(int)); write(sock, argv[3], len); printf("Successfully Disconnected.\nQuitting..\n"); /* close socket */ close(sock); return 0; } } }
int initbrevheader(int tillpers) { int length=0,x=0,lappnr; long tid,tempmott; struct tm *ts; struct User usr; char filnamn[40],*mottagare,tempbuf[10],*vemskrev; Servermem->action[nodnr] = SKRIVER; Servermem->varmote[nodnr] = -1; memset(&brevspar,0,sizeof(struct ReadLetter)); if(tillpers==-1) { strcpy(brevspar.to,brevread.from); mottagare=brevread.to; while(mottagare[0]) { tempmott=atoi(mottagare); if(tempmott==inloggad || recisthere(brevspar.to,tempmott)) { mottagare=hittaefter(mottagare); continue; } sprintf(tempbuf," %d",tempmott); strcat(brevspar.to,tempbuf); mottagare=hittaefter(mottagare); } sprintf(brevspar.reply,"%d %d %s",senast_brev_anv,senast_brev_nr,brevread.from); } else { sprintf(brevspar.to,"%d",tillpers); } sprintf(brevspar.from,"%d",inloggad); readuser(atoi(brevspar.to),&usr); if(usr.flaggor & LAPPBREV) { puttekn("\r\n\n",-1); lappnr=atoi(brevspar.to); sprintf(filnamn,"NiKom:Users/%d/%d/Lapp",lappnr/100,lappnr); if(!access(filnamn,0)) sendfile(filnamn); puttekn("\r\n",-1); } time(&tid); ts=localtime(&tid); sprintf(brevspar.date,"%2d%02d%02d %02d:%02d",ts->tm_year,ts->tm_mon+1,ts->tm_mday,ts->tm_hour,ts->tm_min); strcpy(brevspar.systemid,"NiKom"); sprintf(outbuffer,"\r\n\nMöte: %s\r\n",Servermem->cfg.brevnamn); puttekn(outbuffer,-1); sprintf(outbuffer,"Lokalt brev, %s\n\r",brevspar.date); puttekn(outbuffer,-1); sprintf(outbuffer,"Avsändare: %s\r\n",getusername(inloggad)); puttekn(outbuffer,-1); if(brevspar.reply[0]) { vemskrev=hittaefter(hittaefter(brevspar.reply)); sprintf(outbuffer,"Kommentar till en text av %s\r\n",getusername(atoi(vemskrev))); puttekn(outbuffer,-1); } mottagare=brevspar.to; while(mottagare[0]) { sprintf(outbuffer,"Mottagare: %s\n\r",getusername(atoi(mottagare))); puttekn(outbuffer,-1); mottagare=hittaefter(mottagare); } puttekn("Ärende: ",-1); if(tillpers==-1) { strcpy(brevspar.subject,brevread.subject); puttekn(brevspar.subject,-1); } else { if(getstring(EKO,40,NULL)) return(1); if(!inmat[0]) { eka('\n'); return(2); } strcpy(brevspar.subject,inmat); } puttekn("\r\n",-1); if(Servermem->inne[nodnr].flaggor & STRECKRAD) { length=strlen(brevspar.subject); for(x=0;x<length+8;x++) outbuffer[x]='-'; outbuffer[x]=0; puttekn(outbuffer,-1); puttekn("\r\n\n",-1); } else puttekn("\n",-1); return(0); }
/** * @short This shortcut returns the given file contents. * * It sets all the compilant headers (TODO), cache and so on. * * This is the recomended way to send static files; it even can use sendfile Linux call * if suitable (TODO). * * It does no security checks, so caller must be security aware. */ onion_connection_status onion_shortcut_response_file(const char *filename, onion_request *request, onion_response *res){ int fd=open(filename,O_RDONLY|O_CLOEXEC); if (fd<0) return OCS_NOT_PROCESSED; if(O_CLOEXEC == 0) { // Good compiler know how to cut this out int flags=fcntl(fd, F_GETFD); if (flags==-1){ ONION_ERROR("Retrieving flags from file descriptor"); } flags|=FD_CLOEXEC; if (fcntl(fd, F_SETFD, flags)==-1){ ONION_ERROR("Setting O_CLOEXEC to file descriptor"); } } struct stat st; if (stat(filename, &st)!=0){ ONION_WARNING("File does not exist: %s",filename); close(fd); return OCS_NOT_PROCESSED; } if (S_ISDIR(st.st_mode)){ close(fd); return OCS_NOT_PROCESSED; } size_t length=st.st_size; char etag[64]; onion_shortcut_etag(&st, etag); const char *range=onion_request_get_header(request, "Range"); if (range){ strncat(etag,range,sizeof(etag)-1); } onion_response_set_header(res, "Etag", etag); if (range && strncmp(range,"bytes=",6)==0){ onion_response_set_code(res, HTTP_PARTIAL_CONTENT); //ONION_DEBUG("Need just a range: %s",range); char tmp[1024]; strncpy(tmp, range+6, 1024); char *start=tmp; char *end=tmp; while (*end!='-' && *end) end++; if (*end=='-'){ *end='\0'; end++; //ONION_DEBUG("Start %s, end %s",start,end); size_t ends, starts; if (*end) ends=atol(end); else ends=length; starts=atol(start); length=ends-starts+1; lseek(fd, starts, SEEK_SET); snprintf(tmp,sizeof(tmp),"bytes %d-%d/%d",(unsigned int)starts, (unsigned int)ends, (unsigned int)st.st_size); //onion_response_set_header(res, "Accept-Ranges","bytes"); onion_response_set_header(res, "Content-Range",tmp); } } onion_response_set_length(res, length); onion_response_set_header(res, "Content-Type", onion_mime_get(filename) ); ONION_DEBUG("Mime type is %s",onion_mime_get(filename)); ONION_DEBUG0("Etag %s", etag); const char *prev_etag=onion_request_get_header(request, "If-None-Match"); if (prev_etag && (strcmp(prev_etag, etag)==0)){ ONION_DEBUG0("Not modified"); onion_response_set_length(res, 0); onion_response_set_code(res, HTTP_NOT_MODIFIED); onion_response_write_headers(res); close(fd); return OCS_PROCESSED; } onion_response_write_headers(res); if ((onion_request_get_flags(request)&OR_HEAD) == OR_HEAD){ // Just head. length=0; } if (length){ #ifdef USE_SENDFILE if (request->connection.listen_point->write==(void*)onion_http_write){ // Lets have a house party! I can use sendfile! onion_response_write(res,NULL,0); ONION_DEBUG("Using sendfile"); int r=sendfile(request->connection.fd, fd, NULL, length); ONION_DEBUG("Wrote %d, should be %d (%s)", r, length, r==length ? "ok" : "nok"); if (r!=length || r<0){ ONION_ERROR("Could not send all file (%s)", strerror(errno)); close(fd); return OCS_INTERNAL_ERROR; } res->sent_bytes+=length; res->sent_bytes_total+=length; } else #endif { // Ok, no I cant, do it as always. int r=0,w; size_t tr=0; char tmp[4046]; if (length>sizeof(tmp)){ size_t max=length-sizeof(tmp); while( tr<max ){ r=read(fd,tmp,sizeof(tmp)); tr+=r; if (r<0) break; w=onion_response_write(res, tmp, r); if (w!=r){ ONION_ERROR("Wrote less than read: write %d, read %d. Quite probably closed connection.",w,r); break; } } } if (sizeof(tmp) >= (length-tr)){ r=read(fd, tmp, length-tr); w=onion_response_write(res, tmp, r); if (w!=r){ ONION_ERROR("Wrote less than read: write %d, read %d. Quite probably closed connection.",w,r); } } } } close(fd); return OCS_PROCESSED; }
static ssize_t uv__fs_sendfile(uv_fs_t* req) { int in_fd; int out_fd; in_fd = req->flags; out_fd = req->file; #if defined(__linux__) || defined(__sun) { off_t off; ssize_t r; off = req->off; r = sendfile(out_fd, in_fd, &off, req->len); /* sendfile() on SunOS returns EINVAL if the target fd is not a socket but * it still writes out data. Fortunately, we can detect it by checking if * the offset has been updated. */ if (r != -1 || off > req->off) { r = off - req->off; req->off = off; return r; } if (errno == EINVAL || errno == EIO || errno == ENOTSOCK || errno == EXDEV) { errno = 0; return uv__fs_sendfile_emul(req); } return -1; } #elif defined(__FreeBSD__) || defined(__APPLE__) { off_t len; ssize_t r; /* sendfile() on FreeBSD and Darwin returns EAGAIN if the target fd is in * non-blocking mode and not all data could be written. If a non-zero * number of bytes have been sent, we don't consider it an error. */ len = 0; #if defined(__FreeBSD__) r = sendfile(in_fd, out_fd, req->off, req->len, NULL, &len, 0); #else r = sendfile(in_fd, out_fd, req->off, &len, NULL, 0); #endif if (r != -1 || len != 0) { req->off += len; return (ssize_t) len; } if (errno == EINVAL || errno == EIO || errno == ENOTSOCK || errno == EXDEV) { errno = 0; return uv__fs_sendfile_emul(req); } return -1; } #else return uv__fs_sendfile_emul(req); #endif }
int main(int argc, char *argv[]) { int c; extern int optind; const char *optlet = "v"; int verbose = 0; int fd, rfd; char *file, *rfile; int i, ret; off_t off; pid_t pid; char* addr, *raddr; char buf[4096]; void *first, *second; while ((c = getopt(argc, argv, optlet)) != EOF) { switch (c) { case 'v': verbose = 1; break; case '?': default: usage(argv[0]); return (1); } } if (optind == argc) { usage(argv[0]); return (1); } // verify that mmap to a busy location works printf("region allocation errors expected for next test\n"); first = mmap(0, 4096, PROT_WRITE, MAP_ANONYMOUS, 0, 0); second = mmap(first, 4096, PROT_WRITE, MAP_ANONYMOUS, 0, 0); file = argv[optind]; fd = open(file, O_RDWR | O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP); if (fd == -1) { fprintf(stderr, "%s: open(): %s: %s\n", argv[0], file, strerror(errno)); return (1); } verbose_out(verbose, "open() succeeded, going to mmap\n"); addr = mmap(0, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); if (addr == MAP_FAILED) { fprintf(stderr, "%s: mmap(): %s: %s\n", argv[0], file, strerror(errno)); return (1); } if (optind+1 < argc) { rfile = argv[optind+1]; rfd = open(rfile, O_RDONLY, 0); if (rfd == -1) { fprintf(stderr, "%s: open(): %s: %s\n", argv[0], rfile, strerror(errno)); return (1); } verbose_out(verbose, "open() succeeded, going to mmap\n"); raddr = mmap(0, 4096, PROT_READ, MAP_SHARED, rfd, 0); if (raddr == MAP_FAILED) { fprintf(stderr, "%s: mmap(): %s: %s\n", argv[0], rfile, strerror(errno)); return (1); } } else { rfd = -1; rfile = 0; raddr = 0; // prevent compile warnings } verbose_out(verbose, "It is going to write\n"); for (i = 0; i < 4096; i++) { addr[i] = i; } verbose_out(verbose, "writing succeeded\n"); verbose_out(verbose, "it's going to fork\n"); if ((pid = fork()) == 0) { // child verbose_out(verbose, "fork() succeeded\n"); for (i = 0; i < 4096; i++) { if(addr[i] != (i&0xff)) { fprintf(stderr, "compare failed: byte %d contained %d\n", i, addr[i]); return (1); } } off = lseek(fd, 0, SEEK_SET); if (off == -1) { fprintf(stderr, "%s: lseek(): %s: %s\n", argv[0], file, strerror(errno)); return (1); } if (off != 0) { fprintf(stderr, "%s: lseek() didn't returned 0 as expected\n", argv[0]); return (1); } verbose_out(verbose, "lseek() in child succeeded\n"); verbose_out(verbose, "Child is going to read\n"); i = read(fd, buf, 4096); if (i == -1) { fprintf(stderr, "%s: read(): %s: %s\n", argv[0], file, strerror(errno)); return (1); } else if (i != 4096) { fprintf(stderr, "%s: file length wrong", argv[0]); return (1); } for (i = 0; i < 4096; i++) { if(buf[i] != (i&0xff)) { fprintf(stderr, "compare failed: byte %d contained %d\n", i, buf[i]); return (1); } } verbose_out(verbose, "reading in child process succeeded\n"); if (rfd != -1) { ssize_t count; off_t offset; fprintf(stdout, "read of first line of %s\n", rfile); for(i = 0;raddr[i] != '\n' && i < 128; i++) { buf[i] = raddr[i]; } buf[i] = 0; fprintf(stdout, "%s\n", buf); // now test sendfile ftruncate(fd, 0); lseek(fd, 0, SEEK_SET); offset = 0; count = sendfile(fd, rfd, &offset, 1000000); if(count == -1) { fprintf(stderr, "%s: sendfile(): %s: %s\n", argv[0], file, strerror(errno)); return (1); } } return 0; } else if (pid != -1) { i = wait(&ret); if (i == -1) { fprintf(stderr, "%s: wait failed:%s\n", argv[0], strerror(errno)); return(1); } } else { fprintf(stderr, "%s: fork failed:%s\n", argv[0], strerror(errno)); return(1); } if (!ret) { verbose_out(verbose, "Test succeeded.\n"); } return (ret); }