mirror of
https://github.com/autc04/Retro68.git
synced 2025-04-11 14:37:50 +00:00
LaunchAPPL: TCP support
This commit is contained in:
parent
749b7c5db8
commit
9dd308687b
@ -5,6 +5,7 @@ set(LAUNCHMETHODS
|
||||
MiniVMac.h MiniVMac.cc
|
||||
SSH.h SSH.cc
|
||||
Serial.h Serial.cc
|
||||
TCP.h TCP.cc
|
||||
)
|
||||
|
||||
if(APPLE)
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "MiniVMac.h"
|
||||
#include "SSH.h"
|
||||
#include "Serial.h"
|
||||
#include "TCP.h"
|
||||
|
||||
namespace po = boost::program_options;
|
||||
namespace fs = boost::filesystem;
|
||||
@ -44,7 +45,8 @@ static void RegisterLaunchMethods()
|
||||
#endif
|
||||
new Executor(), new MiniVMac(),
|
||||
new SSH(),
|
||||
new Serial()
|
||||
new Serial(),
|
||||
new TCP()
|
||||
// #### Add new `LaunchMethod`s here.
|
||||
};
|
||||
|
||||
|
179
LaunchAPPL/Client/TCP.cc
Normal file
179
LaunchAPPL/Client/TCP.cc
Normal file
@ -0,0 +1,179 @@
|
||||
#include "TCP.h"
|
||||
#include "Launcher.h"
|
||||
#include "Utilities.h"
|
||||
#include "Stream.h"
|
||||
#include "ServerProtocol.h"
|
||||
#include <termios.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace po = boost::program_options;
|
||||
using namespace std::literals::chrono_literals;
|
||||
|
||||
class TCPStream : public Stream
|
||||
{
|
||||
|
||||
static const long kReadBufferSize = 4096;
|
||||
uint8_t readBuffer[kReadBufferSize];
|
||||
public:
|
||||
int fd;
|
||||
|
||||
virtual void write(const void* p, size_t n) override;
|
||||
|
||||
void wait();
|
||||
|
||||
TCPStream(po::variables_map &options);
|
||||
~TCPStream();
|
||||
};
|
||||
|
||||
class TCPLauncher : public Launcher
|
||||
{
|
||||
TCPStream stream;
|
||||
TCPStream& rStream = stream;
|
||||
std::vector<char> outputBytes;
|
||||
bool upgradeMode = false;
|
||||
public:
|
||||
TCPLauncher(po::variables_map& options);
|
||||
virtual ~TCPLauncher();
|
||||
|
||||
virtual bool Go(int timeout = 0);
|
||||
virtual void DumpOutput();
|
||||
|
||||
private:
|
||||
void write(const void *p, size_t n);
|
||||
ssize_t read(void * p, size_t n);
|
||||
};
|
||||
|
||||
|
||||
TCPStream::TCPStream(po::variables_map &options)
|
||||
{
|
||||
fd = socket(AF_INET , SOCK_STREAM , 0);
|
||||
struct sockaddr_in addr;
|
||||
addr.sin_addr.s_addr = inet_addr(options["tcp-address"].as<std::string>().c_str());
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons( 1984 );
|
||||
|
||||
//Connect to remote server
|
||||
int result = connect(fd , (struct sockaddr *)&addr , sizeof(addr));
|
||||
if(result < 0)
|
||||
perror("connect");
|
||||
}
|
||||
TCPStream::~TCPStream()
|
||||
{
|
||||
close(fd);
|
||||
}
|
||||
|
||||
void TCPStream::write(const void* p, size_t n)
|
||||
{
|
||||
::write(fd, p, n);
|
||||
}
|
||||
|
||||
void TCPStream::wait()
|
||||
{
|
||||
ssize_t n = ::read(fd, readBuffer, kReadBufferSize);
|
||||
if(n > 0)
|
||||
notifyReceive(readBuffer, n);
|
||||
}
|
||||
|
||||
|
||||
TCPLauncher::TCPLauncher(po::variables_map &options)
|
||||
: Launcher(options), stream(options)
|
||||
{
|
||||
if(options.count("upgrade-server"))
|
||||
upgradeMode = true;
|
||||
}
|
||||
|
||||
TCPLauncher::~TCPLauncher()
|
||||
{
|
||||
}
|
||||
|
||||
ssize_t TCPLauncher::read(void *p0, size_t n)
|
||||
{
|
||||
uint8_t* p = (uint8_t*)p0;
|
||||
ssize_t gotBytes = rStream.read(p, n);
|
||||
while(gotBytes < n)
|
||||
{
|
||||
rStream.flushWrite();
|
||||
stream.wait();
|
||||
gotBytes += rStream.read(p + gotBytes, n - gotBytes);
|
||||
}
|
||||
return gotBytes;
|
||||
}
|
||||
|
||||
void TCPLauncher::write(const void *p, size_t n)
|
||||
{
|
||||
while(!rStream.readyToWrite())
|
||||
stream.wait();
|
||||
rStream.write(p, n);
|
||||
}
|
||||
|
||||
bool TCPLauncher::Go(int timeout)
|
||||
{
|
||||
uint32_t tmp;
|
||||
|
||||
|
||||
{
|
||||
RemoteCommand cmd = upgradeMode ? RemoteCommand::upgradeLauncher : RemoteCommand::launchApp;
|
||||
write(&cmd, 1);
|
||||
|
||||
write(std::string(app.type).data(), 4);
|
||||
write(std::string(app.creator).data(), 4);
|
||||
|
||||
std::ostringstream rsrcOut;
|
||||
app.resources.writeFork(rsrcOut);
|
||||
std::string rsrc = rsrcOut.str();
|
||||
std::string& data = app.data;
|
||||
std::cerr << "Transfering " << (data.size() + rsrc.size() + 1023) / 1024 << " KB." << std::endl;
|
||||
|
||||
tmp = htonl(data.size());
|
||||
write(&tmp, 4);
|
||||
tmp = htonl(rsrc.size());
|
||||
write(&tmp, 4);
|
||||
|
||||
write(data.data(), data.size());
|
||||
write(rsrc.data(), rsrc.size());
|
||||
}
|
||||
while(!rStream.allDataArrived())
|
||||
stream.wait();
|
||||
std::cerr << "Running Appliation..." << std::endl;
|
||||
read(&tmp, 4);
|
||||
uint32_t result = ntohl(tmp);
|
||||
std::cerr << "Finished (result = " << result << ")." << std::endl;
|
||||
|
||||
if(result == 0)
|
||||
{
|
||||
read(&tmp, 4);
|
||||
uint32_t size = ntohl(tmp);
|
||||
outputBytes.resize(size);
|
||||
if(size > 0)
|
||||
read(outputBytes.data(), size);
|
||||
}
|
||||
|
||||
return result == 0;
|
||||
}
|
||||
|
||||
void TCPLauncher::DumpOutput()
|
||||
{
|
||||
std::cout.write(outputBytes.data(), outputBytes.size());
|
||||
}
|
||||
|
||||
void TCP::GetOptions(options_description &desc)
|
||||
{
|
||||
desc.add_options()
|
||||
("tcp-address", po::value<std::string>(), "IP address of Mac")
|
||||
;
|
||||
}
|
||||
|
||||
bool TCP::CheckOptions(variables_map &options)
|
||||
{
|
||||
return options.count("tcp-address") != 0;
|
||||
}
|
||||
|
||||
std::unique_ptr<Launcher> TCP::MakeLauncher(variables_map &options)
|
||||
{
|
||||
return std::unique_ptr<Launcher>(new TCPLauncher(options));
|
||||
}
|
16
LaunchAPPL/Client/TCP.h
Normal file
16
LaunchAPPL/Client/TCP.h
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef TCP_H
|
||||
#define TCP_H
|
||||
|
||||
#include "LaunchMethod.h"
|
||||
|
||||
class TCP : public LaunchMethod
|
||||
{
|
||||
public:
|
||||
virtual std::string GetName() { return "tcp"; }
|
||||
virtual void GetOptions(options_description& desc);
|
||||
virtual bool CheckOptions(variables_map& options);
|
||||
|
||||
virtual std::unique_ptr<Launcher> MakeLauncher(variables_map& options);
|
||||
};
|
||||
|
||||
#endif // EXECUTOR_H
|
@ -1,3 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <MacTypes.h>
|
||||
|
||||
|
@ -16,6 +16,11 @@ add_application(LaunchAPPLServer
|
||||
ConnectionProvider.h
|
||||
SerialConnectionProvider.h
|
||||
SerialConnectionProvider.cc
|
||||
|
||||
MacTCPStream.h
|
||||
MacTCPStream.cc
|
||||
TCPConnectionProvider.h
|
||||
TCPConnectionProvider.cc
|
||||
)
|
||||
|
||||
target_link_libraries(LaunchAPPLServer LaunchAPPLCommon)
|
||||
|
@ -3,6 +3,10 @@ SEGMENT Serial
|
||||
*/MacSerialStream.*
|
||||
*/SerialConnectionProvider.*
|
||||
|
||||
SEGMENT MacTCP
|
||||
*/MacTCPStream.*
|
||||
*/TCPConnectionProvider.*
|
||||
|
||||
SEGMENT Launcher
|
||||
*/AppLauncher.*
|
||||
*/ToolLauncher.*
|
||||
|
@ -96,7 +96,3 @@ void MacSerialStream::setBaud(int baud)
|
||||
else if(baud == 230400)
|
||||
Control(outRefNum, kSERD230KBaud, nullptr);
|
||||
}
|
||||
|
||||
void MacSerialStream::unloadSegDummy()
|
||||
{
|
||||
}
|
||||
|
@ -24,8 +24,6 @@ public:
|
||||
void open();
|
||||
|
||||
void setBaud(int baud);
|
||||
|
||||
static void unloadSegDummy();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
138
LaunchAPPL/Server/MacTCPStream.cc
Normal file
138
LaunchAPPL/Server/MacTCPStream.cc
Normal file
@ -0,0 +1,138 @@
|
||||
#include "MacTCPStream.h"
|
||||
#include <Devices.h>
|
||||
#include <string.h>
|
||||
|
||||
MacTCPStream::MacTCPStream()
|
||||
{
|
||||
OpenDriver("\p.IPP",&refNum);
|
||||
|
||||
memset(&readPB, 0, sizeof(readPB));
|
||||
readPB.ioCRefNum = refNum;
|
||||
readPB.csCode = TCPCreate;
|
||||
readPB.csParam.create.rcvBuff = inputBuffer;
|
||||
readPB.csParam.create.rcvBuffLen = kInputBufferSize;
|
||||
OSErr err = PBControlSync((ParmBlkPtr)&readPB);
|
||||
tcpStream = readPB.tcpStream;
|
||||
if(err == 0)
|
||||
;//DebugStr("\pTCPCreate noError");
|
||||
else
|
||||
DebugStr("\pTCPCreate error");
|
||||
|
||||
memset(&writePB, 0, sizeof(writePB));
|
||||
|
||||
startListening();
|
||||
}
|
||||
|
||||
void MacTCPStream::startListening()
|
||||
{
|
||||
memset(&readPB, 0, sizeof(readPB));
|
||||
readPB.ioCRefNum = refNum;
|
||||
readPB.tcpStream = tcpStream;
|
||||
|
||||
readPB.csCode = TCPPassiveOpen;
|
||||
readPB.ioResult = 1;
|
||||
readPB.csParam.open.ulpTimeoutValue = 5;// ###
|
||||
readPB.csParam.open.ulpTimeoutAction = 1;
|
||||
readPB.csParam.open.validityFlags = 0xC0;
|
||||
readPB.csParam.open.commandTimeoutValue = 0;
|
||||
readPB.csParam.open.localPort = 1984;
|
||||
PBControlAsync((ParmBlkPtr)&readPB);
|
||||
}
|
||||
|
||||
MacTCPStream::~MacTCPStream()
|
||||
{
|
||||
TCPiopb pb;
|
||||
|
||||
memset(&pb, 0, sizeof(pb));
|
||||
pb.ioCRefNum = refNum;
|
||||
pb.tcpStream = tcpStream;
|
||||
pb.csCode = TCPAbort;
|
||||
PBControlSync((ParmBlkPtr)&pb);
|
||||
|
||||
while(readPB.ioResult > 0 || writePB.ioResult > 0)
|
||||
;
|
||||
|
||||
memset(&pb, 0, sizeof(pb));
|
||||
pb.ioCRefNum = refNum;
|
||||
pb.tcpStream = tcpStream;
|
||||
pb.csCode = TCPRelease;
|
||||
PBControlSync((ParmBlkPtr)&pb);
|
||||
}
|
||||
|
||||
void MacTCPStream::write(const void* p, size_t n)
|
||||
{
|
||||
memset(&writePB, 0, sizeof(writePB));
|
||||
writePB.ioCRefNum = refNum;
|
||||
writePB.tcpStream = tcpStream;
|
||||
|
||||
|
||||
writePB.csCode = TCPSend;
|
||||
writePB.ioResult = 1;
|
||||
writePB.csParam.send.ulpTimeoutValue = 0;
|
||||
writePB.csParam.send.ulpTimeoutAction = 1;
|
||||
writePB.csParam.send.validityFlags = 0xC0;
|
||||
writePB.csParam.send.pushFlag = false;
|
||||
writePB.csParam.send.urgentFlag = false;
|
||||
|
||||
struct wdsEntry wds[2] = { {(unsigned short)n, (Ptr)p}, {0, nullptr} };
|
||||
writePB.csParam.send.wdsPtr = (Ptr)&wds;
|
||||
PBControlSync((ParmBlkPtr)&writePB);
|
||||
|
||||
}
|
||||
|
||||
void MacTCPStream::startReading()
|
||||
{
|
||||
memset(&readPB, 0, sizeof(readPB));
|
||||
readPB.ioCRefNum = refNum;
|
||||
readPB.tcpStream = tcpStream;
|
||||
|
||||
|
||||
readPB.csCode = TCPRcv;
|
||||
readPB.ioResult = 1;
|
||||
readPB.csParam.receive.rcvBuff = readBuffer;
|
||||
readPB.csParam.receive.rcvBuffLen = kReadBufferSize;
|
||||
readPB.csParam.receive.commandTimeoutValue = 0;
|
||||
PBControlAsync((ParmBlkPtr)&readPB);
|
||||
}
|
||||
|
||||
void MacTCPStream::idle()
|
||||
{
|
||||
if(!connected)
|
||||
{
|
||||
if(readPB.ioResult == 0)
|
||||
{
|
||||
connected = true;
|
||||
notifyReset();
|
||||
startReading();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(readPB.ioResult == 0)
|
||||
{
|
||||
if(readPB.csParam.receive.rcvBuffLen > 0)
|
||||
notifyReceive((uint8_t*)readBuffer, readPB.csParam.receive.rcvBuffLen);
|
||||
startReading();
|
||||
}
|
||||
else if(readPB.ioResult == connectionClosing || readPB.ioResult == connectionTerminated)
|
||||
{
|
||||
connected = false;
|
||||
|
||||
memset(&readPB, 0, sizeof(readPB));
|
||||
readPB.ioCRefNum = refNum;
|
||||
readPB.tcpStream = tcpStream;
|
||||
|
||||
readPB.csCode = TCPClose;
|
||||
readPB.csParam.close.ulpTimeoutValue = 5;
|
||||
readPB.csParam.close.ulpTimeoutAction = 1;
|
||||
readPB.csParam.close.validityFlags = 0xC0;
|
||||
PBControlSync((ParmBlkPtr)&readPB);
|
||||
|
||||
readPB.csCode = TCPAbort;
|
||||
PBControlSync((ParmBlkPtr)&readPB);
|
||||
|
||||
startListening();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
30
LaunchAPPL/Server/MacTCPStream.h
Normal file
30
LaunchAPPL/Server/MacTCPStream.h
Normal file
@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include <Stream.h>
|
||||
#include <MacTCP.h>
|
||||
|
||||
class MacTCPStream : public Stream
|
||||
{
|
||||
static const long kInputBufferSize = 8192;
|
||||
static const long kReadBufferSize = 4096;
|
||||
char inputBuffer[kInputBufferSize];
|
||||
char readBuffer[kReadBufferSize];
|
||||
|
||||
short refNum;
|
||||
bool connected = false;
|
||||
|
||||
StreamPtr tcpStream;
|
||||
TCPiopb readPB, writePB;
|
||||
|
||||
void startListening();
|
||||
void startReading();
|
||||
public:
|
||||
virtual void write(const void* p, size_t n) override;
|
||||
|
||||
void idle();
|
||||
|
||||
MacTCPStream();
|
||||
~MacTCPStream();
|
||||
};
|
||||
|
||||
|
39
LaunchAPPL/Server/TCPConnectionProvider.cc
Normal file
39
LaunchAPPL/Server/TCPConnectionProvider.cc
Normal file
@ -0,0 +1,39 @@
|
||||
#include "TCPConnectionProvider.h"
|
||||
#include "MacTCPStream.h"
|
||||
#include <ReliableStream.h>
|
||||
#include "StatusDisplay.h"
|
||||
|
||||
|
||||
TCPConnectionProvider::TCPConnectionProvider(StatusDisplay *statusDisplay)
|
||||
: statusDisplay(statusDisplay)
|
||||
{
|
||||
stream = std::make_unique<MacTCPStream>();
|
||||
}
|
||||
|
||||
TCPConnectionProvider::~TCPConnectionProvider()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Stream* TCPConnectionProvider::getStream()
|
||||
{
|
||||
return stream.get();
|
||||
}
|
||||
|
||||
void TCPConnectionProvider::idle()
|
||||
{
|
||||
if(stream)
|
||||
{
|
||||
stream->setListener(listener);
|
||||
stream->idle();
|
||||
}
|
||||
}
|
||||
|
||||
void TCPConnectionProvider::unloadSegDummy()
|
||||
{
|
||||
}
|
||||
|
||||
void *TCPConnectionProvider::segmentToUnload()
|
||||
{
|
||||
return nullptr;//(void*) &unloadSegDummy;
|
||||
}
|
24
LaunchAPPL/Server/TCPConnectionProvider.h
Normal file
24
LaunchAPPL/Server/TCPConnectionProvider.h
Normal file
@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
#include "ConnectionProvider.h"
|
||||
#include <memory>
|
||||
|
||||
class StatusDisplay;
|
||||
class MacTCPStream;
|
||||
|
||||
class TCPConnectionProvider : public ConnectionProvider
|
||||
{
|
||||
StatusDisplay *statusDisplay;
|
||||
|
||||
std::unique_ptr<MacTCPStream> stream;
|
||||
|
||||
static void unloadSegDummy();
|
||||
public:
|
||||
TCPConnectionProvider(StatusDisplay *statusDisplay);
|
||||
virtual ~TCPConnectionProvider();
|
||||
|
||||
virtual Stream* getStream();
|
||||
|
||||
virtual void idle();
|
||||
|
||||
virtual void* segmentToUnload();
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user