Python send() with binary data
zts_py_send() was using strlen() to determine the length of the send(). This works fine with strings, but fails with binary data. To fix this, I have removed the string encoding code, and converted to using the Buffer protocol as is done in the Python socketmodule send() implementation. This does mean that this send() implementation only takes byte-like objects. The workaround for this could be at the python level rather than the C++ level. NOTE: This implementation has a bug in the exception handling if a non-bytes-like object is passed. You get an exception, but the exception is not accurate, it reports the TypeError, but the actual raised exception is due to there being a return value when the error indicator is set. I spent a few hours trying to fix this but was unable to. I'm afraid I just couldn't figure it out. My SSH proxy was misbehaving because the second block of data going from the client to the server had a NUL byte as the first byte to send, so the send was returning 0 bytes sent, but that was due to send() being told to send 0 bytes. With this, my SSH proxy is now working, including able to run an rsync of my boot initrd over SSH over ZeroTier entirely in userspace.
This commit is contained in:
@@ -168,40 +168,16 @@ PyObject * zts_py_recv(int fd, int len, int flags)
|
||||
|
||||
int zts_py_send(int fd, PyObject *buf, int flags)
|
||||
{
|
||||
int bytes_sent = ZTS_ERR_OK;
|
||||
char *bytes = NULL;
|
||||
PyObject *encodedStr = NULL;
|
||||
Py_buffer output;
|
||||
int bytes_sent;
|
||||
|
||||
// Check for various encodings, or lack thereof
|
||||
|
||||
if (PyByteArray_Check(buf)) {
|
||||
bytes = PyByteArray_AsString(buf);
|
||||
if (PyObject_GetBuffer(buf, &output, PyBUF_SIMPLE) != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (PyUnicode_Check(buf)) {
|
||||
encodedStr = PyUnicode_AsEncodedString(buf, "UTF-8", "strict");
|
||||
if (!encodedStr) {
|
||||
return ZTS_ERR_ARG;
|
||||
}
|
||||
bytes = PyBytes_AsString(encodedStr);
|
||||
}
|
||||
bytes_sent = zts_send(fd, output.buf, output.len, flags);
|
||||
PyBuffer_Release(&output);
|
||||
|
||||
if (!bytes) {
|
||||
// No encoding detected
|
||||
bytes = PyBytes_AsString(buf);
|
||||
}
|
||||
|
||||
// If we still don't have a valid pointer to a C-string, fail
|
||||
if (!bytes) {
|
||||
bytes_sent = ZTS_ERR_ARG;
|
||||
}
|
||||
else {
|
||||
bytes_sent = zts_send(fd, bytes, strlen(bytes), flags);
|
||||
}
|
||||
|
||||
if (encodedStr) {
|
||||
Py_DECREF(encodedStr);
|
||||
}
|
||||
return bytes_sent;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user