static void check_version (void) { int version; rpc_get (msock, RPC_INT, &version, RPC_END); if (version >= 1 && version <= RPC_PROGVER) rpc_send (msock, RPC_INT, MC_VERSION_OK, RPC_END); else rpc_send (msock, RPC_INT, MC_VERSION_MISMATCH, RPC_END); clnt_version = version; }
/* FIXME: Implement the anonymous login */ static void do_login (void) { char *username; char *password; int result; rpc_get (msock, RPC_LIMITED_STRING, &up_dir, RPC_LIMITED_STRING, &username, RPC_END); if (verbose) printf ("username: %s\n", username); if (r_auth) { logged_in = do_rauth (msock); if (logged_in) { login_reply (logged_in); return; } } rpc_send (msock, RPC_INT, MC_NEED_PASSWORD, RPC_END); rpc_get (msock, RPC_INT, &result, RPC_END); if (result == MC_QUIT) DO_QUIT_VOID (); if (result != MC_PASS) { if (verbose) printf ("do_login: Unknown response: %d\n", result); DO_QUIT_VOID (); } rpc_get (msock, RPC_LIMITED_STRING, &password, RPC_END); logged_in = do_auth (username, password); endpwent (); login_reply (logged_in); }
/* send a request for a directory item */ int nfs_readdir(struct cookie *pfh, int cookie, int size, void (*func) (uintptr_t , int, int, struct nfs_filename *, int), uintptr_t token) { readdirargs_t args; struct pbuf *pbuf; /* now the user data struct is setup, do some call stuff! */ pbuf = initbuf(NFS_NUMBER, NFS_VERSION, NFSPROC_READDIR); /* copy the buffer */ memcpy(&args.dir, pfh, sizeof(struct cookie)); /* set the cookie */ args.cookie = cookie; args.count = size; /* copy the arguments into the packet */ addtobuf(pbuf, (char*) &args, sizeof(args)); /* make the call! */ return rpc_send(pbuf, nfs_port, nfs_readdir_cb, func, token); }
int rpc_call(struct rpc *r, int func_id, void *in_arg, size_t in_len, void *out_arg, size_t out_len) { rpc_packet_format(r, func_id); return rpc_send(r, in_arg, in_len); }
int rpc_call(struct rpc *r, uint32_t msg_id, const void *in_arg, size_t in_len, void *out_arg, size_t out_len) { if (!r) { loge("invalid parament!\n"); return -1; } size_t pkt_len = pack_msg(&r->send_pkt, msg_id, in_arg, in_len); if (pkt_len == 0) { loge("pack_msg failed!\n"); return -1; } if (0 > rpc_send(r, in_arg, in_len)) { loge("skt_send failed, fd = %d!\n", r->fd); return -1; } if (IS_RPC_MSG_NEED_RETURN(msg_id)) { if (thread_sem_wait(r->dispatch_thread, 2000) == -1) { loge("wait response failed %d:%s\n", errno, strerror(errno)); return -1; } logi("recv_pkt.len = %d\n", r->recv_pkt.header.payload_len); memcpy(out_arg, r->recv_pkt.payload, out_len); } else { } return 0; }
int nfs_write(struct cookie *fh, int offset, int count, void *data, void (*func) (uintptr_t, int, fattr_t *), uintptr_t token) { struct pbuf *pbuf; writeargs_t args; /* now the user data struct is setup, do some call stuff! */ pbuf = initbuf(NFS_NUMBER, NFS_VERSION, NFSPROC_WRITE); /* copy in the fhandle */ memcpy(&args.file, (char*) fh, sizeof(struct cookie)); args.offset = offset; args.beginoffset = 0; /* unused as per RFC */ args.totalcount = 0; /* unused as per RFC */ /* add them to the buffer */ addtobuf(pbuf, (char*) &args, sizeof(args)); /* put the data in */ adddata(pbuf, data, count); return rpc_send(pbuf, nfs_port, nfs_write_cb, func, token); }
static void send_stat_info (struct stat *st) { long mylong; int blocks = #ifdef HAVE_STRUCT_STAT_ST_BLOCKS st->st_blocks; #else st->st_size / 1024; #endif #ifdef HAVE_STRUCT_STAT_ST_RDEV mylong = st->st_rdev; #else mylong = 0; #endif rpc_send (msock, RPC_INT, (long) mylong, RPC_INT, (long) st->st_ino, RPC_INT, (long) st->st_mode, RPC_INT, (long) st->st_nlink, RPC_INT, (long) st->st_uid, RPC_INT, (long) st->st_gid, RPC_INT, (long) st->st_size, RPC_INT, (long) blocks, RPC_END); send_time (msock, st->st_atime); send_time (msock, st->st_mtime); send_time (msock, st->st_ctime); }
static void do_read (void) { int handle, count, n; void *data; rpc_get (msock, RPC_INT, &handle, RPC_INT, &count, RPC_END); data = malloc (count); if (!data) { send_status (-1, ENOMEM); return; } if (verbose) printf ("count=%d\n", count); n = read (handle, data, count); if (verbose) printf ("result=%d\n", n); if (n < 0) { send_status (-1, errno); return; } send_status (n, 0); rpc_send (msock, RPC_BLOCK, n, data, RPC_END); g_free (data); }
struct rpc *rpc_connect_create(struct rpcd *rpcd, int fd, uint32_t ip, uint16_t port) { char str_ip[INET_ADDRSTRLEN]; char uuid[MAX_UUID_LEN]; int ret; struct rpc *r = (struct rpc *)calloc(1, sizeof(struct rpc)); if (!r) { loge("malloc failed!\n"); return NULL; } r->fd = fd; create_uuid(uuid, MAX_UUID_LEN, fd, ip, port); struct gevent *e = gevent_create(fd, on_recv, NULL, on_error, (void *)r); if (-1 == gevent_add(rpcd->evbase, e)) { loge("event_add failed!\n"); } r->ev = e; rpc_header_format(r, uuid, uuid, 0, 0); ret = rpc_send(r, uuid, MAX_UUID_LEN); if (ret != MAX_UUID_LEN) { loge("rpc_send failed!\n"); } rpcd_connect_add(rpcd, r, fd, uuid); skt_addr_ntop(str_ip, ip); logi("on_connect fd = %d, remote_addr = %s:%d, uuid=%s\n", fd, str_ip, port, uuid); return r; }
static void send_time (int sock, time_t time) { if (clnt_version == 1) { char *ct; int month; ct = ctime (&time); ct[3] = ct[10] = ct[13] = ct[16] = ct[19] = 0; /* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */ if (ct[4] == 'J') { if (ct[5] == 'a') { month = 0; } else month = (ct[6] == 'n') ? 5 : 6; } else if (ct[4] == 'F') { month = 1; } else if (ct[4] == 'M') { month = (ct[6] == 'r') ? 2 : 5; } else if (ct[4] == 'A') { month = (ct[5] == 'p') ? 3 : 7; } else if (ct[4] == 'S') { month = 8; } else if (ct[4] == 'O') { month = 9; } else if (ct[4] == 'N') { month = 10; } else month = 11; rpc_send (msock, RPC_INT, atoi (&ct[17]), /* sec */ RPC_INT, atoi (&ct[14]), /* min */ RPC_INT, atoi (&ct[11]), /* hour */ RPC_INT, atoi (&ct[8]), /* mday */ RPC_INT, atoi (&ct[20]), /* year */ RPC_INT, month, /* month */ RPC_END); } else { long ltime = (long) time; char buf[BUF_SMALL]; snprintf (buf, sizeof (buf), "%lx", ltime); rpc_send (msock, RPC_STRING, buf, RPC_END); } }
enum rpc_stat rpc_call(struct pbuf *pbuf, int len, struct udp_pcb *pcb, void (*func)(void *, uintptr_t, struct pbuf *), void *callback, uintptr_t token) { struct rpc_call_arg call_arg; struct rpc_queue *q_item; int time_out; enum rpc_stat stat; xid_t xid; /* If we give up early, we must ensure that the argument remains in memory * just in case the packet comes in later */ assert(pcb); assert(pbuf); /* GeneratrSend the thing with the unlock frunction as a callback */ call_arg.func = func; call_arg.callback = callback; call_arg.token = token; call_arg.complete = 0; /* Make the call */ xid = extract_xid(pbuf); stat = rpc_send(pbuf, pbuf->tot_len, pcb, &rpc_call_cb, NULL, (uintptr_t)&call_arg); if(stat){ return stat; } /* Wait for the response */ time_out = RETRANSMIT_DELAY_MS * (CALL_RETRIES + 1); while(time_out >= 0){ _usleep(CALL_TIMEOUT_MS * 1000); if(call_arg.complete) { /* Success */ return 0; } rpc_timeout(CALL_TIMEOUT_MS); time_out -= CALL_TIMEOUT_MS; } /* If we get here, we have failed. Data is on the stack so make sure * we remove references from the queue */ q_item = get_from_queue(xid); assert(q_item); pbuf_free(q_item->pbuf); free(q_item); return RPCERR_COMM; }
/* Sends the complete directory listing, as well as the stat information */ static void do_readdir (void) { struct dirent *dirent; struct stat st; int handle, n; rpc_get (msock, RPC_INT, &handle, RPC_END); if (!handle) { rpc_send (msock, RPC_INT, 0, RPC_END); return; } /* We incremented it in opendir */ handle--; while ((dirent = readdir (mcfs_DIR.dirs[handle]))) { int fname_len; char *fname; int length = NLENGTH (dirent); rpc_send (msock, RPC_INT, length, RPC_END); rpc_send (msock, RPC_BLOCK, length, dirent->d_name, RPC_END); fname_len = strlen (mcfs_DIR.names[handle]) + strlen (dirent->d_name) + 2; fname = malloc (fname_len); snprintf (fname, fname_len, "%s/%s", mcfs_DIR.names[handle], dirent->d_name); n = lstat (fname, &st); g_free (fname); send_status (n, errno); if (n >= 0) send_stat_info (&st); } rpc_send (msock, RPC_INT, 0, RPC_END); }
struct pbuf * rpc_call(struct pbuf *pbuf, int port) { L4_ThreadId_t from; opaque_auth_t auth; reply_stat r; /* Send the thing */ rpc_send(pbuf, port, signal, NULL, L4_Myself().raw); /* We wait for a reply */ L4_Wait(&from); pbuf_adv_arg(call_pbuf, 0, 8); /* check if it was an accepted reply */ getfrombuf(call_pbuf, (char*) &r, sizeof(r)); if(r != MSG_ACCEPTED) { debug( "Message NOT accepted (%d)\n", r ); /* extract error code */ getfrombuf(call_pbuf, (char*) &r, sizeof(r)); debug( "Error code %d\n", r ); if(r == 1) { /* get the auth problem */ getfrombuf(call_pbuf, (char*) &r, sizeof(r)); debug( "auth_stat %d\n", r ); } return 0; } /* and the auth data!*/ getfrombuf(call_pbuf, (char*) &auth, sizeof(auth)); debug("Got auth data. size is %d\n", auth.size); /* check its accept stat */ getfrombuf(call_pbuf, (char*) &r, sizeof(r)); if( r == SUCCESS ) return call_pbuf; else { debug( "reply stat was %d\n", r ); return NULL; } }
static void* do_rpc_thread(void *data) { LOG_ENTRY; struct rpc *rpc = data; if (!rpc || !rpc->handler) { RPC_PUTS("bad rpc"); LOG_EXIT; return NULL; } rpc->active = 1; rpc_cond_signal(rpc); fd_set fds; while (rpc->active) { RPC_DEBUG("+loop"); FD_ZERO(&fds); FD_SET(rpc->fd, &fds); FD_SET(rpc->pipefd[READ_END], &fds); select(max(rpc->fd, rpc->pipefd[READ_END]) + 1, &fds, NULL, NULL, NULL); pthread_mutex_lock(&rpc->fd_mutex); if (FD_ISSET(rpc->fd, &fds)) { RPC_DEBUG("receiving RPC message"); if (rpc_recv(rpc) < 0) { RPC_ERROR("receive error"); rpc->active = 0; goto handled; } } if (FD_ISSET(rpc->pipefd[READ_END], &fds)) { RPC_DEBUG("calling remote party"); if (rpc_send(rpc) < 0) { RPC_ERROR("call error"); rpc->active = 0; goto handled; } } handled: pthread_mutex_unlock(&rpc->fd_mutex); RPC_DEBUG("-loop"); } rpc_cond_signal(rpc); LOG_EXIT; return NULL; }
static void do_opendir (void) { int handle, i; char *arg; DIR *p; rpc_get (msock, RPC_STRING, &arg, RPC_END); if (mcfs_DIR.used == OPENDIR_HANDLES) { send_status (-1, ENFILE); /* Error */ g_free (arg); return; } handle = -1; for (i = 0; i < OPENDIR_HANDLES; i++) { if (mcfs_DIR.dirs[i] == 0) { handle = i; break; } } if (handle == -1) { send_status (-1, EMFILE); g_free (arg); if (!inetd_started) fprintf (stderr, "OOPS! you have found a bug in mc - do_opendir()!\n"); return; } if (verbose) printf ("handle=%d\n", handle); p = opendir (arg); if (p) { mcfs_DIR.dirs[handle] = p; mcfs_DIR.names[handle] = arg; mcfs_DIR.used++; /* Because 0 is an error value */ rpc_send (msock, RPC_INT, handle + 1, RPC_INT, 0, RPC_END); } else { send_status (-1, errno); g_free (arg); } }
int nfs_getattr(struct cookie *fh, void (*func) (uintptr_t, int, fattr_t *), uintptr_t token) { struct pbuf *pbuf; /* now the user data struct is setup, do some call stuff! */ pbuf = initbuf(NFS_NUMBER, NFS_VERSION, NFSPROC_GETATTR); /* put in the fhandle */ addtobuf(pbuf, (char*) fh, sizeof(struct cookie)); /* send it! */ return rpc_send(pbuf, nfs_port, nfs_getattr_cb, func, token); }
static void do_readlink (void) { char buffer[2048]; char *file; int n; rpc_get (msock, RPC_STRING, &file, RPC_END); n = readlink (file, buffer, 2048 - 1); send_status (n, errno); if (n >= 0) { buffer[n] = 0; rpc_send (msock, RPC_STRING, buffer, RPC_END); } g_free (file); }
/* remove a file named 'name' in directory 'cwd' */ int nfs_remove(struct cookie *cwd, char *name, void (*func) (uintptr_t, int), uintptr_t token) { struct pbuf *pbuf; /* now the user data struct is setup, do some call stuff! */ pbuf = initbuf(NFS_NUMBER, NFS_VERSION, NFSPROC_REMOVE); /* put in the fhandle */ addtobuf(pbuf, (char*) cwd, sizeof(struct cookie)); /* put in the name */ addstring(pbuf, name); /* send it! */ return rpc_send(pbuf, nfs_port, nfs_remove_cb, func, token); }
int nfs_create(struct cookie *fh, char *name, sattr_t *sat, void (*func) (uintptr_t, int, struct cookie *, fattr_t *), uintptr_t token) { struct pbuf *pbuf; /* now the user data struct is setup, do some call stuff! */ pbuf = initbuf(NFS_NUMBER, NFS_VERSION, NFSPROC_CREATE); /* put in the fhandle */ addtobuf(pbuf, (char*) fh, sizeof(struct cookie)); /* put in the name */ addstring(pbuf, name); addtobuf(pbuf, (char*) sat, sizeof(sattr_t)); return rpc_send(pbuf, nfs_port, nfs_create_cb, func, token); }
int process_msg(struct rpc *r, struct iobuf *buf) { int ret; msg_handler_t msg_handler; struct rpc_header *h = &r->packet.header; int msg_id = rpc_packet_parse(r); if (find_msg_handler(msg_id, &msg_handler) == 0) { msg_handler.cb(r, buf->addr, buf->len); } else { loge("no callback for this MSG ID in process_msg\n"); char *valfd = (char *)dict_get(_rpcd->dict_uuid2fd, h->uuid_dst, NULL); if (!valfd) { loge("dict_get failed: key=%s\n", h->uuid_dst); return -1; } int dst_fd = strtol(valfd, NULL, 16); r->fd = dst_fd; ret = rpc_send(r, buf->addr, buf->len); } return ret; }
int nfs_read(struct cookie *fh, int pos, int count, void (*func) (uintptr_t, int, fattr_t *, int, char *), uintptr_t token) { struct pbuf *pbuf; readargs_t args; /* now the user data struct is setup, do some call stuff! */ pbuf = initbuf(NFS_NUMBER, NFS_VERSION, NFSPROC_READ); /* copy in the fhandle */ memcpy(&args.file, (char*) fh, sizeof(struct cookie)); args.offset = pos; args.count = count; args.totalcount = 0; /* unused as per RFC */ /* add them to the buffer */ addtobuf(pbuf, (char*) &args, sizeof(args)); return rpc_send(pbuf, nfs_port, nfs_read_cb, func, token); }
/* * Man FIFO routine running in the FIFO * processes requests received * through the FIFO file repeatedly */ int fifo_process(char* msg_buf, int size, int* bytes_needed, void *sh, void** saved_state) { rpc_export_t* exp; char* buf; int line_len; char *file_sep; struct text_chunk* p; struct rpc_struct* s; int r; int req_size; static rpc_ctx_t context; DBG("process_fifo: called with %d bytes, offset %d: %.*s\n", size, (int)(long)*saved_state, size, msg_buf); /* search for the end of the request (\n\r) */ if (size < 6){ /* min fifo request */ *bytes_needed=6-size; return 0; /* we want more bytes, nothing processed */ } for (r=1+(int)(long)*saved_state;r<size;r++){ if ((msg_buf[r]=='\n' || msg_buf[r]=='\r') && (msg_buf[r-1]=='\n'|| msg_buf[r-1]=='\r')){ /* found double cr, or double lf => end of request */ req_size=r; goto process; } } /* no end of request found => ask for more bytes */ *bytes_needed=1; /* save current offset, to optimize search */ *saved_state=(void*)(long)(r-1); return 0; /* we want again the whole buffer */ process: DBG("process_fifo %d bytes request: %.*s\n", req_size, req_size, msg_buf); file_sep = 0; context.method = 0; context.reply_file = 0; context.body = 0; context.code = 200; context.reason = "OK"; context.reply_sent = 0; context.last = 0; context.line_no = 0; context.read_h.s=msg_buf; context.read_h.end=msg_buf+size; context.read_h.crt=msg_buf; context.send_h=(struct send_handle*)sh; /* commands must look this way ':<command>:[filename]' */ if (read_line(&buf, &line_len, &context.read_h) < 0) { /* line breaking must have failed -- consume the rest * and proceed to a new request */ ERR("Command expected\n"); goto consume; } context.line_no++; if (line_len == 0) { DBG("Empty command received\n"); goto consume; } if (line_len < 3) { ERR("Command must have at least 3 chars\n"); goto consume; } if (*buf != CMD_SEPARATOR) { ERR("Command must begin with %c: %.*s\n", CMD_SEPARATOR, line_len, buf); goto consume; } context.method = buf + 1; file_sep = strchr(context.method, CMD_SEPARATOR); if (file_sep == NULL) { ERR("File separator missing\n"); goto consume; } if (file_sep == context.method) { ERR("Empty command\n"); goto consume; } if (*(file_sep + 1) == 0) context.reply_file = NULL; else { context.reply_file = file_sep + 1; context.reply_file = trim_filename(context.reply_file); if (context.reply_file == 0) { ERR("Trimming filename\n"); goto consume; } } /* make command zero-terminated */ *file_sep = 0; exp = find_rpc_export(context.method, 0); if (!exp || !exp->function) { DBG("Command %s not found\n", context.method); rpc_fault(&context, 500, "Command '%s' not found", context.method); goto consume; } exp->function(&func_param, &context); consume: if (!context.reply_sent) { rpc_send(&context); } if (context.reply_file) { ctl_free(context.reply_file); context.reply_file = 0; } /* Collect garbage (unescaped strings and structures) */ while(context.strs) { p = context.strs; context.strs = context.strs->next; free_chunk(p); } while(context.structs) { s = context.structs; context.structs = context.structs->next; free_struct(s); } *bytes_needed=0; DBG("Command consumed\n"); DBG("process_fifo: returning %d, bytes_needed 0\n", req_size+1); return req_size+1; /* all was processed (including terminating \n)*/ }
static void login_reply (int logged_in) { rpc_send (msock, RPC_INT, logged_in ? MC_LOGINOK : MC_INVALID_PASS, RPC_END); }
static void do_getupdir (void) { rpc_send (msock, RPC_STRING, (up_dir) ? up_dir : "/", RPC_END); }
static void do_gethome (void) { rpc_send (msock, RPC_STRING, (home_dir) ? home_dir : "/", RPC_END); }
void on_recv_pkg(nw_ses *ses, rpc_pkg *pkg) { rpc_send(ses, pkg); }
static void send_status (int status, int errno_number) { rpc_send (msock, RPC_INT, status, RPC_INT, errno_number, RPC_END); errno = 0; }