Skip to content
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

More changes for windows. #16

Merged
merged 1 commit into from
Dec 23, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 119 additions & 1 deletion common/src/jni/main/cpp/org_conscrypt_NativeCrypto.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@
#include <winsock2.h>
#else
#include <arpa/inet.h>
#include <poll.h>
#endif

#include <fcntl.h>
#include <poll.h>
#include <pthread.h>
#include <sys/socket.h>
#include <sys/syscall.h>
Expand Down Expand Up @@ -6434,6 +6434,123 @@ class AppData {
}
};

#ifdef _WIN32

/**
* Dark magic helper function that checks, for a given SSL session, whether it
* can SSL_read() or SSL_write() without blocking. Takes into account any
* concurrent attempts to close the SSLSocket from the Java side. This is
* needed to get rid of the hangs that occur when thread #1 closes the SSLSocket
* while thread #2 is sitting in a blocking read or write. The type argument
* specifies whether we are waiting for readability or writability. It expects
* to be passed either SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE, since we
* only need to wait in case one of these problems occurs.
*
* @param env
* @param type Either SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE
* @param fdObject The FileDescriptor, since appData->fileDescriptor should be NULL
* @param appData The application data structure with mutex info etc.
* @param timeout_millis The timeout value for select call, with the special value
* 0 meaning no timeout at all (wait indefinitely). Note: This is
* the Java semantics of the timeout value, not the usual
* select() semantics.
* @return The result of the inner select() call,
* THROW_SOCKETEXCEPTION if a SocketException was thrown, -1 on
* additional errors
*/
static int sslSelect(JNIEnv* env, int type, jobject fdObject, AppData* appData, int timeout_millis) {
// This loop is an expanded version of the NET_FAILURE_RETRY
// macro. It cannot simply be used in this case because select
// cannot be restarted without recreating the fd_sets and timeout
// structure.
int result;
fd_set rfds;
fd_set wfds;
do {
NetFd fd(env, fdObject);
if (fd.isClosed()) {
result = THROWN_EXCEPTION;
break;
}
int intFd = fd.get();
JNI_TRACE("sslSelect type=%s fd=%d appData=%p timeout_millis=%d",
(type == SSL_ERROR_WANT_READ) ? "READ" : "WRITE", intFd, appData, timeout_millis);

FD_ZERO(&rfds);
FD_ZERO(&wfds);

if (type == SSL_ERROR_WANT_READ) {
FD_SET(intFd, &rfds);
} else {
FD_SET(intFd, &wfds);
}

FD_SET(appData->fdsEmergency[0], &rfds);

int maxFd = (intFd > appData->fdsEmergency[0]) ? intFd : appData->fdsEmergency[0];

// Build a struct for the timeout data if we actually want a timeout.
timeval tv;
timeval* ptv;
if (timeout_millis > 0) {
tv.tv_sec = timeout_millis / 1000;
tv.tv_usec = (timeout_millis % 1000) * 1000;
ptv = &tv;
} else {
ptv = NULL;
}

#ifndef CONSCRYPT_UNBUNDLED
AsynchronousCloseMonitor monitor(intFd);
#else
CompatibilityCloseMonitor monitor(intFd);
#endif
result = select(maxFd + 1, &rfds, &wfds, NULL, ptv);
JNI_TRACE("sslSelect %s fd=%d appData=%p timeout_millis=%d => %d",
(type == SSL_ERROR_WANT_READ) ? "READ" : "WRITE",
fd.get(), appData, timeout_millis, result);
if (result == -1) {
if (fd.isClosed()) {
result = THROWN_EXCEPTION;
break;
}
if (errno != EINTR) {
break;
}
}
} while (result == -1);

if (MUTEX_LOCK(appData->mutex) == -1) {
return -1;
}

if (result > 0) {
// We have been woken up by a token in the emergency pipe. We
// can't be sure the token is still in the pipe at this point
// because it could have already been read by the thread that
// originally wrote it if it entered sslSelect and acquired
// the mutex before we did. Thus we cannot safely read from
// the pipe in a blocking way (so we make the pipe
// non-blocking at creation).
if (FD_ISSET(appData->fdsEmergency[0], &rfds)) {
char token;
do {
(void) read(appData->fdsEmergency[0], &token, 1);
} while (errno == EINTR);
}
}

// Tell the world that there is now one thread less waiting for the
// underlying network.
appData->waitingThreads--;

MUTEX_UNLOCK(appData->mutex);

return result;
}

#else // !defined(_WIN32)

/**
* Dark magic helper function that checks, for a given SSL session, whether it
* can SSL_read() or SSL_write() without blocking. Takes into account any
Expand Down Expand Up @@ -6531,6 +6648,7 @@ static int sslSelect(JNIEnv* env, int type, jobject fdObject, AppData* appData,

return result;
}
#endif // !defined(_WIN32)

/**
* Helper function that wakes up a thread blocked in select(), in case there is
Expand Down
37 changes: 37 additions & 0 deletions common/src/jni/unbundled/cpp/JNIHelp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,43 @@
#include <stdlib.h>
#include <assert.h>

#ifdef _WIN32
// Windows uses strerror_s instead of strerror_r.
#define strerror_r(errno,buf,len) strerror_s(buf,len,errno)

// Windows doesn't define this either *sigh*...
int vasprintf(char **ret, const char *format, va_list args)
{
va_list copy;
va_copy(copy, args);

*ret = NULL;

int count = vsnprintf(NULL, 0, format, args);
if (count >= 0)
{
char* buffer = (char*) malloc(count + 1);
if (buffer == NULL)
count = -1;
else if ((count = vsnprintf(buffer, count + 1, format, copy)) < 0)
free(buffer);
else
*ret = buffer;
}
va_end(copy); // Each va_start() or va_copy() needs a va_end()

return count;
}

int asprintf(char **strp, const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
int r = vasprintf(strp, fmt, ap);
va_end(ap);
return r;
}
#endif

/**
* Equivalent to ScopedLocalRef, but slightly more powerful.
*/
Expand Down
7 changes: 6 additions & 1 deletion common/src/jni/unbundled/include/JNIHelp.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,12 @@
#include "jni.h"

#include <errno.h>
#include <unistd.h>

#ifdef _WIN32
#include <io.h>
#else
#include <unistd.h>
#endif

#ifndef NELEM
# define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
Expand Down