#include "ioSock.h"
#include <errno.h>
#include <stdio.h>
#include <Security/SecBase.h>
#include <unistd.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <Security/SecBase.h>
#include <time.h>
#include <strings.h>
#define SSL_OT_DEBUG 1
#define SSL_OT_ERRLOG 1
#define SSL_OT_IO_TRACE 0
#define SSL_OT_IO_TRACE_NZ 1
#define SSL_OT_IO_PAUSE 0
#define SSL_OT_DOT 1
#define SSL_OT_IO_DUMP 0
#define SSL_OT_IO_DUMP_SIZE 256
#define SSL_DISPL_WOULD_BLOCK 0
#if SSL_OT_DEBUG
#define dprintf(s) printf s
#else
#define dprintf(s)
#endif
#if SSL_OT_ERRLOG
#define eprintf(s) printf s
#else
#define eprintf(s)
#endif
#if SSL_OT_IO_TRACE
static void tprintf(
const char *str,
UInt32 req,
UInt32 act,
const UInt8 *buf)
{
#if SSL_OT_IO_TRACE_NZ
if(act == 0) {
return;
}
#endif
printf("%s(%u): moved (%u) bytes\n", str, (unsigned)req, (unsigned)act);
#if SSL_OT_IO_DUMP
{
unsigned i;
for(i=0; i<act; i++) {
printf("%02X ", buf[i]);
if(i >= (SSL_OT_IO_DUMP_SIZE - 1)) {
break;
}
}
printf("\n");
}
#endif
#if SSL_OT_IO_PAUSE
{
char instr[20];
printf("CR to continue: ");
gets(instr);
}
#endif
}
#else
#define tprintf(str, req, act, buf)
#endif
#if SSL_OT_DOT
static time_t lastTime = (time_t)0;
#define TIME_INTERVAL 3
static void outputDot()
{
time_t thisTime = time(0);
if((thisTime - lastTime) >= TIME_INTERVAL) {
printf("."); fflush(stdout);
lastTime = thisTime;
}
}
#else
#define outputDot()
#endif
void initSslOt(void)
{
}
#define GETHOST_RETRIES 3
OSStatus MakeServerConnection(
const char *hostName,
int port,
int nonBlocking, otSocket *socketNo, PeerSpec *peer) {
struct sockaddr_in addr;
struct hostent *ent = NULL;
struct in_addr host;
int sock = 0;
*socketNo = 0;
if (hostName[0] >= '0' && hostName[0] <= '9')
{
host.s_addr = inet_addr(hostName);
}
else {
unsigned dex;
for(dex=0; dex<GETHOST_RETRIES; dex++) {
if(dex != 0) {
printf("\n...retrying gethostbyname(%s)", hostName);
}
ent = gethostbyname(hostName);
if(ent != NULL) {
break;
}
}
if(ent == NULL) {
printf("\n***gethostbyname(%s) returned: %s\n", hostName, hstrerror(h_errno));
return errSecIO;
}
memcpy(&host, ent->h_addr, sizeof(struct in_addr));
}
sock = socket(AF_INET, SOCK_STREAM, 0);
addr.sin_addr = host;
addr.sin_port = htons((u_short)port);
addr.sin_family = AF_INET;
if (connect(sock, (struct sockaddr *) &addr, sizeof(struct sockaddr_in)) != 0)
{
perror("connect returned error");
return errSecIO;
}
if(nonBlocking) {
int rtn = fcntl(sock, F_SETFL, O_NONBLOCK);
if(rtn == -1) {
perror("fctnl(O_NONBLOCK)");
return errSecIO;
}
}
peer->ipAddr = addr.sin_addr.s_addr;
peer->port = htons((u_short)port);
*socketNo = (otSocket)sock;
return errSecSuccess;
}
OSStatus ListenForClients(
int port,
int nonBlocking, otSocket *socketNo) {
struct sockaddr_in addr;
struct hostent *ent;
int len;
int sock;
sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock < 1) {
perror("socket");
return errSecIO;
}
int reuse = 1;
int err = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
if (err != 0) {
perror("setsockopt");
return err;
}
ent = gethostbyname("localhost");
if (!ent) {
perror("gethostbyname");
return errSecIO;
}
memcpy(&addr.sin_addr, ent->h_addr, sizeof(struct in_addr));
addr.sin_port = htons((u_short)port);
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_family = AF_INET;
len = sizeof(struct sockaddr_in);
if (bind(sock, (struct sockaddr *) &addr, len)) {
int theErr = errno;
perror("bind");
if(theErr == EADDRINUSE) {
return errSecOpWr;
}
else {
return errSecIO;
}
}
if(nonBlocking) {
int rtn = fcntl(sock, F_SETFL, O_NONBLOCK);
if(rtn == -1) {
perror("fctnl(O_NONBLOCK)");
return errSecIO;
}
}
for(;;) {
int rtn = listen(sock, 1);
switch(rtn) {
case 0:
*socketNo = (otSocket)sock;
rtn = errSecSuccess;
break;
case EWOULDBLOCK:
continue;
default:
perror("listen");
rtn = errSecIO;
break;
}
return rtn;
}
}
#define FORCE_ACCEPT_PEER_PORT_ZERO 1
OSStatus AcceptClientConnection(
otSocket listenSock, otSocket *acceptSock, PeerSpec *peer) {
struct sockaddr_in addr;
int sock;
socklen_t len;
len = sizeof(struct sockaddr_in);
do {
sock = accept((int)listenSock, (struct sockaddr *) &addr, &len);
if (sock < 0) {
if(errno == EAGAIN) {
continue;
}
else {
perror("accept");
return errSecIO;
}
}
else {
break;
}
} while(1);
*acceptSock = (otSocket)sock;
peer->ipAddr = addr.sin_addr.s_addr;
#if FORCE_ACCEPT_PEER_PORT_ZERO
peer->port = 0;
#else
peer->port = ntohs(addr.sin_port);
#endif
return errSecSuccess;
}
void endpointShutdown(
otSocket sock)
{
close((int)sock);
}
OSStatus SocketRead(
SSLConnectionRef connection,
void *data,
size_t *dataLength)
{
size_t bytesToGo = *dataLength;
size_t initLen = bytesToGo;
UInt8 *currData = (UInt8 *)data;
int sock = (int)((long)connection);
OSStatus rtn = errSecSuccess;
size_t bytesRead = 0;
ssize_t rrtn;
*dataLength = 0;
for(;;) {
errno = -555;
rrtn = recv(sock, currData, bytesToGo, 0);
if (rrtn <= 0) {
if(rrtn == 0) {
rtn = errSSLClosedGraceful;
break;
}
int theErr = errno;
switch(theErr) {
case ENOENT:
dprintf(("SocketRead RETRYING on ENOENT, rrtn %d\n",
(int)rrtn));
rtn = errSecIO;
break;
case ECONNRESET:
rtn = errSSLClosedAbort;
break;
case EAGAIN:
rtn = errSSLWouldBlock;
break;
default:
dprintf(("SocketRead: read(%u) error %d, rrtn %d\n",
(unsigned)bytesToGo, theErr, (int)rrtn));
rtn = errSecIO;
break;
}
break;
}
bytesRead = rrtn;
bytesToGo -= bytesRead;
currData += bytesRead;
if(bytesToGo == 0) {
break;
}
}
*dataLength = initLen - bytesToGo;
tprintf("SocketRead", initLen, *dataLength, (UInt8 *)data);
#if SSL_OT_DOT || (SSL_OT_DEBUG && !SSL_OT_IO_TRACE)
if((rtn == 0) && (*dataLength == 0)) {
outputDot();
}
#endif
#if SSL_DISPL_WOULD_BLOCK
if(rtn == errSSLWouldBlock) {
printf("."); fflush(stdout);
}
#endif
return rtn;
}
int oneAtATime = 0;
OSStatus SocketWrite(
SSLConnectionRef connection,
const void *data,
size_t *dataLength)
{
size_t bytesSent = 0;
int sock = (int)((long)connection);
size_t length;
size_t dataLen = *dataLength;
const UInt8 *dataPtr = (UInt8 *)data;
OSStatus ortn;
if(oneAtATime && (*dataLength > 1)) {
size_t i;
size_t outLen;
size_t thisMove;
outLen = 0;
for(i=0; i<dataLen; i++) {
thisMove = 1;
ortn = SocketWrite(connection, dataPtr, &thisMove);
outLen += thisMove;
dataPtr++;
if(ortn) {
return ortn;
}
}
return errSecSuccess;
}
*dataLength = 0;
do {
length = write(sock,
(char*)dataPtr + bytesSent,
dataLen - bytesSent);
} while ((length > 0) &&
( (bytesSent += length) < dataLen) );
if(length <= 0) {
int theErr = errno;
switch(theErr) {
case EAGAIN:
ortn = errSSLWouldBlock; break;
case EPIPE:
ortn = errSSLClosedAbort; break;
default:
dprintf(("SocketWrite: write(%u) error %d\n",
(unsigned)(dataLen - bytesSent), theErr));
ortn = errSecIO;
break;
}
}
else {
ortn = errSecSuccess;
}
tprintf("SocketWrite", dataLen, bytesSent, dataPtr);
*dataLength = bytesSent;
return ortn;
}