-
Notifications
You must be signed in to change notification settings - Fork 914
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
First try at disconnect/reconnect detection #516
base: master
Are you sure you want to change the base?
Changes from 1 commit
96aab06
2a3f94d
1ab4fc9
6e0b2d0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -38,6 +38,7 @@ | |
pthread_mutex_t print_lock; | ||
|
||
static serial_port sp; | ||
static char* sp_name; | ||
static UsbCommand txcmd; | ||
volatile static bool txcmd_pending = false; | ||
|
||
|
@@ -70,16 +71,63 @@ byte_t* prx = rx; | |
static void *uart_receiver(void *targ) { | ||
struct receiver_arg *arg = (struct receiver_arg*)targ; | ||
size_t rxlen; | ||
bool need_reconnect = false; | ||
UsbCommand version_cmd = {CMD_VERSION}; | ||
static bool request_version = false; | ||
|
||
while (arg->run) { | ||
rxlen = 0; | ||
if (uart_receive(sp, prx, sizeof(UsbCommand) - (prx-rx), &rxlen) && rxlen) { | ||
prx += rxlen; | ||
if (prx-rx < sizeof(UsbCommand)) { | ||
if( need_reconnect ) { | ||
sp = uart_open(sp_name); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This will break on Android. Is there a better way to pass this from within the Currently, this assumes that the "serial port identifier will always be a string". This isn't true if There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have no idea what part of the above code will fail on Android, that link doesn't explain it. The original PM3 code takes main()'s argv[1] and feeds it to uart_open(). sp_name is just a copy of argv[1]. In what cases will argv[1] not be a char* ? If main() is changed to not feed argv[1] into uart_open then obviously the other instances of uart_open() will need to be changed too. Surely replacing "char*" with whatever becomes appropriate at that time isn't that difficult... The entire point of this patch is to simply detect a disconnection and attempt to reopen the same port. It is not to rewrite the entire uart system. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. All of it will fail on Android, because the "serial port" is a reference to a bunch of JNI object IDs, which allow it to pass This is implemented in these files:
PM3 doesn't get called by This is done because there is no Having an API call for "reconnect" means that it doesn't matter how At least on Android I'd bring "reconnect" up into Java space, hit the USB stack on the head a few times, and then pass it back. As for precedent: @iceman1001 objected when I proposed removing If that went in as-is, even when it was "internal", I would no longer be able to track upstream PM3 for Android until it was replaced with the API extensions I proposed. |
||
|
||
if( sp == INVALID_SERIAL_PORT || sp == CLAIMED_SERIAL_PORT ) | ||
{ | ||
PrintAndLog("Reconnect failed, retrying..."); | ||
|
||
if( txcmd_pending ) { | ||
PrintAndLog("Cannot send bytes to offline proxmark"); | ||
txcmd_pending = false; | ||
} | ||
|
||
sleep(2); | ||
continue; | ||
} | ||
UsbCommandReceived((UsbCommand*)rx); | ||
|
||
PrintAndLog("Proxmark reconnected!"); | ||
need_reconnect = false; | ||
offline = 0; | ||
//CmdVersionW(NULL, true); | ||
clearCommandBuffer(); | ||
uart_send(sp, (byte_t*) &version_cmd, sizeof(UsbCommand)); // request it from the HW | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This would destroy all data in BigBuf[] when reconnecting. I think the major purpose of the possibility to reconnect is to support offline functionality like sniffing some data? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As it is now, unplugging causes the CPU to shoot to 100% used and the only way to continue what you're doing is to exit and restart the client. When I'm on my laptop I sometimes need to move USB ports or occasionally it accidentally comes unplugged, and needing to restart is annoying. At any rate I've seen some odd segfaults in readline with this, so I was thinking about ripping out the "re-get version info" stuff anyway. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also, as far as I can tell clearing the command buf doesn't touch BigBuf[]. Not sure if the act of disconnecting/reconnecting the USB cable will do that, though without a battery whatever's in the hardware will be gone. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Indeed,
The latter is obviously easier to implement. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Newest version still has clearCommandBuffer() but instead of querying the version on re-connect it simply clears CmdVersion()'s cache. |
||
request_version = true; | ||
} | ||
|
||
rxlen = 0; | ||
if (uart_receive(sp, prx, sizeof(UsbCommand) - (prx-rx), &rxlen) ) { | ||
if( rxlen ) { | ||
prx += rxlen; | ||
if (prx-rx < sizeof(UsbCommand)) { | ||
continue; | ||
} | ||
|
||
UsbCommandReceived((UsbCommand*)rx); | ||
|
||
if( request_version && ((UsbCommand*)rx)->cmd == CMD_ACK) | ||
{ | ||
request_version = false; | ||
CmdVersionW(NULL, true); | ||
} | ||
} | ||
} | ||
else { | ||
PrintAndLog("Receiving data from proxmark failed, attempting a reconnect"); | ||
uart_close(sp); | ||
sp = INVALID_SERIAL_PORT; | ||
offline = 1; | ||
txcmd_pending = false; | ||
need_reconnect = true; | ||
continue; | ||
} | ||
|
||
prx = rx; | ||
|
||
if(txcmd_pending) { | ||
|
@@ -351,6 +399,7 @@ int main(int argc, char* argv[]) { | |
set_my_executable_path(); | ||
|
||
// open uart | ||
sp_name = argv[1]; | ||
if (!waitCOMPort) { | ||
sp = uart_open(argv[1]); | ||
} else { | ||
|
@@ -405,7 +454,7 @@ int main(int argc, char* argv[]) { | |
#endif | ||
|
||
// Clean up the port | ||
if (usb_present) { | ||
if (sp != INVALID_SERIAL_PORT && sp != CLAIMED_SERIAL_PORT) { | ||
uart_close(sp); | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -141,7 +141,7 @@ bool uart_receive(const serial_port sp, byte_t* pbtRx, size_t pszMaxRxLen, size_ | |
|
||
// Reset the output count | ||
*pszRxLen = 0; | ||
|
||
do { | ||
// Reset file descriptor | ||
FD_ZERO(&rfds); | ||
|
@@ -153,12 +153,12 @@ bool uart_receive(const serial_port sp, byte_t* pbtRx, size_t pszMaxRxLen, size_ | |
if (res < 0) { | ||
return false; | ||
} | ||
|
||
// Read time-out | ||
if (res == 0) { | ||
if (*pszRxLen == 0) { | ||
// Error, we received no data | ||
return false; | ||
return true; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why does this path also return true? Don't you want to know when there is an error? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Timing out without receiving any data may not be an error if the hardware just doesn't have any data ready for us at the moment. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. uart_posix.c does some additional and unnecessary re-packaging which is already handled in proxmark3.c
uart_win32.c doesn't do that. Why not aligning/simplyfying the Unix version and make it behave like the Windows version? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah true. I also double checked So that entire There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The Win and *nix APIs are totally different. It's been a while since I looked at uart_posix.c and I really didn't spend a huge amount of time in there, but from what I recall the various return's are to break out of a loop or to handle the various conditions the select() can result in (read error vs "no data available" which isn't an error). If it's rewritten to be like uart_win32.c then it will block forever (or at least until the PM3 is unplugged) and not allow the comms thread to exit on client shutdown due to the "do { ... } while(byteCount);" . The only clean-up I see is the "if(..) return true; else return true;" As per my first comment I have absolutely no clue if the WIN32 routine returns an error on no data or not, or an error on a read error or not. No windoze boxen in this building... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. FYI, if you want to test stuff on Windows, http://modern.ie/ has time-limited trial Windows virtual machines. They're ostensibly for testing websites in Internet Explorer and Edge, but you can install any software you like on them. That should be sufficient for getting ProxSpace (the Windows build environment) going. |
||
} else { | ||
// We received some data, but nothing more is available | ||
return true; | ||
|
@@ -168,7 +168,7 @@ bool uart_receive(const serial_port sp, byte_t* pbtRx, size_t pszMaxRxLen, size_ | |
// Retrieve the count of the incoming bytes | ||
res = ioctl(((serial_port_unix*)sp)->fd, FIONREAD, &byteCount); | ||
if (res < 0) return false; | ||
|
||
// Cap the number of bytes, so we don't overrun the buffer | ||
if (pszMaxRxLen - (*pszRxLen) < byteCount) { | ||
byteCount = pszMaxRxLen - (*pszRxLen); | ||
|
@@ -178,8 +178,8 @@ bool uart_receive(const serial_port sp, byte_t* pbtRx, size_t pszMaxRxLen, size_ | |
res = read(((serial_port_unix*)sp)->fd, pbtRx+(*pszRxLen), byteCount); | ||
|
||
// Stop if the OS has some troubles reading the data | ||
if (res <= 0) return false; | ||
if (res < 0) return false; | ||
|
||
*pszRxLen += res; | ||
|
||
if (*pszRxLen == pszMaxRxLen) { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey, can you please hold up on this until #463 is in? Aside from not wanting to have to go through a merge conflict process again, I address some of the reconnection issues already in that for flasher.