/* Automatically generated from Squeak on #(21 October 2001 9:17:57 pm) */

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

/* Default EXPORT macro that does nothing (see comment in sq.h): */
#define EXPORT(returnType) returnType

/* Do not include the entire sq.h file but just those parts needed. */
/*  The virtual machine proxy definition */
#include "sqVirtualMachine.h"
/* Configuration options */
#include "sqConfig.h"
/* Platform specific definitions */
#include "sqPlatformSpecific.h"

#define true 1
#define false 0
#define null 0  /* using 'null' because nil is predefined in Think C */
#include "SocketPlugin.h"

/* memory access macros */
#define byteAt(i) (*((unsigned char *) (i)))
#define byteAtput(i, val) (*((unsigned char *) (i)) = val)
#define longAt(i) (*((int *) (i)))
#define longAtput(i, val) (*((int *) (i)) = val)

/*** Variables ***/
static struct VirtualMachine* interpreterProxy;
static const char *moduleName = "SocketPlugin 21 October 2001 (i)";

/*** Function Prototypes ***/
#pragma export on
EXPORT(const char*) SocketPlugin_getModuleName(void);
EXPORT(int) SocketPlugin_initialiseModule(void);
#pragma export off
static int intToNetAddress(int addr);
static int netAddressToInt(unsigned char * ptrToByteArray);
#pragma export on
EXPORT(int) SocketPlugin_primitiveDisableSocketAccess(void);
EXPORT(int) SocketPlugin_primitiveHasSocketAccess(void);
EXPORT(int) SocketPlugin_primitiveInitializeNetwork(void);
EXPORT(int) SocketPlugin_primitiveResolverAbortLookup(void);
EXPORT(int) SocketPlugin_primitiveResolverAddressLookupResult(void);
EXPORT(int) SocketPlugin_primitiveResolverError(void);
EXPORT(int) SocketPlugin_primitiveResolverLocalAddress(void);
EXPORT(int) SocketPlugin_primitiveResolverNameLookupResult(void);
EXPORT(int) SocketPlugin_primitiveResolverStartAddressLookup(void);
EXPORT(int) SocketPlugin_primitiveResolverStartNameLookup(void);
EXPORT(int) SocketPlugin_primitiveResolverStatus(void);
EXPORT(int) SocketPlugin_primitiveSocketAbortConnection(void);
EXPORT(int) SocketPlugin_primitiveSocketAccept(void);
EXPORT(int) SocketPlugin_primitiveSocketAccept3Semaphores(void);
EXPORT(int) SocketPlugin_primitiveSocketCloseConnection(void);
EXPORT(int) SocketPlugin_primitiveSocketConnectToPort(void);
EXPORT(int) SocketPlugin_primitiveSocketConnectionStatus(void);
EXPORT(int) SocketPlugin_primitiveSocketCreate(void);
EXPORT(int) SocketPlugin_primitiveSocketCreate3Semaphores(void);
EXPORT(int) SocketPlugin_primitiveSocketDestroy(void);
EXPORT(int) SocketPlugin_primitiveSocketError(void);
EXPORT(int) SocketPlugin_primitiveSocketGetOptions(void);
EXPORT(int) SocketPlugin_primitiveSocketListenOnPort(void);
EXPORT(int) SocketPlugin_primitiveSocketListenOnPortBacklog(void);
EXPORT(int) SocketPlugin_primitiveSocketListenWithOrWithoutBacklog(void);
EXPORT(int) SocketPlugin_primitiveSocketLocalAddress(void);
EXPORT(int) SocketPlugin_primitiveSocketLocalPort(void);
EXPORT(int) SocketPlugin_primitiveSocketReceiveDataAvailable(void);
EXPORT(int) SocketPlugin_primitiveSocketReceiveDataBufCount(void);
EXPORT(int) SocketPlugin_primitiveSocketReceiveUDPDataBufCount(void);
EXPORT(int) SocketPlugin_primitiveSocketRemoteAddress(void);
EXPORT(int) SocketPlugin_primitiveSocketRemotePort(void);
EXPORT(int) SocketPlugin_primitiveSocketSendDataBufCount(void);
EXPORT(int) SocketPlugin_primitiveSocketSendDone(void);
EXPORT(int) SocketPlugin_primitiveSocketSendUDPDataBufCount(void);
EXPORT(int) SocketPlugin_primitiveSocketSetOptions(void);
EXPORT(int) SocketPlugin_setInterpreter(struct VirtualMachine* anInterpreter);
EXPORT(int) SocketPlugin_shutdownModule(void);
#pragma export off
static int socketRecordSize(void);
static SQSocket * socketValueOf(int socketOop);


/*	Note: This is hardcoded so it can be run from Squeak.
	The module name is used for validating a module *after*
	it is loaded to check if it does really contain the module
	we're thinking it contains. This is important! */

EXPORT(const char*) SocketPlugin_getModuleName(void) {
	return moduleName;
}

EXPORT(int) SocketPlugin_initialiseModule(void) {
	return socketInit();
}


/*	Convert the given 32-bit integer into an internet network address represented as a four-byte ByteArray. */

static int intToNetAddress(int addr) {
	int netAddressOop;
	char * naPtr;

	netAddressOop = interpreterProxy->instantiateClassindexableSize(interpreterProxy->classByteArray(), 4);
	naPtr = (char *) interpreterProxy->firstIndexableField(netAddressOop);
	naPtr[0] = (((char) ((((unsigned) addr) >> 24) & 255)));
	naPtr[1] = (((char) ((((unsigned) addr) >> 16) & 255)));
	naPtr[2] = (((char) ((((unsigned) addr) >> 8) & 255)));
	naPtr[3] = (((char) (addr & 255)));
	return netAddressOop;
}


/*	Convert the given internet network address (represented as a four-byte ByteArray) into a 32-bit integer. Fail if the given ptrToByteArray does not appear to point to a four-byte ByteArray. */

static int netAddressToInt(unsigned char * ptrToByteArray) {
	int sz;

	sz = interpreterProxy->byteSizeOf(((int) (ptrToByteArray) -4));
	if (!(sz == 4)) {
		return interpreterProxy->primitiveFail();
	}
	return (((ptrToByteArray[3]) + ((ptrToByteArray[2]) << 8)) + ((ptrToByteArray[1]) << 16)) + ((ptrToByteArray[0]) << 24);
}

EXPORT(int) SocketPlugin_primitiveDisableSocketAccess(void) {
	ioDisableSocketAccess();
	if (!(interpreterProxy->failed())) {
		interpreterProxy->pop(1);
	}
}

EXPORT(int) SocketPlugin_primitiveHasSocketAccess(void) {
	interpreterProxy->pop(1);
	interpreterProxy->pushBool(ioHasSocketAccess());
}

EXPORT(int) SocketPlugin_primitiveInitializeNetwork(void) {
	int err;
	int resolverSemaIndex;

	resolverSemaIndex = interpreterProxy->stackIntegerValue(0);
	if (interpreterProxy->failed()) {
		return null;
	}
	err = sqNetworkInit(resolverSemaIndex);
	interpreterProxy->success(err == 0);
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(1);
	return null;
}

EXPORT(int) SocketPlugin_primitiveResolverAbortLookup(void) {
	sqResolverAbort();
	if (interpreterProxy->failed()) {
		return null;
	}
	return null;
}

EXPORT(int) SocketPlugin_primitiveResolverAddressLookupResult(void) {
	int s;
	int sz;

	sz = sqResolverAddrLookupResultSize();
	if (!(interpreterProxy->failed())) {
		s = interpreterProxy->instantiateClassindexableSize(interpreterProxy->classString(), sz);
		sqResolverAddrLookupResult((char *) interpreterProxy->firstIndexableField(s), sz);
	}
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->popthenPush(1, s);
	return null;
}

EXPORT(int) SocketPlugin_primitiveResolverError(void) {
	int _return_value;

	_return_value = interpreterProxy->integerObjectOf((sqResolverError()));
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->popthenPush(1, _return_value);
	return null;
}

EXPORT(int) SocketPlugin_primitiveResolverLocalAddress(void) {
	int addr;
	int _return_value;

	addr = sqResolverLocalAddress();
	_return_value = intToNetAddress(addr);
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->popthenPush(1, _return_value);
	return null;
}

EXPORT(int) SocketPlugin_primitiveResolverNameLookupResult(void) {
	int addr;
	int _return_value;

	addr = sqResolverNameLookupResult();
	_return_value = intToNetAddress(addr);
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->popthenPush(1, _return_value);
	return null;
}

EXPORT(int) SocketPlugin_primitiveResolverStartAddressLookup(void) {
	int addr;
	char *address;

	interpreterProxy->success(interpreterProxy->isBytes(interpreterProxy->stackValue(0)));
	address = ((char *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(0))));
	if (interpreterProxy->failed()) {
		return null;
	}
	addr = netAddressToInt(((unsigned char *) address));
	if (!(interpreterProxy->failed())) {
		sqResolverStartAddrLookup(addr);
	}
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(1);
	return null;
}

EXPORT(int) SocketPlugin_primitiveResolverStartNameLookup(void) {
	int sz;
	char *name;

	interpreterProxy->success(interpreterProxy->isBytes(interpreterProxy->stackValue(0)));
	name = ((char *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(0))));
	if (interpreterProxy->failed()) {
		return null;
	}
	if (!(interpreterProxy->failed())) {
		sz = interpreterProxy->byteSizeOf(((int) (name) -4));
		sqResolverStartNameLookup(name, sz);
	}
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(1);
	return null;
}

EXPORT(int) SocketPlugin_primitiveResolverStatus(void) {
	int status;
	int _return_value;

	status = sqResolverStatus();
	_return_value = interpreterProxy->integerObjectOf(status);
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->popthenPush(1, _return_value);
	return null;
}

EXPORT(int) SocketPlugin_primitiveSocketAbortConnection(void) {
	SocketPtr s;
	int socket;

	socket = interpreterProxy->stackValue(0);
	if (interpreterProxy->failed()) {
		return null;
	}
	s = socketValueOf(socket);
	if (!(interpreterProxy->failed())) {
		sqSocketAbortConnection(s);
	}
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(1);
	return null;
}

EXPORT(int) SocketPlugin_primitiveSocketAccept(void) {
	int socketOop;
	SocketPtr s;
	SocketPtr serverSocket;
	int sockHandle;
	int recvBufSize;
	int sendBufSize;
	int semaIndex;

	sockHandle = interpreterProxy->stackValue(3);
	recvBufSize = interpreterProxy->stackIntegerValue(2);
	sendBufSize = interpreterProxy->stackIntegerValue(1);
	semaIndex = interpreterProxy->stackIntegerValue(0);
	if (interpreterProxy->failed()) {
		return null;
	}
	serverSocket = socketValueOf(sockHandle);
	if (!(interpreterProxy->failed())) {
		socketOop = interpreterProxy->instantiateClassindexableSize(interpreterProxy->classByteArray(), socketRecordSize());
		s = socketValueOf(socketOop);
		sqSocketAcceptFromRecvBytesSendBytesSemaID(s, serverSocket, recvBufSize, sendBufSize, semaIndex);
	}
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->popthenPush(5, socketOop);
	return null;
}

EXPORT(int) SocketPlugin_primitiveSocketAccept3Semaphores(void) {
	int socketOop;
	SocketPtr s;
	SocketPtr serverSocket;
	int sockHandle;
	int recvBufSize;
	int sendBufSize;
	int semaIndex;
	int aReadSema;
	int aWriteSema;

	sockHandle = interpreterProxy->stackValue(5);
	recvBufSize = interpreterProxy->stackIntegerValue(4);
	sendBufSize = interpreterProxy->stackIntegerValue(3);
	semaIndex = interpreterProxy->stackIntegerValue(2);
	aReadSema = interpreterProxy->stackIntegerValue(1);
	aWriteSema = interpreterProxy->stackIntegerValue(0);
	if (interpreterProxy->failed()) {
		return null;
	}
	serverSocket = socketValueOf(sockHandle);
	if (!(interpreterProxy->failed())) {
		socketOop = interpreterProxy->instantiateClassindexableSize(interpreterProxy->classByteArray(), socketRecordSize());
		s = socketValueOf(socketOop);
		sqSocketAcceptFromRecvBytesSendBytesSemaIDReadSemaIDWriteSemaID(s, serverSocket, recvBufSize, sendBufSize, semaIndex, aReadSema, aWriteSema);
	}
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->popthenPush(7, socketOop);
	return null;
}

EXPORT(int) SocketPlugin_primitiveSocketCloseConnection(void) {
	SocketPtr s;
	int socket;

	socket = interpreterProxy->stackValue(0);
	if (interpreterProxy->failed()) {
		return null;
	}
	s = socketValueOf(socket);
	if (!(interpreterProxy->failed())) {
		sqSocketCloseConnection(s);
	}
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(1);
	return null;
}

EXPORT(int) SocketPlugin_primitiveSocketConnectToPort(void) {
	int addr;
	SocketPtr s;
	int socket;
	char *address;
	int port;

	socket = interpreterProxy->stackValue(2);
	interpreterProxy->success(interpreterProxy->isBytes(interpreterProxy->stackValue(1)));
	address = ((char *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(1))));
	port = interpreterProxy->stackIntegerValue(0);
	if (interpreterProxy->failed()) {
		return null;
	}
	addr = netAddressToInt(((unsigned char *) address));
	if (!(ioCanConnectToPort(addr, port))) {
		interpreterProxy->primitiveFail();
		return null;
	}
	s = socketValueOf(socket);
	if (!(interpreterProxy->failed())) {
		sqSocketConnectToPort(s, addr, port);
	}
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(3);
	return null;
}

EXPORT(int) SocketPlugin_primitiveSocketConnectionStatus(void) {
	SocketPtr s;
	int status;
	int socket;
	int _return_value;

	socket = interpreterProxy->stackValue(0);
	if (interpreterProxy->failed()) {
		return null;
	}
	s = socketValueOf(socket);
	if (!(interpreterProxy->failed())) {
		status = sqSocketConnectionStatus(s);
	}
	_return_value = interpreterProxy->integerObjectOf(status);
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->popthenPush(2, _return_value);
	return null;
}

EXPORT(int) SocketPlugin_primitiveSocketCreate(void) {
	int socketOop;
	SocketPtr s;
	int netType;
	int socketType;
	int recvBufSize;
	int sendBufSize;
	int semaIndex;

	netType = interpreterProxy->stackIntegerValue(4);
	socketType = interpreterProxy->stackIntegerValue(3);
	recvBufSize = interpreterProxy->stackIntegerValue(2);
	sendBufSize = interpreterProxy->stackIntegerValue(1);
	semaIndex = interpreterProxy->stackIntegerValue(0);
	if (interpreterProxy->failed()) {
		return null;
	}
	if (!(ioCanCreateSocketOfType(netType, socketType))) {
		interpreterProxy->primitiveFail();
		return null;
	}
	socketOop = interpreterProxy->instantiateClassindexableSize(interpreterProxy->classByteArray(), socketRecordSize());
	s = socketValueOf(socketOop);
	sqSocketCreateNetTypeSocketTypeRecvBytesSendBytesSemaID(s, netType, socketType, recvBufSize, sendBufSize, semaIndex);
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->popthenPush(6, socketOop);
	return null;
}

EXPORT(int) SocketPlugin_primitiveSocketCreate3Semaphores(void) {
	int socketOop;
	SocketPtr s;
	int netType;
	int socketType;
	int recvBufSize;
	int sendBufSize;
	int semaIndex;
	int aReadSema;
	int aWriteSema;

	netType = interpreterProxy->stackIntegerValue(6);
	socketType = interpreterProxy->stackIntegerValue(5);
	recvBufSize = interpreterProxy->stackIntegerValue(4);
	sendBufSize = interpreterProxy->stackIntegerValue(3);
	semaIndex = interpreterProxy->stackIntegerValue(2);
	aReadSema = interpreterProxy->stackIntegerValue(1);
	aWriteSema = interpreterProxy->stackIntegerValue(0);
	if (interpreterProxy->failed()) {
		return null;
	}
	if (!(ioCanCreateSocketOfType(netType, socketType))) {
		interpreterProxy->primitiveFail();
		return null;
	}
	socketOop = interpreterProxy->instantiateClassindexableSize(interpreterProxy->classByteArray(), socketRecordSize());
	s = socketValueOf(socketOop);
	sqSocketCreateNetTypeSocketTypeRecvBytesSendBytesSemaIDReadSemaIDWriteSemaID(s, netType, socketType, recvBufSize, sendBufSize, semaIndex, aReadSema, aWriteSema);
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->popthenPush(8, socketOop);
	return null;
}

EXPORT(int) SocketPlugin_primitiveSocketDestroy(void) {
	SocketPtr s;
	int socket;

	socket = interpreterProxy->stackValue(0);
	if (interpreterProxy->failed()) {
		return null;
	}
	s = socketValueOf(socket);
	if (!(interpreterProxy->failed())) {
		sqSocketDestroy(s);
	}
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(1);
	return null;
}

EXPORT(int) SocketPlugin_primitiveSocketError(void) {
	SocketPtr s;
	int err;
	int socket;
	int _return_value;

	socket = interpreterProxy->stackValue(0);
	if (interpreterProxy->failed()) {
		return null;
	}
	s = socketValueOf(socket);
	if (!(interpreterProxy->failed())) {
		err = sqSocketError(s);
	}
	_return_value = interpreterProxy->integerObjectOf(err);
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->popthenPush(2, _return_value);
	return null;
}

EXPORT(int) SocketPlugin_primitiveSocketGetOptions(void) {
	SocketPtr s;
	int optionNameStart;
	int returnedValue;
	int errorCode;
	int optionNameSize;
	int results;
	int socket;
	int optionName;

	socket = interpreterProxy->stackValue(1);
	optionName = interpreterProxy->stackValue(0);
	if (interpreterProxy->failed()) {
		return null;
	}
	s = socketValueOf(socket);
	interpreterProxy->success(interpreterProxy->isBytes(optionName));
	optionNameStart = ((int) (interpreterProxy->firstIndexableField(optionName)));
	optionNameSize = interpreterProxy->slotSizeOf(optionName);
	if (interpreterProxy->failed()) {
		return null;
	}
	returnedValue = 0;
	errorCode = sqSocketGetOptionsoptionNameStartoptionNameSizereturnedValue(s, optionNameStart, optionNameSize, &returnedValue);
	interpreterProxy->pushRemappableOop(interpreterProxy->integerObjectOf(returnedValue));
	interpreterProxy->pushRemappableOop(interpreterProxy->integerObjectOf(errorCode));
	interpreterProxy->pushRemappableOop(interpreterProxy->instantiateClassindexableSize(interpreterProxy->classArray(), 2));
	results = interpreterProxy->popRemappableOop();
	interpreterProxy->storePointerofObjectwithValue(0, results, interpreterProxy->popRemappableOop());
	interpreterProxy->storePointerofObjectwithValue(1, results, interpreterProxy->popRemappableOop());
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->popthenPush(3, results);
	return null;
}


/*	one part of the wierdass dual prim primitiveSocketListenOnPort which was warped by some demented evil person determined to twist the very nature of reality */

EXPORT(int) SocketPlugin_primitiveSocketListenOnPort(void) {
	SocketPtr s;
	int socket;
	int port;

	socket = interpreterProxy->stackValue(1);
	port = interpreterProxy->stackIntegerValue(0);
	if (interpreterProxy->failed()) {
		return null;
	}
	s = socketValueOf(socket);
	if (!(ioCanListenOnPort(s, port))) {
		interpreterProxy->primitiveFail();
		return null;
	}
	sqSocketListenOnPort(s, port);
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(2);
	return null;
}


/*	second part of the wierdass dual prim primitiveSocketListenOnPort which was warped by some demented evil person determined to twist the very nature of reality */

EXPORT(int) SocketPlugin_primitiveSocketListenOnPortBacklog(void) {
	SocketPtr s;
	int socket;
	int port;
	int backlog;

	socket = interpreterProxy->stackValue(2);
	port = interpreterProxy->stackIntegerValue(1);
	backlog = interpreterProxy->stackIntegerValue(0);
	if (interpreterProxy->failed()) {
		return null;
	}
	s = socketValueOf(socket);
	if (!(ioCanListenOnPort(s, port))) {
		interpreterProxy->primitiveFail();
		return null;
	}
	sqSocketListenOnPortBacklogSize(s, port, backlog);
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(3);
	return null;
}


/*	Backward compatibility */

EXPORT(int) SocketPlugin_primitiveSocketListenWithOrWithoutBacklog(void) {
	if ((interpreterProxy->methodArgumentCount()) == 2) {
		return SocketPlugin_primitiveSocketListenOnPort();
	} else {
		return SocketPlugin_primitiveSocketListenOnPortBacklog();
	}
}

EXPORT(int) SocketPlugin_primitiveSocketLocalAddress(void) {
	SocketPtr s;
	int addr;
	int socket;
	int _return_value;

	socket = interpreterProxy->stackValue(0);
	if (interpreterProxy->failed()) {
		return null;
	}
	s = socketValueOf(socket);
	addr = sqSocketLocalAddress(s);
	_return_value = intToNetAddress(addr);
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->popthenPush(2, _return_value);
	return null;
}

EXPORT(int) SocketPlugin_primitiveSocketLocalPort(void) {
	int port;
	SocketPtr s;
	int socket;
	int _return_value;

	socket = interpreterProxy->stackValue(0);
	if (interpreterProxy->failed()) {
		return null;
	}
	s = socketValueOf(socket);
	port = sqSocketLocalPort(s);
	_return_value = interpreterProxy->integerObjectOf(port);
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->popthenPush(2, _return_value);
	return null;
}

EXPORT(int) SocketPlugin_primitiveSocketReceiveDataAvailable(void) {
	int dataIsAvailable;
	SocketPtr s;
	int socket;
	int _return_value;

	socket = interpreterProxy->stackValue(0);
	if (interpreterProxy->failed()) {
		return null;
	}
	s = socketValueOf(socket);
	dataIsAvailable = sqSocketReceiveDataAvailable(s);
	_return_value = (dataIsAvailable) ? interpreterProxy->trueObject(): interpreterProxy->falseObject();
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->popthenPush(2, _return_value);
	return null;
}

EXPORT(int) SocketPlugin_primitiveSocketReceiveDataBufCount(void) {
	SocketPtr s;
	int byteSize;
	int arrayBase;
	int bufStart;
	int bytesReceived;
	int socket;
	int array;
	int startIndex;
	int count;
	int _return_value;

	socket = interpreterProxy->stackValue(3);
	array = interpreterProxy->stackValue(2);
	startIndex = interpreterProxy->stackIntegerValue(1);
	count = interpreterProxy->stackIntegerValue(0);
	if (interpreterProxy->failed()) {
		return null;
	}

	/* buffer can be any indexable words or bytes object */

	s = socketValueOf(socket);
	interpreterProxy->success(interpreterProxy->isWordsOrBytes(array));
	if (interpreterProxy->isWords(array)) {
		byteSize = 4;
	} else {
		byteSize = 1;
	}
	interpreterProxy->success((startIndex >= 1) && ((count >= 0) && (((startIndex + count) - 1) <= (interpreterProxy->slotSizeOf(array)))));
	if (!(interpreterProxy->failed())) {
		arrayBase = ((int) (interpreterProxy->firstIndexableField(array)));
		bufStart = arrayBase + ((startIndex - 1) * byteSize);
		bytesReceived = sqSocketReceiveDataBufCount(s, bufStart, count * byteSize);
	}
	_return_value = interpreterProxy->integerObjectOf((bytesReceived / byteSize));
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->popthenPush(5, _return_value);
	return null;
}

EXPORT(int) SocketPlugin_primitiveSocketReceiveUDPDataBufCount(void) {
	int bufStart;
	int byteSize;
	int moreFlag;
	int results;
	int port;
	int arrayBase;
	int bytesReceived;
	SocketPtr s;
	int address;
	int socket;
	int array;
	int startIndex;
	int count;

	socket = interpreterProxy->stackValue(3);
	array = interpreterProxy->stackValue(2);
	startIndex = interpreterProxy->stackIntegerValue(1);
	count = interpreterProxy->stackIntegerValue(0);
	if (interpreterProxy->failed()) {
		return null;
	}

	/* buffer can be any indexable words or bytes object */

	s = socketValueOf(socket);
	interpreterProxy->success(interpreterProxy->isWordsOrBytes(array));
	if (interpreterProxy->isWords(array)) {
		byteSize = 4;
	} else {
		byteSize = 1;
	}
	interpreterProxy->success((startIndex >= 1) && ((count >= 0) && (((startIndex + count) - 1) <= (interpreterProxy->slotSizeOf(array)))));
	if (!(interpreterProxy->failed())) {
		arrayBase = ((int) (interpreterProxy->firstIndexableField(array)));

		/* allocate storage for results, remapping newly allocated
			 oops in case GC happens during allocation */

		bufStart = arrayBase + ((startIndex - 1) * byteSize);
		address = 0;
		port = 0;
		moreFlag = 0;
		bytesReceived = sqSocketReceiveUDPDataBufCountaddressportmoreFlag(s, bufStart, count * byteSize, &address, &port, &moreFlag);
		interpreterProxy->pushRemappableOop(interpreterProxy->integerObjectOf(port));
		interpreterProxy->pushRemappableOop(intToNetAddress(address));
		interpreterProxy->pushRemappableOop(interpreterProxy->integerObjectOf((bytesReceived / byteSize)));
		interpreterProxy->pushRemappableOop(interpreterProxy->instantiateClassindexableSize(interpreterProxy->classArray(), 4));
		results = interpreterProxy->popRemappableOop();
		interpreterProxy->storePointerofObjectwithValue(0, results, interpreterProxy->popRemappableOop());
		interpreterProxy->storePointerofObjectwithValue(1, results, interpreterProxy->popRemappableOop());
		interpreterProxy->storePointerofObjectwithValue(2, results, interpreterProxy->popRemappableOop());
		if (moreFlag) {
			interpreterProxy->storePointerofObjectwithValue(3, results, interpreterProxy->trueObject());
		} else {
			interpreterProxy->storePointerofObjectwithValue(3, results, interpreterProxy->falseObject());
		}
	}
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->popthenPush(5, results);
	return null;
}

EXPORT(int) SocketPlugin_primitiveSocketRemoteAddress(void) {
	SocketPtr s;
	int addr;
	int socket;
	int _return_value;

	socket = interpreterProxy->stackValue(0);
	if (interpreterProxy->failed()) {
		return null;
	}
	s = socketValueOf(socket);
	addr = sqSocketRemoteAddress(s);
	_return_value = intToNetAddress(addr);
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->popthenPush(2, _return_value);
	return null;
}

EXPORT(int) SocketPlugin_primitiveSocketRemotePort(void) {
	int port;
	SocketPtr s;
	int socket;
	int _return_value;

	socket = interpreterProxy->stackValue(0);
	if (interpreterProxy->failed()) {
		return null;
	}
	s = socketValueOf(socket);
	port = sqSocketRemotePort(s);
	_return_value = interpreterProxy->integerObjectOf(port);
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->popthenPush(2, _return_value);
	return null;
}

EXPORT(int) SocketPlugin_primitiveSocketSendDataBufCount(void) {
	SocketPtr s;
	int byteSize;
	int arrayBase;
	int bufStart;
	int bytesSent;
	int socket;
	int array;
	int startIndex;
	int count;
	int _return_value;

	socket = interpreterProxy->stackValue(3);
	array = interpreterProxy->stackValue(2);
	startIndex = interpreterProxy->stackIntegerValue(1);
	count = interpreterProxy->stackIntegerValue(0);
	if (interpreterProxy->failed()) {
		return null;
	}

	/* buffer can be any indexable words or bytes object except CompiledMethod  */

	s = socketValueOf(socket);
	interpreterProxy->success(interpreterProxy->isWordsOrBytes(array));
	if (interpreterProxy->isWords(array)) {
		byteSize = 4;
	} else {
		byteSize = 1;
	}
	interpreterProxy->success((startIndex >= 1) && ((count >= 0) && (((startIndex + count) - 1) <= (interpreterProxy->slotSizeOf(array)))));
	if (!(interpreterProxy->failed())) {
		arrayBase = ((int) (interpreterProxy->firstIndexableField(array)));
		bufStart = arrayBase + ((startIndex - 1) * byteSize);
		bytesSent = sqSocketSendDataBufCount(s, bufStart, count * byteSize);
	}
	_return_value = interpreterProxy->integerObjectOf((bytesSent / byteSize));
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->popthenPush(5, _return_value);
	return null;
}

EXPORT(int) SocketPlugin_primitiveSocketSendDone(void) {
	SocketPtr s;
	int done;
	int socket;
	int _return_value;

	socket = interpreterProxy->stackValue(0);
	if (interpreterProxy->failed()) {
		return null;
	}
	s = socketValueOf(socket);
	done = sqSocketSendDone(s);
	_return_value = (done) ? interpreterProxy->trueObject(): interpreterProxy->falseObject();
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->popthenPush(2, _return_value);
	return null;
}

EXPORT(int) SocketPlugin_primitiveSocketSendUDPDataBufCount(void) {
	int bufStart;
	int byteSize;
	int arrayBase;
	SocketPtr s;
	int bytesSent;
	int address;
	int socket;
	int array;
	char *hostAddress;
	int portNumber;
	int startIndex;
	int count;
	int _return_value;

	socket = interpreterProxy->stackValue(5);
	array = interpreterProxy->stackValue(4);
	interpreterProxy->success(interpreterProxy->isBytes(interpreterProxy->stackValue(3)));
	hostAddress = ((char *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(3))));
	portNumber = interpreterProxy->stackIntegerValue(2);
	startIndex = interpreterProxy->stackIntegerValue(1);
	count = interpreterProxy->stackIntegerValue(0);
	if (interpreterProxy->failed()) {
		return null;
	}

	/* buffer can be any indexable words or bytes object except CompiledMethod  */

	s = socketValueOf(socket);
	interpreterProxy->success(interpreterProxy->isWordsOrBytes(array));
	if (interpreterProxy->isWords(array)) {
		byteSize = 4;
	} else {
		byteSize = 1;
	}
	interpreterProxy->success((startIndex >= 1) && ((count >= 0) && (((startIndex + count) - 1) <= (interpreterProxy->slotSizeOf(array)))));
	if (!(interpreterProxy->failed())) {
		arrayBase = ((int) (interpreterProxy->firstIndexableField(array)));
		bufStart = arrayBase + ((startIndex - 1) * byteSize);
		address = netAddressToInt(((unsigned char *) hostAddress));
		bytesSent = sqSockettoHostportSendDataBufCount(s, address, portNumber, bufStart, count * byteSize);
	}
	_return_value = interpreterProxy->integerObjectOf((bytesSent / byteSize));
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->popthenPush(7, _return_value);
	return null;
}

EXPORT(int) SocketPlugin_primitiveSocketSetOptions(void) {
	int optionValueStart;
	int optionValueSize;
	int returnedValue;
	int errorCode;
	int optionNameSize;
	int results;
	int optionNameStart;
	SocketPtr s;
	int socket;
	int optionName;
	int optionValue;

	socket = interpreterProxy->stackValue(2);
	optionName = interpreterProxy->stackValue(1);
	optionValue = interpreterProxy->stackValue(0);
	if (interpreterProxy->failed()) {
		return null;
	}
	s = socketValueOf(socket);
	interpreterProxy->success(interpreterProxy->isBytes(optionName));
	optionNameStart = ((int) (interpreterProxy->firstIndexableField(optionName)));
	optionNameSize = interpreterProxy->slotSizeOf(optionName);
	interpreterProxy->success(interpreterProxy->isBytes(optionValue));
	optionValueStart = ((int) (interpreterProxy->firstIndexableField(optionValue)));
	optionValueSize = interpreterProxy->slotSizeOf(optionValue);
	if (interpreterProxy->failed()) {
		return null;
	}
	returnedValue = 0;
	errorCode = sqSocketSetOptionsoptionNameStartoptionNameSizeoptionValueStartoptionValueSizereturnedValue(s, optionNameStart, optionNameSize, optionValueStart, optionValueSize, &returnedValue);
	interpreterProxy->pushRemappableOop(interpreterProxy->integerObjectOf(returnedValue));
	interpreterProxy->pushRemappableOop(interpreterProxy->integerObjectOf(errorCode));
	interpreterProxy->pushRemappableOop(interpreterProxy->instantiateClassindexableSize(interpreterProxy->classArray(), 2));
	results = interpreterProxy->popRemappableOop();
	interpreterProxy->storePointerofObjectwithValue(0, results, interpreterProxy->popRemappableOop());
	interpreterProxy->storePointerofObjectwithValue(1, results, interpreterProxy->popRemappableOop());
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->popthenPush(4, results);
	return null;
}


/*	Note: This is coded so that is can be run from Squeak. */

EXPORT(int) SocketPlugin_setInterpreter(struct VirtualMachine* anInterpreter) {
	int ok;

	interpreterProxy = anInterpreter;
	ok = interpreterProxy->majorVersion() == VM_PROXY_MAJOR;
	if (ok == 0) {
		return 0;
	}
	ok = interpreterProxy->minorVersion() >= VM_PROXY_MINOR;
	return ok;
}

EXPORT(int) SocketPlugin_shutdownModule(void) {
	return socketShutdown();
}


/*	Return the size of a Smalltalk socket record in bytes. */

static int socketRecordSize(void) {
	return sizeof(SQSocket);
}


/*	Return a pointer to the first byte of of the socket record within the  
	given Smalltalk object, or nil if socketOop is not a socket record. */

static SQSocket * socketValueOf(int socketOop) {
	int socketIndex;

	interpreterProxy->success((interpreterProxy->isBytes(socketOop)) && ((interpreterProxy->byteSizeOf(socketOop)) == (socketRecordSize())));
	if (interpreterProxy->failed()) {
		return null;
	} else {
		socketIndex = ((int) (interpreterProxy->firstIndexableField(socketOop)));
		return (SQSocket *) socketIndex;
	}
}
