void net::do_write() { if (write_queue_.empty()) { fdcb(fd_, selwrite, 0); return; } strbuf data = write_queue_.pop_front(); uint32_t size = data.len(); int res = write(fd_, (void*) &size, sizeof(uint32_t)); if (res != sizeof(uint32_t)) fatal << "write failed()"; res = data.tosuio()->output(fd_); check_ret(res, "write()"); // Schedule write again. if (data.tosuio()->resid()){ //warn << "Scheduling write again\n"; fdcb(fd_, selwrite, wrap(this, &net::do_write_partial, data)); return; } }
// This is called if only part of a message was previously read. void net::do_read_partial(cbsb cb, strbuf data, int remaining) { int res; res = data.tosuio()->input(fd_, remaining); if (res != remaining) { if (res == 0 || errno == ECONNRESET) { warn << "Connection has been closed\n"; fdcb(fd_, selread, 0); exit(0); //return; } else if (res < 0) { fatal << "input() failed\n"; } else { // res is > and < remaining // partial message received. fdcb(fd_, selread, wrap(this, &net::do_read_partial, cb, data, remaining - res)); return; } } fdcb(fd_, selread, wrap(this, &net::do_read, cb)); // Call function (*cb)(data); }
// close connection void net::close_net() { fdcb(fd_, selread, 0); fdcb(fd_, selwrite, 0); close(fd_); }
void chanfd::wcb (int fdn) { if (fdi[fdn].wuio.resid ()) { assert (fdi[fdn].wuio.iovcnt () >= 1); if (fdi[fdn].fdsendq.empty ()) { if (fdi[fdn].wuio.output (fdi[fdn].fd) < 0) { fdi[fdn].seterr (); return; } } else { int n = writevfd (fdi[fdn].fd, fdi[fdn].wuio.iov (), 1, fdi[fdn].fdsendq.front ()); if (n > 0) { ::close (fdi[fdn].fdsendq.pop_front ()); fdi[fdn].wuio.rembytes (n); } else { fdi[fdn].seterr (); return; } } } if (fdi[fdn].wuio.resid ()) fdcb (fdi[fdn].fd, selwrite, (wrap (this, &chanfd::wcb, fdn))); else if (fdi[fdn].weof && fdi[fdn].reof) fdi[fdn].seterr (); else fdcb (fdi[fdn].fd, selwrite, NULL); }
void aios::input () { if (rlock) return; rlock = true; ref<aios> hold = mkref (this); // Don't let this be freed under us int n = ::readv (fd, const_cast<iovec *> (inb.iniov ()), inb.iniovcnt ()); if (n > 0) inb.addbytes (n); else if (n < 0 && errno != EAGAIN) { fail (errno); rlock = false; return; } else if (!n && !(this->*infn) ()) { fail (0); rlock = false; return; } while ((this->*infn) ()) ; if (fd >= 0) { if (rcb) fdcb (fd, selread, wrap (this, &aios::input)); else fdcb (fd, selread, NULL); //timeoutbump (); } rlock = false; }
static PyObject * Core_fdcb (PyObject *self, PyObject *args) { int fd = 0; int i_op = 0; PyObject *cb = NULL; if (!PyArg_ParseTuple (args, "ii|O", &fd, &i_op, &cb)) return NULL; selop op = selop (i_op); if (op != selread && op != selwrite) { PyErr_SetString (PyExc_TypeError, "unknown select option"); return NULL; } if (!cb) { fdcb (fd, op, NULL); } else { if (!PyCallable_Check (cb)) { PyErr_SetString (PyExc_TypeError, "callable object expected"); return NULL; } ptr<pop_t> pop = pop_t::alloc (cb); make_async (fd); fdcb (fd, op, wrap (Core_cb, pop)); } Py_INCREF (Py_None); return Py_None; }
void kbdinput::output (str s) { suio_print (&outq, s); if (outq.resid ()) { fdcb (kbdfd, selread, NULL); fdcb (kbdfd, selwrite, wrap (this, &kbdinput::writecb)); } }
void kbdinput::writecb () { if (outq.output (kbdfd) < 0) fatal ("keyboard (output): %m\n"); if (!outq.resid ()) { fdcb (kbdfd, selwrite, NULL); fdcb (kbdfd, selread, wrap (this, &kbdinput::readcb)); } }
proxy::~proxy () { list<proxy, &proxy::llink>::remove (this); for (int i = 0; i < 2; i++) { fdcb (con[i].fd, selread, NULL); fdcb (con[i].fd, selwrite, NULL); close (con[i].fd); timecb_remove (con[i].tmo); } }
aios::~aios () { if (fd >= 0) { if (debugname) warnx << debugname << " === EOF\n"; fdcb (fd, selread, NULL); fdcb (fd, selwrite, NULL); ::close (fd); } if (timeoutcb) timecb_remove (timeoutcb); }
void reset () { if (fdreset) return; fdreset = true; if (tok) setorig (); if (outq.resid ()) writecb (); if (kbdfd >= 0) { fdcb (kbdfd, selread, NULL); fdcb (kbdfd, selwrite, NULL); } }
void unixfd::rcb () { if (reof) { fdcb (localfd_in, selread, NULL); return; } char buf[16*1024]; int fdrecved = -1; ssize_t n; if (unixsock) n = readfd (localfd_in, buf, sizeof (buf), &fdrecved); else n = read (localfd_in, buf, sizeof (buf)); if (n < 0) { if (errno != EAGAIN) abort (); return; } if (!n) { readeof (); return; } else { rex_payload arg; arg.channel = channo; arg.fd = fd; arg.data.set (buf, n); if (fdrecved >= 0) { close_on_exec (fdrecved); rex_newfd_arg arg; arg.channel = channo; arg.fd = fd; ref<rex_newfd_res> resp (New refcounted<rex_newfd_res> (false)); proxy->call (REX_NEWFD, &arg, resp, wrap (mkref (this), &unixfd::newfdcb, fdrecved, resp)); } ref<bool> pres (New refcounted<bool> (false)); rsize += n; proxy->call (REX_DATA, &arg, pres, wrap (mkref (this), &unixfd::datacb, n, pres)); } if (rsize >= hiwat) fdcb (localfd_in, selread, NULL); }
void net::do_read(cbsb cb) { strbuf data; int size; int res; res = read(fd_, (void*) &size, sizeof(int)); if (res != sizeof(int)) { if (res == 0 || errno == ECONNRESET) { // Connection was closed. Disable reading. warn << "Connection has been closed\n"; fdcb(fd_, selread, 0); exit(0); //return; } else if (errno == EAGAIN) { // Just ignore. return; } else { //TODO: Handle case where only a fraction of first 4 bytes is read. fatal << "read() failed. errno = " << errno << "\n"; } } res = data.tosuio()->input(fd_, size); if (res != size) { if (res == 0 || errno == ECONNRESET) { warn << "Connection has been closed\n"; fdcb(fd_, selread, 0); return; } else if (res < 0) { if (errno == EAGAIN) { //warn << "Reading partial message\n"; fdcb(fd_, selread, wrap(this, &net::do_read_partial, cb, data, size)); return; } fatal << "input() failed. errno: " << errno <<"\n"; } else { // res is > and < size // partial message received. //warn << "Reading partial message\n"; fdcb(fd_, selread, wrap(this, &net::do_read_partial, cb, data, size - res)); return; } } // Call function (*cb)(data); }
void proxy::setcb (int i) { /* If we have data or an EOF to transmit, schedule a write callback. */ if (con[i].wbuf.resid () || con[!i].eof && !con[i].closed) { fdcb (con[i].fd, selwrite, wrap (this, &proxy::wcb, i)); if (!con[i].tmo) con[i].tmo = delaycb (120, wrap (this, &proxy::timeout, i)); } /* If buffer falls beneath low-water mark, schedule a read callback. */ if (!con[!i].eof && con[i].wbuf.resid () <= lowat) fdcb (con[!i].fd, selread, wrap (this, &proxy::rcb, !i)); }
void chanfd::fdinfo::seterr () { if (fd >= 0) { while (!fdsendq.empty ()) ::close (fdsendq.pop_front ()); fdcb (fd, selread, NULL); fdcb (fd, selwrite, NULL); int savedfd = fd; fd = -1; wuio.clear (); ::close (savedfd); } reof = weof = true; }
void aios::setoutcb () { if (err && err != ETIMEDOUT) { fdcb (fd, selwrite, NULL); outb.tosuio ()->clear (); } else if (outb.tosuio ()->resid ()) { if (!timeoutcb) timeoutbump (); fdcb (fd, selwrite, wrap (this, &aios::output)); } else fdcb (fd, selwrite, NULL); }
void proxy::wcb (int i) { size_t bufsize = con[i].wbuf.resid (); if (bufsize && con[i].wbuf.output (con[i].fd) < 0 && errno != EAGAIN) { warn << "write-" << (i ? "client" : "server") << ": " << strerror (errno) << "\n"; delete this; return; } if (con[i].wbuf.resid () < bufsize && con[i].tmo) { timecb_remove (con[i].tmo); con[i].tmo = NULL; } if (!con[i].wbuf.resid ()) { fdcb (con[i].fd, selwrite, NULL); if (con[!i].eof && !con[i].closed) { if (con[!i].closed) { delete this; return; } con[i].closed = true; shutdown (con[i].fd, 1); } } setcb (i); }
/* unixfd specific arguments: localfd_in: local file descriptor for input (or everything for non-tty) localfd_out: local file descriptor for output (only used for tty support) Set localfd_out = -1 (or omit the argument entirely) if you're not working with a remote tty; then the localfd_in is connected directly to the remote FD for both reads and writes (except it it's RO or WO). noclose: Unixfd will not use close or shutdown calls on the local file descriptor (localfd_in); useful for terminal descriptors, which must hang around so that raw mode can be disabled, etc. shutrdonexit: When the remote module exits, we shutdown the read direction of the local file descriptor (_in). This isn't always done since not all file descriptors managed on the REX channel are necessarily connected to the remote module. */ unixfd::unixfd (rexchannel *pch, int fd, int localfd_in, int localfd_out, bool noclose, bool shutrdonexit, cbv closecb) : rexfd::rexfd (pch, fd), localfd_in (localfd_in), localfd_out (localfd_out), rsize (0), unixsock (isunixsocket (localfd_in)), weof (false), reof (false), shutrdonexit (shutrdonexit), closecb (closecb) { if (noclose) { int duplocalfd = dup (localfd_in); if (duplocalfd < 0) warn ("failed to duplicate fd for noclose behavior (%m)\n"); else unixfd::localfd_in = duplocalfd; } make_async (this->localfd_in); if (!is_fd_wronly (this->localfd_in)) fdcb (this->localfd_in, selread, wrap (this, &unixfd::rcb)); /* for tty support we split the input/output to two local FDs */ if (localfd_out >= 0) paios_out = aios::alloc (this->localfd_out); else paios_out = aios::alloc (this->localfd_in); }
void proxy::rcb (int i) { if (con[!i].wbuf.resid () >= hiwat) { fdcb (con[i].fd, selread, NULL); return; } int n = con[!i].wbuf.input (con[i].fd); if (n == 0 || n < 0 && errno != EAGAIN) { if (n < 0) warn << "read: " << strerror (errno) << "\n"; con[i].eof = true; fdcb (con[i].fd, selread, NULL); } setcb (!i); }
axprt_dgram::~axprt_dgram () { fdcb (fd, selread, NULL); close (fd); xfree (sabuf); xfree (pktbuf); }
void dnssock_tcp::wcb (bool selected) { if (selected) write_ok = true; if (!write_ok) return; int n = tcpstate.output (fd); if (n < 0) { fdcb (fd, selwrite, NULL); (*cb) (NULL, -1); } else if (n > 0) fdcb (fd, selwrite, NULL); else fdcb (fd, selwrite, wrap (this, &dnssock_tcp::wcb, true)); }
void aios::abort () { if (fd < 0) return; if (debugname) warnx << debugname << " === EOF\n"; rcb = NULL; fdcb (fd, selread, NULL); fdcb (fd, selwrite, NULL); ::close (fd); fd = -1; eof = true; weof = true; err = EBADF; outb.tosuio ()->clear (); }
static void err_wcb () { int n; int cnt; if (!erruio->resid () || _err_output != _err_output_async) { fdcb (errfd, selwrite, NULL); return; } /* Try to write whole lines at a time. */ for (cnt = min (erruio->iovcnt (), (size_t) UIO_MAXIOV); cnt > 0 && (erruio->iov ()[cnt-1].iov_len == 0 || *((char *) erruio->iov ()[cnt-1].iov_base + erruio->iov ()[cnt-1].iov_len - 1) != '\n'); cnt--) ; if (!cnt) { if (erruio->iovcnt () < UIO_MAXIOV) { /* Wait for a carriage return */ fdcb (errfd, selwrite, NULL); return; } else cnt = -1; } /* Write asynchronously, but keep stderr synchronous in case of * emergency (e.g. maybe assert wants to fprintf to stderr). */ if (globaldestruction) n = erruio->output (errfd, cnt); else { _make_async (errfd); n = erruio->output (errfd, cnt); make_sync (errfd); } if (n < 0) err_reset (); if (erruio->resid () && !globaldestruction) fdcb (errfd, selwrite, wrap (err_wcb)); else fdcb (errfd, selwrite, NULL); }
void fdtab_t::close (fd_t *obj, int del) { FLUMEDBG4(FDS, CHATTER, "[%" PRIx64 "] close (%s); unreg: %d\n", getflmpid ().value (), obj->desc (), obj->_dereg); assert (_tab[obj->_fd]); if (obj->_dereg) { fdcb (obj->_fd, selread, NULL); fdcb (obj->_fd, selwrite, NULL); } ::close (obj->_fd); remove (obj); if (del) delete obj; }
// Asynchronous write void net::a_write(str data) { write_queue_.push_back(data); if (write_queue_.size() == 1) fdcb(fd_, selwrite, wrap(this, &net::do_write)); }
void turn_off () { if (selread_on && fd >= 0) { fdcb (fd, selread, NULL); selread_on = false; success = true; } else { success = false; } }
void aios::fail (int e) { ref<aios> hold = mkref (this); // Don't let this be freed under us eof = true; if (e) err = e; if (fd >= 0) { fdcb (fd, selread, NULL); if (rcb) mkrcb (NULL); if (fd >= 0 && err && err != ETIMEDOUT) { fdcb (fd, selwrite, NULL); outb.tosuio ()->clear (); } } }
void merkle_disk_server::client_listen (int fd) { if (listen (fd, 5) < 0) { fatal ("Error from listen: %m\n"); close (fd); } else { fdcb (fd, selread, wrap (this, &merkle_disk_server::client_accept_socket, fd)); } }
stalesrv::~stalesrv () { if (nf->sotype == SOCK_STREAM) { fdcb (nf->fd, selread, NULL); close (nf->fd); } while (srvelm *s = srvs.first) { srvs.remove (s); delete s; } }
// This is only invoked if only a fraction of the message was sent. void net::do_write_partial(strbuf data) { int res = data.tosuio()->output(fd_); check_ret(res, "write()"); // Schedule partial write again. if (data.tosuio()->resid()) return; // Go back to normal write. fdcb(fd_, selwrite, wrap(this, &net::do_write)); }