/* read a request from a thread */ void read_request( struct thread *thread ) { int ret; if (!thread->req_toread) /* no pending request */ { if ((ret = read( get_unix_fd( thread->request_fd ), &thread->req, sizeof(thread->req) )) != sizeof(thread->req)) goto error; if (!(thread->req_toread = thread->req.request_header.request_size)) { /* no data, handle request at once */ call_req_handler( thread ); return; } if (!(thread->req_data = malloc( thread->req_toread ))) { fatal_protocol_error( thread, "no memory for %u bytes request %d\n", thread->req_toread, thread->req.request_header.req ); return; } } /* read the variable sized data */ for (;;) { ret = read( get_unix_fd( thread->request_fd ), (char *)thread->req_data + thread->req.request_header.request_size - thread->req_toread, thread->req_toread ); if (ret <= 0) break; if (!(thread->req_toread -= ret)) { call_req_handler( thread ); free( thread->req_data ); thread->req_data = NULL; return; } } error: if (!ret) /* closed pipe */ kill_thread( thread, 0 ); else if (ret > 0) fatal_protocol_error( thread, "partial read %d\n", ret ); else if (errno != EWOULDBLOCK && errno != EAGAIN) fatal_protocol_perror( thread, "read" ); }
/* send a reply to the current thread */ static void send_reply( union generic_reply *reply ) { int ret; if (!current->reply_size) { if ((ret = write( get_unix_fd( current->reply_fd ), reply, sizeof(*reply) )) != sizeof(*reply)) goto error; } else { struct iovec vec[2]; vec[0].iov_base = (void *)reply; vec[0].iov_len = sizeof(*reply); vec[1].iov_base = current->reply_data; vec[1].iov_len = current->reply_size; if ((ret = writev( get_unix_fd( current->reply_fd ), vec, 2 )) < sizeof(*reply)) goto error; if ((current->reply_towrite = current->reply_size - (ret - sizeof(*reply)))) { /* couldn't write it all, wait for POLLOUT */ set_fd_events( current->reply_fd, POLLOUT ); set_fd_events( current->request_fd, 0 ); return; } } if (current->reply_data) { free( current->reply_data ); current->reply_data = NULL; } return; error: if (ret >= 0) fatal_protocol_error( current, "partial write %d\n", ret ); else if (errno == EPIPE) kill_thread( current, 0 ); /* normal death */ else fatal_protocol_perror( current, "reply write" ); }
/* write the remaining part of the reply */ void write_reply( struct thread *thread ) { int ret; if ((ret = write( get_unix_fd( thread->reply_fd ), (char *)thread->reply_data + thread->reply_size - thread->reply_towrite, thread->reply_towrite )) >= 0) { if (!(thread->reply_towrite -= ret)) { free( thread->reply_data ); thread->reply_data = NULL; /* sent everything, can go back to waiting for requests */ set_fd_events( thread->request_fd, POLLIN ); set_fd_events( thread->reply_fd, 0 ); } return; } if (errno == EPIPE) kill_thread( thread, 0 ); /* normal death */ else if (errno != EWOULDBLOCK && errno != EAGAIN) fatal_protocol_perror( thread, "reply write" ); }