oops, forgot this file
[newos.git] / tools / netblocksrv.cpp
blob0db55d835ad3eabc3ed3b8290be597458d6a838b
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <sys/stat.h>
5 #include <fcntl.h>
6 #include <unistd.h>
7 #include <sys/types.h>
8 #include <sys/socket.h>
9 #include <netinet/in.h>
11 #ifndef O_BINARY
12 #define O_BINARY 0
13 #endif
15 typedef struct blockdevice {
16 int id;
17 int filefd;
18 off_t size;
19 } blockdevice;
21 static blockdevice *dev;
22 static int sockfd;
24 #define BLOCKSIZE 512
26 #define MAGIC 0x14983543
28 typedef struct message {
29 int magic;
30 int block_id;
31 int command;
32 int arg;
33 int arg2;
34 char data[0];
35 } message;
37 #define CMD_NULL 0
38 #define CMD_GETSIZE 1
39 #define CMD_READBLOCK 2
40 #define CMD_WRITEBLOCK 3
42 static int validate_message(message *msg, int len)
44 if(len < sizeof(message))
45 return 0;
47 // validate the message
48 if(ntohl(msg->magic) != MAGIC)
49 return 0;
50 if(ntohl(msg->block_id) != 0)
51 return 0;
53 switch(ntohl(msg->command)) {
54 case CMD_NULL:
55 case ~CMD_NULL:
56 case CMD_GETSIZE:
57 case ~CMD_GETSIZE:
58 case CMD_READBLOCK:
59 case ~CMD_READBLOCK:
60 case CMD_WRITEBLOCK:
61 case ~CMD_WRITEBLOCK:
62 break;
63 default:
64 return 0;
67 return 1;
70 static int net_loop()
72 struct sockaddr_in from_addr;
73 socklen_t slen = sizeof(struct sockaddr);
74 char buf[4096];
75 int err;
76 int reply_size;
78 for(;;) {
79 err = recvfrom(sockfd, buf, sizeof(buf), 0, (struct sockaddr *)&from_addr, &slen);
80 if(err < 0) {
81 printf("error reading from socket\n");
82 return -1;
85 message *msg = (message *)buf;
87 if(!validate_message(msg, err))
88 continue;
90 // printf("got message, command %d\n", ntohl(msg->command));
91 reply_size = sizeof(message);
92 switch(ntohl(msg->command)) {
93 case CMD_NULL:
94 // respond
95 msg->command = htonl(~CMD_NULL);
96 break;
97 case CMD_GETSIZE:
98 msg->command = htonl(~CMD_GETSIZE);
99 printf("GETSIZE %d\n", htonl(dev->size));
100 *(int *)&msg->data[0] = htonl(dev->size);
101 reply_size += 4;
102 break;
103 case CMD_READBLOCK:
104 msg->command = htonl(~CMD_READBLOCK);
105 printf("R %d %d\n", ntohl(msg->arg), ntohl(msg->arg2));
106 if(ntohl(msg->arg) + ntohl(msg->arg2) <= dev->size) {
107 lseek(dev->filefd, ntohl(msg->arg), SEEK_SET);
108 read(dev->filefd, &msg->data[0], ntohl(msg->arg2));
109 } else {
110 printf("CMD_READBLOCK: invalid offset %d and size %d\n", ntohl(msg->arg), ntohl(msg->arg2));
111 memset(&msg->data[0], 0, ntohl(msg->arg2));
113 reply_size += BLOCKSIZE;
114 break;
115 case CMD_WRITEBLOCK:
116 msg->command = htonl(~CMD_WRITEBLOCK);
117 printf("W %d %d\n", ntohl(msg->arg), ntohl(msg->arg2));
118 if(ntohl(msg->arg) + ntohl(msg->arg2) <= dev->size) {
119 lseek(dev->filefd, ntohl(msg->arg), SEEK_SET);
120 write(dev->filefd, &msg->data[0], ntohl(msg->arg2));
121 } else {
122 printf("CMD_WRITEBLOCK: invalid offset %d and size %d\n", ntohl(msg->arg), ntohl(msg->arg2));
124 break;
125 default:
126 continue;
129 // send the reply
130 err = sendto(sockfd, buf, reply_size, 0, (struct sockaddr *)&from_addr, slen);
131 if(err < 0) {
132 printf("error replying to message\n");
133 return -1;
137 return 0;
140 static void usage()
142 printf("usage: netblock <blockdev file>\n");
145 int main(int argc, char *argv[])
147 int err;
149 if(argc < 2) {
150 usage();
151 return -1;
154 dev = NULL;
155 sockfd = -1;
157 dev = new blockdevice;
159 // open the block device and figure out how big it is
160 dev->filefd = open(argv[1], O_RDWR|O_BINARY);
161 if(dev->filefd < 0) {
162 printf("error opening file '%s'\n", argv[1]);
163 return -1;
166 struct stat stat;
167 err = fstat(dev->filefd, &stat);
168 if(err < 0) {
169 printf("error statting file\n");
170 return -1;
173 if(stat.st_size < 512) {
174 printf("file is too small to use as a block device\n");
175 return -1;
178 dev->size = stat.st_size;
180 printf("opened file '%s', size %Ld\n", argv[1], dev->size);
182 dev->id = 0;
184 // open the server socket
185 struct sockaddr_in addr;
186 addr.sin_family = AF_INET;
187 addr.sin_port = htons(9999);
188 memset(&addr.sin_addr, 0, sizeof(addr.sin_addr));
190 sockfd = socket(PF_INET, SOCK_DGRAM, 0);
191 if(sockfd < 0) {
192 printf("error creating socket\n");
193 return -1;
196 err = bind(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr));
197 if(err < 0) {
198 printf("error binding socket\n");
199 return -1;
202 net_loop();
204 return 0;