📄 remote_access.c
字号:
/* * Copyright (C) 1996-1998 by the Board of Trustees * of Leland Stanford Junior University. * * This file is part of the SimOS distribution. * See LICENSE file for terms of the license. * *//* * remote_access.c - Routines to provide remote access to SimOS files. */#include "sim.h"#include <stdio.h>#include <sys/types.h>#ifndef __alpha#ifndef i386#include <sys/unistd.h>#include <sys/ioccom.h>#include <sys/filio.h>#endif#endif#include <sys/mman.h>#include <sys/file.h>#include <sys/signal.h>#include <sys/time.h>#include <sys/uio.h>#include <unistd.h>#ifndef linux#include <sys/socket.h>#include <netinet/in.h>#endif#include <sys/param.h>#include <errno.h>#include <netdb.h>#include <string.h>#include "remote_access.h"#include "sim_error.h"#include "simutil.h"#include "rmtaccess.h"extern char *MemFileDir;#define RMT_MAXHOSTNAMELEN 64#define RMT_MAXCONN 64enum {RMT_DISK = 0, RMT_CPT, RMT_END};static char server[RMT_END][RMT_MAXHOSTNAMELEN];static struct sockaddr_in rmt_addr[RMT_END];static char cpt_rootname[MAX_PATH_LENGTH];/* --------------------------------------- */static int StartRequest(struct sockaddr_in *rmtsrv, int cmd, char *arg, int argsize);static int ReadForSure(int fd, byte *buf, int size);static int CopyFile(int infd, int outfd);/* * Simrmt_init -Initialized access to a remote checkpoint. * returns < 0 on error, 1 if sucessful. */intSimrmt_cptinit(char *fullname, char *rootname){ int port; struct hostent *host; /* * We assume that the root pathname encodes the host and port as follows: * hostname:port:masterlog_root */ if (sscanf(fullname, "%[^:]:%d:%s", server[RMT_CPT], &port, rootname) != 3) { Sim_Warning("Simrmt_init: Bad remote checkpoint name <%s>\n", fullname); return -1; } /* * Fill in the internet address to be used in later calls. */ strcpy(cpt_rootname, rootname); host = gethostbyname(server[RMT_CPT]); if (!host) { perror( "Simrmt_init:gethostbyname bad host"); Sim_Warning("Bad hostname %s\n", server[RMT_CPT]); return -1; } rmt_addr[RMT_CPT].sin_family = host->h_addrtype; bcopy(host->h_addr, (char *) &rmt_addr[RMT_CPT].sin_addr, host->h_length); rmt_addr[RMT_CPT].sin_port = htons((short)port); return 1;}/* * Simrmt_diskinit - Initialize remote disk for access. * Return the open file descriptor. */int Simrmt_diskinit(char *remoteName){ int port; struct hostent *host; /* If no remote name is given, then we are using the remote checkpoint server as a remote disk server as well */ if (remoteName == NULL) { return StartRequest(&(rmt_addr[RMT_CPT]), SIMRMT_DISKINIT, (char *) NULL, 0); } else { /* * We assume that the remote name encodes the host and port as follows: * $hostname:port */ if (sscanf(remoteName, "$%[^:]:%d", server[RMT_DISK], &port) != 2) { Sim_Warning("Simrmt_diskinit: Bad remote disk name <%s>\n", remoteName); return -1; } /* * Fill in the internet address to be used in later calls. */ host = gethostbyname(server[RMT_DISK]); if (!host) { perror( "Simrmt_diskinit:gethostbyname bad host"); Sim_Warning("Bad hostname %s\n", server[RMT_DISK]); return -1; } rmt_addr[RMT_DISK].sin_family = host->h_addrtype; bcopy(host->h_addr, (char *) &rmt_addr[RMT_DISK].sin_addr, host->h_length); rmt_addr[RMT_DISK].sin_port = htons((short)port); return StartRequest(&(rmt_addr[RMT_DISK]), SIMRMT_DISKINIT, (char *) NULL, 0); }}/* * Simrmt_access - See if a remote file is readable * Returns: TRUE if file exists and is readable, FALSE otherwise */boolSimrmt_access(char *pathname){ int fd = StartRequest(&(rmt_addr[RMT_CPT]), SIMRMT_ACCESS, pathname, strlen(pathname)); if (fd == -1) return FALSE; close(fd); return TRUE;}/* * Simrmt_fopen - Open a remote file. * Returns: NULL on error, otherwise the open file pointer */FILE *Simrmt_fopen(char *pathname){ int fd = StartRequest(&(rmt_addr[RMT_CPT]), SIMRMT_OPEN, pathname, strlen(pathname)); if (fd < 0) return NULL; else return fdopen(fd, "r");}/* * Simrmt_diskcmd - Send a remote disk command. */int64Simrmt_diskcmd(int diskfd, int op, int node, int ctrl, int unit, int64 sectorNum,int64 sizeInBytes, byte *buffer) { NetDiskHdr hdr, rhdr; int size; static int reqnum; reqnum++; bzero((char *) &hdr, sizeof(hdr)); hdr.op = (DiskOp)op; hdr.node = node; hdr.ctrl = ctrl; hdr.unit = unit; hdr.sectorNum = sectorNum; hdr.sizeInBytes = sizeInBytes; hdr.reqnum = reqnum; if( write(diskfd, &hdr,sizeof(hdr))!=sizeof(hdr) ) { CPUError("write to rmtaccess server failed\n"); }; if( (op == NETDISK_WRITE) || (op == NETDISK_ATTACH) ) { if( write(diskfd,buffer,sizeInBytes)!=sizeInBytes) { CPUError("write to rmtaccess server failed\n"); } } size = ReadForSure(diskfd, (byte *)&rhdr, sizeof(rhdr)); if (size != sizeof(rhdr)) { perror("simckpt_netdisk:read"); rhdr.retVal = EIO; return rhdr.retVal; } if (rhdr.reqnum != hdr.reqnum) { Sim_Warning("Simnetdisk: Bad reqnum (%d)\n", rhdr.reqnum); } if (((op == NETDISK_READ) || (op == NETDISK_ATTACH)) && (rhdr.retVal > 0)) { size = ReadForSure(diskfd, buffer, rhdr.retVal); if (size != rhdr.retVal) { Sim_Warning("Simnetdisk: Reply packet too small (%d)\n", size); rhdr.retVal = EIO; } } return rhdr.retVal;}/* * ReadForSure - just like the read() system call execpt it keeps trying * if not enough data was returned by the read or it was interrupted * by a signal. */static intReadForSure(int fd, byte *buf, int size){ int a; for(a = 0; a < size;) { int ret = read(fd, buf + a, size-a); if (ret < 0) { if (errno == EINTR) continue; return -1; } a += ret; } return size;}/* * StartRequest - * Establish a connection with the remote server and exchange the specified command * with it. * Returns the open connection to the server. < 0 if the connection * fails or the command encountes an errors. */static intStartRequest(struct sockaddr_in *rmtsrv, int cmd, char *arg, int argsize){ int fd, err; RmtAccessStartRequest req; byte ack[8]; /* * Create the TCP socket and send command, returning socket * blocks to and from the net disk server. */ fd = socket(rmtsrv->sin_family, SOCK_STREAM, IPPROTO_TCP); if (fd < 0) { perror("Simrmt:StartRequest:socket"); return -1; } if (connect(fd, (struct sockaddr *)rmtsrv, sizeof (*rmtsrv)) < 0) { perror("Simrmt:StartRequest:connect"); close(fd); return -1; } /* * format and send the request over the connection. */ req.magic = RMTACCESS_MAGIC; req.cmd = (Rmtaccess_op)cmd; req.arglen = argsize; err = write(fd, (char *) &req, sizeof(req)); if (err != sizeof(req)) { perror("Simrmt:StartRequest:write"); close(fd); goto error; } if (req.arglen > 0) { err = write(fd, arg, req.arglen); if (err != req.arglen) { perror("Simrmt:StartRequest:write2"); goto error; } } /* * Get error code for command: OK\n or Enn */ err = ReadForSure(fd, ack, 3); if (err < 0) { perror("Simrmt:StartRequest:ReadForSure ack"); goto error; } if ((ack[0] == 'O') && (ack[1] == 'K')) { return fd; } error: close(fd); return -1;}static intCopyFile(int infd, int outfd){ char buf[8192]; int cnt, cnt2; while(1) { cnt = read(infd, buf, sizeof(buf)); if (cnt == 0) break; if (cnt < 0) { perror("CopyFile -- read"); exit(1); } cnt2 = write(outfd, buf, cnt); if (cnt2 != cnt) { perror("CopyFile -- write"); exit(1); } } return 0;}/* * Open a file across a remote server and return the FILE ptr * The client must close the FILE ptr when done. */FILE* Simrmt_RemoteFileOpen(char *pathName) { struct hostent *host; char hostName[RMT_MAXHOSTNAMELEN]; int port; char fileName[RMT_MAXHOSTNAMELEN]; int fd; struct sockaddr_in rmtsrv; if (sscanf(pathName, "%[^:]:%d:%s", hostName, &port, fileName) != 3) { Sim_Warning("Simrmt_RemoteFileOpen: Bad remote file name <%s>", pathName); return NULL; } host = gethostbyname(hostName); if (!host) { perror( "Simrmt_RemoteFileOpen: gethostbyname bad host"); Sim_Warning("Bad host name %s\n", hostName); return NULL; } bzero((char *) &rmtsrv, sizeof(rmtsrv)); rmtsrv.sin_family = host->h_addrtype; bcopy(host->h_addr, (char *) &(rmtsrv.sin_addr), host->h_length); rmtsrv.sin_port = htons((short) port); fd = StartRequest(&rmtsrv, SIMRMT_OPEN, fileName, strlen(fileName)); if (fd < 0) { return NULL; } else { return fdopen(fd, "r"); }}/* * This routine implements an mmap of a remote file. Currently we do the * dumb thing, which is to copy the file to a temporary local file * and then mmaps it. The parameters to the call are exactly the same as * for the mmap call, except that you pass a remoteserver filepath instead of * of a file descriptor. */void *Simrmt_mmap(void *addr, size_t len, int prot, int flags, char* pathName, off_t off){ struct stat statbuf; struct hostent *host; char hostName[RMT_MAXHOSTNAMELEN]; int port; char fileName[RMT_MAXHOSTNAMELEN]; int fd, tmpfd; struct sockaddr_in rmtsrv; void *maddr; if (sscanf(pathName, "%[^:]:%d:%s", hostName, &port, fileName) != 3) { Sim_Warning("Simrmt_mmap: Bad remote file name <%s>", pathName); return NULL; } host = gethostbyname(hostName); if (!host) { perror( "Simrmt_mmap: gethostbyname bad host"); Sim_Warning("Bad host name %s\n", hostName); return NULL; } rmtsrv.sin_family = host->h_addrtype; bcopy(host->h_addr, (char *) &(rmtsrv.sin_addr), host->h_length); rmtsrv.sin_port = htons((short) port); fd = StartRequest(&rmtsrv, SIMRMT_OPEN, fileName, strlen(fileName)); if (fd < 0) { return NULL; } tmpfd = MakeFile(MemFileDir, NULL, 0, 1); CopyFile(fd, tmpfd); close(fd); if (len == 0) { /* this means we want to map to the end of file */ if (fstat(tmpfd, &statbuf) < 0) { perror("Simrmt_mmap fstat"); exit(1); } len = statbuf.st_size - off; } if((maddr = mmap(addr, len, prot, flags, tmpfd, off)) == (void *)-1) { perror("Simrmt_mmap"); exit(1); } close(tmpfd); return maddr;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -