int wl_connection_data(struct wl_connection *connection, uint32_t mask) { struct wl_buffer *b; struct iovec iov[2]; int len, head, tail, count, size, available; if (mask & WL_CONNECTION_READABLE) { b = &connection->in; head = connection->in.head; if (head < b->tail) { iov[0].iov_base = b->data + head; iov[0].iov_len = b->tail - head; count = 1; } else { size = ARRAY_LENGTH(b->data) - head; iov[0].iov_base = b->data + head; iov[0].iov_len = size; iov[1].iov_base = b->data; iov[1].iov_len = b->tail; count = 2; } len = readv(connection->fd, iov, count); if (len < 0) { fprintf(stderr, "read error from connection %p: %m (%d)\n", connection, errno); return -1; } else if (len == 0) { /* FIXME: Handle this better? */ return -1; } else if (head + len <= ARRAY_LENGTH(b->data)) { b->head += len; } else { b->head = head + len - ARRAY_LENGTH(b->data); } /* We know we have data in the buffer at this point, * so if head equals tail, it means the buffer is * full. */ available = b->head - b->tail; if (available == 0) available = sizeof b->data; else if (available < 0) available += ARRAY_LENGTH(b->data); } else { available = 0; } if (mask & WL_CONNECTION_WRITABLE) { b = &connection->out; tail = b->tail; if (tail < b->head) { iov[0].iov_base = b->data + tail; iov[0].iov_len = b->head - tail; count = 1; } else { size = ARRAY_LENGTH(b->data) - tail; iov[0].iov_base = b->data + tail; iov[0].iov_len = size; iov[1].iov_base = b->data; iov[1].iov_len = b->head; count = 2; } len = writev(connection->fd, iov, count); if (len < 0) { fprintf(stderr, "write error for connection %p: %m\n", connection); return -1; } else if (tail + len <= ARRAY_LENGTH(b->data)) { b->tail += len; } else { b->tail = tail + len - ARRAY_LENGTH(b->data); } /* We just took data out of the buffer, so at this * point if head equals tail, the buffer is empty. */ if (b->tail == b->head) connection->update(connection, WL_CONNECTION_READABLE, connection->data); } return available; }
ngx_chain_t * ngx_linux_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) { ngx_log_debug(NGX_LOG_DEBUG_HTTP, c->log, 0, "ngx_linux_sendfile_chain"); int rc, tcp_nodelay; off_t size, send, prev_send, aligned, sent, fprev; u_char *prev; size_t file_size; ngx_err_t err; ngx_buf_t *file; ngx_uint_t eintr, complete; ngx_array_t header; ngx_event_t *wev; ngx_chain_t *cl; struct iovec *iov, headers[NGX_HEADERS]; #if (NGX_HAVE_SENDFILE64) off_t offset; #else int32_t offset; #endif wev = c->write; if (!wev->ready) { return in; } /* the maximum limit size is 2G-1 - the page size */ if (limit == 0 || limit > (off_t) (NGX_SENDFILE_MAXSIZE - ngx_pagesize)) { limit = NGX_SENDFILE_MAXSIZE - ngx_pagesize; } send = 0; header.elts = headers; header.size = sizeof(struct iovec); header.nalloc = NGX_HEADERS; header.pool = c->pool; for ( ;; ) { file = NULL; file_size = 0; eintr = 0; complete = 0; prev_send = send; header.nelts = 0; prev = NULL; iov = NULL; /* create the iovec and coalesce the neighbouring bufs */ for (cl = in; cl && send < limit; cl = cl->next) { if (ngx_buf_special(cl->buf)) { continue; } #if 1 if (!ngx_buf_in_memory(cl->buf) && !cl->buf->in_file) { ngx_log_error(NGX_LOG_ALERT, c->log, 0, "zero size buf in sendfile " "t:%d r:%d f:%d %p %p-%p %p %O-%O", cl->buf->temporary, cl->buf->recycled, cl->buf->in_file, cl->buf->start, cl->buf->pos, cl->buf->last, cl->buf->file, cl->buf->file_pos, cl->buf->file_last); ngx_debug_point(); return NGX_CHAIN_ERROR; } #endif if (!ngx_buf_in_memory_only(cl->buf)) { break; } size = cl->buf->last - cl->buf->pos; if (send + size > limit) { size = limit - send; } if (prev == cl->buf->pos) { iov->iov_len += (size_t) size; } else { if (header.nelts >= IOV_MAX) { break; } iov = ngx_array_push(&header); if (iov == NULL) { return NGX_CHAIN_ERROR; } iov->iov_base = (void *) cl->buf->pos; iov->iov_len = (size_t) size; } prev = cl->buf->pos + (size_t) size; send += size; } /* set TCP_CORK if there is a header before a file */ if (c->tcp_nopush == NGX_TCP_NOPUSH_UNSET && header.nelts != 0 && cl && cl->buf->in_file) { /* the TCP_CORK and TCP_NODELAY are mutually exclusive */ if (c->tcp_nodelay == NGX_TCP_NODELAY_SET) { tcp_nodelay = 0; if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY, (const void *) &tcp_nodelay, sizeof(int)) == -1) { err = ngx_socket_errno; /* * there is a tiny chance to be interrupted, however, * we continue a processing with the TCP_NODELAY * and without the TCP_CORK */ if (err != NGX_EINTR) { wev->error = 1; ngx_connection_error(c, err, "setsockopt(TCP_NODELAY) failed"); return NGX_CHAIN_ERROR; } } else { c->tcp_nodelay = NGX_TCP_NODELAY_UNSET; ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "no tcp_nodelay"); } } if (c->tcp_nodelay == NGX_TCP_NODELAY_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_CORK */ if (err != NGX_EINTR) { wev->error = 1; 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"); } } } /* get the file buf */ if (header.nelts == 0 && cl && cl->buf->in_file && send < limit) { file = cl->buf; /* coalesce the neighbouring file bufs */ do { size = cl->buf->file_last - cl->buf->file_pos; if (send + size > limit) { size = limit - send; aligned = (cl->buf->file_pos + size + ngx_pagesize - 1) & ~((off_t) ngx_pagesize - 1); if (aligned <= cl->buf->file_last) { size = aligned - cl->buf->file_pos; } } file_size += (size_t) size; send += size; fprev = cl->buf->file_pos + size; cl = cl->next; } while (cl && cl->buf->in_file && send < limit && file->file->fd == cl->buf->file->fd && fprev == cl->buf->file_pos); } if (file) { #if 1 if (file_size == 0) { ngx_debug_point(); return NGX_CHAIN_ERROR; } #endif #if (NGX_HAVE_SENDFILE64) offset = file->file_pos; #else offset = (int32_t) file->file_pos; #endif ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, "sendfile: @%O %uz", file->file_pos, file_size); rc = sendfile(c->fd, file->file->fd, &offset, file_size); if (rc == -1) { err = ngx_errno; switch (err) { case NGX_EAGAIN: break; case NGX_EINTR: eintr = 1; break; default: wev->error = 1; ngx_connection_error(c, err, "sendfile() failed"); return NGX_CHAIN_ERROR; } ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, "sendfile() is not ready"); } sent = rc > 0 ? rc : 0; ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, "sendfile: %d, @%O %O:%uz", rc, file->file_pos, sent, file_size); } else { rc = writev(c->fd, header.elts, header.nelts); if (rc == -1) { err = ngx_errno; switch (err) { case NGX_EAGAIN: break; case NGX_EINTR: eintr = 1; break; default: wev->error = 1; ngx_connection_error(c, err, "writev() failed"); return NGX_CHAIN_ERROR; } ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, "writev() not ready"); } sent = rc > 0 ? rc : 0; ngx_log_debug(NGX_LOG_DEBUG_EVENT, c->log, 0, "writev: %O, fd:%d", sent, c->fd); } if (send - prev_send == sent) { complete = 1; } c->sent += sent; for ( /* void */ ; in; in = in->next) { if (ngx_buf_special(in->buf)) { continue; } if (sent == 0) { break; } size = ngx_buf_size(in->buf); if (sent >= size) { sent -= size; if (ngx_buf_in_memory(in->buf)) { in->buf->pos = in->buf->last; } if (in->buf->in_file) { in->buf->file_pos = in->buf->file_last; } continue; } if (ngx_buf_in_memory(in->buf)) { in->buf->pos += (size_t) sent; } if (in->buf->in_file) { in->buf->file_pos += sent; } break; } if (eintr) { continue; } if (!complete) { wev->ready = 0; return in; } if (send >= limit || in == NULL) { return in; } } }
void write_file(iface_t *ifa) { struct if_file *ifc = (struct if_file *) ifa->info; senblk_t *sptr; int usereturn=flag_test(ifa,F_NOCR)?0:1; int data=0; int cnt=1; struct iovec iov[2]; /* ifc->fd will only be < 0 if we're opening a FIFO. */ if (ifc->fd < 0) { if ((ifc->fd=open(ifc->filename,O_WRONLY)) < 0) { logerr(errno,"Failed to open FIFO %s for writing\n",ifc->filename); iface_thread_exit(errno); } if ((ifa->q =init_q(ifc->qsize)) == NULL) { logerr(errno,"Could not create queue for FIFO %s",ifc->filename); iface_thread_exit(errno); } } if (ifa->tagflags) { if ((iov[0].iov_base=malloc(TAGMAX)) == NULL) { logerr(errno,"Disabing tag output on interface id %u (%s)", ifa->id,(ifa->name)?ifa->name:"unlabelled"); ifa->tagflags=0; } else { cnt=2; data=1; } } for(;;) { if ((sptr = next_senblk(ifa->q)) == NULL) { break; } if (senfilter(sptr,ifa->ofilter)) { senblk_free(sptr,ifa->q); continue; } if (!usereturn) { sptr->data[sptr->len-2] = '\n'; sptr->len--; } if (ifa->tagflags) if ((iov[0].iov_len = gettag(ifa,iov[0].iov_base,sptr)) == 0) { logerr(errno,"Disabing tag output on interface id %u (%s)", ifa->id,(ifa->name)?ifa->name:"unlabelled"); ifa->tagflags=0; cnt=1; data=0; free(iov[0].iov_base); } iov[data].iov_base=sptr->data; iov[data].iov_len=sptr->len; if (writev(ifc->fd,iov,cnt) <0) { if (!(flag_test(ifa,F_PERSIST) && errno == EPIPE) ) break; if ((ifc->fd=open(ifc->filename,O_WRONLY)) < 0) break; } senblk_free(sptr,ifa->q); } if (cnt == 2) free(iov[0].iov_base); iface_thread_exit(errno); }
int32_t sdp_register_service(void *xss, uint16_t uuid, bdaddr_p const bdaddr, uint8_t const *data, uint32_t datalen, uint32_t *handle) { sdp_session_p ss = (sdp_session_p) xss; struct iovec iov[4]; sdp_pdu_t pdu; int32_t len; if (ss == NULL) return (-1); if (bdaddr == NULL || data == NULL || datalen == 0 || !(ss->flags & SDP_SESSION_LOCAL)) { ss->error = EINVAL; return (-1); } if (sizeof(pdu)+sizeof(uuid)+sizeof(*bdaddr)+datalen > SDP_LOCAL_MTU) { ss->error = EMSGSIZE; return (-1); } pdu.pid = SDP_PDU_SERVICE_REGISTER_REQUEST; pdu.tid = htons(++ss->tid); pdu.len = htons(sizeof(uuid) + sizeof(*bdaddr) + datalen); uuid = htons(uuid); iov[0].iov_base = (void *) &pdu; iov[0].iov_len = sizeof(pdu); iov[1].iov_base = (void *) &uuid; iov[1].iov_len = sizeof(uuid); iov[2].iov_base = (void *) bdaddr; iov[2].iov_len = sizeof(*bdaddr); iov[3].iov_base = (void *) data; iov[3].iov_len = datalen; do { len = writev(ss->s, iov, sizeof(iov)/sizeof(iov[0])); } while (len < 0 && errno == EINTR); if (len < 0) { ss->error = errno; return (-1); } len = sdp_receive_error_pdu(ss); if (len < 0) return (-1); if (len != sizeof(pdu) + sizeof(uint16_t) + sizeof(uint32_t)) { ss->error = EIO; return (-1); } if (handle != NULL) { *handle = (uint32_t) ss->rsp[--len]; *handle |= (uint32_t) ss->rsp[--len] << 8; *handle |= (uint32_t) ss->rsp[--len] << 16; *handle |= (uint32_t) ss->rsp[--len] << 24; } return (0); }
static void * replay_thread(void *arg) { struct iovec iov[6]; char space[1] = " ", crlf[2] = "\r\n"; struct replay_thread *thr = arg; struct message *msg; enum shmlogtag tag; size_t len; char *ptr; const char *next; int i; int reopen = 1; while ((msg = mailbox_get(&thr->mbox)) != NULL) { tag = msg->tag; len = msg->len; ptr = msg->ptr; thread_log(2, 0, "%s(%s)", VSL_tags[tag], msg->ptr); switch (tag) { case SLT_RxRequest: if (thr->method != NULL) thr->bogus = 1; else thr->method = trimline(thr, ptr); break; case SLT_RxURL: if (thr->url != NULL) thr->bogus = 1; else thr->url = trimline(thr, ptr); break; case SLT_RxProtocol: if (thr->proto != NULL) thr->bogus = 1; else thr->proto = trimline(thr, ptr); break; case SLT_RxHeader: if (thr->nhdr >= sizeof thr->hdr / sizeof *thr->hdr) { thr->bogus = 1; } else { thr->hdr[thr->nhdr++] = trimline(thr, ptr); if (isprefix(ptr, "connection:", &next)) thr->conn = trimline(thr, next); } break; default: break; } freez(msg->ptr); freez(msg); if (tag != SLT_ReqEnd) continue; if (!thr->method || !thr->url || !thr->proto) { thr->bogus = 1; } else if (strcmp(thr->method, "GET") != 0 && strcmp(thr->method, "HEAD") != 0) { thr->bogus = 1; } else if (strcmp(thr->proto, "HTTP/1.0") == 0) { reopen = !(thr->conn && strcasecmp(thr->conn, "keep-alive") == 0); } else if (strcmp(thr->proto, "HTTP/1.1") == 0) { reopen = (thr->conn && strcasecmp(thr->conn, "close") == 0); } else { thr->bogus = 1; } if (thr->bogus) { thread_log(1, 0, "bogus"); goto clear; } if (thr->sock == -1) { for (;;) { thread_log(1, 0, "sleeping before connect..."); usleep(1000 * (thr->fd % 3001)); if ((thr->sock = VSS_connect(addr_info)) >= 0) break; thread_log(0, errno, "connect failed"); } } thread_log(1, 0, "%s %s %s", thr->method, thr->url, thr->proto); iov[0].iov_base = thr->method; iov[0].iov_len = strlen(thr->method); iov[2].iov_base = thr->url; iov[2].iov_len = strlen(thr->url); iov[4].iov_base = thr->proto; iov[4].iov_len = strlen(thr->proto); iov[1].iov_base = iov[3].iov_base = space; iov[1].iov_len = iov[3].iov_len = 1; iov[5].iov_base = crlf; iov[5].iov_len = 2; if (writev(thr->sock, iov, 6) == -1) { thread_log(0, errno, "writev()"); goto close; } for (i = 0; i < thr->nhdr; ++i) { thread_log(2, 0, "%d %s", i, thr->hdr[i]); iov[0].iov_base = thr->hdr[i]; iov[0].iov_len = strlen(thr->hdr[i]); iov[1].iov_base = crlf; iov[1].iov_len = 2; if (writev(thr->sock, iov, 2) == -1) { thread_log(0, errno, "writev()"); goto close; } } if (write(thr->sock, crlf, 2) == -1) { thread_log(0, errno, "writev()"); goto close; } if (receive_response(thr) || reopen) { close: thread_log(1, 0, "close"); assert(thr->sock != -1); close(thr->sock); thr->sock = -1; } sleep(1); clear: /* clean up */ thread_clear(thr); } /* leftovers */ thread_clear(thr); return (0); }
apr_status_t apr_socket_sendfile(apr_socket_t *sock, apr_file_t *file, apr_hdtr_t *hdtr, apr_off_t *offset, apr_size_t *len, apr_int32_t flags) { int i; apr_ssize_t rc; apr_size_t nbytes = *len, headerlen, trailerlen; struct iovec hdtrarray[2]; char *headerbuf, *trailerbuf; if (!hdtr) { hdtr = &no_hdtr; } /* Ignore flags for now. */ flags = 0; /* HP-UX can only send one header iovec and one footer iovec; try to * only allocate storage to combine input iovecs when we really have to */ switch(hdtr->numheaders) { case 0: hdtrarray[0].iov_base = NULL; hdtrarray[0].iov_len = 0; break; case 1: hdtrarray[0] = hdtr->headers[0]; break; default: headerlen = 0; for (i = 0; i < hdtr->numheaders; i++) { headerlen += hdtr->headers[i].iov_len; } /* XXX: BUHHH? wow, what a memory leak! */ headerbuf = hdtrarray[0].iov_base = apr_palloc(sock->cntxt, headerlen); hdtrarray[0].iov_len = headerlen; for (i = 0; i < hdtr->numheaders; i++) { memcpy(headerbuf, hdtr->headers[i].iov_base, hdtr->headers[i].iov_len); headerbuf += hdtr->headers[i].iov_len; } } switch(hdtr->numtrailers) { case 0: hdtrarray[1].iov_base = NULL; hdtrarray[1].iov_len = 0; break; case 1: hdtrarray[1] = hdtr->trailers[0]; break; default: trailerlen = 0; for (i = 0; i < hdtr->numtrailers; i++) { trailerlen += hdtr->trailers[i].iov_len; } /* XXX: BUHHH? wow, what a memory leak! */ trailerbuf = hdtrarray[1].iov_base = apr_palloc(sock->cntxt, trailerlen); hdtrarray[1].iov_len = trailerlen; for (i = 0; i < hdtr->numtrailers; i++) { memcpy(trailerbuf, hdtr->trailers[i].iov_base, hdtr->trailers[i].iov_len); trailerbuf += hdtr->trailers[i].iov_len; } } do { if (nbytes) { /* any bytes to send from the file? */ rc = sendfile(sock->socketdes, /* socket */ file->filedes, /* file descriptor to send */ *offset, /* where in the file to start */ nbytes, /* number of bytes to send from file */ hdtrarray, /* Headers/footers */ flags); /* undefined, set to 0 */ } else { /* we can't call sendfile() with no bytes to send from the file */ rc = writev(sock->socketdes, hdtrarray, 2); } } while (rc == -1 && errno == EINTR); while (rc == -1 && (errno == EAGAIN || errno == EWOULDBLOCK) && apr_is_option_set(sock->netmask, APR_SO_TIMEOUT)) { apr_status_t arv = apr_wait_for_io_or_timeout(NULL, sock, 0); if (arv != APR_SUCCESS) { *len = 0; return arv; } else { do { if (nbytes) { rc = sendfile(sock->socketdes, /* socket */ file->filedes, /* file descriptor to send */ *offset, /* where in the file to start */ nbytes, /* number of bytes to send from file */ hdtrarray, /* Headers/footers */ flags); /* undefined, set to 0 */ } else { /* we can't call sendfile() with no bytes to send from the file */ rc = writev(sock->socketdes, hdtrarray, 2); } } while (rc == -1 && errno == EINTR); } } if (rc == -1) { *len = 0; return errno; } /* Set len to the number of bytes written */ *len = rc; return APR_SUCCESS; }
/* On success returns NULL. On error returns a pointer to the write request * which had the error. */ static void uv__write(uv_stream_t* stream) { uv_write_t* req; struct iovec* iov; int iovcnt; ssize_t n; if (stream->flags & UV_CLOSING) { /* Handle was closed this tick. We've received a stale * 'is writable' callback from the event loop, ignore. */ return; } start: assert(stream->fd >= 0); /* Get the request at the head of the queue. */ req = uv_write_queue_head(stream); if (!req) { assert(stream->write_queue_size == 0); return; } assert(req->handle == stream); /* * Cast to iovec. We had to have our own uv_buf_t instead of iovec * because Windows's WSABUF is not an iovec. */ assert(sizeof(uv_buf_t) == sizeof(struct iovec)); iov = (struct iovec*) &(req->bufs[req->write_index]); iovcnt = req->bufcnt - req->write_index; /* * Now do the actual writev. Note that we've been updating the pointers * inside the iov each time we write. So there is no need to offset it. */ if (req->send_handle) { struct msghdr msg; char scratch[64]; struct cmsghdr *cmsg; int fd_to_send = req->send_handle->fd; assert(fd_to_send >= 0); msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_iov = iov; msg.msg_iovlen = iovcnt; msg.msg_flags = 0; msg.msg_control = (void*) scratch; msg.msg_controllen = CMSG_LEN(sizeof(fd_to_send)); cmsg = CMSG_FIRSTHDR(&msg); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; cmsg->cmsg_len = msg.msg_controllen; /* silence aliasing warning */ { void* pv = CMSG_DATA(cmsg); int* pi = pv; *pi = fd_to_send; } do { n = sendmsg(stream->fd, &msg, 0); } while (n == -1 && errno == EINTR); } else { do { if (iovcnt == 1) { n = write(stream->fd, iov[0].iov_base, iov[0].iov_len); } else { n = writev(stream->fd, iov, iovcnt); } } while (n == -1 && errno == EINTR); } if (n < 0) { if (errno != EAGAIN && errno != EWOULDBLOCK) { /* Error */ req->error = errno; stream->write_queue_size -= uv__write_req_size(req); uv__write_req_finish(req); return; } else if (stream->flags & UV_STREAM_BLOCKING) { /* If this is a blocking stream, try again. */ goto start; } } else { /* Successful write */ while (n >= 0) { uv_buf_t* buf = &(req->bufs[req->write_index]); size_t len = buf->len; assert(req->write_index < req->bufcnt); if ((size_t)n < len) { buf->base += n; buf->len -= n; stream->write_queue_size -= n; n = 0; /* There is more to write. */ if (stream->flags & UV_STREAM_BLOCKING) { /* * If we're blocking then we should not be enabling the write * watcher - instead we need to try again. */ goto start; } else { /* Break loop and ensure the watcher is pending. */ break; } } else { /* Finished writing the buf at index req->write_index. */ req->write_index++; assert((size_t)n >= len); n -= len; assert(stream->write_queue_size >= len); stream->write_queue_size -= len; if (req->write_index == req->bufcnt) { /* Then we're done! */ assert(n == 0); uv__write_req_finish(req); /* TODO: start trying to write the next request. */ return; } } } } /* Either we've counted n down to zero or we've got EAGAIN. */ assert(n == 0 || n == -1); /* Only non-blocking streams should use the write_watcher. */ assert(!(stream->flags & UV_STREAM_BLOCKING)); /* We're not done. */ uv__io_start(stream->loop, &stream->write_watcher); }
void* log_thread_function(void* arg) { log_item* item; int len; int done; int total_size; time_t now; char* p = NULL; char* time_str; struct iovec iv[3]; char end = '\n'; char log_type_info[6][12] = {{"LOG_INFO\t"}, {"LOG_WARING\t"}, {"LOG_NOTICE\t"}, {"LOG_ERROR\t"}, {"LOG_DEBUG\t"}, {"LOG_CRIT\t"}}; syslog(LOG_DEBUG, "log thread start\n"); assert(log_que.fd > 0 && log_que.buf); while(1) { pthread_mutex_lock(&log_que.buf_lock); while(log_que.curr == 0) pthread_cond_wait(&log_que.log_cond, &log_que.buf_lock); done = 0; while(done < log_que.curr) { p = log_que.buf + done; item = (log_item*)p; now = time(NULL); time_str = ctime(&now); len = strlen(time_str); // 去掉时间字符串最后的那个\n time_str[len-1] = '\0'; strcat(time_str, "\t"); iv[0].iov_len = len; iv[0].iov_base = (void*)time_str; iv[1].iov_len = strlen(log_type_info[item->type]); iv[1].iov_base = (void*)log_type_info[item->type]; iv[2].iov_len = item->len; iv[2].iov_base = p + sizeof(log_item); if(iv[2].iov_len <= 0) { iv[2].iov_len = 1; iv[2].iov_base = &end; } total_size = iv[0].iov_len + iv[1].iov_len + iv[2].iov_len; while(total_size > 0) { if((len = writev(log_que.fd, iv, 3)) < 0) { if(errno == EINTR) continue; syslog(LOG_WARNING, "error occured:%s when write log", strerror(errno)); pthread_mutex_unlock(&log_que.buf_lock); return NULL; } total_size -= len; } done += sizeof(log_item) + item->len; } log_que.curr = 0; pthread_mutex_unlock(&log_que.buf_lock); } return NULL; }
void test_file(void) { int fd, i, len, ret; uint8_t buf[FILE_BUF_SIZE]; uint8_t buf2[FILE_BUF_SIZE]; uint8_t buf3[FILE_BUF_SIZE]; char cur_dir[1024]; struct stat st; struct utimbuf tbuf; struct iovec vecs[2]; DIR *dir; struct dirent *de; /* clean up, just in case */ unlink(TESTPATH "/file1"); unlink(TESTPATH "/file2"); unlink(TESTPATH "/file3"); rmdir(TESTPATH); if (getcwd(cur_dir, sizeof(cur_dir)) == NULL) error("getcwd"); chk_error(mkdir(TESTPATH, 0755)); chk_error(chdir(TESTPATH)); /* open/read/write/close/readv/writev/lseek */ fd = chk_error(open("file1", O_WRONLY | O_TRUNC | O_CREAT, 0644)); for(i=0;i < FILE_BUF_SIZE; i++) buf[i] = i; len = chk_error(qemu_write(fd, buf, FILE_BUF_SIZE / 2)); if (len != (FILE_BUF_SIZE / 2)) error("write"); vecs[0].iov_base = buf + (FILE_BUF_SIZE / 2); vecs[0].iov_len = 16; vecs[1].iov_base = buf + (FILE_BUF_SIZE / 2) + 16; vecs[1].iov_len = (FILE_BUF_SIZE / 2) - 16; len = chk_error(writev(fd, vecs, 2)); if (len != (FILE_BUF_SIZE / 2)) error("writev"); chk_error(close(fd)); chk_error(rename("file1", "file2")); fd = chk_error(open("file2", O_RDONLY)); len = chk_error(read(fd, buf2, FILE_BUF_SIZE)); if (len != FILE_BUF_SIZE) error("read"); if (memcmp(buf, buf2, FILE_BUF_SIZE) != 0) error("memcmp"); #define FOFFSET 16 ret = chk_error(lseek(fd, FOFFSET, SEEK_SET)); if (ret != 16) error("lseek"); vecs[0].iov_base = buf3; vecs[0].iov_len = 32; vecs[1].iov_base = buf3 + 32; vecs[1].iov_len = FILE_BUF_SIZE - FOFFSET - 32; len = chk_error(readv(fd, vecs, 2)); if (len != FILE_BUF_SIZE - FOFFSET) error("readv"); if (memcmp(buf + FOFFSET, buf3, FILE_BUF_SIZE - FOFFSET) != 0) error("memcmp"); chk_error(close(fd)); /* access */ chk_error(access("file2", R_OK)); /* stat/chmod/utime/truncate */ chk_error(chmod("file2", 0600)); tbuf.actime = 1001; tbuf.modtime = 1000; chk_error(truncate("file2", 100)); chk_error(utime("file2", &tbuf)); chk_error(stat("file2", &st)); if (st.st_size != 100) error("stat size"); if (!S_ISREG(st.st_mode)) error("stat mode"); if ((st.st_mode & 0777) != 0600) error("stat mode2"); if (st.st_atime != 1001 || st.st_mtime != 1000) error("stat time"); chk_error(stat(TESTPATH, &st)); if (!S_ISDIR(st.st_mode)) error("stat mode"); /* fstat */ fd = chk_error(open("file2", O_RDWR)); chk_error(ftruncate(fd, 50)); chk_error(fstat(fd, &st)); chk_error(close(fd)); if (st.st_size != 50) error("stat size"); if (!S_ISREG(st.st_mode)) error("stat mode"); /* symlink/lstat */ chk_error(symlink("file2", "file3")); chk_error(lstat("file3", &st)); if (!S_ISLNK(st.st_mode)) error("stat mode"); /* getdents */ dir = opendir(TESTPATH); if (!dir) error("opendir"); len = 0; for(;;) { de = readdir(dir); if (!de) break; if (strcmp(de->d_name, ".") != 0 && strcmp(de->d_name, "..") != 0 && strcmp(de->d_name, "file2") != 0 && strcmp(de->d_name, "file3") != 0) error("readdir"); len++; } closedir(dir); if (len != 4) error("readdir"); chk_error(unlink("file3")); chk_error(unlink("file2")); chk_error(chdir(cur_dir)); chk_error(rmdir(TESTPATH)); }
ssize_t uwsgi_redis_logger(struct uwsgi_logger *ul, char *message, size_t len) { ssize_t ret,ret2; struct uwsgi_redislog_state *uredislog = NULL; if (!ul->configured) { if (!ul->data) { ul->data = uwsgi_calloc(sizeof(struct uwsgi_redislog_state)); uredislog = (struct uwsgi_redislog_state *) ul->data; } if (ul->arg != NULL) { char *logarg = uwsgi_str(ul->arg); char *comma1 = strchr(logarg, ','); if (!comma1) { uredislog->address = logarg; goto done; } *comma1 = 0; uredislog->address = logarg; comma1++; if (*comma1 == 0) goto done; char *comma2 = strchr(comma1,','); if (!comma2) { uredislog->command = uwsgi_redis_logger_build_command(comma1); goto done; } *comma2 = 0; uredislog->command = uwsgi_redis_logger_build_command(comma1); comma2++; if (*comma2 == 0) goto done; uredislog->prefix = comma2; } done: if (!uredislog->address) uredislog->address = uwsgi_str("127.0.0.1:6379"); if (!uredislog->command) uredislog->command = "*3\r\n$7\r\npublish\r\n$5\r\nuwsgi\r\n"; if (!uredislog->prefix) uredislog->prefix = ""; uredislog->fd = -1; uredislog->iovec[0].iov_base = uredislog->command; uredislog->iovec[0].iov_len = strlen(uredislog->command); uredislog->iovec[1].iov_base = "$"; uredislog->iovec[1].iov_len = 1; uredislog->iovec[2].iov_base = uredislog->msgsize; uredislog->iovec[3].iov_base = "\r\n"; uredislog->iovec[3].iov_len = 2; uredislog->iovec[4].iov_base = uredislog->prefix; uredislog->iovec[4].iov_len = strlen(uredislog->prefix); uredislog->iovec[6].iov_base = "\r\n"; uredislog->iovec[6].iov_len = 2; ul->configured = 1; } uredislog = (struct uwsgi_redislog_state *) ul->data; if (uredislog->fd == -1) { uredislog->fd = uwsgi_connect(uredislog->address, uwsgi.socket_timeout, 0); } if (uredislog->fd == -1) return -1; // drop newline if (message[len-1] == '\n') len--; uwsgi_num2str2(len + uredislog->iovec[4].iov_len, uredislog->msgsize); uredislog->iovec[2].iov_len = strlen(uredislog->msgsize); uredislog->iovec[5].iov_base = message; uredislog->iovec[5].iov_len = len; ret = writev(uredislog->fd, uredislog->iovec, 7); if (ret <= 0) { close(uredislog->fd); uredislog->fd = -1; return -1; } again: // read til a \n is found (ugly but fast) ret2 = read(uredislog->fd, uredislog->response, 8); if (ret2 <= 0) { close(uredislog->fd); uredislog->fd = -1; return -1; } if (!memchr(uredislog->response, '\n', ret2)) { goto again; } return ret; }
/* * Write a line to log file (unbuffered) */ static void direct_write_log_line (rspamd_logger_t *rspamd_log, void *data, gsize count, gboolean is_iov) { gchar errmsg[128]; struct iovec *iov; const gchar *line; glong r; if (rspamd_log->enabled) { if (!rspamd_log->no_lock) { #ifndef DISABLE_PTHREAD_MUTEX if (rspamd_log->mtx) { rspamd_mempool_lock_mutex (rspamd_log->mtx); } else { rspamd_file_lock (rspamd_log->fd, FALSE); } #else rspamd_file_lock (rspamd_log->fd, FALSE); #endif } if (is_iov) { iov = (struct iovec *) data; r = writev (rspamd_log->fd, iov, count); } else { line = (const gchar *) data; r = write (rspamd_log->fd, line, count); } if (!rspamd_log->no_lock) { #ifndef DISABLE_PTHREAD_MUTEX if (rspamd_log->mtx) { rspamd_mempool_unlock_mutex (rspamd_log->mtx); } else { rspamd_file_unlock (rspamd_log->fd, FALSE); } #else rspamd_file_unlock (rspamd_log->fd, FALSE); #endif } if (r == -1) { /* We cannot write message to file, so we need to detect error and make decision */ if (errno == EINTR) { /* Try again */ direct_write_log_line (rspamd_log, data, count, is_iov); return; } r = rspamd_snprintf (errmsg, sizeof (errmsg), "direct_write_log_line: cannot write log line: %s", strerror (errno)); if (errno == EFAULT || errno == EINVAL || errno == EFBIG || errno == ENOSPC) { /* Rare case */ rspamd_log->throttling = TRUE; rspamd_log->throttling_time = time (NULL); } else if (errno == EPIPE || errno == EBADF) { /* We write to some pipe and it disappears, disable logging or we has opened bad file descriptor */ rspamd_log->enabled = FALSE; } } else if (rspamd_log->throttling) { rspamd_log->throttling = FALSE; } } }
/* * Display the contents of a uio structure on a terminal. Used by wall(1), * syslogd(8), and talkd(8). Forks and finishes in child if write would block, * waiting up to tmout seconds. Returns pointer to error string on unexpected * error; string is not newline-terminated. Various "normal" errors are * ignored (exclusive-use, lack of permission, etc.). */ const char * ttymsg(struct iovec *iov, int iovcnt, const char *line, int tmout) { struct iovec localiov[7]; ssize_t left, wret; int cnt, fd; static char device[MAXNAMLEN] = _PATH_DEV; static char errbuf[1024]; char *p; int forked; forked = 0; if (iovcnt > (int)(sizeof(localiov) / sizeof(localiov[0]))) return ("too many iov's (change code in wall/ttymsg.c)"); p = device + sizeof(_PATH_DEV) - 1; strlcpy(p, line, sizeof(device)); if (strncmp(p, "pts/", 4) == 0) p += 4; if (strchr(p, '/') != NULL) { /* A slash is an attempt to break security... */ (void) snprintf(errbuf, sizeof(errbuf), "Too many '/' in \"%s\"", device); return (errbuf); } /* * open will fail on slip lines or exclusive-use lines * if not running as root; not an error. */ if ((fd = open(device, O_WRONLY|O_NONBLOCK, 0)) < 0) { if (errno == EBUSY || errno == EACCES) return (NULL); (void) snprintf(errbuf, sizeof(errbuf), "%s: %s", device, strerror(errno)); return (errbuf); } for (cnt = 0, left = 0; cnt < iovcnt; ++cnt) left += iov[cnt].iov_len; for (;;) { wret = writev(fd, iov, iovcnt); if (wret >= left) break; if (wret >= 0) { left -= wret; if (iov != localiov) { bcopy(iov, localiov, iovcnt * sizeof(struct iovec)); iov = localiov; } for (cnt = 0; (size_t)wret >= iov->iov_len; ++cnt) { wret -= iov->iov_len; ++iov; --iovcnt; } if (wret) { iov->iov_base = (char *)iov->iov_base + wret; iov->iov_len -= wret; } continue; } if (errno == EWOULDBLOCK) { int cpid; if (forked) { (void) close(fd); _exit(1); } cpid = fork(); if (cpid < 0) { (void) snprintf(errbuf, sizeof(errbuf), "fork: %s", strerror(errno)); (void) close(fd); return (errbuf); } if (cpid) { /* parent */ (void) close(fd); return (NULL); } forked++; /* wait at most tmout seconds */ (void) signal(SIGALRM, SIG_DFL); (void) signal(SIGTERM, SIG_DFL); /* XXX */ (void) sigsetmask(0); (void) alarm((u_int)tmout); (void) fcntl(fd, F_SETFL, 0); /* clear O_NONBLOCK */ continue; } /* * We get ENODEV on a slip line if we're running as root, * and EIO if the line just went away. */ if (errno == ENODEV || errno == EIO) break; (void) close(fd); if (forked) _exit(1); (void) snprintf(errbuf, sizeof(errbuf), "%s: %s", device, strerror(errno)); return (errbuf); } (void) close(fd); if (forked) _exit(0); return (NULL); }
static int /* R: bytes written, or -1 on error */ retry_writev ( /* PARAMETERS */ int fd, /* I: fd to write on */ struct iovec *iov, /* U: iovec array base * modified as data written */ int iovcnt /* I: number of iovec entries */ /* END PARAMETERS */ ) { /* VARIABLES */ int n; /* return value from writev() */ int i; /* loop counter */ int written; /* bytes written so far */ static int iov_max; /* max number of iovec entries */ /* END VARIABLES */ /* initialization */ #ifdef MAXIOV iov_max = MAXIOV; #else /* ! MAXIOV */ # ifdef IOV_MAX iov_max = IOV_MAX; # else /* ! IOV_MAX */ iov_max = 8192; # endif /* ! IOV_MAX */ #endif /* ! MAXIOV */ written = 0; for (;;) { while (iovcnt && iov[0].iov_len == 0) { iov++; iovcnt--; } if (!iovcnt) { return written; } n = writev(fd, iov, iovcnt > iov_max ? iov_max : iovcnt); if (n == -1) { if (errno == EINVAL && iov_max > 10) { iov_max /= 2; continue; } if (errno == EINTR) { continue; } return -1; } else { written += n; } for (i = 0; i < iovcnt; i++) { if (iov[i].iov_len > (unsigned) n) { iov[i].iov_base = (char *)iov[i].iov_base + n; iov[i].iov_len -= n; break; } n -= iov[i].iov_len; iov[i].iov_len = 0; } if (i == iovcnt) { return written; } } /* NOTREACHED */ }
apr_status_t apr_socket_sendfile(apr_socket_t *sock, apr_file_t *file, apr_hdtr_t *hdtr, apr_off_t *offset, apr_size_t *len, apr_int32_t flags) { int i; apr_ssize_t rc; apr_size_t nbytes = *len, headerlen, trailerlen; struct iovec hdtrarray[2]; char *headerbuf, *trailerbuf; #if APR_HAS_LARGE_FILES && defined(HAVE_SENDFILE64) /* later HP-UXes have a sendfile64() */ #define sendfile sendfile64 apr_off_t off = *offset; #elif APR_HAS_LARGE_FILES && SIZEOF_OFF_T == 4 /* HP-UX 11.00 doesn't have a sendfile64(): fail if trying to send * past the 2Gb limit */ off_t off; if ((apr_int64_t)*offset + *len > INT_MAX) { return EINVAL; } off = *offset; #else apr_off_t off = *offset; #endif if (!hdtr) { hdtr = &no_hdtr; } /* Ignore flags for now. */ flags = 0; /* HP-UX can only send one header iovec and one footer iovec; try to * only allocate storage to combine input iovecs when we really have to */ switch(hdtr->numheaders) { case 0: hdtrarray[0].iov_base = NULL; hdtrarray[0].iov_len = 0; break; case 1: hdtrarray[0] = hdtr->headers[0]; break; default: headerlen = 0; for (i = 0; i < hdtr->numheaders; i++) { headerlen += hdtr->headers[i].iov_len; } /* XXX: BUHHH? wow, what a memory leak! */ headerbuf = hdtrarray[0].iov_base = apr_palloc(sock->pool, headerlen); hdtrarray[0].iov_len = headerlen; for (i = 0; i < hdtr->numheaders; i++) { memcpy(headerbuf, hdtr->headers[i].iov_base, hdtr->headers[i].iov_len); headerbuf += hdtr->headers[i].iov_len; } } switch(hdtr->numtrailers) { case 0: hdtrarray[1].iov_base = NULL; hdtrarray[1].iov_len = 0; break; case 1: hdtrarray[1] = hdtr->trailers[0]; break; default: trailerlen = 0; for (i = 0; i < hdtr->numtrailers; i++) { trailerlen += hdtr->trailers[i].iov_len; } /* XXX: BUHHH? wow, what a memory leak! */ trailerbuf = hdtrarray[1].iov_base = apr_palloc(sock->pool, trailerlen); hdtrarray[1].iov_len = trailerlen; for (i = 0; i < hdtr->numtrailers; i++) { memcpy(trailerbuf, hdtr->trailers[i].iov_base, hdtr->trailers[i].iov_len); trailerbuf += hdtr->trailers[i].iov_len; } } do { if (nbytes) { /* any bytes to send from the file? */ rc = sendfile(sock->socketdes, /* socket */ file->filedes, /* file descriptor to send */ off, /* where in the file to start */ nbytes, /* number of bytes to send from file */ hdtrarray, /* Headers/footers */ flags); /* undefined, set to 0 */ } else { /* we can't call sendfile() with no bytes to send from the file */ rc = writev(sock->socketdes, hdtrarray, 2); } } while (rc == -1 && errno == EINTR); while ((rc == -1) && (errno == EAGAIN || errno == EWOULDBLOCK) && (sock->timeout > 0)) { apr_status_t arv = apr_wait_for_io_or_timeout(NULL, sock, 0); if (arv != APR_SUCCESS) { *len = 0; return arv; } else { do { if (nbytes) { rc = sendfile(sock->socketdes, /* socket */ file->filedes, /* file descriptor to send */ off, /* where in the file to start */ nbytes, /* number of bytes to send from file */ hdtrarray, /* Headers/footers */ flags); /* undefined, set to 0 */ } else { /* we can't call sendfile() with no bytes to send from the file */ rc = writev(sock->socketdes, hdtrarray, 2); } } while (rc == -1 && errno == EINTR); } } if (rc == -1) { *len = 0; return errno; } /* Set len to the number of bytes written */ *len = rc; return APR_SUCCESS; }
ngx_chain_t * ngx_writev_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) { u_char *prev; ssize_t n, size, sent; off_t send, prev_send; ngx_uint_t eintr, complete; ngx_err_t err; ngx_array_t vec; ngx_chain_t *cl; ngx_event_t *wev; struct iovec *iov, iovs[NGX_IOVS]; 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; complete = 0; vec.elts = iovs; vec.size = sizeof(struct iovec); vec.nalloc = NGX_IOVS; vec.pool = c->pool; for ( ;; ) { prev = NULL; iov = NULL; eintr = 0; prev_send = send; vec.nelts = 0; /* create the iovec and coalesce the neighbouring bufs */ for (cl = in; cl && vec.nelts < IOV_MAX && send < limit; cl = cl->next) { if (ngx_buf_special(cl->buf)) { continue; } #if 1 if (!ngx_buf_in_memory(cl->buf)) { ngx_debug_point(); } #endif size = cl->buf->last - cl->buf->pos; if (send + size > limit) { size = (ssize_t) (limit - send); } if (prev == cl->buf->pos) { iov->iov_len += size; } else { iov = ngx_array_push(&vec); if (iov == NULL) { return NGX_CHAIN_ERROR; } iov->iov_base = (void *) cl->buf->pos; iov->iov_len = size; } prev = cl->buf->pos + size; send += size; } n = writev(c->fd, vec.elts, vec.nelts); if (n == -1) { err = ngx_errno; if (err == NGX_EAGAIN || err == NGX_EINTR) { if (err == NGX_EINTR) { eintr = 1; } ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, "writev() not ready"); } else { wev->error = 1; (void) ngx_connection_error(c, err, "writev() failed"); return NGX_CHAIN_ERROR; } } sent = n > 0 ? n : 0; ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "writev: %z", sent); if (send - prev_send == sent) { complete = 1; } c->sent += sent; for (cl = in; cl; cl = cl->next) { if (ngx_buf_special(cl->buf)) { continue; } if (sent == 0) { break; } size = cl->buf->last - cl->buf->pos; if (sent >= size) { sent -= size; cl->buf->pos = cl->buf->last; continue; } cl->buf->pos += sent; break; } if (eintr) { continue; } if (!complete) { wev->ready = 0; return cl; } if (send >= limit || cl == NULL) { return cl; } in = cl; } }
int main(int argc, char *argv[]) { int nflag; /* if not set, output a trailing newline. */ int veclen; /* number of writev arguments. */ struct iovec *iov, *vp; /* Elements to write, current element. */ char space[] = " "; char newline[] = "\n"; char *progname = argv[0]; if (caph_limit_stdio() < 0 || (cap_enter() < 0 && errno != ENOSYS)) err(1, "capsicum"); /* This utility may NOT do getopt(3) option parsing. */ if (*++argv && !strcmp(*argv, "-n")) { ++argv; --argc; nflag = 1; } else nflag = 0; veclen = (argc >= 2) ? (argc - 2) * 2 + 1 : 0; if ((vp = iov = malloc((veclen + 1) * sizeof(struct iovec))) == NULL) errexit(progname, "malloc"); while (argv[0] != NULL) { size_t len; len = strlen(argv[0]); /* * If the next argument is NULL then this is this * the last argument, therefore we need to check * for a trailing \c. */ if (argv[1] == NULL) { /* is there room for a '\c' and is there one? */ if (len >= 2 && argv[0][len - 2] == '\\' && argv[0][len - 1] == 'c') { /* chop it and set the no-newline flag. */ len -= 2; nflag = 1; } } vp->iov_base = *argv; vp++->iov_len = len; if (*++argv) { vp->iov_base = space; vp++->iov_len = 1; } } if (!nflag) { veclen++; vp->iov_base = newline; vp++->iov_len = 1; } /* assert(veclen == (vp - iov)); */ while (veclen) { int nwrite; nwrite = (veclen > IOV_MAX) ? IOV_MAX : veclen; if (writev(STDOUT_FILENO, iov, nwrite) == -1) errexit(progname, "write"); iov += nwrite; veclen -= nwrite; } return 0; }
/* Release 3.1 or greater */ apr_status_t apr_socket_sendfile(apr_socket_t * sock, apr_file_t * file, apr_hdtr_t * hdtr, apr_off_t * offset, apr_size_t * len, apr_int32_t flags) { off_t nbytes = 0; int rv, i; struct sf_hdtr headerstruct; apr_size_t bytes_to_send = *len; /* Ignore flags for now. */ flags = 0; if (!hdtr) { hdtr = &no_hdtr; } else if (hdtr->numheaders && include_hdrs_in_length()) { /* On early versions of FreeBSD sendfile, the number of bytes to send * must include the length of the headers. Don't look at the man page * for this :( Instead, look at the the logic in * src/sys/kern/uipc_syscalls::sendfile(). * * This was fixed in the middle of 4.6-STABLE */ for (i = 0; i < hdtr->numheaders; i++) { bytes_to_send += hdtr->headers[i].iov_len; } } headerstruct.headers = hdtr->headers; headerstruct.hdr_cnt = hdtr->numheaders; headerstruct.trailers = hdtr->trailers; headerstruct.trl_cnt = hdtr->numtrailers; /* FreeBSD can send the headers/footers as part of the system call */ do { if (sock->netmask & APR_INCOMPLETE_WRITE) { apr_status_t arv; sock->netmask &= ~APR_INCOMPLETE_WRITE; arv = apr_wait_for_io_or_timeout(NULL, sock, 0); if (arv != APR_SUCCESS) { *len = 0; return arv; } } if (bytes_to_send) { /* We won't dare call sendfile() if we don't have * header or file bytes to send because bytes_to_send == 0 * means send the whole file. */ rv = sendfile(file->filedes, /* file to be sent */ sock->socketdes, /* socket */ *offset, /* where in the file to start */ bytes_to_send, /* number of bytes to send */ &headerstruct, /* Headers/footers */ &nbytes, /* number of bytes written */ flags); /* undefined, set to 0 */ if (rv == -1) { if (errno == EAGAIN) { if (apr_is_option_set(sock->netmask, APR_SO_TIMEOUT)) { sock->netmask |= APR_INCOMPLETE_WRITE; } /* FreeBSD's sendfile can return -1/EAGAIN even if it * sent bytes. Sanitize the result so we get normal EAGAIN * semantics w.r.t. bytes sent. */ if (nbytes) { /* normal exit for a big file & non-blocking io */ (*len) = nbytes; return APR_SUCCESS; } } } else { /* rv == 0 (or the kernel is broken) */ if (nbytes == 0) { /* Most likely the file got smaller after the stat. * Return an error so the caller can do the Right Thing. */ (*len) = nbytes; return APR_EOF; } } } else { /* just trailer bytes... use writev() */ rv = writev(sock->socketdes, hdtr->trailers, hdtr->numtrailers); if (rv > 0) { nbytes = rv; rv = 0; } else { nbytes = 0; } } if (rv == -1 && errno == EAGAIN && apr_is_option_set(sock->netmask, APR_SO_TIMEOUT)) { apr_status_t arv = apr_wait_for_io_or_timeout(NULL, sock, 0); if (arv != APR_SUCCESS) { *len = 0; return arv; } } } while (rv == -1 && (errno == EINTR || errno == EAGAIN)); (*len) = nbytes; if (rv == -1) { return errno; } return APR_SUCCESS; }
int bus_machine_method_get_addresses(sd_bus_message *message, void *userdata, sd_bus_error *error) { _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; Machine *m = userdata; int r; assert(message); assert(m); r = sd_bus_message_new_method_return(message, &reply); if (r < 0) return r; r = sd_bus_message_open_container(reply, 'a', "(iay)"); if (r < 0) return r; switch (m->class) { case MACHINE_HOST: { _cleanup_free_ struct local_address *addresses = NULL; struct local_address *a; int n, i; n = local_addresses(NULL, 0, AF_UNSPEC, &addresses); if (n < 0) return n; for (a = addresses, i = 0; i < n; a++, i++) { r = sd_bus_message_open_container(reply, 'r', "iay"); if (r < 0) return r; r = sd_bus_message_append(reply, "i", addresses[i].family); if (r < 0) return r; r = sd_bus_message_append_array(reply, 'y', &addresses[i].address, FAMILY_ADDRESS_SIZE(addresses[i].family)); if (r < 0) return r; r = sd_bus_message_close_container(reply); if (r < 0) return r; } break; } case MACHINE_CONTAINER: { _cleanup_close_pair_ int pair[2] = { -1, -1 }; _cleanup_free_ char *us = NULL, *them = NULL; _cleanup_close_ int netns_fd = -1; const char *p; siginfo_t si; pid_t child; r = readlink_malloc("/proc/self/ns/net", &us); if (r < 0) return r; p = procfs_file_alloca(m->leader, "ns/net"); r = readlink_malloc(p, &them); if (r < 0) return r; if (streq(us, them)) return sd_bus_error_setf(error, BUS_ERROR_NO_PRIVATE_NETWORKING, "Machine %s does not use private networking", m->name); r = namespace_open(m->leader, NULL, NULL, &netns_fd, NULL, NULL); if (r < 0) return r; if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0) return -errno; child = fork(); if (child < 0) return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m"); if (child == 0) { _cleanup_free_ struct local_address *addresses = NULL; struct local_address *a; int i, n; pair[0] = safe_close(pair[0]); r = namespace_enter(-1, -1, netns_fd, -1, -1); if (r < 0) _exit(EXIT_FAILURE); n = local_addresses(NULL, 0, AF_UNSPEC, &addresses); if (n < 0) _exit(EXIT_FAILURE); for (a = addresses, i = 0; i < n; a++, i++) { struct iovec iov[2] = { { .iov_base = &a->family, .iov_len = sizeof(a->family) }, { .iov_base = &a->address, .iov_len = FAMILY_ADDRESS_SIZE(a->family) }, }; r = writev(pair[1], iov, 2); if (r < 0) _exit(EXIT_FAILURE); } pair[1] = safe_close(pair[1]); _exit(EXIT_SUCCESS); }
ngx_chain_t * ngx_darwin_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) { int rc; u_char *prev; off_t size, send, prev_send, aligned, sent, fprev; off_t header_size, file_size; ngx_uint_t eintr, complete; ngx_err_t err; ngx_buf_t *file; ngx_array_t header, trailer; ngx_event_t *wev; ngx_chain_t *cl; struct sf_hdtr hdtr; struct iovec *iov, headers[NGX_HEADERS], trailers[NGX_TRAILERS]; 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; header.elts = headers; header.size = sizeof(struct iovec); header.nalloc = NGX_HEADERS; header.pool = c->pool; trailer.elts = trailers; trailer.size = sizeof(struct iovec); trailer.nalloc = NGX_TRAILERS; trailer.pool = c->pool; for ( ;; ) { file = NULL; file_size = 0; header_size = 0; eintr = 0; complete = 0; prev_send = send; header.nelts = 0; trailer.nelts = 0; /* create the header iovec and coalesce the neighbouring bufs */ prev = NULL; iov = NULL; for (cl = in; cl && header.nelts < IOV_MAX && send < limit; cl = cl->next) { if (ngx_buf_special(cl->buf)) { continue; } if (!ngx_buf_in_memory_only(cl->buf)) { break; } size = cl->buf->last - cl->buf->pos; if (send + size > limit) { size = limit - send; } if (prev == cl->buf->pos) { iov->iov_len += (size_t) size; } else { iov = ngx_array_push(&header); if (iov == NULL) { return NGX_CHAIN_ERROR; } iov->iov_base = (void *) cl->buf->pos; iov->iov_len = (size_t) size; } prev = cl->buf->pos + (size_t) size; header_size += size; send += size; } if (cl && cl->buf->in_file && send < limit) { file = cl->buf; /* coalesce the neighbouring file bufs */ do { size = cl->buf->file_last - cl->buf->file_pos; if (send + size > limit) { size = limit - send; aligned = (cl->buf->file_pos + size + ngx_pagesize - 1) & ~((off_t) ngx_pagesize - 1); if (aligned <= cl->buf->file_last) { size = aligned - cl->buf->file_pos; } } file_size += size; send += size; fprev = cl->buf->file_pos + size; cl = cl->next; } while (cl && cl->buf->in_file && send < limit && file->file->fd == cl->buf->file->fd && fprev == cl->buf->file_pos); } if (file && header.nelts == 0) { /* create the tailer iovec and coalesce the neighbouring bufs */ prev = NULL; iov = NULL; while (cl && header.nelts < IOV_MAX && send < limit) { if (ngx_buf_special(cl->buf)) { cl = cl->next; continue; } if (!ngx_buf_in_memory_only(cl->buf)) { break; } size = cl->buf->last - cl->buf->pos; if (send + size > limit) { size = limit - send; } if (prev == cl->buf->pos) { iov->iov_len += (size_t) size; } else { iov = ngx_array_push(&trailer); if (iov == NULL) { return NGX_CHAIN_ERROR; } iov->iov_base = (void *) cl->buf->pos; iov->iov_len = (size_t) size; } prev = cl->buf->pos + (size_t) size; send += size; cl = cl->next; } } if (file) { /* * sendfile() returns EINVAL if sf_hdtr's count is 0, * but corresponding pointer is not NULL */ hdtr.headers = header.nelts ? (struct iovec *) header.elts: NULL; hdtr.hdr_cnt = header.nelts; hdtr.trailers = trailer.nelts ? (struct iovec *) trailer.elts: NULL; hdtr.trl_cnt = trailer.nelts; sent = header_size + file_size; ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, "sendfile: @%O %O h:%O", file->file_pos, sent, header_size); rc = sendfile(file->file->fd, c->fd, file->file_pos, &sent, &hdtr, 0); if (rc == -1) { err = ngx_errno; switch (err) { case NGX_EAGAIN: break; case NGX_EINTR: eintr = 1; break; 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); } if (rc == 0 && sent == 0) { /* * if rc 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", file->file->name.data); return NGX_CHAIN_ERROR; } ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, "sendfile: %d, @%O %O:%O", rc, file->file_pos, sent, file_size + header_size); } else { rc = writev(c->fd, header.elts, header.nelts); ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, "writev: %d of %uz", rc, send); if (rc == -1) { err = ngx_errno; switch (err) { case NGX_EAGAIN: break; case NGX_EINTR: eintr = 1; break; default: wev->error = 1; ngx_connection_error(c, err, "writev() failed"); return NGX_CHAIN_ERROR; } ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, "writev() not ready"); } sent = rc > 0 ? rc : 0; } if (send - prev_send == sent) { complete = 1; } c->sent += sent; for (cl = in; cl; cl = cl->next) { if (ngx_buf_special(cl->buf)) { continue; } if (sent == 0) { break; } size = ngx_buf_size(cl->buf); if (sent >= size) { sent -= size; if (ngx_buf_in_memory(cl->buf)) { cl->buf->pos = cl->buf->last; } if (cl->buf->in_file) { cl->buf->file_pos = cl->buf->file_last; } continue; } if (ngx_buf_in_memory(cl->buf)) { cl->buf->pos += (size_t) sent; } if (cl->buf->in_file) { cl->buf->file_pos += sent; } break; } if (eintr) { continue; } if (!complete) { wev->ready = 0; return cl; } if (send >= limit || cl == NULL) { return cl; } in = cl; } }
ssize_t st_writev(_st_netfd_t *fd, const struct iovec *iov, int iov_size, st_utime_t timeout) { ssize_t n, rv; size_t nleft, nbyte; int index, iov_cnt; struct iovec *tmp_iov; struct iovec local_iov[_LOCAL_MAXIOV]; /* Calculate the total number of bytes to be sent */ nbyte = 0; for (index = 0; index < iov_size; index++) nbyte += iov[index].iov_len; rv = (ssize_t)nbyte; nleft = nbyte; tmp_iov = (struct iovec *) iov; /* we promise not to modify iov */ iov_cnt = iov_size; while (nleft > 0) { if (iov_cnt == 1) { if (st_write(fd, tmp_iov[0].iov_base, nleft, timeout) != (ssize_t) nleft) rv = -1; break; } if ((n = writev(fd->osfd, tmp_iov, iov_cnt)) < 0) { if (errno == EINTR) continue; if (!_IO_NOT_READY_ERROR) { rv = -1; break; } } else { if ((size_t) n == nleft) break; nleft -= n; /* Find the next unwritten vector */ n = (ssize_t)(nbyte - nleft); for (index = 0; (size_t) n >= iov[index].iov_len; index++) n -= iov[index].iov_len; if (tmp_iov == iov) { /* Must copy iov's around */ if (iov_size - index <= _LOCAL_MAXIOV) { tmp_iov = local_iov; } else { tmp_iov = calloc(1, (iov_size - index) * sizeof(struct iovec)); if (tmp_iov == NULL) return -1; } } /* Fill in the first partial read */ tmp_iov[0].iov_base = &(((char *)iov[index].iov_base)[n]); tmp_iov[0].iov_len = iov[index].iov_len - n; index++; /* Copy the remaining vectors */ for (iov_cnt = 1; index < iov_size; iov_cnt++, index++) { tmp_iov[iov_cnt].iov_base = iov[index].iov_base; tmp_iov[iov_cnt].iov_len = iov[index].iov_len; } } /* Wait until the socket becomes writable */ if (st_netfd_poll(fd, POLLOUT, timeout) < 0) { rv = -1; break; } } if (tmp_iov != iov && tmp_iov != local_iov) free(tmp_iov); return rv; }
static int writeData(void* _call) { WriterAVCallData_t* call = (WriterAVCallData_t*) _call; int len = 0; wma_printf(10, "\n"); if (call == NULL) { wma_err("call data is NULL...\n"); return 0; } wma_printf(10, "AudioPts %lld\n", call->Pts); if ((call->data == NULL) || (call->len <= 0)) { wma_err("parsing NULL Data. ignoring...\n"); return 0; } if (call->fd < 0) { wma_err("file pointer < 0. ignoring ...\n"); return 0; } if (initialHeader) { unsigned char PesHeader[PES_MAX_HEADER_SIZE]; if ((call->private_size <= 0) || (call->private_data == NULL)) { wma_err("private NULL.\n"); return -1; } struct iovec iov[2]; iov[0].iov_base = PesHeader; iov[0].iov_len = InsertPesHeader (PesHeader, call->private_size, MPEG_AUDIO_PES_START_CODE, 0, 0); iov[1].iov_base = call->private_data; iov[1].iov_len = call->private_size; len = writev(call->fd, iov, 2); initialHeader = 0; } if (len > -1 && call->len > 0 && call->data) { unsigned char PesHeader[PES_MAX_HEADER_SIZE]; struct iovec iov[2]; iov[0].iov_base = PesHeader; iov[0].iov_len = InsertPesHeader (PesHeader, call->len, MPEG_AUDIO_PES_START_CODE, call->Pts, 0); iov[1].iov_base = call->data; iov[1].iov_len = call->len; ssize_t l = writev(call->fd, iov, 2); if (l > -1) len += l; else len = l; } wma_printf(10, "wma < %d\n", len); return len; }
static void dotest(int testers, int me, int fd) { char *bits; char val, val0; int count, collide, chunk, whenmisc, xfr, i; /* Stuff for the readv call */ struct iovec r_iovec[MAXIOVCNT]; int r_ioveclen; /* Stuff for the writev call */ struct iovec val0_iovec[MAXIOVCNT]; struct iovec val_iovec[MAXIOVCNT]; int w_ioveclen; nchunks = max_size / (testers * csize); whenmisc = 0; if ((bits = malloc((nchunks + 7) / 8)) == NULL) { tst_brkm(TBROK, NULL, "\tmalloc failed(bits)"); } /* Allocate memory for the iovec buffers and init the iovec arrays */ r_ioveclen = w_ioveclen = csize / MAXIOVCNT; /* Please note that the above statement implies that csize * be evenly divisible by MAXIOVCNT. */ for (i = 0; i < MAXIOVCNT; i++) { if ((r_iovec[i].iov_base = malloc(r_ioveclen)) == NULL) { tst_brkm(TBROK, NULL, "\tmalloc failed(iov_base)"); } r_iovec[i].iov_len = r_ioveclen; /* Allocate unused memory areas between all the buffers to * make things more diffult for the OS. */ if (malloc((i + 1) * 8) == NULL) { tst_brkm(TBROK, NULL, "\tmalloc failed((i+1)*8)"); } if ((val0_iovec[i].iov_base = malloc(w_ioveclen)) == NULL) { tst_brkm(TBROK, NULL, "\tmalloc failed(val0_iovec)"); } val0_iovec[i].iov_len = w_ioveclen; if (malloc((i + 1) * 8) == NULL) { tst_brkm(TBROK, NULL, "\tmalloc failed((i+1)*8)"); } if ((val_iovec[i].iov_base = malloc(w_ioveclen)) == NULL) { tst_brkm(TBROK, NULL, "\tmalloc failed(iov_base)"); } val_iovec[i].iov_len = w_ioveclen; if (malloc((i + 1) * 8) == NULL) { tst_brkm(TBROK, NULL, "\tmalloc failed(((i+1)*8)"); } } /* * No init sectors; file-sys makes 0 to start. */ val = (64 / testers) * me + 1; val0 = 0; /* * For each iteration: * zap bits array * loop: * pick random chunk, read it. * if corresponding bit off { * verify == 0. (sparse file) * ++count; * } else * verify == val. * write "val" on it. * repeat until count = nchunks. * ++val. */ srand(getpid()); if (misc_intvl) whenmisc = NEXTMISC; while (iterations-- > 0) { for (i = 0; i < NMISC; i++) misc_cnt[i] = 0; memset(bits, 0, (nchunks + 7) / 8); /* Have to fill the val0 and val iov buffers in a different manner */ for (i = 0; i < MAXIOVCNT; i++) { memset(val0_iovec[i].iov_base, val0, val0_iovec[i].iov_len); memset(val_iovec[i].iov_base, val, val_iovec[i].iov_len); } count = 0; collide = 0; while (count < nchunks) { chunk = rand() % nchunks; /* * Read it. */ if (lseek64(fd, CHUNK(chunk), 0) < 0) { tst_brkm(TFAIL, NULL, "\tTest[%d]: lseek64(0) fail at %" PRIx64 "x, errno = %d.", me, CHUNK(chunk), errno); } if ((xfr = readv(fd, &r_iovec[0], MAXIOVCNT)) < 0) { tst_brkm(TFAIL, NULL, "\tTest[%d]: readv fail at %" PRIx64 "x, errno = %d.", me, CHUNK(chunk), errno); } /* * If chunk beyond EOF just write on it. * Else if bit off, haven't seen it yet. * Else, have. Verify values. */ if (xfr == 0) { bits[chunk / 8] |= (1 << (chunk % 8)); } else if ((bits[chunk / 8] & (1 << (chunk % 8))) == 0) { if (xfr != csize) { tst_brkm(TFAIL, NULL, "\tTest[%d]: xfr=%d != %d, zero read.", me, xfr, csize); } for (i = 0; i < MAXIOVCNT; i++) { if (memcmp (r_iovec[i].iov_base, val0_iovec[i].iov_base, r_iovec[i].iov_len)) { tst_resm(TFAIL, "\tTest[%d] bad verify @ 0x%" PRIx64 " for val %d count %d xfr %d.", me, CHUNK(chunk), val0, count, xfr); ft_dumpiov(&r_iovec[i]); ft_dumpbits(bits, (nchunks + 7) / 8); tst_exit(); } } bits[chunk / 8] |= (1 << (chunk % 8)); ++count; } else { if (xfr != csize) { tst_brkm(TFAIL, NULL, "\tTest[%d]: xfr=%d != %d, val read.", me, xfr, csize); } ++collide; for (i = 0; i < MAXIOVCNT; i++) { if (memcmp (r_iovec[i].iov_base, val_iovec[i].iov_base, r_iovec[i].iov_len)) { tst_resm(TFAIL, "\tTest[%d] bad verify @ 0x%" PRIx64 " for val %d count %d xfr %d.", me, CHUNK(chunk), val, count, xfr); ft_dumpiov(&r_iovec[i]); ft_dumpbits(bits, (nchunks + 7) / 8); tst_exit(); } } } /* * Write it. */ if (lseek64(fd, -xfr, 1) < 0) { tst_brkm(TFAIL, NULL, "\tTest[%d]: lseek64(1) fail at %" PRIx64 ", errno = %d.", me, CHUNK(chunk), errno); } if ((xfr = writev(fd, &val_iovec[0], MAXIOVCNT)) < csize) { if (errno == ENOSPC) { tst_resm(TFAIL, "\tTest[%d]: no space, exiting.", me); fsync(fd); tst_exit(); } tst_brkm(TFAIL, NULL, "\tTest[%d]: writev fail at %" PRIx64 "x xfr %d, errno = %d.", me, CHUNK(chunk), xfr, errno); } /* * If hit "misc" interval, do it. */ if (misc_intvl && --whenmisc <= 0) { domisc(me, fd); whenmisc = NEXTMISC; } if (count + collide > 2 * nchunks) break; } /* * End of iteration, maybe before doing all chunks. */ if (count < nchunks) { //tst_resm(TINFO, "\tTest{%d} val %d stopping @ %d, collide = {%d}.", // me, val, count, collide); for (i = 0; i < nchunks; i++) { if ((bits[i / 8] & (1 << (i % 8))) == 0) { if (lseek64(fd, CHUNK(i), 0) < (off64_t) 0) { tst_brkm(TFAIL, NULL, "\tTest[%d]: lseek64 fail at %" PRIx64 "x, errno = %d.", me, CHUNK(i), errno); } if (writev(fd, &val_iovec[0], MAXIOVCNT) != csize) { tst_brkm(TFAIL, NULL, "\tTest[%d]: writev fail at %" PRIx64 "x, errno = %d.", me, CHUNK(i), errno); } } } } fsync(fd); ++misc_cnt[m_fsync]; //tst_resm(TINFO, "\tTest[%d] val %d done, count = %d, collide = %d.", // me, val, count, collide); //for (i = 0; i < NMISC; i++) // tst_resm(TINFO, "\t\tTest[%d]: %d %s's.", me, misc_cnt[i], m_str[i]); val0 = val++; } }
int32_t TransportUDP::write(uint8_t* buffer, uint32_t size) { { boost::mutex::scoped_lock lock(close_mutex_); if (closed_) { ROSCPP_LOG_DEBUG("Tried to write on a closed socket [%d]", sock_); return -1; } } ROS_ASSERT((int32_t)size > 0); const uint32_t max_payload_size = max_datagram_size_ - sizeof(TransportUDPHeader); uint32_t bytes_sent = 0; uint32_t this_block = 0; if (++current_message_id_ == 0) ++current_message_id_; while (bytes_sent < size) { TransportUDPHeader header; header.connection_id_ = connection_id_; header.message_id_ = current_message_id_; if (this_block == 0) { header.op_ = ROS_UDP_DATA0; header.block_ = (size + max_payload_size - 1) / max_payload_size; } else { header.op_ = ROS_UDP_DATAN; header.block_ = this_block; } ++this_block; #if defined(WIN32) WSABUF iov[2]; iov[0].buf = reinterpret_cast<char*>(&header); iov[0].len = sizeof(header); iov[1].buf = reinterpret_cast<char*>(buffer + bytes_sent); iov[1].len = std::min(max_payload_size, size - bytes_sent); ssize_t num_bytes; if (WSASend(sock_, iov, 2, reinterpret_cast<LPDWORD>(&num_bytes), 0, NULL, NULL) == SOCKET_ERROR) { num_bytes = -1; } #else struct iovec iov[2]; iov[0].iov_base = &header; iov[0].iov_len = sizeof(header); iov[1].iov_base = buffer + bytes_sent; iov[1].iov_len = std::min(max_payload_size, size - bytes_sent); ssize_t num_bytes = writev(sock_, iov, 2); #endif //usleep(100); if (num_bytes < 0) { if( last_socket_error_is_would_block() ) { ROSCPP_LOG_DEBUG("writev() failed with error [%s]", last_socket_error_string()); close(); break; } else { num_bytes = 0; } } else if (num_bytes < ssize_t(sizeof(header))) { ROSCPP_LOG_DEBUG("Socket [%d] short write (%d bytes), closing", sock_, int(num_bytes)); close(); break; } else { num_bytes -= sizeof(header); } bytes_sent += num_bytes; } return bytes_sent; }
/* WARNING: all parameters MUST be valid, * NULL pointers lead to a crash. */ ret_t cherokee_socket_writev (cherokee_socket_t *socket, const struct iovec *vector, uint16_t vector_len, size_t *pcnt_written) { int re; int i; ret_t ret; size_t cnt; *pcnt_written = 0; /* There must be something to send, otherwise behaviour is undefined * and as we don't want this case, we have to enforce assertions. */ return_if_fail (vector != NULL && vector_len > 0, ret_error); if (likely (socket->is_tls != TLS)) { #ifdef _WIN32 int i; size_t total; for (i = 0, re = 0, total = 0; i < vector_len; i++) { if (vector[i].iov_len == 0) continue; do { re = send (SOCKET_FD(socket), vector[i].iov_base, vector[i].iov_len, 0); } while ((re == -1) && (errno == EINTR)); if (re < 0) break; total += re; /* if it is a partial send, then stop sending data */ if (re != vector[i].iov_len) break; } *pcnt_written = total; /* if we have sent at least one byte, * then return OK. */ if (likely (total > 0)) return ret_ok; if (re == 0) { int err = SOCK_ERRNO(); if (i == vector_len) return ret_ok; /* Retry later. */ return ret_eagain; } #else /* ! WIN32 */ do { re = writev (SOCKET_FD(socket), vector, vector_len); } while ((re == -1) && (errno == EINTR)); if (likely (re > 0)) { *pcnt_written = (size_t) re; return ret_ok; } if (re == 0) { int i; /* Find out whether there was something to send or not. */ for (i = 0; i < vector_len; i++) { if (vector[i].iov_base != NULL && vector[i].iov_len > 0) break; } if (i < vector_len) return ret_eagain; /* No, nothing to send, so return ok. */ return ret_ok; } #endif if (re < 0) { int err = SOCK_ERRNO(); switch (err) { #if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN) case EWOULDBLOCK: #endif case EAGAIN: return ret_eagain; case EPIPE: #ifdef ENOTCONN case ENOTCONN: #endif case ECONNRESET: socket->status = socket_closed; case ETIMEDOUT: case EHOSTUNREACH: return ret_error; } LOG_ERRNO (errno, cherokee_err_error, CHEROKEE_ERROR_SOCKET_WRITEV, SOCKET_FD(socket)); } return ret_error; } /* TLS connection: Here we don't worry about sparing a few CPU * cycles, so we reuse the single send case for TLS. */ for (i = 0; i < vector_len; i++) { if ((vector[i].iov_len == 0) || (vector[i].iov_base == NULL)) continue; cnt = 0; ret = cherokee_socket_write (socket, vector[i].iov_base, vector[i].iov_len, &cnt); if (ret != ret_ok) { return ret; } *pcnt_written += cnt; if (cnt == vector[i].iov_len) continue; /* Unfinished */ return ret_ok; } /* Did send everything */ return ret_ok; }
/* * Write a filtered log message to stderr. * * Log format parsing taken from the long-dead utils/Log.cpp. */ static void showLog(LogState *state, int logPrio, const char* tag, const char* msg) { #if defined(HAVE_LOCALTIME_R) struct tm tmBuf; #endif struct tm* ptm; char timeBuf[32]; char prefixBuf[128], suffixBuf[128]; char priChar; time_t when; pid_t pid, tid; TRACE("LOG %d: %s %s", logPrio, tag, msg); priChar = getPriorityString(logPrio)[0]; when = time(NULL); pid = tid = getpid(); // find gettid()? /* * Get the current date/time in pretty form * * It's often useful when examining a log with "less" to jump to * a specific point in the file by searching for the date/time stamp. * For this reason it's very annoying to have regexp meta characters * in the time stamp. Don't use forward slashes, parenthesis, * brackets, asterisks, or other special chars here. */ #if defined(HAVE_LOCALTIME_R) ptm = localtime_r(&when, &tmBuf); #else ptm = localtime(&when); #endif //strftime(timeBuf, sizeof(timeBuf), "%Y-%m-%d %H:%M:%S", ptm); strftime(timeBuf, sizeof(timeBuf), "%m-%d %H:%M:%S", ptm); /* * Construct a buffer containing the log header and log message. */ size_t prefixLen, suffixLen; switch (state->outputFormat) { case FORMAT_TAG: prefixLen = snprintf(prefixBuf, sizeof(prefixBuf), "%c/%-8s: ", priChar, tag); strcpy(suffixBuf, "\n"); suffixLen = 1; break; case FORMAT_PROCESS: prefixLen = snprintf(prefixBuf, sizeof(prefixBuf), "%c(%5d) ", priChar, pid); suffixLen = snprintf(suffixBuf, sizeof(suffixBuf), " (%s)\n", tag); break; case FORMAT_THREAD: prefixLen = snprintf(prefixBuf, sizeof(prefixBuf), "%c(%5d:%5d) ", priChar, pid, tid); strcpy(suffixBuf, "\n"); suffixLen = 1; break; case FORMAT_RAW: prefixBuf[0] = 0; prefixLen = 0; strcpy(suffixBuf, "\n"); suffixLen = 1; break; case FORMAT_TIME: prefixLen = snprintf(prefixBuf, sizeof(prefixBuf), "%s %-8s\n\t", timeBuf, tag); strcpy(suffixBuf, "\n"); suffixLen = 1; break; case FORMAT_THREADTIME: prefixLen = snprintf(prefixBuf, sizeof(prefixBuf), "%s %5d %5d %c %-8s \n\t", timeBuf, pid, tid, priChar, tag); strcpy(suffixBuf, "\n"); suffixLen = 1; break; case FORMAT_LONG: prefixLen = snprintf(prefixBuf, sizeof(prefixBuf), "[ %s %5d:%5d %c/%-8s ]\n", timeBuf, pid, tid, priChar, tag); strcpy(suffixBuf, "\n\n"); suffixLen = 2; break; default: prefixLen = snprintf(prefixBuf, sizeof(prefixBuf), "%c/%-8s(%5d): ", priChar, tag, pid); strcpy(suffixBuf, "\n"); suffixLen = 1; break; } /* * Figure out how many lines there will be. */ const char* end = msg + strlen(msg); size_t numLines = 0; const char* p = msg; while (p < end) { if (*p++ == '\n') numLines++; } if (p > msg && *(p-1) != '\n') numLines++; /* * Create an array of iovecs large enough to write all of * the lines with a prefix and a suffix. */ const size_t INLINE_VECS = 6; const size_t MAX_LINES = ((size_t)~0)/(3*sizeof(struct iovec*)); struct iovec stackVec[INLINE_VECS]; struct iovec* vec = stackVec; size_t numVecs; if (numLines > MAX_LINES) numLines = MAX_LINES; numVecs = numLines*3; // 3 iovecs per line. if (numVecs > INLINE_VECS) { vec = (struct iovec*)malloc(sizeof(struct iovec)*numVecs); if (vec == NULL) { msg = "LOG: write failed, no memory"; numVecs = 3; numLines = 1; vec = stackVec; } } /* * Fill in the iovec pointers. */ p = msg; struct iovec* v = vec; int totalLen = 0; while (numLines > 0 && p < end) { if (prefixLen > 0) { v->iov_base = prefixBuf; v->iov_len = prefixLen; totalLen += prefixLen; v++; } const char* start = p; while (p < end && *p != '\n') p++; if ((p-start) > 0) { v->iov_base = (void*)start; v->iov_len = p-start; totalLen += p-start; v++; } if (*p == '\n') p++; if (suffixLen > 0) { v->iov_base = suffixBuf; v->iov_len = suffixLen; totalLen += suffixLen; v++; } numLines -= 1; } /* * Write the entire message to the log file with a single writev() call. * We need to use this rather than a collection of printf()s on a FILE* * because of multi-threading and multi-process issues. * * If the file was not opened with O_APPEND, this will produce interleaved * output when called on the same file from multiple processes. * * If the file descriptor is actually a network socket, the writev() * call may return with a partial write. Putting the writev() call in * a loop can result in interleaved data. This can be alleviated * somewhat by wrapping the writev call in the Mutex. */ for(;;) { int cc = writev(fileno(stderr), vec, v-vec); if (cc == totalLen) break; if (cc < 0) { if(errno == EINTR) continue; /* can't really log the failure; for now, throw out a stderr */ fprintf(stderr, "+++ LOG: write failed (errno=%d)\n", errno); break; } else { /* shouldn't happen when writing to file or tty */ fprintf(stderr, "+++ LOG: write partial (%d of %d)\n", cc, totalLen); break; } } /* if we allocated storage for the iovecs, free it */ if (vec != stackVec) free(vec); }
static int write_message(Server *s, const char *buf, struct ucred *ucred) { ssize_t k; char priority[6], pid[16]; struct iovec iovec[5]; unsigned i = 0; char *process = NULL; int r = 0; int prio = LOG_USER | LOG_INFO; assert(s); assert(buf); parse_syslog_priority((char**) &buf, &prio); if (*buf == 0) return 0; if ((prio & LOG_FACMASK) == 0) prio = LOG_USER | LOG_PRI(prio); /* First, set priority field */ snprintf(priority, sizeof(priority), "<%i>", prio); char_array_0(priority); IOVEC_SET_STRING(iovec[i++], priority); /* Second, skip date */ skip_date(&buf); /* Then, add process if set */ if (read_process(&buf, &iovec[i]) > 0) i++; else if (ucred && ucred->pid > 0 && get_process_name(ucred->pid, &process) >= 0) IOVEC_SET_STRING(iovec[i++], process); /* Skip the stored PID if we have a better one */ if (ucred) { snprintf(pid, sizeof(pid), "[%lu]: ", (unsigned long) ucred->pid); char_array_0(pid); IOVEC_SET_STRING(iovec[i++], pid); skip_pid(&buf); if (*buf == ':') buf++; buf += strspn(buf, WHITESPACE); } /* Is the remaining message empty? */ if (*buf) { /* And the rest is the message */ IOVEC_SET_STRING(iovec[i++], buf); IOVEC_SET_STRING(iovec[i++], "\n"); if ((k = writev(s->kmsg_fd, iovec, i)) <= 0) { log_error("Failed to write log message to kmsg: %s", k < 0 ? strerror(errno) : "short write"); r = k < 0 ? -errno : -EIO; } } free(process); return r; }
int echo_main(int argc, char **argv) { struct iovec io[argc]; struct iovec *cur_io = io; char *arg; char *p; #if !ENABLE_FEATURE_FANCY_ECHO enum { eflag = '\\', nflag = 1, /* 1 -- print '\n' */ }; arg = *++argv; if (!arg) goto newline_ret; #else char nflag = 1; char eflag = 0; while (1) { arg = *++argv; if (!arg) goto newline_ret; if (*arg != '-') break; /* If it appears that we are handling options, then make sure * that all of the options specified are actually valid. * Otherwise, the string should just be echoed. */ p = arg + 1; if (!*p) /* A single '-', so echo it. */ goto just_echo; do { if (!strrchr("neE", *p)) goto just_echo; } while (*++p); /* All of the options in this arg are valid, so handle them. */ p = arg + 1; do { if (*p == 'n') nflag = 0; if (*p == 'e') eflag = '\\'; } while (*++p); } just_echo: #endif while (1) { /* arg is already == *argv and isn't NULL */ int c; cur_io->iov_base = p = arg; if (!eflag) { /* optimization for very common case */ p += strlen(arg); } else while ((c = *arg++)) { if (c == eflag) { /* Check for escape seq. */ if (*arg == 'c') { /* '\c' means cancel newline and * ignore all subsequent chars. */ cur_io->iov_len = p - (char*)cur_io->iov_base; cur_io++; goto ret; } #if !ENABLE_FEATURE_FANCY_ECHO /* SUSv3 specifies that octal escapes must begin with '0'. */ if ( (((unsigned char)*arg) - '1') >= 7) #endif { /* Since SUSv3 mandates a first digit of 0, 4-digit octals * of the form \0### are accepted. */ if (*arg == '0' && ((unsigned char)(arg[1]) - '0') < 8) { arg++; } /* bb_process_escape_sequence can handle nul correctly */ c = bb_process_escape_sequence( (void*) &arg); } } *p++ = c; } arg = *++argv; if (arg) *p++ = ' '; cur_io->iov_len = p - (char*)cur_io->iov_base; cur_io++; if (!arg) break; } newline_ret: if (nflag) { cur_io->iov_base = (char*)"\n"; cur_io->iov_len = 1; cur_io++; } ret: /* TODO: implement and use full_writev? */ return writev(1, io, (cur_io - io)) >= 0; }
int status_vprintf(const char *status, bool ellipse, bool ephemeral, const char *format, va_list ap) { static const char status_indent[] = " "; /* "[" STATUS "] " */ _cleanup_free_ char *s = NULL; _cleanup_close_ int fd = -1; struct iovec iovec[6] = {}; int n = 0; static bool prev_ephemeral; assert(format); /* This is independent of logging, as status messages are * optional and go exclusively to the console. */ if (vasprintf(&s, format, ap) < 0) return log_oom(); fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC); if (fd < 0) return fd; if (ellipse) { char *e; size_t emax, sl; int c; c = fd_columns(fd); if (c <= 0) c = 80; sl = status ? sizeof(status_indent)-1 : 0; emax = c - sl - 1; if (emax < 3) emax = 3; e = ellipsize(s, emax, 50); if (e) { free(s); s = e; } } if (prev_ephemeral) IOVEC_SET_STRING(iovec[n++], "\r" ANSI_ERASE_TO_END_OF_LINE); prev_ephemeral = ephemeral; if (status) { if (!isempty(status)) { IOVEC_SET_STRING(iovec[n++], "["); IOVEC_SET_STRING(iovec[n++], status); IOVEC_SET_STRING(iovec[n++], "] "); } else IOVEC_SET_STRING(iovec[n++], status_indent); } IOVEC_SET_STRING(iovec[n++], s); if (!ephemeral) IOVEC_SET_STRING(iovec[n++], "\n"); if (writev(fd, iovec, n) < 0) return -errno; return 0; }
void module_generate(int fd) { size_t i; DIR* proc_listing; /* Set up an iovec array. We'll fill this with buffers that'll * be part of our output, growing it dynamically as necessary. */ /* The number of elements in the array that we've used. */ size_t vec_length = 0; /* The allocate size of the array. */ size_t vec_size = 16; /* The array of iovcec elements. */ struct iovec* vec = (struct iovec*) xmalloc(vec_size * sizeof(struct iovec)); /* The first buffer is the HTML source for the start of the pate. */ vec[vec_length].iov_base = page_start; vec[vec_length].iov_len = strlen(page_start); ++vec_length; /* Start a directory listing for /proc. */ proc_listing = opendir("/proc"); if (proc_listing == NULL) { system_error("opendir"); } /* Loop over directory entries in /proc. */ while (1) { struct dirent* proc_entry; const char* name; pid_t pid; char* process_info; /* Get the next entry in /proc. */ proc_entry = readdir(proc_listing); if (proc_entry == NULL) { /* We've hit the end of the listing. */ break; } /* If this entry is not composed purely of digits, it's not a * process directory, so skip it. */ name = proc_entry->d_name; if (strspn(name, "0123456789") != strlen(name)) { continue; } /* The name of the entry is the process ID. */ pid = (pid_t) atoi(name); /* Generate HTML for a table row describing this process. */ process_info = format_process_info(pid); if (process_info == NULL) { /* Something went wrong. The process may have vanished * while we were looking at it. Use a placeholder row * instead. */ process_info = " <tr><td colspan=\"5\">ERROR</td></tr>"; } /* Make sure the iovec array is long enough to hold this buffer * (plus one more because we'll add an extra element when we're * done listing processes). If not, grow it to twice its current * size. */ if (vec_length == vec_size - 1) { vec_size *= 2; vec = xrealloc(vec, vec_size * sizeof(struct iovec)); } /* Store this buffer as the next element of the array. */ vec[vec_length].iov_base = process_info; vec[vec_length].iov_len = strlen(process_info); ++vec_length; } /* End the directory listing operation. */ closedir(proc_listing); /* Add one last buffer with HTML that ends the page. */ vec[vec_length].iov_base = page_end; vec[vec_length].iov_len = strlen(page_end); ++vec_length; /* Output the entire page to the client file descriptor all * at once. */ writev(fd, vec, vec_length); /* Deallocate the buffers we created. The first and last are * static and should not be deallocated. */ for (i = 1; i < vec_length - 1; ++i) { free(vec[i].iov_base); } /* Deallocate the iovec array. */ free(vec); }
/***************************************************************************** * output_Flush *****************************************************************************/ static void output_Flush( output_t *p_output ) { packet_t *p_packet = p_output->p_packets; int i_block_cnt = output_BlockCount( p_output ); struct iovec p_iov[i_block_cnt + 2]; uint8_t p_rtp_hdr[RTP_HEADER_SIZE]; int i_iov = 0, i_payload_len, i_block; if ( (p_output->config.i_config & OUTPUT_RAW) ) { p_iov[i_iov].iov_base = &p_output->raw_pkt_header; p_iov[i_iov].iov_len = sizeof(struct udprawpkt); i_iov++; } if ( !(p_output->config.i_config & OUTPUT_UDP) ) { p_iov[i_iov].iov_base = p_rtp_hdr; p_iov[i_iov].iov_len = sizeof(p_rtp_hdr); rtp_set_hdr( p_rtp_hdr ); rtp_set_type( p_rtp_hdr, RTP_TYPE_TS ); rtp_set_seqnum( p_rtp_hdr, p_output->i_seqnum++ ); rtp_set_timestamp( p_rtp_hdr, p_output->i_ref_timestamp + (p_packet->i_dts - p_output->i_ref_wallclock) * 9 / 100 ); rtp_set_ssrc( p_rtp_hdr, p_output->config.pi_ssrc ); i_iov++; } for ( i_block = 0; i_block < p_packet->i_depth; i_block++ ) { /* Do pid mapping here if needed. * save the original pid in the block. * set the pid to the new pid * later we re-instate the old pid for the next output */ if ( b_do_remap || p_output->b_do_remap ) { block_t *p_block = p_packet->pp_blocks[i_block]; uint16_t i_pid = ts_get_pid( p_block->p_ts ); p_block->tmp_pid = UNUSED_PID; if ( p_output->pi_newpids[i_pid] != UNUSED_PID ) { uint16_t i_newpid = p_output->pi_newpids[i_pid]; /* Need to map this pid to the new pid */ ts_set_pid( p_block->p_ts, i_newpid ); p_block->tmp_pid = i_pid; } } p_iov[i_iov].iov_base = p_packet->pp_blocks[i_block]->p_ts; p_iov[i_iov].iov_len = TS_SIZE; i_iov++; } for ( ; i_block < i_block_cnt; i_block++ ) { p_iov[i_iov].iov_base = p_pad_ts; p_iov[i_iov].iov_len = TS_SIZE; i_iov++; } if ( (p_output->config.i_config & OUTPUT_RAW) ) { i_payload_len = 0; for ( i_block = 1; i_block < i_iov; i_block++ ) { i_payload_len += p_iov[i_block].iov_len; } p_output->raw_pkt_header.udph.len = htons(sizeof(struct udpheader) + i_payload_len); } if ( writev( p_output->i_handle, p_iov, i_iov ) < 0 ) { msg_Err( NULL, "couldn't writev to %s (%s)", p_output->config.psz_displayname, strerror(errno) ); } /* Update the wallclock because writev() can take some time. */ i_wallclock = mdate(); for ( i_block = 0; i_block < p_packet->i_depth; i_block++ ) { p_packet->pp_blocks[i_block]->i_refcount--; if ( !p_packet->pp_blocks[i_block]->i_refcount ) block_Delete( p_packet->pp_blocks[i_block] ); else if ( b_do_remap || p_output->b_do_remap ) { /* still referenced so re-instate the orignial pid if remapped */ block_t * p_block = p_packet->pp_blocks[i_block]; if (p_block->tmp_pid != UNUSED_PID) ts_set_pid( p_block->p_ts, p_block->tmp_pid ); } } p_output->p_packets = p_packet->p_next; free( p_packet ); if ( p_output->p_packets == NULL ) p_output->p_last_packet = NULL; }