#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/errno.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <SystemConfiguration/SystemConfiguration.h>
#include <SystemConfiguration/SCPrivate.h>
#include "moh.h"
#include "moh_msg.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;
}
__private_extern__
int
MOHInit(int *ref, CFStringRef deviceName)
{
int sock;
int status;
struct sockaddr_un sun;
sock = socket(AF_LOCAL, SOCK_STREAM, 0);
bzero(&sun, sizeof(sun));
sun.sun_family = AF_LOCAL;
strncpy(sun.sun_path, MOH_PATH, sizeof(sun.sun_path));
status = connect(sock, (struct sockaddr *)&sun, sizeof(sun));
if (status == -1) {
return errno;
}
*ref = sock;
return 0;
}
__private_extern__
int
MOHDispose(int ref)
{
if (close(ref) == -1) {
return errno;
}
return 0;
}
__private_extern__
int
MOHExec(int ref,
uint32_t link,
uint32_t cmd,
void *request,
size_t requestLen,
void **reply,
size_t *replyLen)
{
struct moh_msg_hdr msg;
char *buf = NULL;
ssize_t n;
bzero(&msg, sizeof(msg));
msg.m_type = cmd;
msg.m_link = link;
msg.m_len = ((request != NULL) && (requestLen > 0)) ? (uint32_t)requestLen : 0;
n = writen(ref, &msg, sizeof(msg));
if (n == -1) {
SC_log(LOG_INFO, "writen() failed: %s", strerror(errno));
return errno;
} else if (n != sizeof(msg)) {
SC_log(LOG_INFO, "writen() failed: wrote=%ld", n);
return -1;
}
if ((request != NULL) && (requestLen > 0)) {
n = writen(ref, request, requestLen);
if (n == -1) {
SC_log(LOG_INFO, "writen() failed: %s", strerror(errno));
return errno;
} else if (n != (ssize_t)requestLen) {
SC_log(LOG_INFO, "writen() failed: wrote=%ld", n);
return -1;
}
}
n = readn(ref, &msg, sizeof(msg));
if (n == -1) {
SC_log(LOG_INFO, "readn() failed: error=%s", strerror(errno));
return errno;
} else if (n != sizeof(msg)) {
SC_log(LOG_INFO, "readn() failed: insufficent data, read=%ld", n);
return -1;
}
if (msg.m_len) {
buf = CFAllocatorAllocate(NULL, msg.m_len, 0);
if (buf) {
n = readn(ref, buf, msg.m_len);
if (n == -1) {
SC_log(LOG_INFO, "readn() failed: error=%s", strerror(errno));
CFAllocatorDeallocate(NULL, buf);
return errno;
} else if (n != (ssize_t)msg.m_len) {
SC_log(LOG_INFO, "readn() failed: insufficent data, read=%ld", n);
CFAllocatorDeallocate(NULL, buf);
return -1;
}
}
}
if (reply && replyLen) {
*reply = buf;
*replyLen = msg.m_len;
} else if (buf) {
CFAllocatorDeallocate(NULL, buf);
}
return msg.m_result;
}