#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <Memory.h>
#include <Devices.h>
#include <errno.h>
#ifndef ENOMEM
#define ENOMEM ENOSPC
#endif
#include "macsock.h"
#include "MacTCPCommonTypes.h"
#include "UDPPB.h"
#include "AddressXlation.h"
#define SOCKET_SET_ERRNO WSASetLastError
struct WSAData macsock_data = {
0x0101,
0x0101,
"Mac Sockets implemented on top of MacTCP, by John Gilmore of\
Cygnus Support (email info@cygnus.com).",
"It only implements a small subset of UDP for now.",
107,
UDPbuflen,
0
};
static struct timeval last_timeout;
static pascal void DNRresultproc(struct hostInfo *hinfo, char *userdata);
int
WSAStartup(WORD wVersionRequested, WSADATA *data)
{
if (LOBYTE (wVersionRequested) < 1 ||
(LOBYTE (wVersionRequested) == 1 && HIBYTE (wVersionRequested) < 1))
return WSAVERNOTSUPPORTED;
if (data)
*data = macsock_data;
return 0;
}
int
WSACleanup()
{
return 0;
}
SOCKET
socket(af, type, protocol)
int af;
int type;
int protocol;
{
SOCKET theUDP;
short refNum;
UDPiopb pb;
OSErr err;
if (af != AF_INET) {
SOCKET_SET_ERRNO (EINVAL);
return INVALID_SOCKET;
}
if (type != SOCK_DGRAM) {
SOCKET_SET_ERRNO (EINVAL);
return INVALID_SOCKET;
}
if (protocol != 0) {
SOCKET_SET_ERRNO (EINVAL);
return INVALID_SOCKET;
}
theUDP = malloc (sizeof (*theUDP));
if (theUDP == 0) {
SOCKET_SET_ERRNO (ENOMEM);
return INVALID_SOCKET;
}
err = OpenDriver( "\p.IPP", &refNum );
if (err) {
free (theUDP);
SOCKET_SET_ERRNO (EIO);
return INVALID_SOCKET;
}
theUDP->fMacTCPRef = refNum;
pb.ioCRefNum = theUDP->fMacTCPRef;
pb.csCode = UDPCreate;
pb.csParam.create.rcvBuff = theUDP->fRecvBuf;
pb.csParam.create.rcvBuffLen = UDPbuflen;
pb.csParam.create.notifyProc = NULL;
pb.csParam.create.localPort = 0;
err = PBControl( (ParamBlockRec *) &pb, false );
if (err) {
free (theUDP);
SOCKET_SET_ERRNO (EIO);
return INVALID_SOCKET;
}
theUDP->fStream = (unsigned long)pb.udpStream;
return theUDP;
}
int
closesocket (theUDP)
SOCKET theUDP;
{
UDPiopb pb;
if (theUDP->fStream) {
pb.ioCRefNum = theUDP->fMacTCPRef;
pb.csCode = UDPRelease;
pb.udpStream = (StreamPtr) theUDP->fStream;
(void) PBControl( (ParamBlockRec *) &pb, false );
}
free(theUDP);
return 0;
}
int
bind (s, name, namelen)
SOCKET s;
const struct sockaddr *name;
int namelen;
{
if (name->sin_family != AF_INET) {
SOCKET_SET_ERRNO (EINVAL);
return SOCKET_ERROR;
}
#if 0
if (namelen != sizeof (struct sockaddr_in)) {
SOCKET_SET_ERRNO (EINVAL);
return SOCKET_ERROR;
}
if (name->sin_addr.s_addr != INADDR_ANY) {
SOCKET_SET_ERRNO (EINVAL);
return SOCKET_ERROR;
}
#endif
s - s;
return 0;
}
int
sendto (theUDP, buf, len, flags, to_param, tolen)
SOCKET theUDP;
const char *buf;
const int len;
int flags;
const struct sockaddr *to_param;
int tolen;
{
OSErr err;
wdsEntry wds[2];
UDPiopb pb;
struct sockaddr_in *to = (struct sockaddr_in *)to_param;
if (tolen != sizeof (struct sockaddr_in)) {
SOCKET_SET_ERRNO (EINVAL);
return SOCKET_ERROR;
}
if (to->sin_family != AF_INET) {
SOCKET_SET_ERRNO (EINVAL);
return SOCKET_ERROR;
}
wds[0].length = len;
wds[0].ptr = (char *) buf;
wds[1].length = 0;
pb.ioCRefNum = theUDP->fMacTCPRef;
pb.csCode = UDPWrite;
pb.udpStream = (StreamPtr) theUDP->fStream;
pb.csParam.send.remotePort = to->sin_port;
pb.csParam.send.wdsPtr = (Ptr) wds;
pb.csParam.send.checkSum = 1; pb.csParam.send.sendLength = 0; pb.csParam.send.remoteHost = to->sin_addr.s_addr;
err = PBControl( (ParamBlockRec *) &pb, false );
if (err != noErr) {
SOCKET_SET_ERRNO (EIO);
return SOCKET_ERROR;
}
return len;
}
int
select (nfds, readfds, writefds, exceptfds, timeout)
int nfds;
fd_set *readfds;
fd_set *writefds;
fd_set *exceptfds;
const struct timeval *timeout;
{
if (timeout)
last_timeout = *timeout;
return 1;
}
int
recvfrom (theUDP, buf, len, flags, from_param, fromlen)
SOCKET theUDP;
char *buf;
int len;
int flags;
struct sockaddr *from_param;
int *fromlen;
{
OSErr err;
UDPiopb pb;
int packet_len;
struct sockaddr_in *from = (struct sockaddr_in *)from_param;
if (*fromlen < sizeof (*from)) {
SOCKET_SET_ERRNO (EINVAL);
return SOCKET_ERROR;
}
pb.ioCRefNum = theUDP->fMacTCPRef;
pb.csCode = UDPRead;
pb.udpStream = (StreamPtr) theUDP->fStream;
pb.csParam.receive.timeOut = last_timeout.tv_sec;
pb.csParam.receive.secondTimeStamp = 0;
err = PBControl( (ParamBlockRec *) &pb, false );
if( err ) {
SOCKET_SET_ERRNO (EIO);
return SOCKET_ERROR;
}
packet_len = pb.csParam.receive.rcvBuffLen;
if( len > packet_len )
len = packet_len;
BlockMove( pb.csParam.receive.rcvBuff, buf, len );
*fromlen = sizeof (*from);
from->sin_family = AF_INET;
from->sin_port = pb.csParam.receive.remotePort;
from->sin_addr.s_addr = pb.csParam.receive.remoteHost;
if( pb.csParam.receive.rcvBuffLen ) {
pb.csCode = UDPBfrReturn;
err = PBControl( (ParamBlockRec *) &pb, false );
}
if (len < packet_len) {
SOCKET_SET_ERRNO (EMSGSIZE);
return SOCKET_ERROR;
}
return len;
}
char*
inet_ntoa(struct in_addr ina) {
OSErr err;
#define max_addr_str 16
char addrStr[max_addr_str];
err = AddrToStr(ina.s_addr, addrStr);
return addrStr;
}
static struct hostInfo host;
static char * ipaddr_ptrs[NUM_ALT_ADDRS+1];
static struct hostent result;
struct hostent *
gethostbyname (char *hostname)
{
OSErr err;
char done = false;
int i;
if (err = OpenResolver(NULL))
return(0); err = StrToAddr(hostname, &host, DNRresultproc, &done);
if (err == cacheFault) {
while(!done) ;
err = host.rtnCode;
}
if (err != noErr) {
return 0;
}
result.h_name = host.cname;
result.h_aliases = 0;
result.h_addrtype = AF_INET;
result.h_length = sizeof (host.addr[0]);
result.h_addr_list = ipaddr_ptrs;
for (i = 0; i < NUM_ALT_ADDRS; i++)
if (host.addr[i] != 0)
ipaddr_ptrs[i] = (char*) &host.addr[i];
else
break;
ipaddr_ptrs[i] = 0;
return &result;
}
struct hostent *
gethostbyaddr (char *addr, int len, int type)
{
OSErr err;
char done = false;
ip_addr macaddr;
if (type != AF_INET)
return 0;
if (len != sizeof (ip_addr))
return 0;
memcpy ((void *)&macaddr, (void *)addr, (size_t)len);
if (err = OpenResolver(NULL))
return 0; err = AddrToName(macaddr, &host, DNRresultproc, &done);
if (err == cacheFault) {
while(!done) ;
err = host.rtnCode;
}
if (err != noErr) {
return 0;
}
result.h_name = host.cname;
result.h_aliases = 0;
result.h_addrtype = AF_INET;
result.h_length = sizeof (host.addr[0]);
result.h_addr_list = 0;
return &result;
}
static pascal void
DNRresultproc(struct hostInfo *hinfo, char *userdata)
{
*userdata = true;
}
int
gethostname(char *name, int namelen)
{
return -1;
}
#if 0
int
gethostname(name, namelen)
char *name;
int namelen;
{
ip_addr ourAddress;
SOCKET sock;
struct IPParamBlock pb;
struct hostent *host;
struct sockaddr_in hostaddr;
sock = socket (AF_INET, SOCK_DGRAM, 0);
if (!sock)
return -1;
pb.ioCRefNum = sock->fMacTCPRef;
pb.csCode = ipctlGetAddr;
err = PBControl( (ParamBlockRec *) &pb, false );
if (err) {
free (theUDP);
SOCKET_SET_ERRNO (EIO);
return -1;
}
pb.csParam.xxxx
host = gethostbyaddr (&hostaddr, sizeof (hostaddr), AF_INET);
if (!host)
return -1;
len = strlen (host->h_name);
if (len > namelen)
return -1;
memcpy (name, host->h_name, len+1);
return 0;
}
#endif