LaunchAPPL: TCP support

This commit is contained in:
Wolfgang Thaller 2018-05-09 23:16:45 +02:00
parent 749b7c5db8
commit 9dd308687b
13 changed files with 441 additions and 7 deletions

View File

@ -5,6 +5,7 @@ set(LAUNCHMETHODS
MiniVMac.h MiniVMac.cc
SSH.h SSH.cc
Serial.h Serial.cc
TCP.h TCP.cc
)
if(APPLE)

View File

@ -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
View 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
View 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

View File

@ -1,3 +1,5 @@
#pragma once
#include <memory>
#include <MacTypes.h>

View File

@ -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)

View File

@ -3,6 +3,10 @@ SEGMENT Serial
*/MacSerialStream.*
*/SerialConnectionProvider.*
SEGMENT MacTCP
*/MacTCPStream.*
*/TCPConnectionProvider.*
SEGMENT Launcher
*/AppLauncher.*
*/ToolLauncher.*

View File

@ -96,7 +96,3 @@ void MacSerialStream::setBaud(int baud)
else if(baud == 230400)
Control(outRefNum, kSERD230KBaud, nullptr);
}
void MacSerialStream::unloadSegDummy()
{
}

View File

@ -24,8 +24,6 @@ public:
void open();
void setBaud(int baud);
static void unloadSegDummy();
};
#endif

View 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();
}
}
}

View 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();
};

View 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;
}

View 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();
};