#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#include <CoreFoundation/CoreFoundation.h>
#include "helper_comm.h"
#include <SystemConfiguration/SCPrivate.h>
static ssize_t
readn(int ref, void *data, size_t len)
{
size_t left = len;
ssize_t n;
void *p = data;
while (left > 0) {
if ((n = read(ref, p, left)) == -1) {
if (errno != EINTR) {
return -1;
}
n = 0;
} else if (n == 0) {
break;
}
left -= n;
p += n;
}
return (len - left);
}
static ssize_t
writen(int ref, const void *data, size_t len)
{
size_t left = len;
ssize_t n;
const void *p = data;
while (left > 0) {
if ((n = write(ref, p, left)) == -1) {
if (errno != EINTR) {
return -1;
}
n = 0;
}
left -= n;
p += n;
}
return len;
}
Boolean
__SCHelper_txMessage(int fd, uint32_t msgID, CFDataRef data)
{
ssize_t n_written;
uint32_t header[2];
header[0] = msgID;
header[1] = (data != NULL) ? CFDataGetLength(data) : 0;
n_written = writen(fd, header, sizeof(header));
if (n_written != sizeof(header)) {
if ((n_written == -1) && (errno != EPIPE)) {
perror("write() failed while sending msgID");
}
return FALSE;
}
if (header[1] == 0) {
return TRUE;
}
n_written = writen(fd, CFDataGetBytePtr(data), header[1]);
if (n_written != header[1]) {
if ((n_written == -1) && (errno != EPIPE)) {
perror("write() failed while sending data");
}
return FALSE;
}
return TRUE;
}
Boolean
__SCHelper_rxMessage(int fd, uint32_t *msgID, CFDataRef *data)
{
void *bytes;
size_t n_read;
uint32_t header[2];
n_read = readn(fd, header, sizeof(header));
if (n_read != sizeof(header)) {
if (n_read == -1) {
perror("read() failed while reading msgID");
}
return FALSE;
}
if (msgID != NULL) {
*msgID = header[0];
}
if (header[1] == 0) {
if (data != NULL) {
*data = NULL;
}
return TRUE;
} else if ((int32_t)header[1] < 0) {
perror("read() failed, invalid data length");
return FALSE;
}
bytes = CFAllocatorAllocate(NULL, header[1], 0);
n_read = readn(fd, bytes, header[1]);
if (n_read != header[1]) {
if (n_read == -1) {
perror("read() failed while reading data");
}
CFAllocatorDeallocate(NULL, bytes);
return FALSE;
}
if (data != NULL) {
*data = CFDataCreateWithBytesNoCopy(NULL, bytes, header[1], NULL);
} else {
CFAllocatorDeallocate(NULL, bytes);
}
return TRUE;
}
Boolean
_SCHelperExec(int fd, uint32_t msgID, CFDataRef data, uint32_t *status, CFDataRef *reply)
{
Boolean ok;
ok = __SCHelper_txMessage(fd, msgID, data);
if (!ok) {
return FALSE;
}
if ((status == NULL) && (reply == NULL)) {
return TRUE;
}
ok = __SCHelper_rxMessage(fd, status, reply);
if (!ok) {
return FALSE;
}
return TRUE;
}