⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 netblock.c

📁 newos is new operation system
💻 C
字号:
/*** Copyright 2002, Travis Geiselbrecht. All rights reserved.** Distributed under the terms of the NewOS License.*/#include <kernel/kernel.h>#include <kernel/console.h>#include <kernel/debug.h>#include <kernel/heap.h>#include <kernel/int.h>#include <kernel/vm.h>#include <kernel/thread.h>#include <kernel/lock.h>#include <kernel/fs/devfs.h>#include <kernel/net/socket.h>#include <kernel/net/misc.h>#include <kernel/net/ipv4.h>#include <newos/errors.h>#include <string.h>#include <stdio.h>#define NB_TRACE 0#if NB_TRACE#define TRACE(x) dprintf x#else#define TRACE(x)#endif#define BLOCKSIZE 512struct netblock_dev {	sock_id sockfd;	mutex lock;	off_t size;	sockaddr saddr;};struct netblock_cookie {	struct netblock_dev *dev;	off_t curr_pos;};#define MAGIC 0x14983543typedef struct message {	int magic;	int block_id;	int command;	int arg;	int arg2;	char data[0];} message;#define CMD_NULL 0#define CMD_GETSIZE 1#define CMD_READBLOCK 2#define CMD_WRITEBLOCK 3// unused#if 0static void dump_message(message *msg){	dprintf("message:\n");	dprintf(" magic: 0x%x\n", ntohl(msg->magic));	dprintf(" block_id: %d\n", ntohl(msg->block_id));	dprintf(" command: %d\n", ntohl(msg->command));	dprintf(" arg: %d\n", ntohl(msg->arg));	dprintf(" arg2: %d\n", ntohl(msg->arg2));}#endifstatic int validate_message(message *msg, int len){	if(len < (int)sizeof(message))		return 0;	// validate the message	if(ntohl(msg->magic) != MAGIC)		return 0;	if(ntohl(msg->block_id) != 0)		return 0;	switch(ntohl(msg->command)) {		case CMD_NULL:		case ~CMD_NULL:		case CMD_GETSIZE:		case ~CMD_GETSIZE:		case CMD_READBLOCK:		case ~CMD_READBLOCK:		case CMD_WRITEBLOCK:		case ~CMD_WRITEBLOCK:			break;		default:			return 0;	}	return 1;}static void init_message(message *msg, int command){	msg->magic = htonl(MAGIC);	msg->block_id = htonl(0);	msg->command = htonl(command);	msg->arg = 0;	msg->arg2 = 0;}static int send_message(struct netblock_dev *dev, message *msg, ssize_t len, void *recv_buf, int recv_len){	int err;	sockaddr fromaddr;	message *rmsg = (message *)recv_buf;retry:	err = socket_sendto(dev->sockfd, msg, len, &dev->saddr);	if(err < 0)		return err;	err = socket_recvfrom_etc(dev->sockfd, recv_buf, recv_len, &fromaddr, SOCK_FLAG_TIMEOUT, 10000000); // 10 secs	if(err < 0)		goto retry;	// look at the message and see if it's valid	if(!validate_message(rmsg, err))		goto retry;	// wait for the valid response	if(rmsg->command != ~msg->command)		goto retry;	return NO_ERROR;}static off_t get_device_size(struct netblock_dev *dev){	message msg;	char buf[4096];	message *rmsg;	init_message(&msg, CMD_GETSIZE);	send_message(dev, &msg, sizeof(message), buf, sizeof(buf));	rmsg = (message *)buf;	return ntohl(*(int *)&rmsg->data[0]);}static int read_block(struct netblock_dev *dev, off_t offset, void *out_buf){	message msg;	char buf[sizeof(message) + BLOCKSIZE];	message *rmsg = (message *)buf;//	TRACE(("read_block: offset 0x%Lx\n", offset));	init_message(&msg, CMD_READBLOCK);	msg.arg = htonl(offset);	msg.arg2 = htonl(BLOCKSIZE);	send_message(dev, &msg, sizeof(message), buf, sizeof(buf));	memcpy(out_buf, &rmsg->data[0], BLOCKSIZE);	return 0;}static int write_block(struct netblock_dev *dev, off_t offset, const void *out_buf){	message *msg;	char buf[sizeof(message) + BLOCKSIZE];	char buf2[sizeof(message) + BLOCKSIZE];//	TRACE(("write_block: offset 0x%Lx\n", offset));	msg = (message *)buf;	init_message(msg, CMD_WRITEBLOCK);	msg->arg = htonl(offset);	msg->arg2 = htonl(BLOCKSIZE);	memcpy(&msg->data[0], out_buf, BLOCKSIZE);	send_message(dev, msg, sizeof(message) + BLOCKSIZE, buf2, sizeof(buf2));	return 0;}static int netblock_open(dev_ident ident, dev_cookie *_cookie){	struct netblock_cookie *cookie;	cookie = kmalloc(sizeof(struct netblock_cookie));	if(!cookie)		return ERR_NO_MEMORY;	cookie->dev = ident;	cookie->curr_pos = 0;	cookie->dev->size = get_device_size(cookie->dev);	TRACE(("netblock_open: cookie %p, size 0x%Lx\n", cookie, cookie->dev->size));	*_cookie = cookie;	return 0;}static int netblock_freecookie(dev_cookie cookie){	kfree(cookie);	return 0;}static int netblock_seek(dev_cookie _cookie, off_t pos, seek_type st){	struct netblock_cookie *cookie = _cookie;	int err = NO_ERROR;	TRACE(("netblock_seek: cookie %p, pos 0x%Lx, st %d\n", cookie, pos, st));	mutex_lock(&cookie->dev->lock);	switch(st) {		case _SEEK_CUR:			pos += cookie->curr_pos;			goto __set;		case _SEEK_END:			pos += cookie->dev->size;__set:		case _SEEK_SET:			if(pos > cookie->dev->size)				pos = cookie->dev->size;			if(pos < 0)				pos = 0;			cookie->curr_pos = pos;			break;		default:			err = ERR_INVALID_ARGS;	}	mutex_unlock(&cookie->dev->lock);	return err;}static int netblock_close(dev_cookie cookie){//	dprintf("netblock_close: entry\n");	return 0;}static int netblock_ioctl(dev_cookie _cookie, int op, void *buf, size_t len){	struct netblock_cookie *cookie = _cookie;	int err;	TRACE(("netblock_ioctl: cookie %p, op %d, buf %p, len %lu\n", cookie, op, buf, (unsigned long)len));	mutex_lock(&cookie->dev->lock);	err = NO_ERROR;	switch(op) {		case 90000: { // set the netblock server address			sockaddr *saddr = (sockaddr *)buf;			memcpy(&cookie->dev->saddr, saddr, sizeof(sockaddr));			break;		}		case 90001: { // read the device's size			cookie->dev->size = get_device_size(cookie->dev);			dprintf("netblock_ioctl: device size is %Ld\n", cookie->dev->size);			break;		}		default:			err = ERR_INVALID_ARGS;	}	mutex_unlock(&cookie->dev->lock);	return err;}static ssize_t _netblock_readwrite(struct netblock_dev *dev, bool write, void *_buf, off_t pos, ssize_t len){	uint8 *buf = _buf;	ssize_t bytes_transferred = 0;//	TRACE(("_netblock_readwrite: write %d, pos 0x%Lx, len %d\n", write, pos, len));	if(pos % BLOCKSIZE > 0){		// partial first buffer		ssize_t tomove = min(len, BLOCKSIZE - (pos % BLOCKSIZE));		off_t blockaddr = ROUNDOWN(pos, BLOCKSIZE);		int blockoff = pos % BLOCKSIZE;		uint8 temp_buf[BLOCKSIZE];		if(write) {			read_block(dev, blockaddr, temp_buf);			memcpy(&temp_buf[blockoff], buf, tomove);			write_block(dev, blockaddr, temp_buf);		} else {			read_block(dev, blockaddr, temp_buf);			memcpy(buf, &temp_buf[blockoff], tomove);		}		buf += tomove;		len -= tomove;		pos += tomove;		bytes_transferred += tomove;	}	while(len >= BLOCKSIZE) {		if(write)			write_block(dev, pos, buf);		else			read_block(dev, pos, buf);		buf += BLOCKSIZE;		len -= BLOCKSIZE;		pos += BLOCKSIZE;		bytes_transferred += BLOCKSIZE;	}	if(len > 0) {		// partial last buffer		ssize_t tomove = min(len, BLOCKSIZE);		off_t blockaddr = ROUNDOWN(pos, BLOCKSIZE);		uint8 temp_buf[BLOCKSIZE];		if(write) {			read_block(dev, blockaddr, temp_buf);			memcpy(temp_buf, buf, tomove);			write_block(dev, blockaddr, temp_buf);		} else {			read_block(dev, blockaddr, temp_buf);			memcpy(buf, temp_buf, tomove);		}		len -= tomove;		bytes_transferred += tomove;	}	return bytes_transferred;}static ssize_t netblock_read(dev_cookie _cookie, void *_buf, off_t pos, ssize_t len){	struct netblock_cookie *cookie = _cookie;	ssize_t bytes_read = 0;	TRACE(("netblock_read: cookie %p, buf %p, pos 0x%Ld, len %lu\n", cookie, _buf, pos, (long)len));	mutex_lock(&cookie->dev->lock);	// trim the pos and len to be proper	if(pos < 0) {		pos = cookie->curr_pos;	}	if(pos > cookie->dev->size) {		bytes_read = 0;		goto out;	}	if(len <= 0) {		bytes_read = 0;		goto out;	}	if(pos + len > cookie->dev->size) {		len = cookie->dev->size - pos;	}	bytes_read = _netblock_readwrite(cookie->dev, false, _buf, pos, len);	if(bytes_read > 0)		cookie->curr_pos += bytes_read;out://	TRACE(("netblock_read: exit, curr_pos is now 0x%Lx, bytes_read %ld\n", cookie->curr_pos, bytes_read));		mutex_unlock(&cookie->dev->lock);	return bytes_read;}static ssize_t netblock_write(dev_cookie _cookie, const void *_buf, off_t pos, ssize_t len){	struct netblock_cookie *cookie = _cookie;	ssize_t bytes_written = 0;	TRACE(("netblock_write: cookie %p, buf %p, pos 0x%Ld, len %lu\n", cookie, _buf, pos, (long)len));	mutex_lock(&cookie->dev->lock);	// trim the pos and len to be proper	if(pos < 0) {		pos = cookie->curr_pos;	}	if(pos > cookie->dev->size) {		bytes_written = 0;		goto out;	}	if(len <= 0) {		bytes_written = 0;		goto out;	}	if(pos + len > cookie->dev->size) {		len = cookie->dev->size - pos;	}	bytes_written = _netblock_readwrite(cookie->dev, true, (void *)_buf, pos, len);	if(bytes_written > 0)		cookie->curr_pos += bytes_written;out://	TRACE(("netblock_write: exit, curr_pos is now 0x%Lx, bytes_written %ld\n", cookie->curr_pos, bytes_written));	mutex_unlock(&cookie->dev->lock);	return bytes_written;}static int netblock_canpage(dev_ident ident){	return 1;}static ssize_t netblock_readpage(dev_ident ident, iovecs *vecs, off_t pos){	struct netblock_dev *dev = ident;	ssize_t bytes_read = 0;	unsigned int curr_vec;	TRACE(("netblock_readpage: dev %p, vecs %p, num %lu, total_len %lu, pos 0x%Ld\n", dev, vecs, (unsigned long)vecs->num, (unsigned long)vecs->total_len, pos));	if(pos % BLOCKSIZE != 0)		return ERR_INVALID_ARGS;	mutex_lock(&dev->lock);	// cycle through all of the iovecs	for(curr_vec = 0; curr_vec < vecs->num; curr_vec++) {		size_t vec_len = vecs->vec[curr_vec].len;		size_t vec_offset = 0;		// make sure this vec has a good len		if(vec_len % BLOCKSIZE != 0)			break;		// read the blocks into the proper place		while(vec_len > 0) {			read_block(dev, pos, ((uint8 *)vecs->vec[curr_vec].start) + vec_offset);			vec_offset += BLOCKSIZE;			vec_len -= BLOCKSIZE;			pos += BLOCKSIZE;			bytes_read += BLOCKSIZE;		}	}	mutex_unlock(&dev->lock);	return bytes_read;}static ssize_t netblock_writepage(dev_ident ident, iovecs *vecs, off_t pos){	struct netblock_dev *dev = ident;	ssize_t bytes_written = 0;	unsigned int curr_vec;	TRACE(("netblock_writepage: dev %p, vecs %p, num %lu, total_len %lu, pos 0x%Ld\n", dev, vecs, (unsigned long)vecs->num, (unsigned long)vecs->total_len, pos));	if(pos % BLOCKSIZE != 0)		return ERR_INVALID_ARGS;	mutex_lock(&dev->lock);	// cycle through all of the iovecs	for(curr_vec = 0; curr_vec < vecs->num; curr_vec++) {		size_t vec_len = vecs->vec[curr_vec].len;		size_t vec_offset = 0;		// make sure this vec has a good len		if(vec_len % BLOCKSIZE != 0)			break;		// read the blocks into the proper place		while(vec_len > 0) {			write_block(dev, pos, ((uint8 *)vecs->vec[curr_vec].start) + vec_offset);			vec_offset += BLOCKSIZE;			vec_len -= BLOCKSIZE;			pos += BLOCKSIZE;			bytes_written += BLOCKSIZE;		}	}	mutex_unlock(&dev->lock);	return bytes_written;}static struct dev_calls netblock_hooks = {	&netblock_open,	&netblock_close,	&netblock_freecookie,	&netblock_seek,	&netblock_ioctl,	&netblock_read,	&netblock_write,	&netblock_canpage,	&netblock_readpage,	&netblock_writepage};int dev_bootstrap(void);int dev_bootstrap(void){	struct netblock_dev *dev;	sockaddr saddr;	int index = 0;	char path[SYS_MAX_PATH_LEN];	// create a device structure	dev = kmalloc(sizeof(struct netblock_dev));	if(!dev)		return -1;	// create the socket	saddr.port = 6789;	saddr.addr.len = 4;	saddr.addr.type = ADDR_TYPE_IP;	memset(&saddr.addr.addr[0], 0, 4);	dev->sockfd = socket_create(SOCK_PROTO_UDP, 0);	if(dev->sockfd < 0) {		dprintf("netblock_dev_init: error creating socket\n");		kfree(dev);		return -1;	}	socket_bind(dev->sockfd, &saddr);	mutex_init(&dev->lock, "netblock_lock");	dev->size = -1;	dev->saddr.port = 9999;	dev->saddr.addr.type = ADDR_TYPE_IP;	NETADDR_TO_IPV4(dev->saddr.addr) = IPV4_DOTADDR_TO_ADDR(192, 168, 0, 3);	index = devfs_publish_indexed_directory("disk/netblock");	if (index >= 0) {		sprintf(path, "disk/netblock/%d/raw", index);		devfs_publish_device(path, dev, &netblock_hooks);	}	return 0;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -