Skip to content

Instantly share code, notes, and snippets.

@mgood7123
Created December 1, 2022 05:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mgood7123/0e38f9aed187cbbeedf734979a550bdf to your computer and use it in GitHub Desktop.
Save mgood7123/0e38f9aed187cbbeedf734979a550bdf to your computer and use it in GitHub Desktop.
#if _WIN32
int
wl_connection_flush(struct wl_connection *connection)
{
struct iovec iov[2];
int len = 0, count;
size_t clen;
uint32_t tail;
if (!connection->want_flush)
return 0;
tail = connection->out.tail;
uid_t uid = 0; gid_t gid = 0; pid_t pid = 0;
struct wl_ring_buffer * buffer = &connection->fds_out;
struct RING_BUFFER_FD_STORAGE s = {0};
RING_BUFFER_INIT_STORAGE(buffer, s);
do {
len = send(connection->fd, s.len, sizeof(size_t), 0);
} while (len == SOCKET_ERROR && WSAGetLastError() == WSAEINTR);
if (s.len > 0) {
wl_os_socket_peercred(connection->fd, &uid, &gid, &pid);
}
if (s.len > 0) {
// send fd's first
size_t handle_array_item_size = sizeof(FD_HANDLE_T);
size_t handle_array_bytes = handle_array_item_size * s.len;
FD_HANDLE_T * handle_array = zalloc(handle_array_bytes);
FD_HANDLE_T * handle_array_start = handle_array;
int handle_count = 0;
size_t socket_array_item_size = sizeof(WSAPROTOCOL_INFO);
size_t socket_array_bytes = socket_array_item_size * s.len;
WSAPROTOCOL_INFO * socket_array = zalloc(socket_array_bytes);
WSAPROTOCOL_INFO * socket_array_start = socket_array;
int socket_count = 0;
for (FD_HANDLE_T * fd = RING_BUFFER_GET_NEXT_FD(s); fd != NULL; fd = RING_BUFFER_GET_NEXT_FD(s)) {
if (FD_HANDLE_IS_SOCKET(*fd)) {
if (WSADuplicateSocket(*fd, pid, socket_array_start) == SOCKET_ERROR) {
wl_log("WSADuplicateSocket(): failed. Error = %d\n", WSAGetLastError());
continue;
}
socket_array_start += socket_array_item_size;
socket_count++;
} else {
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
if (!DuplicateHandle(
GetCurrentProcess(),
*fd,
hProcess,
handle_array_start,
DUPLICATE_SAME_ACCESS,
FALSE,
DUPLICATE_SAME_ACCESS
)) {
wl_log("DuplicateHandle(): failed. Error = %d\n", GetLastError());
CloseHandle(hProcess);
continue;
}
handle_array_start += handle_array_item_size;
handle_count++;
CloseHandle(hProcess);
}
}
bool has[2] = { socket_count != 0, handle_count != 0};
do {
len = send(connection->fd, has, sizeof(bool)*2, 0);
} while (len == SOCKET_ERROR && WSAGetLastError() == WSAEINTR);
if (has[0]) {
size_t size = socket_array_item_size * socket_count;
do {
len = send(connection->fd, size, sizeof(size_t), 0);
} while (len == SOCKET_ERROR && WSAGetLastError() == WSAEINTR);
do {
len = send(connection->fd, socket_array, size, 0);
} while (len == SOCKET_ERROR && WSAGetLastError() == WSAEINTR);
}
if (has[1]) {
size_t size = handle_array_item_size * handle_count;
do {
len = send(connection->fd, size, sizeof(size_t), 0);
} while (len == SOCKET_ERROR && WSAGetLastError() == WSAEINTR);
do {
len = send(connection->fd, handle_array, size, 0);
} while (len == SOCKET_ERROR && WSAGetLastError() == WSAEINTR);
}
free(handle_array);
free(socket_array);
close_fds(&connection->fds_out, MAX_FDS_OUT);
}
if (len == SOCKET_ERROR)
return -1;
// send data
while (connection->out.head - connection->out.tail > 0) {
ring_buffer_get_iov(&connection->out, iov, &count);
if (len == SOCKET_ERROR)
return -1;
do {
len = send(connection->fd, iov, sizeof(iov), 0);
} while (len == SOCKET_ERROR && WSAGetLastError() == WSAEINTR);
/*
struct wl_ring_buffer * buffer = &connection->out;
do {
len = send(connection->fd, ring_buffer_size(buffer), sizeof(size_t), 0);
} while (len == SOCKET_ERROR && WSAGetLastError() == WSAEINTR);
do {
len = send(connection->fd, connection->out.data, ring_buffer_size(buffer), 0);
} while (len == SOCKET_ERROR && WSAGetLastError() == WSAEINTR);
*/
connection->out.tail += len;
}
connection->want_flush = 0;
return connection->out.head - tail;
}
int
wl_connection_read(struct wl_connection *connection)
{
struct iovec iov[2];
char cmsg[CLEN];
int len, count, ret;
if (ring_buffer_size(&connection->in) >= sizeof(connection->in.data)) {
errno = EOVERFLOW;
return -1;
}
size_t s_len;
do {
len = recv(connection->fd, &s_len, sizeof(size_t), 0);
} while (len == SOCKET_ERROR && WSAGetLastError() == WSAEINTR);
if (s_len > 0) {
bool has[2];
do {
len = recv(connection->fd, has, sizeof(bool)*2, 0);
} while (len == SOCKET_ERROR && WSAGetLastError() == WSAEINTR);
if (has[0]) {
size_t size;
do {
len = recv(connection->fd, &size, sizeof(size_t), 0);
} while (len == SOCKET_ERROR && WSAGetLastError() == WSAEINTR);
WSAPROTOCOL_INFO * socket_array = zalloc(size);
do {
len = recv(connection->fd, socket_array, size, 0);
} while (len == SOCKET_ERROR && WSAGetLastError() == WSAEINTR);
size_t size_, max, i;
int overflow = 0;
int count = size / sizeof(WSAPROTOCOL_INFO);
struct wl_ring_buffer * buffer = &connection->fds_in;
size_ = sizeof(FD_HANDLE_T) * count;
max = sizeof(buffer->data) - ring_buffer_size(buffer);
if (size > max || overflow) {
overflow = 1;
} else for (int i_ = 0; i_ < count; i_++) {
FD_HANDLE_T socket = WSASocket(
FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO,
FROM_PROTOCOL_INFO, &socket_array[i], 0, 0
);
if (ring_buffer_put(buffer, &socket, sizeof(FD_HANDLE_T)) < 0) {
free(socket_array);
return -1;
}
}
if (overflow) {
errno = EOVERFLOW;
free(socket_array);
return -1;
}
free(socket_array);
}
if (has[1]) {
size_t size;
do {
len = recv(connection->fd, &size, sizeof(size_t), 0);
} while (len == SOCKET_ERROR && WSAGetLastError() == WSAEINTR);
FD_HANDLE_T * handle_array = zalloc(size);
do {
len = recv(connection->fd, handle_array, size, 0);
} while (len == SOCKET_ERROR && WSAGetLastError() == WSAEINTR);
size_t max, i;
int overflow = 0;
struct wl_ring_buffer * buffer = &connection->fds_in;
max = sizeof(buffer->data) - ring_buffer_size(buffer);
if (size > max || overflow) {
overflow = 1;
size /= sizeof(FD_HANDLE_T);
for (i = 0; i < size; i++)
CLOSE_FD_HANDLE(handle_array[i]);
} else if (ring_buffer_put(buffer, handle_array, size) < 0) {
free(handle_array);
return -1;
}
if (overflow) {
errno = EOVERFLOW;
free(handle_array);
return -1;
}
free(handle_array);
}
}
// recieve data
ring_buffer_put_iov(&connection->in, iov, &count);
do {
len = recv(connection->fd, &iov, sizeof(iov), 0);
} while (len == SOCKET_ERROR && WSAGetLastError() == WSAEINTR);
/*
size_t ring_buf_len;
do {
len = recv(connection->fd, &ring_buf_len, sizeof(size_t), 0);
} while (len == SOCKET_ERROR && WSAGetLastError() == WSAEINTR);
RING_BUFFER_TYPE * ring_buf_data = zalloc(ring_buf_len);
do {
len = recv(connection->fd, ring_buf_data, ring_buf_len, 0);
} while (len == SOCKET_ERROR && WSAGetLastError() == WSAEINTR);
*/
if (len <= 0)
return len;
connection->in.head += len;
return wl_connection_pending_input(connection);
}
#else
static void
build_cmsg(struct wl_ring_buffer *buffer, char *data, size_t *clen)
{
struct cmsghdr *cmsg;
size_t size;
size = ring_buffer_size(buffer);
if (size > MAX_FDS_OUT * sizeof(int32_t))
size = MAX_FDS_OUT * sizeof(int32_t);
if (size > 0) {
cmsg = (struct cmsghdr *) data;
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_len = CMSG_LEN(size);
ring_buffer_copy(buffer, CMSG_DATA(cmsg), size);
*clen = cmsg->cmsg_len;
} else {
*clen = 0;
}
}
static int
decode_cmsg(struct wl_ring_buffer *buffer, struct msghdr *msg)
{
struct cmsghdr *cmsg;
size_t size, max, i;
int overflow = 0;
for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL;
cmsg = CMSG_NXTHDR(msg, cmsg)) {
if (cmsg->cmsg_level != SOL_SOCKET ||
cmsg->cmsg_type != SCM_RIGHTS)
continue;
size = cmsg->cmsg_len - CMSG_LEN(0);
max = sizeof(buffer->data) - ring_buffer_size(buffer);
if (size > max || overflow) {
overflow = 1;
size /= sizeof(int32_t);
for (i = 0; i < size; i++)
close(((int*)CMSG_DATA(cmsg))[i]);
} else if (ring_buffer_put(buffer, CMSG_DATA(cmsg), size) < 0) {
return -1;
}
}
if (overflow) {
errno = EOVERFLOW;
return -1;
}
return 0;
}
int
wl_connection_flush(struct wl_connection *connection)
{
struct iovec iov[2];
struct msghdr msg = {0};
char cmsg[CLEN];
int len = 0, count;
size_t clen;
uint32_t tail;
if (!connection->want_flush)
return 0;
tail = connection->out.tail;
while (connection->out.head - connection->out.tail > 0) {
ring_buffer_get_iov(&connection->out, iov, &count);
build_cmsg(&connection->fds_out, cmsg, &clen);
msg.msg_iov = iov;
msg.msg_iovlen = count;
msg.msg_control = (clen > 0) ? cmsg : NULL;
msg.msg_controllen = clen;
do {
len = sendmsg(connection->fd, &msg,
MSG_NOSIGNAL | MSG_DONTWAIT);
} while (len == -1 && errno == EINTR);
if (len == -1)
return -1;
close_fds(&connection->fds_out, MAX_FDS_OUT);
connection->out.tail += len;
}
connection->want_flush = 0;
return connection->out.head - tail;
}
int
wl_connection_read(struct wl_connection *connection)
{
struct iovec iov[2];
struct msghdr msg;
char cmsg[CLEN];
int len, count, ret;
if (ring_buffer_size(&connection->in) >= sizeof(connection->in.data)) {
errno = EOVERFLOW;
return -1;
}
ring_buffer_put_iov(&connection->in, iov, &count);
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = iov;
msg.msg_iovlen = count;
msg.msg_control = cmsg;
msg.msg_controllen = sizeof cmsg;
msg.msg_flags = 0;
do {
len = wl_os_recvmsg_cloexec(connection->fd, &msg, MSG_DONTWAIT);
} while (len < 0 && errno == EINTR);
if (len <= 0)
return len;
ret = decode_cmsg(&connection->fds_in, &msg);
if (ret)
return -1;
connection->in.head += len;
return wl_connection_pending_input(connection);
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment