remote/windows/WindowsPipe.cpp (283 lines of code) (raw):
#include <jni.h>
#include <windows.h>
#include <winerror.h>
#include <winnt.h>
#include <vector>
#include <string>
#define THROW_IO(prefix, ...) \
do { \
char _buf[1024]; \
snprintf(_buf, 1024, prefix ? prefix : "%s", __VA_ARGS__); \
jclass exClass = (env)->FindClass("java/io/IOException"); \
if (exClass != NULL) { \
(env)->ThrowNew(exClass, _buf); \
} \
} while (0);
#define FILL_ERROR(prefix, buf) \
do { \
char err[sizeof(buf)]; \
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, \
NULL, GetLastError(), \
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), err, sizeof(buf), \
NULL); \
size_t len = strnlen(err, sizeof(err)); \
if (err[len - 2] == '\r') \
err[len - 2] = '\0'; \
snprintf(buf, sizeof(buf), prefix ? prefix : "%s (error code %ld)", err, \
GetLastError()); \
} while (0);
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT jlong JNICALL
Java_com_jetbrains_cef_remote_WindowsPipe_CreateNamedPipe(
JNIEnv *env, jclass clazz, jstring pipeName, jint dwOpenMode,
jint dwPipeMode, jint nMaxInstances, jint nOutBufferSize,
jint nInBufferSize, jint nDefaultTimeout
) {
LPCWSTR name = (LPCWSTR)(env)->GetStringChars(pipeName, 0);
jlong handle = (jlong)(CreateNamedPipeW(
name,
dwOpenMode,
dwPipeMode,
nMaxInstances,
nOutBufferSize,
nInBufferSize,
nDefaultTimeout,
NULL));
if (handle == (jlong)INVALID_HANDLE_VALUE) {
char buf[512];
FILL_ERROR(NULL, buf);
THROW_IO("Couldn't create named pipe for %ws (%s)", name, buf);
}
return (jlong)handle;
}
JNIEXPORT jlong JNICALL
Java_com_jetbrains_cef_remote_WindowsPipe_OpenFile(
JNIEnv *env, jclass clazz, jstring pipeName) {
LPCWSTR name = (LPCWSTR)(env)->GetStringChars(pipeName, 0);
HANDLE handle =
CreateFileW(name, GENERIC_READ | GENERIC_WRITE,
0, // no sharing
NULL, // default security attributes
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED, // need overlapped for true
// asynchronous read/write access
NULL); // no template file
if (handle == INVALID_HANDLE_VALUE) {
char buf[512];
FILL_ERROR(NULL, buf);
THROW_IO("Couldn't open file %ws (%s)", name, buf);
}
return (jlong)handle;
}
JNIEXPORT jint JNICALL
Java_com_jetbrains_cef_remote_WindowsPipe_ConnectNamedPipe(
JNIEnv *env, jclass clazz, jlong handlePointer,
jlong overlappedPointer
) {
jboolean result = ConnectNamedPipe((HANDLE)handlePointer, (LPOVERLAPPED)overlappedPointer);
return result ? -1 : (jint)GetLastError();
}
JNIEXPORT jboolean JNICALL
Java_com_jetbrains_cef_remote_WindowsPipe_DisconnectNamedPipe(
JNIEnv *env, jclass clazz, jlong handlePointer
) {
return DisconnectNamedPipe((HANDLE)handlePointer);
}
JNIEXPORT jint JNICALL
Java_com_jetbrains_cef_remote_WindowsPipe_read(
JNIEnv *env, jclass clazz, jlong waitable, jlong hFile,
jbyteArray buffer, jint offset, jint length
) {
HANDLE handle = (HANDLE)hFile;
OVERLAPPED olap = {0};
olap.hEvent = (HANDLE)waitable;
std::vector<unsigned char> readBuf(length);
DWORD bytes_read = 0;
BOOL immediate = ReadFile(handle, readBuf.data(), length, &bytes_read, &olap);
if (!immediate) {
if (GetLastError() != ERROR_IO_PENDING) {
char buf[256];
FILL_ERROR("ReadFile() failed: %s (error code %ld)", buf);
THROW_IO(NULL, buf);
return bytes_read;
}
}
if (!GetOverlappedResult(handle, &olap, &bytes_read, TRUE)) {
char buf[256];
FILL_ERROR("GetOverlappedResult() failed for read operation: %s (error code %ld)", buf);
THROW_IO(NULL, buf);
return bytes_read;
}
(env)->SetByteArrayRegion(buffer, offset, bytes_read, (const jbyte *)readBuf.data());
return bytes_read;
}
JNIEXPORT void JNICALL
Java_com_jetbrains_cef_remote_WindowsPipe_write(
JNIEnv *env, jclass clazz, jlong waitable, jlong hHandle,
jbyteArray buffer, jint offset, jint length
) {
HANDLE handle = (HANDLE)hHandle;
OVERLAPPED olap = {0};
olap.hEvent = (HANDLE)waitable;
jbyte *bytes = (env)->GetByteArrayElements(buffer, 0);
BOOL immediate =
WriteFile(handle, bytes + (DWORD)offset, (DWORD)length, NULL, &olap);
if (!immediate) {
if (GetLastError() != ERROR_IO_PENDING) {
char buf[256];
FILL_ERROR("WriteFile() failed: %s (error code %ld)", buf);
THROW_IO(NULL, buf);
}
}
DWORD bytes_written = 0;
if (!GetOverlappedResult(handle, &olap, &bytes_written, TRUE)) {
char buf[256];
FILL_ERROR("GetOverlappedResult() failed for write operation: %s (error code %ld)", buf);
THROW_IO(NULL, buf);
}
if (bytes_written != (DWORD)length) {
char buf[256];
snprintf(buf, 256,
"WriteFile() wrote less bytes than requested: expected %d bytes, "
"but wrote %ld bytes",
length, bytes_written);
THROW_IO(NULL, buf);
}
(env)->ReleaseByteArrayElements(buffer, bytes, JNI_ABORT);
}
JNIEXPORT jboolean JNICALL
Java_com_jetbrains_cef_remote_WindowsPipe_CloseHandle(
JNIEnv *env, jclass clazz, jlong handlePointer
) {
return CloseHandle((HANDLE)handlePointer);
}
JNIEXPORT jboolean JNICALL
Java_com_jetbrains_cef_remote_WindowsPipe_GetOverlappedResult(
JNIEnv *env, jclass clazz, jlong handlePointer,
jlong overlappedPointer
) {
DWORD len = 0;
return GetOverlappedResult((HANDLE)handlePointer,
(LPOVERLAPPED)overlappedPointer, &len, TRUE);
}
JNIEXPORT jlong JNICALL
Java_com_jetbrains_cef_remote_WindowsPipe_CreateEvent(
JNIEnv *env, jclass clazz, jboolean manualReset,
jboolean initialState, jstring lpName
) {
LPCWSTR name = lpName ? (LPCWSTR)(env)->GetStringChars(lpName, 0) : NULL;
HANDLE handle = CreateEventW(NULL, manualReset, initialState, name);
if (handle == INVALID_HANDLE_VALUE) {
char buf[512];
FILL_ERROR(NULL, buf);
THROW_IO("Couldn't create event %ws (%s)", name, buf);
}
return (jlong)handle;
}
JNIEXPORT jint JNICALL
Java_com_jetbrains_cef_remote_WindowsPipe_GetLastError(
JNIEnv *env, jclass clazz
) {
return GetLastError();
}
JNIEXPORT jboolean JNICALL
Java_com_jetbrains_cef_remote_WindowsPipe_FlushFileBuffers(
JNIEnv *env, jclass clazz, jlong handlePointer
) {
return FlushFileBuffers((HANDLE)handlePointer);
}
JNIEXPORT jlong JNICALL
Java_com_jetbrains_cef_remote_WindowsPipe_NewOverlapped(
JNIEnv *env, jclass clazz, jlong handlePointer
) {
HANDLE handle = (HANDLE)handlePointer;
LPOVERLAPPED op =
(LPOVERLAPPED)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(OVERLAPPED));
op->hEvent = handle;
return (jlong)op;
}
JNIEXPORT void JNICALL
Java_com_jetbrains_cef_remote_WindowsPipe_DeleteOverlapped(
JNIEnv *env, jclass clazz, jlong overlappedPointer
) {
HeapFree(GetProcessHeap(), 0, (void *)overlappedPointer);
}
JNIEXPORT jint JNICALL
Java_com_jetbrains_cef_remote_WindowsPipe_ERROR_1IO_1PENDING(
JNIEnv *env, jclass clazz) {
return ERROR_IO_PENDING;
};
JNIEXPORT jint JNICALL
Java_com_jetbrains_cef_remote_WindowsPipe_ERROR_1NO_1DATA(
JNIEnv *env, jclass clazz) {
return ERROR_NO_DATA;
}
JNIEXPORT jint JNICALL
Java_com_jetbrains_cef_remote_WindowsPipe_ERROR_1PIPE_1CONNECTED(
JNIEnv *env, jclass clazz) {
return ERROR_PIPE_CONNECTED;
}
JNIEXPORT jint JNICALL
Java_com_jetbrains_cef_remote_WindowsPipe_FILE_1ALL_1ACCESS(
JNIEnv *env, jclass clazz) {
return FILE_ALL_ACCESS;
}
JNIEXPORT jint JNICALL
Java_com_jetbrains_cef_remote_WindowsPipe_FILE_1FLAG_1FIRST_1PIPE_1INSTANCE(
JNIEnv *env, jclass clazz) {
return FILE_FLAG_FIRST_PIPE_INSTANCE;
}
JNIEXPORT jint JNICALL
Java_com_jetbrains_cef_remote_WindowsPipe_FILE_1FLAG_1OVERLAPPED(
JNIEnv *env, jclass clazz) {
return FILE_FLAG_OVERLAPPED;
}
JNIEXPORT jint JNICALL
Java_com_jetbrains_cef_remote_WindowsPipe_FILE_1GENERIC_1READ(
JNIEnv *env, jclass clazz) {
return FILE_GENERIC_READ;
}
JNIEXPORT jint JNICALL
Java_com_jetbrains_cef_remote_WindowsPipe_GENERIC_1READ(
JNIEnv *env, jclass clazz) {
return GENERIC_READ;
}
JNIEXPORT jint JNICALL
Java_com_jetbrains_cef_remote_WindowsPipe_GENERIC_1WRITE(
JNIEnv *env, jclass clazz) {
return GENERIC_WRITE;
}
JNIEXPORT jint JNICALL
Java_com_jetbrains_cef_remote_WindowsPipe_PIPE_1ACCESS_1DUPLEX(
JNIEnv *env, jclass clazz) {
return PIPE_ACCESS_DUPLEX;
}
JNIEXPORT jobjectArray JNICALL
Java_com_jetbrains_cef_remote_WindowsPipe_findPipes(JNIEnv *env, jclass clazz, jstring jFileName) {
std::string fileName = "*";
const char* strFileName = env->GetStringUTFChars(jFileName, nullptr);
if (strFileName)
fileName.assign(strFileName);
env->ReleaseStringUTFChars(jFileName, strFileName);
WIN32_FIND_DATA data;
std::string lpFileName = "\\\\.\\pipe\\" + fileName;
HANDLE hFind = FindFirstFile(lpFileName.c_str(), &data);
if (hFind == INVALID_HANDLE_VALUE)
return nullptr;
std::vector<std::string> pipes;
do {
pipes.push_back(std::string(data.cFileName));
} while (FindNextFile(hFind, &data));
FindClose(hFind);
jobjectArray ret = (jobjectArray)env->NewObjectArray(pipes.size(),
env->FindClass("java/lang/String"),
env->NewStringUTF(""));
int c = 0;
for(auto& pipe: pipes)
env->SetObjectArrayElement(ret,c++,env->NewStringUTF(pipe.c_str()));
return ret;
}
#ifdef __cplusplus
}
#endif