static int np_fdtrans_recv(Npfcall **fcp, u32 msize, void *a) { Fdtrans *fdt = (Fdtrans *)a; Npfcall *fc = NULL; int n, size, len; if (fdt->fc) { assert (fdt->fc_msize >= msize); fc = fdt->fc; len = fdt->fc->size; fdt->fc = NULL; size = np_peek_size (fc->pkt, len); } else { if (!(fc = np_alloc_fcall (msize))) { np_uerror (ENOMEM); goto error; } len = 0; size = 0; } while (len < size || len < 4) { n = read(fdt->fdin, fc->pkt + len, msize - len); if (n < 0) { np_uerror (errno); goto error; } if (n == 0) { /* EOF */ free (fc); fc = NULL; goto done; } len += n; if (size == 0) size = np_peek_size(fc->pkt, len); if (size > msize) { np_uerror(EPROTO); goto error; } } if (len > size) { if (!(fdt->fc = np_alloc_fcall (msize))) { np_uerror(ENOMEM); goto error; } fdt->fc_msize = msize; memcpy (fdt->fc->pkt, fc->pkt + size, len - size); fdt->fc->size = len - size; } fc->size = size; done: *fcp = fc; return 0; error: if (fc) free (fc); return -1; }
/* Per-connection read thread. */ static void * np_conn_read_proc(void *a) { int i, n, size; Npsrv *srv; Npconn *conn = (Npconn *)a; Nptrans *trans; Npreq *req; Npfcall *fc, *fc1; pthread_detach(pthread_self()); np_conn_incref(conn); srv = conn->srv; fc = _alloc_npfcall(conn->msize); n = 0; while (fc && conn->trans && (i = np_trans_read(conn->trans, fc->pkt + n, conn->msize - n)) > 0) { n += i; again: size = np_peek_size (fc->pkt, n); if (size == 0 || n < size) continue; /* Corruption on the transport, unhandled op, etc. * is fatal to the connection. We could consider returning * an error to the client here. However, various kernels * may not handle that well, depending on where it happens. */ if (!np_deserialize(fc, fc->pkt)) { _debug_trace (srv, fc); np_logerr (srv, "protocol error - " "dropping connection to '%s'", conn->client_id); break; } if ((srv->flags & SRV_FLAGS_DEBUG_9PTRACE)) _debug_trace (srv, fc); /* Replace fc, and copy any data past the current packet * to the replacement. */ fc1 = _alloc_npfcall(conn->msize); if (!fc1) { np_logerr (srv, "out of memory in receive path - " "dropping connection to '%s'", conn->client_id); break; } if (n > size) memmove(fc1->pkt, fc->pkt + size, n - size); n -= size; /* Encapsulate fc in a request and hand to srv worker threads. * In np_req_alloc, req->fid is looked up/initialized. */ req = np_req_alloc(conn, fc); if (!req) { np_logerr (srv, "out of memory in receive path - " "dropping connection to '%s'", conn->client_id); break; } np_srv_add_req(srv, req); xpthread_mutex_lock(&conn->lock); conn->reqs_in++; xpthread_mutex_unlock(&conn->lock); fc = fc1; if (n > 0) goto again; } /* Just got EOF on read, or some other fatal error for the * connection like out of memory. */ xpthread_mutex_lock(&conn->lock); trans = conn->trans; conn->trans = NULL; if (fc) _free_npfcall(fc); xpthread_mutex_unlock(&conn->lock); np_srv_remove_conn(conn->srv, conn); np_conn_reset(conn); if (trans) np_trans_destroy(trans); np_conn_decref(conn); return NULL; }