Skip to content

Instantly share code, notes, and snippets.

@mgood7123
Last active December 13, 2022 00:55
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/0eaca5cdde08893a0e138852df693f95 to your computer and use it in GitHub Desktop.
Save mgood7123/0eaca5cdde08893a0e138852df693f95 to your computer and use it in GitHub Desktop.
#define COPY_TO_BUF(buf, obj_type, obj) memcpy(buf, obj, sizeof(obj_type)); buf += sizeof(obj_type)
#define COPY_FROM_BUF(buf, obj_type, obj) memcpy(obj, buf, sizeof(obj_type)); buf += sizeof(obj_type)
#ifdef _WIN32
void store_buffer_socket(void** buffer, size_t * buffer_len, wl_miniobj * obj) {
*buffer_len = sizeof(uint16_t)*2;
*buffer_len += sizeof(WSAPROTOCOL_INFO);
*buffer = malloc(*buffer_len);
char * tmp = *buffer;
COPY_TO_BUF(tmp, uint16_t, &obj->type);
COPY_TO_BUF(tmp, uint16_t, &obj->version);
COPY_TO_BUF(tmp, WSAPROTOCOL_INFO, (WSAPROTOCOL_INFO*)obj->data);
}
void store_buffer_handle(void** buffer, size_t * buffer_len, wl_miniobj * obj) {
*buffer_len = sizeof(uint16_t)*2;
*buffer_len += sizeof(HANDLE);
*buffer = malloc(*buffer_len);
char * tmp = *buffer;
COPY_TO_BUF(tmp, uint16_t, &obj->type);
COPY_TO_BUF(tmp, uint16_t, &obj->version);
COPY_TO_BUF(tmp, HANDLE, (HANDLE*)obj->data);
}
#else
void store_buffer_fd(void** buffer, size_t * buffer_len, wl_miniobj * obj) {
*buffer_len = sizeof(uint16_t)*2;
*buffer_len += sizeof(uint32_t);
*buffer = malloc(*buffer_len);
char * tmp = *buffer;
COPY_TO_BUF(tmp, uint16_t, &obj->type);
COPY_TO_BUF(tmp, uint16_t, &obj->version);
COPY_TO_BUF(tmp, uint32_t, &obj->data);
}
#endif
void wl_posix_fd_transfer__add(wl_posix_fd_struct* s, wl_miniobj* obj) {
if (s->first == NULL) {
s->first = malloc(sizeof(wl_posix_fd_linked_list));
s->last = s->first;
} else {
s->last->next = malloc(sizeof(wl_posix_fd_linked_list));
s->last = s->last->next;
}
#ifdef _WIN32
if (obj->type == wl_posix_type_socket) {
store_buffer_socket(&s->last->buffer, &s->last->buffer_len, obj);
} else {
store_buffer_handle(&s->last->buffer, &s->last->buffer_len, obj);
}
#else
store_buffer_fd(&s->last->buffer, &s->last->buffer_len, obj);
#endif
s->count++;
}
wl_posix_fd_struct * wl_posix_fd_transfer__prepare(void) {
wl_posix_fd_struct * data = (wl_posix_fd_struct *) calloc(1, sizeof(wl_posix_fd_struct));
data->data = (wl_posix_transfer*) calloc(1, sizeof(wl_posix_transfer));
wl_posix_transfer* transfer = (wl_posix_transfer*) data->data;
}
#ifndef _WIN32
#define SEND_MSG(fd, msg, data) \
do { \
len = sendmsg(fd, msg, MSG_NOSIGNAL | MSG_DONTWAIT); \
} while (len == -1 && errno == EINTR); \
free(data); \
if (len == -1) { \
return -1; \
}
#define RECV_MSG(fd, msg) \
do { \
len = recvmsg(fd, msg, MSG_NOSIGNAL | MSG_DONTWAIT); \
} while (len == -1 && errno == EINTR); \
if (len == -1) { \
return -1; \
}
#define SEND_FD(fd, fd_, iov, iov_len, CLEN) \
{ \
struct msghdr msg = {0}; \
size_t clen; \
char * data = malloc(sizeof(char)*CLEN); \
struct cmsghdr *cmsg = (struct cmsghdr *) data; \
cmsg->cmsg_level = SOL_SOCKET; \
cmsg->cmsg_type = SCM_RIGHTS; \
memcpy(CMSG_DATA(cmsg), fd_, sizeof(uint32_t)); \
cmsg->cmsg_len = CMSG_LEN(1); \
clen = cmsg->cmsg_len; \
msg.msg_iov = iov; \
msg.msg_iovlen = iov_len; \
msg.msg_control = (clen > 0) ? cmsg : NULL; \
msg.msg_controllen = clen; \
SEND_MSG(fd, msg, data); \
}
#define RECV_FD(fd, fd_) \
{
struct msghdr msg = {0}; \
RECV_MSG(fd, &msg); \
struct cmsghdr *cmsg; \
size_t size; \
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); \
memcpy(fd_, CMSG_DATA(cmsg), sizeof(uint32_t)); \
break; /* we only get 1 fd */
}
}
#endif
int wl_posix_fd_transfer__send(wl_posix_fd_struct* s, wl_miniobj* socket, struct iovec* iov, int iov_len, size_t CLEN) {
int len = 0;
wl_posix_transfer* transfer = s->data;
#ifdef _WIN32
if (!transfer->sent_iovec) {
if (!transfer->have_count) {
transfer->iovec_count = iov_len;
transfer->iovec_current_count = iov_len;
transfer->have_count = true;
}
if (!transfer->sent_iov_count) {
WL_SEND_DATA(socket, &iov_len, sizeof(int));
transfer->sent_iov_count = true;
}
while(transfer->iovec_current_count != 0) {
if (!transfer->sent_iov_base) {
WL_SEND_DATA(socket, iov[transfer->iovec_current_count].iov_base, iov[transfer->iovec_current_count].iov_len);
transfer->sent_iov_base = true;
}
transfer->iovec_current_count--;
transfer->sent_iov_base = false;
}
transfer->sent_iovec = true;
}
if (!transfer->sent_count) {
WL_SEND_DATA(socket, &s->count, sizeof(int));
transfer->sent_count = true;
transfer->current = s->first;
}
WL_SEND_DATA(socket, transfer->current->buffer, transfer->current->buffer_len);
#else
int fd = wl_posix_get_socket(socket);
if (!transfer->sent_count) {
WL_SEND_DATA(fd, &s->count, sizeof(int));
transfer->sent_count = true;
transfer->current = s->first;
}
uint16_t type, version;
uint32_t handle;
COPY_FROM_BUF(transfer->current->buffer, uint16_t, &type);
COPY_FROM_BUF(transfer->current->buffer, uint16_t, &version);
COPY_FROM_BUF(transfer->current->buffer, uint32_t, handle);
WL_SEND_DATA(fd, &type, sizeof(uint16_t));
WL_SEND_DATA(fd, &version, sizeof(uint16_t));
SEND_FD(fd, handle, iov, iov_len, CLEN);
#endif
transfer->current = transfer->current->next;
transfer->complete = transfer->current == NULL;
return len;
}
int wl_posix_fd_transfer__recv(wl_posix_fd_struct* s, wl_miniobj* socket, struct iovec* iov, int iov_len, size_t CLEN) {
int len = 0;
wl_posix_transfer* transfer = s->data;
#ifdef _WIN32
if (!transfer->recv_iovec) {
if (!transfer->recv_iov_count) {
WL_RECV_DATA(socket, &transfer->iovec_count, sizeof(int));
transfer->iovec_current_count = transfer->iovec_count;
transfer->recv_iov_count = true;
if (iov_len != transfer->iovec_count) {
printf("iovec obtained possible incorrect len: given to function = %d, obtained from socket: %d\n", iov_len, transfer->iovec_count);
}
}
while(transfer->iovec_current_count != 0) {
if (!transfer->recv_iov_base) {
WL_RECV_DATA(socket, iov[transfer->iovec_current_count].iov_base, iov[transfer->iovec_current_count].iov_len);
transfer->recv_iov_base = true;
}
transfer->iovec_current_count--;
transfer->recv_iov_base = false;
}
transfer->recv_iovec = true;
}
if (!transfer->recv_count) {
WL_RECV_DATA(socket, &transfer->count, sizeof(int));
transfer->recv_count = true;
transfer->buf = malloc(sizeof(wl_miniobj)*transfer->count);
transfer->buf_start = transfer->buf;
}
wl_miniobj obj;
WL_RECV_DATA(socket, &obj.type, sizeof(uint16_t));
WL_RECV_DATA(socket, &obj.version, sizeof(uint16_t));
if (obj.type == wl_posix_type_socket) {
WSAPROTOCOL_INFO p;
WL_RECV_DATA(socket, &p, sizeof(WSAPROTOCOL_INFO));
obj.data = (SOCKET) WSASocket(
FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO,
FROM_PROTOCOL_INFO, &p, 0, 0
);
} else {
HANDLE h = NULL;
WL_RECV_DATA(socket, &h, sizeof(HANDLE));
obj.data = (uint64_t) h;
}
COPY_TO_BUF(transfer->buf, wl_miniobj, &obj);
transfer->count--;
transfer->complete = transfer->count <= 0;
#else
int fd = wl_posix_get_socket(socket);
if (!transfer->recv_count) {
WL_RECV_DATA(fd, &transfer->count, sizeof(int));
transfer->recv_count = true;
transfer->buf = malloc(sizeof(wl_miniobj)*transfer->count);
transfer->buf_start = transfer->buf;
}
wl_miniobj obj;
WL_RECV_DATA(fd, &obj.type, sizeof(uint16_t));
WL_RECV_DATA(fd, &obj.version, sizeof(uint16_t));
uint32_t h;
RECV_FD(fd, &h);
obj.data = (uint64_t) h;
COPY_TO_BUF(transfer->buf, wl_miniobj, &obj);
transfer->count--;
transfer->complete = transfer->count <= 0;
#endif
return 0;
}
struct wl_posix_fd_linked_list {
void * buffer;
size_t buffer_len;
struct wl_posix_fd_linked_list * next;
};
typedef struct wl_posix_fd_linked_list wl_posix_fd_linked_list;
typedef struct wl_posix_transfer {
bool complete;
int iovec_current_count;
int iovec_count;
bool have_count;
// send
bool sent_iovec;
bool sent_iov_count;
bool sent_iov_base;
bool sent_count;
wl_posix_fd_linked_list * current;
// recv
bool recv_iovec;
bool recv_iov_count;
bool recv_iov_base;
bool recv_count;
int count;
wl_miniobj * buf;
char * buf_start;
} wl_posix_transfer;
typedef struct wl_posix_fd_struct {
wl_posix_fd_linked_list * first;
wl_posix_fd_linked_list * last;
wl_posix_transfer* data;
int count;
} wl_posix_fd_struct;
wl_posix_fd_struct * wl_posix_fd_transfer__prepare(void);
void wl_posix_fd_transfer__add(wl_posix_fd_struct* s, wl_miniobj* obj);
int wl_posix_fd_transfer__send(wl_posix_fd_struct* s, wl_miniobj* socket, struct iovec* iov, int iov_len, size_t CLEN);
int wl_posix_fd_transfer__recv(wl_posix_fd_struct* s, wl_miniobj* socket, struct iovec* iov, int iov_len, size_t CLEN);
void wl_posix_fd_transfer__delete(wl_posix_fd_struct* s);
#ifdef _WIN32
#define WL_SEND_DATA(socket, data, size) \
do { \
len = wl_syscall__send(socket, (char*)data, size, MSG_NOSIGNAL | MSG_DONTWAIT); \
} while (len == SOCKET_ERROR && WSAGetLastError() == WSAEINTR); \
if (len == SOCKET_ERROR) { \
return -1; \
}
#define WL_RECV_DATA(socket, data, size) \
do { \
len = wl_syscall__recv(socket, (char*)data, size, MSG_DONTWAIT); \
} while (len == SOCKET_ERROR && WSAGetLastError() == WSAEINTR); \
if (len == SOCKET_ERROR) { \
return -1; \
}
#else
#define WL_SEND_DATA(fd, data, size) \
do { \
len = send(fd, (char*)data, size, MSG_NOSIGNAL | MSG_DONTWAIT); \
} while (len == -1 && errno == EINTR); \
if (len == -1) { \
return -1; \
}
#define WL_RECV_DATA(fd, data, size) \
do { \
len = recv(fd, (char*)data, size, MSG_DONTWAIT); \
} while (len == -1 && errno == EINTR); \
if (len == -1) { \
return -1; \
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment