989 lines
21 KiB
C
989 lines
21 KiB
C
/***********************************************************
|
|
Copyright 1991, 1992, 1993, 1994 by Stichting Mathematisch Centrum,
|
|
Amsterdam, The Netherlands.
|
|
|
|
All Rights Reserved
|
|
|
|
Permission to use, copy, modify, and distribute this software and its
|
|
documentation for any purpose and without fee is hereby granted,
|
|
provided that the above copyright notice appear in all copies and that
|
|
both that copyright notice and this permission notice appear in
|
|
supporting documentation, and that the names of Stichting Mathematisch
|
|
Centrum or CWI not be used in advertising or publicity pertaining to
|
|
distribution of the software without specific, written prior permission.
|
|
|
|
STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
|
|
THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
|
|
FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
|
OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
******************************************************************/
|
|
|
|
#include "allobjects.h"
|
|
#include "modsupport.h" /* For getargs() etc. */
|
|
|
|
#include "macglue.h"
|
|
#include "tcpglue.h"
|
|
|
|
#include <Desk.h>
|
|
|
|
/* State of a tcp stream, in the connectionState field */
|
|
#define STATE_CLOSED 0
|
|
#define STATE_LISTEN 2
|
|
#define STATE_ESTAB 8
|
|
#define STATE_CWAIT 18
|
|
|
|
/* Python code has an additional reason for asr call: open done */
|
|
#define MY_OPEN_DONE 32766
|
|
|
|
static object *ErrorObject;
|
|
|
|
TCPIOCompletionUPP upp_tcp_done;
|
|
TCPNotifyUPP upp_tcp_asr;
|
|
#if 0
|
|
UDPIOCompletionUPP upp_udp_done;
|
|
#endif
|
|
UDPNotifyUPP upp_udp_asr;
|
|
|
|
/* ----------------------------------------------------- */
|
|
/* Declarations for objects of type MacTCP connection status */
|
|
|
|
typedef struct {
|
|
OB_HEAD
|
|
TCPStatusPB status;
|
|
} tcpcsobject;
|
|
|
|
staticforward typeobject Tcpcstype;
|
|
|
|
#define is_tcpcsobject(v) ((v)->ob_type == &Tcpcstype)
|
|
|
|
/* ---------------------------------------------------------------- */
|
|
/* Declarations for objects of type MacTCP global status */
|
|
|
|
#ifdef TCP_GS
|
|
typedef struct {
|
|
OB_HEAD
|
|
TCPParam *ptr;
|
|
} tcpgsobject;
|
|
|
|
staticforward typeobject Tcpgstype;
|
|
|
|
#define is_tcpgsobject(v) ((v)->ob_type == &Tcpgstype)
|
|
#endif /* TCP_GS */
|
|
|
|
/* ---------------------------------------------------------------- */
|
|
/* Declarations for objects of type MacTCP TCP stream */
|
|
|
|
typedef struct {
|
|
OB_HEAD
|
|
TCPiopb iop;
|
|
long localhost; /* Our IP address */
|
|
short localport; /* Our port number */
|
|
object *asr; /* Optional async notification routine */
|
|
int asr_ec; /* error code parameter to asr */
|
|
int asr_reason; /* detail for some errors */
|
|
int async_busy; /* True when completion routine pending */
|
|
int async_err; /* the error for the async call */
|
|
} tcpsobject;
|
|
|
|
staticforward typeobject Tcpstype;
|
|
|
|
#define is_tcpsobject(v) ((v)->ob_type == &Tcpstype)
|
|
|
|
/* ---------------------------------------------------------------- */
|
|
/* Declarations for objects of type MacTCP UDP stream */
|
|
|
|
typedef struct {
|
|
OB_HEAD
|
|
UDPiopb iop;
|
|
object *asr;
|
|
int asr_ec; /* error code parameter to asr */
|
|
ip_port port;
|
|
} udpsobject;
|
|
|
|
staticforward typeobject Udpstype;
|
|
|
|
#define is_udpsobject(v) ((v)->ob_type == &Udpstype)
|
|
|
|
/* ---------------------------------------------------------------- */
|
|
|
|
static tcpcsobject *
|
|
newtcpcsobject(ptr)
|
|
TCPStatusPB *ptr;
|
|
{
|
|
tcpcsobject *self;
|
|
|
|
self = NEWOBJ(tcpcsobject, &Tcpcstype);
|
|
if (self == NULL)
|
|
return NULL;
|
|
self->status = *ptr;
|
|
return self;
|
|
}
|
|
|
|
static void
|
|
tcpcs_dealloc(self)
|
|
tcpcsobject *self;
|
|
{
|
|
DEL(self);
|
|
}
|
|
/* Code to access structure members by accessing attributes */
|
|
|
|
#include "structmember.h"
|
|
|
|
#define OFF(x) offsetof(TCPStatusPB, x)
|
|
|
|
static struct memberlist tcpcs_memberlist[] = {
|
|
{"remoteHost", T_ULONG, OFF(remoteHost), RO},
|
|
{"remotePort", T_USHORT, OFF(remotePort), RO},
|
|
{"localHost", T_UINT, OFF(localHost), RO},
|
|
{"localPort", T_USHORT, OFF(localPort), RO},
|
|
{"tosFlags", T_BYTE, OFF(tosFlags), RO},
|
|
#if 0 /* Bug in header file: cannot access precedence */
|
|
{"precedence" T_BYTE, OFF(precedence), RO},
|
|
#endif
|
|
{"connectionState", T_BYTE, OFF(connectionState), RO},
|
|
{"sendWindow", T_USHORT, OFF(sendWindow), RO},
|
|
{"rcvWindow", T_USHORT, OFF(rcvWindow), RO},
|
|
{"amtUnackedData", T_USHORT, OFF(amtUnackedData), RO},
|
|
{"amtUnreadData", T_USHORT, OFF(amtUnreadData), RO},
|
|
{"sendUnacked", T_UINT, OFF(sendUnacked), RO},
|
|
{"sendNext", T_UINT, OFF(sendNext), RO},
|
|
{"congestionWindow", T_UINT, OFF(congestionWindow), RO},
|
|
{"rcvNext", T_UINT, OFF(rcvNext), RO},
|
|
{"srtt", T_UINT, OFF(srtt), RO},
|
|
{"lastRTT", T_UINT, OFF(lastRTT), RO},
|
|
{"sendMaxSegSize", T_UINT, OFF(sendMaxSegSize), RO},
|
|
{NULL} /* Sentinel */
|
|
};
|
|
|
|
static object *
|
|
tcpcs_getattr(self, name)
|
|
tcpcsobject *self;
|
|
char *name;
|
|
{
|
|
return getmember((char *)&self->status, tcpcs_memberlist, name);
|
|
}
|
|
|
|
|
|
static typeobject Tcpcstype = {
|
|
OB_HEAD_INIT(&Typetype)
|
|
0, /*ob_size*/
|
|
"MacTCP connection status", /*tp_name*/
|
|
sizeof(tcpcsobject), /*tp_basicsize*/
|
|
0, /*tp_itemsize*/
|
|
/* methods */
|
|
(destructor)tcpcs_dealloc, /*tp_dealloc*/
|
|
(printfunc)0, /*tp_print*/
|
|
(getattrfunc)tcpcs_getattr, /*tp_getattr*/
|
|
(setattrfunc)0, /*tp_setattr*/
|
|
(cmpfunc)0, /*tp_compare*/
|
|
(reprfunc)0, /*tp_repr*/
|
|
0, /*tp_as_number*/
|
|
0, /*tp_as_sequence*/
|
|
0, /*tp_as_mapping*/
|
|
(hashfunc)0, /*tp_hash*/
|
|
};
|
|
|
|
/* End of code for MacTCP connection status objects */
|
|
/* -------------------------------------------------------- */
|
|
|
|
#ifdef TCP_GS
|
|
static tcpgsobject *
|
|
newtcpgsobject(ptr)
|
|
TCPParam *ptr;
|
|
{
|
|
tcpgsobject *self;
|
|
|
|
self = NEWOBJ(tcpgsobject, &Tcpgstype);
|
|
if (self == NULL)
|
|
return NULL;
|
|
self->ptr = ptr;
|
|
return self;
|
|
}
|
|
|
|
static void
|
|
tcpgs_dealloc(self)
|
|
tcpgsobject *self;
|
|
{
|
|
DEL(self);
|
|
}
|
|
/* Code to access structure members by accessing attributes */
|
|
#undef OFF
|
|
#define OFF(x) offsetof(TCPParam, x)
|
|
|
|
static struct memberlist tcpgs_memberlist[] = {
|
|
{"RtoA", T_UINT, OFF(tcpRtoA), RO},
|
|
{"RtoMin", T_UINT, OFF(tcpRtoMin), RO},
|
|
{"RtoMax", T_UINT, OFF(tcpRtoMax), RO},
|
|
{"MaxSegSize", T_UINT, OFF(tcpMaxSegSize), RO},
|
|
{"MaxConn", T_UINT, OFF(tcpMaxConn), RO},
|
|
{"MaxWindow", T_UINT, OFF(tcpMaxWindow), RO},
|
|
{NULL} /* Sentinel */
|
|
};
|
|
|
|
static object *
|
|
tcpgs_getattr(self, name)
|
|
tcpgsobject *self;
|
|
char *name;
|
|
{
|
|
object *rv;
|
|
|
|
return getmember((char *)self->ptr, tcpgs_memberlist, name);
|
|
}
|
|
|
|
static typeobject Tcpgstype = {
|
|
OB_HEAD_INIT(&Typetype)
|
|
0, /*ob_size*/
|
|
"MacTCP global status", /*tp_name*/
|
|
sizeof(tcpgsobject), /*tp_basicsize*/
|
|
0, /*tp_itemsize*/
|
|
/* methods */
|
|
(destructor)tcpgs_dealloc, /*tp_dealloc*/
|
|
(printfunc)0, /*tp_print*/
|
|
(getattrfunc)tcpgs_getattr, /*tp_getattr*/
|
|
(setattrfunc)0, /*tp_setattr*/
|
|
(cmpfunc)0, /*tp_compare*/
|
|
(reprfunc)0, /*tp_repr*/
|
|
0, /*tp_as_number*/
|
|
0, /*tp_as_sequence*/
|
|
0, /*tp_as_mapping*/
|
|
(hashfunc)0, /*tp_hash*/
|
|
};
|
|
#endif /* TCP_GS */
|
|
|
|
/* End of code for MacTCP global status objects */
|
|
/* -------------------------------------------------------- */
|
|
|
|
static int
|
|
tcps_checkstate(self, state, state2)
|
|
tcpsobject *self;
|
|
int state, state2;
|
|
{
|
|
OSErr err;
|
|
TCPStatusPB *pb;
|
|
char buf[80];
|
|
|
|
if ( self->async_busy ) {
|
|
err_setstr(ErrorObject, "Operation not allowed, PassiveOpen in progress");
|
|
return -1;
|
|
}
|
|
if ( state < 0 && state2 < 0 )
|
|
return 0;
|
|
err = xTCPStatus(&self->iop, &pb);
|
|
if ( err ) {
|
|
PyErr_Mac(ErrorObject, err);
|
|
return -1;
|
|
}
|
|
if ( state == pb->connectionState ||
|
|
state2 == pb->connectionState )
|
|
return 0;
|
|
sprintf(buf, "Operation not allowed, connection state=%d", pb->connectionState);
|
|
err_setstr(ErrorObject, buf);
|
|
return -1;
|
|
}
|
|
|
|
static int
|
|
tcps_asr_safe(arg)
|
|
void *arg;
|
|
{
|
|
tcpsobject *self = (tcpsobject *)arg;
|
|
object *args, *rv;
|
|
|
|
if ( self->asr == None )
|
|
return 0;
|
|
args = mkvalue("(ii)", self->asr_ec, self->asr_reason);
|
|
rv = call_object(self->asr, args);
|
|
DECREF(args);
|
|
if ( rv ) {
|
|
DECREF(rv);
|
|
return 0;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static pascal void
|
|
tcps_asr(str, ec, self, reason, icmp)
|
|
StreamPtr str;
|
|
unsigned short ec;
|
|
tcpsobject *self;
|
|
unsigned short reason;
|
|
struct ICMPReport icmp;
|
|
{
|
|
if ( self->asr == None )
|
|
return;
|
|
self->asr_ec = ec;
|
|
self->asr_reason = reason;
|
|
Py_AddPendingCall(tcps_asr_safe, (void *)self);
|
|
}
|
|
|
|
static void
|
|
tcps_done(pb)
|
|
TCPiopb *pb;
|
|
{
|
|
tcpsobject *self = (tcpsobject *)pb->csParam.open.userDataPtr;
|
|
|
|
if ( pb != &self->iop || !self->async_busy ) {
|
|
/* Oops... problems */
|
|
printf("tcps_done: unexpected call\n");
|
|
return;
|
|
}
|
|
self->async_busy = 0;
|
|
self->async_err = pb->ioResult;
|
|
/* Extension of mactcp semantics: also call asr on open complete */
|
|
if ( self->asr == None )
|
|
return;
|
|
self->asr_ec = MY_OPEN_DONE;
|
|
self->asr_reason = 0;
|
|
Py_AddPendingCall(tcps_asr_safe, (void *)self);
|
|
}
|
|
|
|
static object *
|
|
tcps_isdone(self, args)
|
|
tcpsobject *self;
|
|
object *args;
|
|
{
|
|
if (!newgetargs(args, ""))
|
|
return NULL;
|
|
return newintobject(!self->async_busy);
|
|
}
|
|
|
|
static object *
|
|
tcps_wait(self, args)
|
|
tcpsobject *self;
|
|
object *args;
|
|
{
|
|
if (!newgetargs(args, ""))
|
|
return NULL;
|
|
while ( self->async_busy ) {
|
|
if ( PyMac_Idle() ) {
|
|
INCREF(None);
|
|
return None;
|
|
}
|
|
}
|
|
if ( self->async_err ) {
|
|
PyErr_Mac(ErrorObject, self->async_err);
|
|
self->async_err = 0;
|
|
return NULL;
|
|
}
|
|
INCREF(None);
|
|
return None;
|
|
}
|
|
|
|
|
|
static object *
|
|
tcps_PassiveOpen(self, args)
|
|
tcpsobject *self;
|
|
object *args;
|
|
{
|
|
short port;
|
|
OSErr err;
|
|
|
|
if (!newgetargs(args, "h", &port))
|
|
return NULL;
|
|
if ( tcps_checkstate(self, -1, -1) < 0 )
|
|
return NULL;
|
|
self->async_busy = 1;
|
|
self->async_err = 0;
|
|
err = xTCPPassiveOpen(&self->iop, port, upp_tcp_done,
|
|
(void *)self);
|
|
if ( err ) {
|
|
self->async_busy = 0;
|
|
PyErr_Mac(ErrorObject, err);
|
|
return NULL;
|
|
}
|
|
self->localhost = self->iop.csParam.open.localHost;
|
|
self->localport = self->iop.csParam.open.localPort;
|
|
INCREF(None);
|
|
return None;
|
|
}
|
|
|
|
static object *
|
|
tcps_ActiveOpen(self, args)
|
|
tcpsobject *self;
|
|
object *args;
|
|
{
|
|
short lport, rport;
|
|
long rhost;
|
|
OSErr err;
|
|
|
|
if (!newgetargs(args, "hlh", &lport, &rhost, &rport))
|
|
return NULL;
|
|
if ( tcps_checkstate(self, -1, -1) < 0 )
|
|
return NULL;
|
|
err = xTCPActiveOpen(&self->iop, lport, rhost, rport, (TCPIOCompletionUPP)0);
|
|
if ( err ) {
|
|
PyErr_Mac(ErrorObject, err);
|
|
return NULL;
|
|
}
|
|
self->localhost = self->iop.csParam.open.localHost;
|
|
self->localport = self->iop.csParam.open.localPort;
|
|
INCREF(None);
|
|
return None;
|
|
}
|
|
|
|
static object *
|
|
tcps_Send(self, args)
|
|
tcpsobject *self;
|
|
object *args;
|
|
{
|
|
char *buf;
|
|
int bufsize;
|
|
int push = 0, urgent = 0;
|
|
OSErr err;
|
|
miniwds wds;
|
|
|
|
if (!newgetargs(args, "s#|ii", &buf, &bufsize, &push, &urgent))
|
|
return NULL;
|
|
if ( tcps_checkstate(self, STATE_ESTAB, STATE_CWAIT) < 0 )
|
|
return NULL;
|
|
wds.length = bufsize;
|
|
wds.ptr = buf;
|
|
wds.terminus = 0;
|
|
err = xTCPSend(&self->iop, (wdsEntry *)&wds, (Boolean)push, (Boolean)urgent,
|
|
(TCPIOCompletionUPP)0);
|
|
if ( err ) {
|
|
PyErr_Mac(ErrorObject, err);
|
|
return NULL;
|
|
}
|
|
INCREF(None);
|
|
return None;
|
|
}
|
|
|
|
static object *
|
|
tcps_Rcv(self, args)
|
|
tcpsobject *self;
|
|
object *args;
|
|
{
|
|
int timeout;
|
|
rdsEntry rds[2];
|
|
OSErr err;
|
|
object *rv;
|
|
int urgent, mark;
|
|
|
|
if (!newgetargs(args, "i", &timeout))
|
|
return NULL;
|
|
if ( tcps_checkstate(self, -1, -1) < 0 )
|
|
return NULL;
|
|
memset((char *)&rds, 0, sizeof(rds));
|
|
err = xTCPNoCopyRcv(&self->iop, rds, 1, timeout, (TCPIOCompletionUPP)0);
|
|
if ( err ) {
|
|
PyErr_Mac(ErrorObject, err);
|
|
return NULL;
|
|
}
|
|
urgent = self->iop.csParam.receive.urgentFlag;
|
|
mark = self->iop.csParam.receive.markFlag;
|
|
rv = newsizedstringobject((char *)rds[0].ptr, rds[0].length);
|
|
err = xTCPBufReturn(&self->iop, rds, (TCPIOCompletionUPP)0);
|
|
if ( err ) {
|
|
/* Should not happen */printf("mactcp module: BufReturn failed?\n");
|
|
PyErr_Mac(ErrorObject, err);
|
|
DECREF(rv);
|
|
return NULL;
|
|
}
|
|
return mkvalue("(Oii)", rv, urgent, mark);
|
|
}
|
|
|
|
static object *
|
|
tcps_Close(self, args)
|
|
tcpsobject *self;
|
|
object *args;
|
|
{
|
|
OSErr err;
|
|
|
|
if (!newgetargs(args, ""))
|
|
return NULL;
|
|
err = xTCPClose(&self->iop, (TCPIOCompletionUPP)0);
|
|
if ( err ) {
|
|
PyErr_Mac(ErrorObject, err);
|
|
return NULL;
|
|
}
|
|
INCREF(None);
|
|
return None;
|
|
}
|
|
|
|
static object *
|
|
tcps_Abort(self, args)
|
|
tcpsobject *self;
|
|
object *args;
|
|
{
|
|
OSErr err;
|
|
|
|
if (!newgetargs(args, ""))
|
|
return NULL;
|
|
err = xTCPAbort(&self->iop);
|
|
if ( err ) {
|
|
PyErr_Mac(ErrorObject, err);
|
|
return NULL;
|
|
}
|
|
INCREF(None);
|
|
return None;
|
|
}
|
|
|
|
static object *
|
|
tcps_Status(self, args)
|
|
tcpsobject *self;
|
|
object *args;
|
|
{
|
|
OSErr err;
|
|
TCPStatusPB *pb;
|
|
|
|
if (!newgetargs(args, ""))
|
|
return NULL;
|
|
if ( tcps_checkstate(self, -1, -1) < 0 )
|
|
return NULL;
|
|
err = xTCPStatus(&self->iop, &pb);
|
|
if ( err ) {
|
|
PyErr_Mac(ErrorObject, err);
|
|
return NULL;
|
|
}
|
|
return (object *)newtcpcsobject(pb);
|
|
}
|
|
|
|
static object *
|
|
tcps_GetSockName(self, args)
|
|
tcpsobject *self;
|
|
object *args;
|
|
{
|
|
/* This routine is needed so we can get at the local port even when
|
|
** a PassiveOpen is in progress (when we can't do a Status call).
|
|
** This is needed for socket listen(); getsockname(); accept() emulation
|
|
** as used by ftp and the like.
|
|
*/
|
|
if (!newgetargs(args, ""))
|
|
return NULL;
|
|
return mkvalue("(lh)", self->localhost, self->localport);
|
|
}
|
|
|
|
static struct methodlist tcps_methods[] = {
|
|
{"isdone", (method)tcps_isdone, 1},
|
|
{"wait", (method)tcps_wait, 1},
|
|
{"PassiveOpen", (method)tcps_PassiveOpen, 1},
|
|
{"ActiveOpen", (method)tcps_ActiveOpen, 1},
|
|
{"Send", (method)tcps_Send, 1},
|
|
{"Rcv", (method)tcps_Rcv, 1},
|
|
{"Close", (method)tcps_Close, 1},
|
|
{"Abort", (method)tcps_Abort, 1},
|
|
{"Status", (method)tcps_Status, 1},
|
|
{"GetSockName", (method)tcps_GetSockName, 1},
|
|
{NULL, NULL} /* sentinel */
|
|
};
|
|
|
|
/* ---------- */
|
|
|
|
static object *
|
|
tcps_getattr(self, name)
|
|
tcpsobject *self;
|
|
char *name;
|
|
{
|
|
if ( strcmp(name, "asr") == 0 ) {
|
|
INCREF(self->asr);
|
|
return self->asr;
|
|
}
|
|
return findmethod(tcps_methods, (object *)self, name);
|
|
}
|
|
|
|
static int
|
|
tcps_setattr(self, name, value)
|
|
tcpsobject *self;
|
|
char *name;
|
|
object *value;
|
|
{
|
|
if ( strcmp(name, "asr") != 0 || value == NULL )
|
|
return -1;
|
|
self->asr = value; /* XXXX Assuming I don't have to incref */
|
|
return 0;
|
|
}
|
|
|
|
static tcpsobject *
|
|
newtcpsobject(bufsize)
|
|
int bufsize;
|
|
{
|
|
tcpsobject *self;
|
|
OSErr err;
|
|
|
|
self = NEWOBJ(tcpsobject, &Tcpstype);
|
|
if (self == NULL)
|
|
return NULL;
|
|
memset((char *)&self->iop, 0, sizeof(self->iop));
|
|
err= xTCPCreate(bufsize, upp_tcp_asr, (void *)self, &self->iop);
|
|
if ( err ) {
|
|
DEL(self);
|
|
PyErr_Mac(ErrorObject, err);
|
|
return NULL;
|
|
}
|
|
INCREF(None);
|
|
self->asr = None;
|
|
self->async_busy = 0;
|
|
self->async_err = 0;
|
|
return self;
|
|
}
|
|
|
|
static void
|
|
tcps_dealloc(self)
|
|
tcpsobject *self;
|
|
{
|
|
if ( self->async_busy ) {
|
|
printf("mactcp module: error: dealloc with async busy\n");
|
|
return;
|
|
}
|
|
xTCPRelease(&self->iop);
|
|
DEL(self);
|
|
}
|
|
|
|
static typeobject Tcpstype = {
|
|
OB_HEAD_INIT(&Typetype)
|
|
0, /*ob_size*/
|
|
"MacTCP TCP stream", /*tp_name*/
|
|
sizeof(tcpsobject), /*tp_basicsize*/
|
|
0, /*tp_itemsize*/
|
|
/* methods */
|
|
(destructor)tcps_dealloc, /*tp_dealloc*/
|
|
(printfunc)0, /*tp_print*/
|
|
(getattrfunc)tcps_getattr, /*tp_getattr*/
|
|
(setattrfunc)tcps_setattr, /*tp_setattr*/
|
|
(cmpfunc)0, /*tp_compare*/
|
|
(reprfunc)0, /*tp_repr*/
|
|
0, /*tp_as_number*/
|
|
0, /*tp_as_sequence*/
|
|
0, /*tp_as_mapping*/
|
|
(hashfunc)0, /*tp_hash*/
|
|
};
|
|
|
|
/* End of code for MacTCP TCP stream objects */
|
|
/* -------------------------------------------------------- */
|
|
|
|
static int
|
|
udps_asr_safe(arg)
|
|
void *arg;
|
|
{
|
|
udpsobject *self = (udpsobject *)arg;
|
|
object *args, *rv;
|
|
|
|
if ( self->asr == None )
|
|
return 0;
|
|
args = mkvalue("(i)", self->asr_ec);
|
|
rv = call_object(self->asr, args);
|
|
DECREF(args);
|
|
if ( rv ) {
|
|
DECREF(rv);
|
|
return 0;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static pascal void
|
|
udps_asr(str, ec, self, icmp)
|
|
StreamPtr str;
|
|
unsigned short ec;
|
|
udpsobject *self;
|
|
struct ICMPReport icmp;
|
|
{
|
|
if ( self->asr == None )
|
|
return;
|
|
self->asr_ec = ec;
|
|
Py_AddPendingCall(udps_asr_safe, (void *)self);
|
|
}
|
|
|
|
|
|
static object *
|
|
udps_Read(self, args)
|
|
udpsobject *self;
|
|
object *args;
|
|
{
|
|
OSErr err;
|
|
object *rv;
|
|
int timeout;
|
|
|
|
if (!newgetargs(args, "i", &timeout))
|
|
return NULL;
|
|
err = xUDPRead(&self->iop, timeout, (UDPIOCompletionUPP)0);
|
|
if ( err ) {
|
|
PyErr_Mac(ErrorObject, err);
|
|
return NULL;
|
|
}
|
|
rv = newsizedstringobject((char *)self->iop.csParam.receive.rcvBuff,
|
|
self->iop.csParam.receive.rcvBuffLen);
|
|
err = xUDPBfrReturn(&self->iop, self->iop.csParam.receive.rcvBuff);
|
|
if ( err ) {
|
|
PyErr_Mac(ErrorObject, err);
|
|
DECREF(rv);
|
|
return NULL;
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
static object *
|
|
udps_Write(self, args)
|
|
udpsobject *self;
|
|
object *args;
|
|
{
|
|
unsigned long host;
|
|
unsigned short port;
|
|
char *buf;
|
|
int bufsize;
|
|
OSErr err;
|
|
miniwds wds;
|
|
|
|
if (!newgetargs(args, "lhs#", &host, &port, &buf, &bufsize))
|
|
return NULL;
|
|
wds.length = bufsize;
|
|
wds.ptr = buf;
|
|
wds.terminus = 0;
|
|
err = xUDPWrite(&self->iop, host, port, &wds, (UDPIOCompletionUPP)0);
|
|
if ( err ) {
|
|
PyErr_Mac(ErrorObject, err);
|
|
return NULL;
|
|
}
|
|
INCREF(None);
|
|
return None;
|
|
}
|
|
static struct methodlist udps_methods[] = {
|
|
{"Read", (method)udps_Read, 1},
|
|
{"Write", (method)udps_Write, 1},
|
|
|
|
{NULL, NULL} /* sentinel */
|
|
};
|
|
|
|
/* ---------- */
|
|
|
|
static object *
|
|
udps_getattr(self, name)
|
|
udpsobject *self;
|
|
char *name;
|
|
{
|
|
if ( strcmp(name, "asr") == 0 ) {
|
|
INCREF(self->asr);
|
|
return self->asr;
|
|
}
|
|
if ( strcmp(name, "port") == 0 )
|
|
return newintobject((int)self->port);
|
|
return findmethod(udps_methods, (object *)self, name);
|
|
}
|
|
|
|
static int
|
|
udps_setattr(self, name, value)
|
|
udpsobject *self;
|
|
char *name;
|
|
object *value;
|
|
{
|
|
if ( strcmp(name, "asr") != 0 || value == NULL )
|
|
return -1;
|
|
self->asr = value; /* XXXX Assuming I don't have to incref */
|
|
return 0;
|
|
}
|
|
|
|
static udpsobject *
|
|
newudpsobject(bufsize, port)
|
|
int bufsize;
|
|
int port;
|
|
{
|
|
udpsobject *self;
|
|
OSErr err;
|
|
|
|
self = NEWOBJ(udpsobject, &Udpstype);
|
|
if (self == NULL)
|
|
return NULL;
|
|
memset((char *)&self->iop, 0, sizeof(self->iop));
|
|
self->port = port;
|
|
err= xUDPCreate(&self->iop, bufsize, &self->port, upp_udp_asr,
|
|
(void *)self);
|
|
if ( err ) {
|
|
DEL(self);
|
|
PyErr_Mac(ErrorObject, err);
|
|
return NULL;
|
|
}
|
|
INCREF(None);
|
|
self->asr = None;
|
|
return self;
|
|
}
|
|
|
|
static void
|
|
udps_dealloc(self)
|
|
udpsobject *self;
|
|
{
|
|
xUDPRelease(&self->iop);
|
|
DEL(self);
|
|
}
|
|
|
|
static typeobject Udpstype = {
|
|
OB_HEAD_INIT(&Typetype)
|
|
0, /*ob_size*/
|
|
"MacTCP UDP stream", /*tp_name*/
|
|
sizeof(udpsobject), /*tp_basicsize*/
|
|
0, /*tp_itemsize*/
|
|
/* methods */
|
|
(destructor)udps_dealloc, /*tp_dealloc*/
|
|
(printfunc)0, /*tp_print*/
|
|
(getattrfunc)udps_getattr, /*tp_getattr*/
|
|
(setattrfunc)udps_setattr, /*tp_setattr*/
|
|
(cmpfunc)0, /*tp_compare*/
|
|
(reprfunc)0, /*tp_repr*/
|
|
0, /*tp_as_number*/
|
|
0, /*tp_as_sequence*/
|
|
0, /*tp_as_mapping*/
|
|
(hashfunc)0, /*tp_hash*/
|
|
};
|
|
|
|
/* End of code for MacTCP UDP stream objects */
|
|
/* -------------------------------------------------------- */
|
|
|
|
static object *
|
|
mactcp_TCPCreate(self, args)
|
|
object *self; /* Not used */
|
|
object *args;
|
|
{
|
|
OSErr err;
|
|
object *rv;
|
|
int bufsize;
|
|
|
|
if (!newgetargs(args, "i", &bufsize))
|
|
return NULL;
|
|
if ( (err = xOpenDriver()) != noErr ) {
|
|
PyErr_Mac(ErrorObject, err);
|
|
return NULL;
|
|
}
|
|
rv = (object *)newtcpsobject(bufsize);
|
|
return rv;
|
|
}
|
|
|
|
static object *
|
|
mactcp_UDPCreate(self, args)
|
|
object *self; /* Not used */
|
|
object *args;
|
|
{
|
|
OSErr err;
|
|
object *rv;
|
|
int bufsize, port;
|
|
|
|
if (!newgetargs(args, "ii", &bufsize, &port))
|
|
return NULL;
|
|
if ( (err = xOpenDriver()) != noErr ) {
|
|
PyErr_Mac(ErrorObject, err);
|
|
return NULL;
|
|
}
|
|
rv = (object *)newudpsobject(bufsize, port);
|
|
return rv;
|
|
}
|
|
|
|
static object *
|
|
mactcp_MTU(self, args)
|
|
object *self; /* Not used */
|
|
object *args;
|
|
{
|
|
OSErr err;
|
|
unsigned short mtu;
|
|
|
|
if (!newgetargs(args, ""))
|
|
return NULL;
|
|
if ( (err = xOpenDriver()) != noErr ) {
|
|
PyErr_Mac(ErrorObject, err);
|
|
return NULL;
|
|
}
|
|
mtu = xMaxMTU();
|
|
return newintobject((int)mtu);
|
|
}
|
|
|
|
static object *
|
|
mactcp_IPAddr(self, args)
|
|
object *self; /* Not used */
|
|
object *args;
|
|
{
|
|
OSErr err;
|
|
unsigned long rv;
|
|
|
|
if (!newgetargs(args, ""))
|
|
return NULL;
|
|
if ( (err = xOpenDriver()) != noErr ) {
|
|
PyErr_Mac(ErrorObject, err);
|
|
return NULL;
|
|
}
|
|
rv = xIPAddr();
|
|
return newintobject((int)rv);
|
|
}
|
|
|
|
static object *
|
|
mactcp_NetMask(self, args)
|
|
object *self; /* Not used */
|
|
object *args;
|
|
{
|
|
OSErr err;
|
|
unsigned long rv;
|
|
|
|
if (!newgetargs(args, ""))
|
|
return NULL;
|
|
if ( (err = xOpenDriver()) != noErr ) {
|
|
PyErr_Mac(ErrorObject, err);
|
|
return NULL;
|
|
}
|
|
rv = xNetMask();
|
|
return newintobject((int)rv);
|
|
}
|
|
|
|
#ifdef TCP_GS
|
|
static object *
|
|
mactcp_GlobalInfo(self, args)
|
|
object *self; /* Not used */
|
|
object *args;
|
|
{
|
|
OSErr err;
|
|
|
|
if (!newgetargs(args, ""))
|
|
return NULL;
|
|
if ( (err = xOpenDriver()) != noErr ) {
|
|
PyErr_Mac(ErrorObject, err);
|
|
return NULL;
|
|
}
|
|
/* XXXX Allocate, fill */
|
|
INCREF(None);
|
|
return None;
|
|
}
|
|
#endif /* TCP_GS */
|
|
|
|
/* List of methods defined in the module */
|
|
|
|
static struct methodlist mactcp_methods[] = {
|
|
{"TCPCreate", mactcp_TCPCreate, 1},
|
|
{"UDPCreate", mactcp_UDPCreate, 1},
|
|
{"MTU", mactcp_MTU, 1},
|
|
{"IPAddr", mactcp_IPAddr, 1},
|
|
{"NetMask", mactcp_NetMask, 1},
|
|
#ifdef TCP_GS
|
|
{"GlobalInfo", mactcp_GlobalInfo, 1},
|
|
#endif
|
|
|
|
{NULL, NULL} /* sentinel */
|
|
};
|
|
|
|
|
|
/* Initialization function for the module (*must* be called initmactcp) */
|
|
|
|
void
|
|
initmactcp()
|
|
{
|
|
object *m, *d;
|
|
|
|
/* Create the module and add the functions */
|
|
m = initmodule("mactcp", mactcp_methods);
|
|
|
|
/* Add some symbolic constants to the module */
|
|
d = getmoduledict(m);
|
|
ErrorObject = newstringobject("mactcp.error");
|
|
dictinsert(d, "error", ErrorObject);
|
|
|
|
upp_tcp_done = NewTCPIOCompletionProc(tcps_done);
|
|
upp_tcp_asr = NewTCPNotifyProc(tcps_asr);
|
|
#if 0
|
|
upp_udp_done = NewUDPIOCompletionProc(udps_done);
|
|
#endif
|
|
upp_udp_asr = NewUDPNotifyProc(udps_asr);
|
|
|
|
/* XXXX Add constants here */
|
|
|
|
/* Check for errors */
|
|
if (err_occurred())
|
|
fatal("can't initialize module mactcp");
|
|
}
|