📄 fileserverstdio.c
字号:
///////////////////////////////////////////////////////////////
//
// STDIO_FS
//
// STDIO Device Driver using host\FILESERVER over TCP/IP to
// implement the file actions (fopen(), fread(), etc).
//
///////////////////////////////////////////////////////////////
#include <device.h>
#include <ccblkfn.h>
#include <cdefBF533.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <device_int.h>
#define LWIP_COMPAT_SOCKETS 1
#define SOCKET_ERROR -1
#include <lwip\sockets.h>
#include <lwip\inet.h>
static int FS_init (struct DevEntry *dev);
static int FS_open (const char *name, int mode);
static int FS_close (int fd);
static int FS_write (int fd, unsigned char *buf, int size);
static int FS_read (int fd, unsigned char *buf, int size);
static long FS_seek (int fd, long offset, int whence);
static DevEntry FS_DevEntry =
{
0,
NULL,
FS_init,
FS_open,
FS_close,
FS_write,
FS_read,
FS_seek,
dev_not_claimed,
dev_not_claimed,
dev_not_claimed
};
static char stdout_buf[512];
static char stderr_buf[512];
#define MAX_CONNECTIONS 8
typedef struct _ctt {
const char* fileName;
int openMode;
int socket_fd;
struct sockaddr_in srv;
struct sockaddr_in clt;
} connect_t;
typedef struct _skt {
const char* serverIP;
const char* clientIP;
short serverPort;
short nextClientPort;
connect_t connections[MAX_CONNECTIONS];
} sock_tab_t;
static sock_tab_t sock_tab;
//
// accept one of stdin, stdout and stderr and reopen it as "con:" which is
// a special filename known to the file server
//
static int redirect(FILE* std)
{
FILE* fp;
fp = freopen("con:", "a+", std);
if (!fp) {
fprintf(stderr, "ERROR: failed to redirect '%s'\n",
(std == stdin)? "stdin" : (std == stdout)? "stdout" : "stderr");
return -1;
}
return 0;
}
//
// create a connection to file server and request that file be opened
//
static int make_connection(const char* name, int mode, int cndx)
{
connect_t* cp = &sock_tab.connections[cndx];
cp->fileName = name;
cp->openMode = mode;
cp->socket_fd = socket(AF_INET, SOCK_STREAM, 0);
if (cp->socket_fd < 0)
return -1;
cp->srv.sin_family = AF_INET;
cp->srv.sin_addr.s_addr = inet_addr(sock_tab.serverIP);
cp->srv.sin_port = htons(sock_tab.serverPort);
if (connect(cp->socket_fd, (struct sockaddr*)&cp->srv,
sizeof(struct sockaddr_in)) == -1) {
close(cp->socket_fd);
memset(cp, 0, sizeof(connect_t));
return -1;
}
// malloc enough space for the open request
int len = 4 + 4 + strlen(name) + 1;
int* bp = (int*)malloc(len);
if (!bp)
return -1;
bp[0] = len - 4;
bp[1] = mode;
strcpy((char*)&bp[2], name);
if (FS_write(cndx, (unsigned char*)bp, len) == -1) {
close(cp->socket_fd);
memset(cp, 0, sizeof(connect_t));
free(bp);
return -1;
}
free(bp);
return 0;
}
//
// initialisation function for this STDIO device driver
//
// accepts an application-unique device number which it uses to install
// an entry into the runtime's device table; it then makes this driver the
// default one and redirects the standard files
//
// the other arguments identify the network IP address and port of the
// file server machine and the IP address of this machine; the clientPortBase
// argument is the base of a set of 16 port addresses that this driver may use
// for its connections
//
int FS_STDIO_init(int devID,
const char* serverIPaddr,
short serverPort)
{
// initialise the socket table
memset((void*)&sock_tab, 0, sizeof(sock_tab));
sock_tab.serverIP = serverIPaddr;
sock_tab.serverPort = serverPort;
// insert this ethernet-based fileserver client into the runtime's
// device table
FS_DevEntry.DeviceID = devID;
FS_DevEntry.data = (void*)0;
int dev = add_devtab_entry(&FS_DevEntry);
if (dev != devID) {
fprintf(stderr, "ERROR: Unable to register new STDIO device\n");
return -1;
}
// make it the default STDIO device
set_default_io_device(devID);
// freopen special filename "con:" as stdout and stderr
//if (redirect(stdin)) return -2;
if (redirect(stdout)) return -3;
if (redirect(stderr)) return -4;
// ensure stdout and stderr are line-buffered
setvbuf(stdout, stdout_buf, _IOFBF, sizeof(stdout_buf));
setvbuf(stderr, stderr_buf, _IOFBF, sizeof(stderr_buf));
return 0;
}
//
// called when this driver is inserted into the runtime's device table
//
static int FS_init ( struct DevEntry *dev )
{
// just report the redirection using current STDIO
printf("STDIO being redirected to file server on port %d of host %s\n",
sock_tab.serverPort, sock_tab.serverIP);
return 0;
}
//
// called when app does an fopen()
//
// allocate an entry in sock_tab, obtain a socket connection to the
// file server running elsewhere on the network and send it an 'open'
// request; return the index of the sock_tab entry (which the runtime
// then uses as the 'fid' parameter to FS_Read, FS_Write, etc)
//
static int FS_open (const char *name, int mode)
{
// if filename is "con:" map directly to connection number 0; make
// the connection if not already present
if (!strcmp(name, "con:")) {
if (sock_tab.connections[0].fileName == 0) {
if (make_connection(name, mode, 0) == -1)
return -1;
}
return 0;
}
// if not "con:" allocate a free socket table entry and make connection
int i;
for (i = 1; i < MAX_CONNECTIONS; i += 1) {
if (sock_tab.connections[i].fileName == 0)
break;
}
if (i == MAX_CONNECTIONS)
return -1;
if (make_connection(name, mode, i) == -1)
return -1;
// return connection table index
return i;
}
static int FS_write (int fd, unsigned char *buf, int size)
{
// ensure fd indexes a valid socket table entry
if (fd < 0 || fd >= MAX_CONNECTIONS)
return -1;
// write 'buf' directly to the socket
int num_written = 0;
do {
int r = write(sock_tab.connections[fd].socket_fd,
(void*)(buf + num_written),
size - num_written);
if (r == -1)
return -1;
num_written += r;
} while (num_written < size);
return num_written;
}
static int FS_read (int fd, unsigned char *buf, int size)
{
// ensure fd indexes a valid socket table entry
if (fd < 0 || fd >= MAX_CONNECTIONS)
return -1;
// read from socket directly into 'buf'
int r = read(sock_tab.connections[fd].socket_fd, (void*)buf, size);
// return number of bytes actually read, or failure
return r;
}
static long FS_seek (int fd, long offset, int whence)
{
// return failure
return -1;
}
static int FS_close (int fd)
{
// ensure fd indexes a valid socket table entry
if (fd < 0 || fd >= MAX_CONNECTIONS)
return -1;
// close socket
int r = close(sock_tab.connections[fd].socket_fd);
memset((void*)&sock_tab.connections[fd], 0, sizeof(connect_t));
return r;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -