diff --git a/Architecture.cpp b/Architecture.cpp
new file mode 100644
index 0000000..652342e
--- /dev/null
+++ b/Architecture.cpp
@@ -0,0 +1,25 @@
+/*
+U2FDevice - A program to allow Raspberry Pi Zeros to act as U2F tokens
+Copyright (C) 2018 Michael Kuc
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*/
+
+#include "_Architecture.hpp"
+
+using namespace std;
+
+#if ARCHITECTURE == ARCH_ANDROID
+string hidDev = "/dev/hidg2";
+#endif
diff --git a/Architecture.hpp b/Architecture.hpp
index d2053e6..f02b79e 100644
--- a/Architecture.hpp
+++ b/Architecture.hpp
@@ -18,22 +18,7 @@ along with this program. If not, see .
#pragma once
-#define ARCH_RASPBERRY_PI 1
-#define ARCH_ANDROID 2
-#define ARCHITECTURE ARCH_ANDROID
-
-#if ARCHITECTURE == ARCH_RASPBERRY_PI
-# define STORAGE_PREFIX "/usr/share/"
-# define HID_DEV "/dev/hidg0"
-# define DEBUG_STREAMS "/tmp/"
-// #define DEBUG_MSGS
-# define LEDS
-#elif ARCHITECTURE == ARCH_ANDROID
-# define STORAGE_PREFIX "/sdcard/U2F/"
-# define HID_DEV "/dev/hidg2"
-# define DEBUG_STREAMS "/data/local/tmp/"
-// #define DEBUG_MSGS
-#endif
+#include "_Architecture.hpp"
#undef ARCH_ANDROID
#undef ARCH_RASPBERRY_PI
diff --git a/IO.cpp b/IO.cpp
index 127d5f7..2f136e1 100644
--- a/IO.cpp
+++ b/IO.cpp
@@ -29,9 +29,11 @@ along with this program. If not, see .
#include
#include
#include
+#include
#include
#include
#include
+#include
#include
#include
#include
@@ -41,12 +43,13 @@ using namespace std;
bool bytesAvailable(size_t count);
vector& getBuffer();
-string binaryDirectory{};
+#ifdef DEBUG_STREAMS
string cacheDirectory{ DEBUG_STREAMS };
+#endif
-// Thanks to https://stackoverflow.com/a/478960
-vector execOutput(const string& cmd);
-void execInput(const string& cmd, const vector& stdinData);
+#ifdef HID_SOCKET
+string clientSocket{};
+#endif
vector readNonBlock(const size_t count) {
if (!bytesAvailable(count))
@@ -63,13 +66,25 @@ vector readNonBlock(const size_t count) {
}
void write(const vector& bytes) {
- __android_log_print(ANDROID_LOG_DEBUG, "U2FAndroid", "Writing %zu bytes", bytes.size());
- execInput("su -c \"" + binaryDirectory + "/U2FAndroid_Write\"", bytes);
+ size_t totalBytes = 0;
+ auto hostDescriptor = *getHostDescriptor();
+
+ while (totalBytes < bytes.size()) {
+ auto writtenBytes =
+ send(hostDescriptor, bytes.data() + totalBytes, bytes.size() - totalBytes, 0);
+
+ if (writtenBytes > 0)
+ totalBytes += writtenBytes;
+ else if (errno != 0 && errno != EAGAIN &&
+ errno != EWOULDBLOCK) // Expect file blocking behaviour
+ ERR();
+ }
+
+ errno = 0;
}
bool bytesAvailable(const size_t count) {
auto startTime = std::chrono::high_resolution_clock::now();
- const timespec iterDelay{ 0, 10000000 };
chrono::duration delay{ 0 };
while (delay.count() < U2FHID_TRANS_TIMEOUT) {
@@ -79,7 +94,6 @@ bool bytesAvailable(const size_t count) {
#endif
return true;
}
- nanosleep(&iterDelay, nullptr);
delay = chrono::high_resolution_clock::now() - startTime;
}
@@ -96,44 +110,49 @@ vector& bufferVar() {
}
vector& getBuffer() {
- auto& buff = bufferVar();
- vector bytes = execOutput("su -c \"" + binaryDirectory + "/U2FAndroid_Read\"");
+ const timespec delay{ 0, 10'000'000 };
- if (!bytes.empty()) {
- __android_log_print(ANDROID_LOG_DEBUG, "U2FAndroid", "Reading bytes: got %zu",
- bytes.size());
- buff.insert(buff.end(), bytes.begin(), bytes.end());
+ auto& buff = bufferVar();
+ array bytes{};
+ auto hostDescriptor = *getHostDescriptor();
+
+ pollfd pFD{ hostDescriptor, POLLIN };
+
+ while (true) {
+ ppoll(&pFD, 1, &delay, 0);
+
+ if (pFD.revents & POLLIN) {
+ auto readByteCount = recv(hostDescriptor, bytes.data(), HID_RPT_SIZE, 0);
+
+ if (readByteCount > 0 && readByteCount != HID_RPT_SIZE) {
+ // Failed to copy an entire packet in, so log this packet
+#ifdef DEBUG_MSGS
+ cerr << "Only retrieved " << readByteCount << " bytes from expected full packet."
+ << endl;
+#endif
+ }
+
+ if (readByteCount > 0) {
+ copy(bytes.begin(), bytes.begin() + readByteCount, back_inserter(buff));
#ifdef DEBUG_STREAMS
- fwrite(bytes.data(), 1, bytes.size(), getComHostStream().get());
+ fwrite(bytes.data(), 1, readByteCount, getComHostStream().get());
#endif
+
+ } else if (errno != EAGAIN && errno != EWOULDBLOCK) // Expect read would block
+ {
+ ERR();
+#ifdef DEBUG_MSGS
+ cerr << "Unknown stream error: " << errno << endl;
+#endif
+ break;
+ } else {
+ errno = 0;
+ break; // Escape loop if blocking would occur
+ }
+ } else
+ break;
}
return buff;
}
-
-vector execOutput(const string& cmd) {
- // NOLINT(hicpp-member-init)
- array buffer;
- vector result{};
- unique_ptr pipe{ popen(cmd.c_str(), "rb"), pclose };
-
- if (!pipe)
- throw std::runtime_error("popen() failed!");
- while (size_t readBytes = fread(buffer.data(), 1, buffer.size(), pipe.get()))
- copy(buffer.begin(), buffer.begin() + readBytes, back_inserter(result));
-
- return result;
-}
-
-void execInput(const string& cmd, const vector& stdinData) {
- assert(stdinData.size() % HID_RPT_SIZE == 0);
-
- size_t writtenBytes = 0;
- unique_ptr pipe{ popen(cmd.c_str(), "wb"), pclose };
-
- if (!pipe)
- throw std::runtime_error("popen() failed!");
- while (writtenBytes < stdinData.size())
- writtenBytes += fwrite(stdinData.data(), 1, HID_RPT_SIZE, pipe.get());
-}
diff --git a/IO.hpp b/IO.hpp
index 8a39680..2706f6e 100644
--- a/IO.hpp
+++ b/IO.hpp
@@ -21,8 +21,13 @@ along with this program. If not, see .
#include
#include
-extern std::string binaryDirectory;
+#ifdef DEBUG_STREAMS
extern std::string cacheDirectory;
+#endif
+
+#ifdef HID_SOCKET
+extern std::string clientSocket;
+#endif
// Returns either the number of bytes specified,
// or returns empty vector without discarding bytes from HID stream
diff --git a/Streams.cpp b/Streams.cpp
index 93c20fc..1706482 100644
--- a/Streams.cpp
+++ b/Streams.cpp
@@ -17,36 +17,46 @@ along with this program. If not, see .
*/
#include "Streams.hpp"
+#include "Architecture.hpp"
#include "IO.hpp"
+#include
#include
#include
#include
+#include
#include
#include
+#include
#include
-using namespace std;
+using std::cerr;
+using std::clog;
+using std::endl;
+using std::runtime_error;
+using std::shared_ptr;
+using std::string;
+
+int initialiseHostDescriptor();
#ifdef DEBUG_STREAMS
+
FILE* initHTML(FILE* fPtr, const string& title);
+
void closeHTML(FILE* fPtr);
+
#endif
shared_ptr getHostDescriptor() {
- static shared_ptr descriptor{};
-
- descriptor.reset(new int{ open(HID_DEV, O_RDWR | O_NONBLOCK | O_APPEND) }, [](int* fd) {
- close(*fd);
- delete fd;
- });
-
- if (*descriptor == -1)
- throw runtime_error{ "Descriptor is unavailable" };
+ static shared_ptr descriptor{ new int{ initialiseHostDescriptor() }, [](const int* fd) {
+ close(*fd);
+ delete fd;
+ } };
return descriptor;
}
#ifdef DEBUG_STREAMS
+
shared_ptr getComHostStream() {
static shared_ptr stream{ fopen((cacheDirectory + "comhost.txt").c_str(), "wb"),
[](FILE* f) {
@@ -182,4 +192,49 @@ void closeHTML(FILE* fPtr) {
"