Added a little server implementing the "remote disk" protocol featured
by the boot loader. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@15690 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
d561d0ad68
commit
9980540b63
@ -38,6 +38,7 @@ SubInclude HAIKU_TOP src tools hey ;
|
||||
SubInclude HAIKU_TOP src tools keymap ;
|
||||
SubInclude HAIKU_TOP src tools makebootable ;
|
||||
SubInclude HAIKU_TOP src tools rc ;
|
||||
SubInclude HAIKU_TOP src tools remote_disk_server ;
|
||||
SubInclude HAIKU_TOP src tools resattr ;
|
||||
SubInclude HAIKU_TOP src tools rman ;
|
||||
SubInclude HAIKU_TOP src tools translation ;
|
||||
|
8
src/tools/remote_disk_server/Jamfile
Normal file
8
src/tools/remote_disk_server/Jamfile
Normal file
@ -0,0 +1,8 @@
|
||||
SubDir HAIKU_TOP src tools remote_disk_server ;
|
||||
|
||||
UsePrivateHeaders kernel ;
|
||||
|
||||
BuildPlatformMain remote_disk_server
|
||||
: remote_disk_server.cpp
|
||||
: $(HOST_LIBSUPC++)
|
||||
;
|
300
src/tools/remote_disk_server/remote_disk_server.cpp
Normal file
300
src/tools/remote_disk_server/remote_disk_server.cpp
Normal file
@ -0,0 +1,300 @@
|
||||
/*
|
||||
* Copyright 2005, Ingo Weinhold <bonefish@cs.tu-berlin.de>.
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#include <endian.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <boot/net/RemoteDiskDefs.h>
|
||||
|
||||
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
|
||||
static inline
|
||||
uint64_t swap_uint64(uint64_t data)
|
||||
{
|
||||
return ((data & 0xff) << 56)
|
||||
| ((data & 0xff00) << 40)
|
||||
| ((data & 0xff0000) << 24)
|
||||
| ((data & 0xff000000) << 8)
|
||||
| ((data >> 8) & 0xff000000)
|
||||
| ((data >> 24) & 0xff0000)
|
||||
| ((data >> 40) & 0xff00)
|
||||
| ((data >> 56) & 0xff);
|
||||
}
|
||||
|
||||
#define host_to_net64(data) swap_uint64(data)
|
||||
#define net_to_host64(data) swap_uint64(data)
|
||||
|
||||
#endif
|
||||
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
#define host_to_net64(data) (data)
|
||||
#define net_to_host64(data) (data)
|
||||
#endif
|
||||
|
||||
#undef htonll
|
||||
#undef ntohll
|
||||
#define htonll(data) host_to_net64(data)
|
||||
#define ntohll(data) net_to_host64(data)
|
||||
|
||||
|
||||
class Server {
|
||||
public:
|
||||
Server(const char *fileName)
|
||||
: fImagePath(fileName),
|
||||
fImageFD(-1),
|
||||
fImageSize(0),
|
||||
fSocket(-1)
|
||||
{
|
||||
}
|
||||
|
||||
int Run()
|
||||
{
|
||||
_OpenImage();
|
||||
_CreateSocket();
|
||||
|
||||
// main server loop
|
||||
for (;;) {
|
||||
// receive
|
||||
fClientAddress.sin_family = AF_INET;
|
||||
fClientAddress.sin_port = 0;
|
||||
fClientAddress.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
socklen_t addrSize = sizeof(fClientAddress);
|
||||
char buffer[2048];
|
||||
ssize_t bytesRead = recvfrom(fSocket, buffer, sizeof(buffer), 0,
|
||||
(sockaddr*)&fClientAddress, &addrSize);
|
||||
// handle error
|
||||
if (bytesRead < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
fprintf(stderr, "Error: Failed to read from socket: %s.\n",
|
||||
strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// short package?
|
||||
if (bytesRead < (ssize_t)sizeof(remote_disk_header)) {
|
||||
fprintf(stderr, "Dropping short request package (%d bytes).\n",
|
||||
bytesRead);
|
||||
continue;
|
||||
}
|
||||
|
||||
fRequest = (remote_disk_header*)buffer;
|
||||
fRequestSize = bytesRead;
|
||||
|
||||
switch (fRequest->command) {
|
||||
case REMOTE_DISK_HELLO_REQUEST:
|
||||
_HandleHelloRequest();
|
||||
break;
|
||||
|
||||
case REMOTE_DISK_READ_REQUEST:
|
||||
_HandleReadRequest();
|
||||
break;
|
||||
|
||||
case REMOTE_DISK_WRITE_REQUEST:
|
||||
_HandleWriteRequest();
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "Ignoring invalid request %d.\n",
|
||||
(int)fRequest->command);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private:
|
||||
void _OpenImage()
|
||||
{
|
||||
// open the image
|
||||
fImageFD = open(fImagePath, O_RDWR);
|
||||
if (fImageFD < 0) {
|
||||
fprintf(stderr, "Error: Failed to open \"%s\": %s.\n", fImagePath,
|
||||
strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// get its size
|
||||
struct stat st;
|
||||
if (fstat(fImageFD, &st) < 0) {
|
||||
fprintf(stderr, "Error: Failed to stat \"%s\": %s.\n", fImagePath,
|
||||
strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
fImageSize = st.st_size;
|
||||
}
|
||||
|
||||
void _CreateSocket()
|
||||
{
|
||||
// create a socket
|
||||
fSocket = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (fSocket < 0) {
|
||||
fprintf(stderr, "Error: Failed to create a socket: %s.",
|
||||
strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// bind it to the port
|
||||
sockaddr_in addr;
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(REMOTE_DISK_SERVER_PORT);
|
||||
addr.sin_addr.s_addr = INADDR_ANY;
|
||||
if (bind(fSocket, (sockaddr*)&addr, sizeof(addr)) < 0) {
|
||||
fprintf(stderr, "Error: Failed to bind socket to port %hu: %s\n",
|
||||
REMOTE_DISK_SERVER_PORT, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void _HandleHelloRequest()
|
||||
{
|
||||
printf("HELLO request\n");
|
||||
|
||||
remote_disk_header reply;
|
||||
reply.offset = htonll(fImageSize);
|
||||
|
||||
reply.command = REMOTE_DISK_HELLO_REPLY;
|
||||
_SendReply(&reply, sizeof(remote_disk_header));
|
||||
}
|
||||
|
||||
void _HandleReadRequest()
|
||||
{
|
||||
char buffer[2048];
|
||||
remote_disk_header *reply = (remote_disk_header*)buffer;
|
||||
uint64_t offset = ntohll(fRequest->offset);
|
||||
int16_t size = ntohs(fRequest->size);
|
||||
int16_t result = 0;
|
||||
|
||||
printf("READ request: offset: %llu, %hd bytes\n", offset, size);
|
||||
|
||||
if (offset < (uint64_t)fImageSize && size > 0) {
|
||||
// always read 1024 bytes
|
||||
size = REMOTE_DISK_BLOCK_SIZE;
|
||||
if (offset + size > (uint64_t)fImageSize)
|
||||
size = fImageSize - offset;
|
||||
|
||||
// seek to the offset
|
||||
off_t oldOffset = lseek(fImageFD, offset, SEEK_SET);
|
||||
if (oldOffset >= 0) {
|
||||
// read
|
||||
ssize_t bytesRead = read(fImageFD, reply->data, size);
|
||||
if (bytesRead >= 0) {
|
||||
result = bytesRead;
|
||||
} else {
|
||||
fprintf(stderr, "Error: Failed to read at position %llu: "
|
||||
"%s.", offset, strerror(errno));
|
||||
result = REMOTE_DISK_IO_ERROR;
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "Error: Failed to seek to position %llu: %s.",
|
||||
offset, strerror(errno));
|
||||
result = REMOTE_DISK_IO_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
// send reply
|
||||
reply->command = REMOTE_DISK_READ_REPLY;
|
||||
reply->offset = htonll(offset);
|
||||
reply->size = htons(result);
|
||||
_SendReply(reply, sizeof(*reply) + (result >= 0 ? result : 0));
|
||||
}
|
||||
|
||||
void _HandleWriteRequest()
|
||||
{
|
||||
remote_disk_header reply;
|
||||
uint64_t offset = ntohll(fRequest->offset);
|
||||
int16_t size = ntohs(fRequest->size);
|
||||
int16_t result = 0;
|
||||
|
||||
printf("READ request: offset: %llu, %hd bytes\n", offset, size);
|
||||
|
||||
if (size < 0
|
||||
|| (uint32_t)size > fRequestSize - sizeof(remote_disk_header)
|
||||
|| offset > (uint64_t)fImageSize) {
|
||||
result = REMOTE_DISK_BAD_REQUEST;
|
||||
} else if (offset < (uint64_t)fImageSize && size > 0) {
|
||||
if (offset + size > (uint64_t)fImageSize)
|
||||
size = fImageSize - offset;
|
||||
|
||||
// seek to the offset
|
||||
off_t oldOffset = lseek(fImageFD, offset, SEEK_SET);
|
||||
if (oldOffset >= 0) {
|
||||
// write
|
||||
ssize_t bytesWritten = write(fImageFD, fRequest->data, size);
|
||||
if (bytesWritten >= 0) {
|
||||
result = bytesWritten;
|
||||
} else {
|
||||
fprintf(stderr, "Error: Failed to write at position %llu: "
|
||||
"%s.", offset, strerror(errno));
|
||||
result = REMOTE_DISK_IO_ERROR;
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "Error: Failed to seek to position %llu: %s.",
|
||||
offset, strerror(errno));
|
||||
result = REMOTE_DISK_IO_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
// send reply
|
||||
reply.command = REMOTE_DISK_WRITE_REPLY;
|
||||
reply.offset = htonll(offset);
|
||||
reply.size = htons(result);
|
||||
_SendReply(&reply, sizeof(reply));
|
||||
}
|
||||
|
||||
void _SendReply(remote_disk_header *reply, int size)
|
||||
{
|
||||
reply->request_id = fRequest->request_id;
|
||||
reply->port = htons(REMOTE_DISK_SERVER_PORT);
|
||||
|
||||
for (;;) {
|
||||
ssize_t bytesSent = sendto(fSocket, reply, size, 0,
|
||||
(const sockaddr*)&fClientAddress, sizeof(fClientAddress));
|
||||
|
||||
if (bytesSent < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
fprintf(stderr, "Error: Failed to send reply to client: %s.\n",
|
||||
strerror(errno));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const char *fImagePath;
|
||||
int fImageFD;
|
||||
off_t fImageSize;
|
||||
int fSocket;
|
||||
remote_disk_header *fRequest;
|
||||
ssize_t fRequestSize;
|
||||
sockaddr_in fClientAddress;
|
||||
};
|
||||
|
||||
|
||||
// main
|
||||
int
|
||||
main(int argc, const char *const *argv)
|
||||
{
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "Usage: %s <image path>\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
const char *fileName = argv[1];
|
||||
|
||||
Server server(fileName);
|
||||
return server.Run();
|
||||
}
|
Loading…
Reference in New Issue
Block a user