home *** CD-ROM | disk | FTP | other *** search
- /* Register (and deregister) RPC services
-
- ©1999 Joseph Walton
-
- This software is distributed under the terms of the GNU General Public
- License; either version 2 of the License, or (at your option) any
- later version.
- */
-
- #include "rpc.h"
- #include "rpc_register.h"
-
- #include "nfs_utils.h"
-
- #include <stdio.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <sys/time.h>
-
- #include <bsdsocket/socketbasetags.h>
-
- #include <proto/exec.h>
- #include <proto/timer.h>
- #include <proto/socket.h>
-
- static int32 make_xid(void)
- {
- struct timeval now;
-
- GetSysTime(&now);
- return (now.tv_secs ^ now.tv_micro ^ (ULONG)FindTask(NULL));
- }
-
- static int32 mem[14];
- static char buffer[1024];
-
- /* This is called very rarely - psychotic optimisations would be
- self-defeating */
- static BOOL pmap_action(int socket, int action, int prog, int version, int port)
- {
- int l, addr_len, id;
-
- struct timeval try_until, resend_at;
-
- int32 *ptr;
-
- struct sockaddr_in addr;
-
- id = make_xid();
- ptr = mem;
- *ptr++ = P_UINT(id);
- *ptr++ = P_ENUM(CALL);
- *ptr++ = P_UINT(RPC_VERSION);
- *ptr++ = P_UINT(PMAP_PROGRAM);
- *ptr++ = P_UINT(PMAP_VERSION);
- *ptr++ = P_UINT(action);
-
- *ptr++ = P_ENUM(AUTH_NONE);
- *ptr++ = P_UINT(0);
- *ptr++ = P_ENUM(AUTH_NONE);
- *ptr++ = P_UINT(0);
-
- *ptr++ = P_UINT(prog);
- *ptr++ = P_UINT(version);
- *ptr++ = P_UINT(IPPROTO_UDP);
- *ptr++ = P_UINT(port);
-
- // 14 int32s
-
- GetSysTime(&try_until);
- resend_at = try_until;
- try_until.tv_secs += RPC_REGISTER_TIMEOUT_AFTER;
-
- while (TRUE) {
- struct timeval now, timeout;
- fd_set fdset;
- int r;
-
- GetSysTime(&now);
-
- /* There is a wait so long? */
- if (CmpTime(&now, &try_until) <= 0) {
- puts("Portmap operation attempt timed out");
- return FALSE;
- }
-
- /* Should we resend? */
- if (CmpTime(&now, &resend_at) <= 0) {
- int length = 14 * sizeof(int32);
- addr.sin_family = AF_INET;
- addr.sin_port = htons(PMAP_PORT);
- addr.sin_addr.s_addr = LOCAL_ADDR;
-
- l = sendto(socket, (char *)mem, length, 0, &addr, sizeof(addr));
- if (l != length) {
- printSocketError("Could not send to localhost");
- return FALSE;
- }
- resend_at.tv_sec += RPC_REGISTER_SEND_EVERY;
- }
-
- /* Want to wait for a valid response - what's the next scheduled
- checkpoint? */
- if (CmpTime(&resend_at, &try_until) < 0) {
- timeout = try_until;
- } else {
- timeout = resend_at;
- }
- SubTime(&timeout, &now);
-
- FD_ZERO(&fdset);
- FD_SET(socket, &fdset);
-
- r = WaitSelect(FD_SETSIZE, &fdset, NULL, NULL, &timeout, NULL);
-
- if (r > 0) {
- addr_len = sizeof(addr);
- l = recvfrom(socket, buffer, sizeof(buffer), 0, &addr, &addr_len);
- if (l < 0) {
- printSocketError("recvfrom() failed");
- return FALSE;
- }
-
- /* Make sure it's from 127.0.0.1 - that's where we sent to */
- if ((addr_len < sizeof(addr)) || (addr.sin_addr.s_addr != LOCAL_ADDR))
- continue;
-
- l /= sizeof(int32);
- if (l > 5) {
- int32 *ptr = (int32 *)buffer;
- int32 *limit = ptr + l;
-
- if ((id != G_INT(*ptr++)) || (G_INT(*ptr++) != REPLY))
- continue;
-
- if (G_INT(*ptr++) != MSG_ACCEPTED) {
- puts("Portmapper did not accept our registration message");
- return FALSE;
- }
-
- if (G_INT(*ptr++) != SUCCESS) {
- puts("Portmapper registration failed remotely");
- return FALSE;
- }
-
- /* We don't care about authorisation */
- ptr++;
- ptr += INT32S(G_UINT(*ptr)) + 1;
-
- if (ptr < limit) {
- /* This is the actual return code from the remote call */
- return (1 == G_INT(*ptr));
- }
- }
- } else if (r < 0) {
- printSocketError("select() failed");
- return FALSE;
- }
- }
- }
-
- /* Simple user-visible wrappers */
- BOOL pmap_set(int socket, int prog, int version, int port)
- {
- return pmap_action(socket, PMAPPROC_SET, prog, version, port);
- }
-
- BOOL pmap_unset(int socket, int prog, int version)
- {
- return pmap_action(socket, PMAPPROC_UNSET, prog, version, 0);
- }
-
-