/* Allocate a new Npfcall to "receive" raw data from fc->pkt. */ static Npfcall * _rcv_buf (Npfcall *fc, int type, const char *fun) { Npfcall *fc2; char s[256]; printf ("%s(%d): %d\n", fun, type, fc->size); np_set_tag (fc, 42); /* see conn.c:np_conn_new_incall () */ if (!(fc2 = malloc (sizeof (*fc2) + TEST_MSIZE))) msg_exit ("out of memory"); fc2->pkt = (u8 *)fc2 + sizeof (*fc2); /* see conn.c::np_conn_read_proc */ memcpy (fc2->pkt, fc->pkt, fc->size); if (!np_deserialize (fc2)) msg_exit ("np_deserialize error in %s", fun); /* check a few things */ if (fc->type != type) msg_exit ("incorrect type in %s", fun); if (fc->size != fc2->size) msg_exit ("size mismatch in %s", fun); if (fc->type != fc2->type) msg_exit ("type mismatch in %s", fun); np_snprintfcall (s, sizeof (s), fc); printf ("%s\n", s); return fc2; }
/* 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; }
static void * np_conn_read_proc(void *a) { int i, n, size, msize; Npsrv *srv; Npconn *conn; Nptrans *trans; Npreq *req; Npfcall *fc, *fc1; pthread_detach(pthread_self()); conn = a; np_conn_incref(conn); srv = conn->srv; msize = conn->msize; fc = np_conn_new_incall(conn); n = 0; while (conn->trans && (i = np_trans_read(conn->trans, fc->pkt + n, msize - n)) > 0) { pthread_mutex_lock(&conn->lock); if (conn->resetting) { while(conn->resetting) pthread_cond_wait(&conn->resetdonecond, &conn->lock); n = 0; /* discard all input */ i = 0; } pthread_mutex_unlock(&conn->lock); n += i; again: if (n < 4) continue; size = fc->pkt[0] | (fc->pkt[1]<<8) | (fc->pkt[2]<<16) | (fc->pkt[3]<<24); if (n < size) continue; if (!np_deserialize(fc, fc->pkt, conn->dotu)) break; if (conn->srv->debuglevel) { fprintf(stderr, "<<< (%p) ", conn); np_printfcall(stderr, fc, conn->dotu); fprintf(stderr, "\n"); } fc1 = np_conn_new_incall(conn); if (n > size) memmove(fc1->pkt, fc->pkt + size, n - size); n -= size; req = np_req_alloc(conn, fc); pthread_mutex_lock(&srv->lock); if (!conn->resetting) np_srv_add_req(srv, req); else np_req_unref(req); pthread_mutex_unlock(&srv->lock); fc = fc1; if (n > 0) goto again; } pthread_mutex_lock(&conn->lock); trans = conn->trans; conn->trans = NULL; np_conn_free_incall(conn, fc); pthread_mutex_unlock(&conn->lock); np_srv_remove_conn(conn->srv, conn); np_conn_reset(conn, 0, 0); if (trans) np_trans_destroy(trans); np_conn_decref(conn); return NULL; }
static void _flush_series (Npcfsys *fs, Npcfid *root) { Npfcall *rc = NULL, *tc = NULL, *ac = NULL; u16 tag, flushtag; int n, i; struct sigaction sa; assert (fs->trans != NULL); sa.sa_flags = 0; sigemptyset(&sa.sa_mask); sa.sa_handler = _alarm_clock; if (sigaction (SIGALRM, &sa, NULL) < 0) err_exit ("sigaction"); /* write 100 tversions */ for (i = 0; i < 100; i++) { if (!(tc = np_create_tversion (fs->msize, "9P2000.L"))) msg_exit ("out of memory"); flushtag = tag = npc_get_id(fs->tagpool); np_set_tag(tc, tag); n = np_trans_write(fs->trans, tc->pkt, tc->size); if (n < 0) errn_exit (np_rerror (), "np_trans_write"); if (n != tc->size) msg_exit ("np_trans_write came up unexpectedly short"); //msg ("sent tversion tag %d", tc->tag); free(tc); } msg ("sent 100 tversions"); /* flush the most recent */ if (!(ac = np_create_tflush (flushtag))) msg_exit ("out of memory"); tag = npc_get_id(fs->tagpool); np_set_tag(ac, tag); n = np_trans_write(fs->trans, ac->pkt, ac->size); if (n < 0) errn_exit (np_rerror (), "np_trans_write"); if (n != ac->size) msg_exit ("np_trans_write came up unexpectedly short"); //msg ("sent tflush tag %d (flushing tag %d)", ac->tag, flushtag); free (ac); msg ("sent 1 tflush"); /* receive up to 101 responses with 1s timeout */ for (i = 0; i < 101; i++) { if (!(rc = malloc(sizeof(*rc) + fs->msize))) msg_exit ("out of memory"); rc->pkt = (u8*)rc + sizeof(*rc); alarm (1); n = np_trans_read(fs->trans, rc->pkt, fs->msize); if (n < 0) { if (errno == EINTR) break; errn_exit (np_rerror (), "np_trans_read"); } alarm (0); if (n == 0) msg_exit ("np_trans_read: unexpected EOF"); if (!np_deserialize (rc, rc->pkt)) msg_exit ("failed to deserialize response in one go"); //msg ("received tag %d", rc->tag); free(rc); //npc_put_id(fs->tagpool, rc->tag); } if (i == 100 || i == 101) msg ("received 100/101 respones"); else msg ("received %d responses", i); }