1 /***********************************************************
2 Copyright 1991, 1992, 1993, 1994 by Stichting Mathematisch Centrum,
3 Amsterdam, The Netherlands.
7 Permission to use, copy, modify, and distribute this software and its
8 documentation for any purpose and without fee is hereby granted,
9 provided that the above copyright notice appear in all copies and that
10 both that copyright notice and this permission notice appear in
11 supporting documentation, and that the names of Stichting Mathematisch
12 Centrum or CWI not be used in advertising or publicity pertaining to
13 distribution of the software without specific, written prior permission.
15 STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
16 THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
18 FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21 OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 ******************************************************************/
25 #include "allobjects.h"
26 #include "modsupport.h" /* For getargs() etc. */
33 /* State of a tcp stream, in the connectionState field */
34 #define STATE_CLOSED 0
35 #define STATE_LISTEN 2
37 #define STATE_CWAIT 18
39 /* Python code has an additional reason for asr call: open done */
40 #define MY_OPEN_DONE 32766
42 static object
*ErrorObject
;
44 TCPIOCompletionUPP upp_tcp_done
;
45 TCPNotifyUPP upp_tcp_asr
;
47 UDPIOCompletionUPP upp_udp_done
;
49 UDPNotifyUPP upp_udp_asr
;
51 /* ----------------------------------------------------- */
52 /* Declarations for objects of type MacTCP connection status */
59 staticforward typeobject Tcpcstype
;
61 #define is_tcpcsobject(v) ((v)->ob_type == &Tcpcstype)
63 /* ---------------------------------------------------------------- */
64 /* Declarations for objects of type MacTCP global status */
72 staticforward typeobject Tcpgstype
;
74 #define is_tcpgsobject(v) ((v)->ob_type == &Tcpgstype)
77 /* ---------------------------------------------------------------- */
78 /* Declarations for objects of type MacTCP TCP stream */
83 long localhost
; /* Our IP address */
84 short localport
; /* Our port number */
85 object
*asr
; /* Optional async notification routine */
86 int asr_ec
; /* error code parameter to asr */
87 int asr_reason
; /* detail for some errors */
88 int async_busy
; /* True when completion routine pending */
89 int async_err
; /* the error for the async call */
92 staticforward typeobject Tcpstype
;
94 #define is_tcpsobject(v) ((v)->ob_type == &Tcpstype)
96 /* ---------------------------------------------------------------- */
97 /* Declarations for objects of type MacTCP UDP stream */
103 int asr_ec
; /* error code parameter to asr */
107 staticforward typeobject Udpstype
;
109 #define is_udpsobject(v) ((v)->ob_type == &Udpstype)
111 /* ---------------------------------------------------------------- */
119 self
= NEWOBJ(tcpcsobject
, &Tcpcstype
);
132 /* Code to access structure members by accessing attributes */
134 #include "structmember.h"
136 #define OFF(x) offsetof(TCPStatusPB, x)
138 static struct memberlist tcpcs_memberlist
[] = {
139 {"remoteHost", T_ULONG
, OFF(remoteHost
), RO
},
140 {"remotePort", T_USHORT
, OFF(remotePort
), RO
},
141 {"localHost", T_UINT
, OFF(localHost
), RO
},
142 {"localPort", T_USHORT
, OFF(localPort
), RO
},
143 {"tosFlags", T_BYTE
, OFF(tosFlags
), RO
},
144 #if 0 /* Bug in header file: cannot access precedence */
145 {"precedence" T_BYTE
, OFF(precedence
), RO
},
147 {"connectionState", T_BYTE
, OFF(connectionState
), RO
},
148 {"sendWindow", T_USHORT
, OFF(sendWindow
), RO
},
149 {"rcvWindow", T_USHORT
, OFF(rcvWindow
), RO
},
150 {"amtUnackedData", T_USHORT
, OFF(amtUnackedData
), RO
},
151 {"amtUnreadData", T_USHORT
, OFF(amtUnreadData
), RO
},
152 {"sendUnacked", T_UINT
, OFF(sendUnacked
), RO
},
153 {"sendNext", T_UINT
, OFF(sendNext
), RO
},
154 {"congestionWindow", T_UINT
, OFF(congestionWindow
), RO
},
155 {"rcvNext", T_UINT
, OFF(rcvNext
), RO
},
156 {"srtt", T_UINT
, OFF(srtt
), RO
},
157 {"lastRTT", T_UINT
, OFF(lastRTT
), RO
},
158 {"sendMaxSegSize", T_UINT
, OFF(sendMaxSegSize
), RO
},
159 {NULL
} /* Sentinel */
163 tcpcs_getattr(self
, name
)
167 return getmember((char *)&self
->status
, tcpcs_memberlist
, name
);
171 static typeobject Tcpcstype
= {
172 OB_HEAD_INIT(&Typetype
)
174 "MacTCP connection status", /*tp_name*/
175 sizeof(tcpcsobject
), /*tp_basicsize*/
178 (destructor
)tcpcs_dealloc
, /*tp_dealloc*/
179 (printfunc
)0, /*tp_print*/
180 (getattrfunc
)tcpcs_getattr
, /*tp_getattr*/
181 (setattrfunc
)0, /*tp_setattr*/
182 (cmpfunc
)0, /*tp_compare*/
183 (reprfunc
)0, /*tp_repr*/
185 0, /*tp_as_sequence*/
187 (hashfunc
)0, /*tp_hash*/
190 /* End of code for MacTCP connection status objects */
191 /* -------------------------------------------------------- */
200 self
= NEWOBJ(tcpgsobject
, &Tcpgstype
);
213 /* Code to access structure members by accessing attributes */
215 #define OFF(x) offsetof(TCPParam, x)
217 static struct memberlist tcpgs_memberlist
[] = {
218 {"RtoA", T_UINT
, OFF(tcpRtoA
), RO
},
219 {"RtoMin", T_UINT
, OFF(tcpRtoMin
), RO
},
220 {"RtoMax", T_UINT
, OFF(tcpRtoMax
), RO
},
221 {"MaxSegSize", T_UINT
, OFF(tcpMaxSegSize
), RO
},
222 {"MaxConn", T_UINT
, OFF(tcpMaxConn
), RO
},
223 {"MaxWindow", T_UINT
, OFF(tcpMaxWindow
), RO
},
224 {NULL
} /* Sentinel */
228 tcpgs_getattr(self
, name
)
234 return getmember((char *)self
->ptr
, tcpgs_memberlist
, name
);
237 static typeobject Tcpgstype
= {
238 OB_HEAD_INIT(&Typetype
)
240 "MacTCP global status", /*tp_name*/
241 sizeof(tcpgsobject
), /*tp_basicsize*/
244 (destructor
)tcpgs_dealloc
, /*tp_dealloc*/
245 (printfunc
)0, /*tp_print*/
246 (getattrfunc
)tcpgs_getattr
, /*tp_getattr*/
247 (setattrfunc
)0, /*tp_setattr*/
248 (cmpfunc
)0, /*tp_compare*/
249 (reprfunc
)0, /*tp_repr*/
251 0, /*tp_as_sequence*/
253 (hashfunc
)0, /*tp_hash*/
257 /* End of code for MacTCP global status objects */
258 /* -------------------------------------------------------- */
261 tcps_checkstate(self
, state
, state2
)
269 if ( self
->async_busy
) {
270 err_setstr(ErrorObject
, "Operation not allowed, PassiveOpen in progress");
273 if ( state
< 0 && state2
< 0 )
275 err
= xTCPStatus(&self
->iop
, &pb
);
277 PyErr_Mac(ErrorObject
, err
);
280 if ( state
== pb
->connectionState
||
281 state2
== pb
->connectionState
)
283 sprintf(buf
, "Operation not allowed, connection state=%d", pb
->connectionState
);
284 err_setstr(ErrorObject
, buf
);
292 tcpsobject
*self
= (tcpsobject
*)arg
;
295 if ( self
->asr
== None
)
297 args
= mkvalue("(ii)", self
->asr_ec
, self
->asr_reason
);
298 rv
= call_object(self
->asr
, args
);
308 tcps_asr(str
, ec
, self
, reason
, icmp
)
312 unsigned short reason
;
313 struct ICMPReport icmp
;
315 if ( self
->asr
== None
)
318 self
->asr_reason
= reason
;
319 Py_AddPendingCall(tcps_asr_safe
, (void *)self
);
326 tcpsobject
*self
= (tcpsobject
*)pb
->csParam
.open
.userDataPtr
;
328 if ( pb
!= &self
->iop
|| !self
->async_busy
) {
329 /* Oops... problems */
330 printf("tcps_done: unexpected call\n");
333 self
->async_busy
= 0;
334 self
->async_err
= pb
->ioResult
;
335 /* Extension of mactcp semantics: also call asr on open complete */
336 if ( self
->asr
== None
)
338 self
->asr_ec
= MY_OPEN_DONE
;
339 self
->asr_reason
= 0;
340 Py_AddPendingCall(tcps_asr_safe
, (void *)self
);
344 tcps_isdone(self
, args
)
348 if (!newgetargs(args
, ""))
350 return newintobject(!self
->async_busy
);
354 tcps_wait(self
, args
)
358 if (!newgetargs(args
, ""))
360 while ( self
->async_busy
) {
361 if ( PyMac_Idle() ) {
366 if ( self
->async_err
) {
367 PyErr_Mac(ErrorObject
, self
->async_err
);
377 tcps_PassiveOpen(self
, args
)
384 if (!newgetargs(args
, "h", &port
))
386 if ( tcps_checkstate(self
, -1, -1) < 0 )
388 self
->async_busy
= 1;
390 err
= xTCPPassiveOpen(&self
->iop
, port
, upp_tcp_done
,
393 self
->async_busy
= 0;
394 PyErr_Mac(ErrorObject
, err
);
397 self
->localhost
= self
->iop
.csParam
.open
.localHost
;
398 self
->localport
= self
->iop
.csParam
.open
.localPort
;
404 tcps_ActiveOpen(self
, args
)
412 if (!newgetargs(args
, "hlh", &lport
, &rhost
, &rport
))
414 if ( tcps_checkstate(self
, -1, -1) < 0 )
416 err
= xTCPActiveOpen(&self
->iop
, lport
, rhost
, rport
, (TCPIOCompletionUPP
)0);
418 PyErr_Mac(ErrorObject
, err
);
421 self
->localhost
= self
->iop
.csParam
.open
.localHost
;
422 self
->localport
= self
->iop
.csParam
.open
.localPort
;
428 tcps_Send(self
, args
)
434 int push
= 0, urgent
= 0;
438 if (!newgetargs(args
, "s#|ii", &buf
, &bufsize
, &push
, &urgent
))
440 if ( tcps_checkstate(self
, STATE_ESTAB
, STATE_CWAIT
) < 0 )
442 wds
.length
= bufsize
;
445 err
= xTCPSend(&self
->iop
, (wdsEntry
*)&wds
, (Boolean
)push
, (Boolean
)urgent
,
446 (TCPIOCompletionUPP
)0);
448 PyErr_Mac(ErrorObject
, err
);
466 if (!newgetargs(args
, "i", &timeout
))
468 if ( tcps_checkstate(self
, -1, -1) < 0 )
470 memset((char *)&rds
, 0, sizeof(rds
));
471 err
= xTCPNoCopyRcv(&self
->iop
, rds
, 1, timeout
, (TCPIOCompletionUPP
)0);
473 PyErr_Mac(ErrorObject
, err
);
476 urgent
= self
->iop
.csParam
.receive
.urgentFlag
;
477 mark
= self
->iop
.csParam
.receive
.markFlag
;
478 rv
= newsizedstringobject((char *)rds
[0].ptr
, rds
[0].length
);
479 err
= xTCPBufReturn(&self
->iop
, rds
, (TCPIOCompletionUPP
)0);
481 /* Should not happen */printf("mactcp module: BufReturn failed?\n");
482 PyErr_Mac(ErrorObject
, err
);
486 return mkvalue("(Oii)", rv
, urgent
, mark
);
490 tcps_Close(self
, args
)
496 if (!newgetargs(args
, ""))
498 err
= xTCPClose(&self
->iop
, (TCPIOCompletionUPP
)0);
500 PyErr_Mac(ErrorObject
, err
);
508 tcps_Abort(self
, args
)
514 if (!newgetargs(args
, ""))
516 err
= xTCPAbort(&self
->iop
);
518 PyErr_Mac(ErrorObject
, err
);
526 tcps_Status(self
, args
)
533 if (!newgetargs(args
, ""))
535 if ( tcps_checkstate(self
, -1, -1) < 0 )
537 err
= xTCPStatus(&self
->iop
, &pb
);
539 PyErr_Mac(ErrorObject
, err
);
542 return (object
*)newtcpcsobject(pb
);
546 tcps_GetSockName(self
, args
)
550 /* This routine is needed so we can get at the local port even when
551 ** a PassiveOpen is in progress (when we can't do a Status call).
552 ** This is needed for socket listen(); getsockname(); accept() emulation
553 ** as used by ftp and the like.
555 if (!newgetargs(args
, ""))
557 return mkvalue("(lh)", self
->localhost
, self
->localport
);
560 static struct methodlist tcps_methods
[] = {
561 {"isdone", (method
)tcps_isdone
, 1},
562 {"wait", (method
)tcps_wait
, 1},
563 {"PassiveOpen", (method
)tcps_PassiveOpen
, 1},
564 {"ActiveOpen", (method
)tcps_ActiveOpen
, 1},
565 {"Send", (method
)tcps_Send
, 1},
566 {"Rcv", (method
)tcps_Rcv
, 1},
567 {"Close", (method
)tcps_Close
, 1},
568 {"Abort", (method
)tcps_Abort
, 1},
569 {"Status", (method
)tcps_Status
, 1},
570 {"GetSockName", (method
)tcps_GetSockName
, 1},
571 {NULL
, NULL
} /* sentinel */
577 tcps_getattr(self
, name
)
581 if ( strcmp(name
, "asr") == 0 ) {
585 return findmethod(tcps_methods
, (object
*)self
, name
);
589 tcps_setattr(self
, name
, value
)
594 if ( strcmp(name
, "asr") != 0 || value
== NULL
)
596 self
->asr
= value
; /* XXXX Assuming I don't have to incref */
601 newtcpsobject(bufsize
)
607 self
= NEWOBJ(tcpsobject
, &Tcpstype
);
610 memset((char *)&self
->iop
, 0, sizeof(self
->iop
));
611 err
= xTCPCreate(bufsize
, upp_tcp_asr
, (void *)self
, &self
->iop
);
614 PyErr_Mac(ErrorObject
, err
);
621 self
->async_busy
= 0;
630 if ( self
->async_busy
) {
631 printf("mactcp module: error: dealloc with async busy\n");
634 xTCPRelease(&self
->iop
);
638 static typeobject Tcpstype
= {
639 OB_HEAD_INIT(&Typetype
)
641 "MacTCP TCP stream", /*tp_name*/
642 sizeof(tcpsobject
), /*tp_basicsize*/
645 (destructor
)tcps_dealloc
, /*tp_dealloc*/
646 (printfunc
)0, /*tp_print*/
647 (getattrfunc
)tcps_getattr
, /*tp_getattr*/
648 (setattrfunc
)tcps_setattr
, /*tp_setattr*/
649 (cmpfunc
)0, /*tp_compare*/
650 (reprfunc
)0, /*tp_repr*/
652 0, /*tp_as_sequence*/
654 (hashfunc
)0, /*tp_hash*/
657 /* End of code for MacTCP TCP stream objects */
658 /* -------------------------------------------------------- */
664 udpsobject
*self
= (udpsobject
*)arg
;
667 if ( self
->asr
== None
)
669 args
= mkvalue("(i)", self
->asr_ec
);
670 rv
= call_object(self
->asr
, args
);
680 udps_asr(str
, ec
, self
, icmp
)
684 struct ICMPReport icmp
;
686 if ( self
->asr
== None
)
689 Py_AddPendingCall(udps_asr_safe
, (void *)self
);
694 udps_Read(self
, args
)
702 if (!newgetargs(args
, "i", &timeout
))
704 err
= xUDPRead(&self
->iop
, timeout
, (UDPIOCompletionUPP
)0);
706 PyErr_Mac(ErrorObject
, err
);
709 rv
= newsizedstringobject((char *)self
->iop
.csParam
.receive
.rcvBuff
,
710 self
->iop
.csParam
.receive
.rcvBuffLen
);
711 err
= xUDPBfrReturn(&self
->iop
, self
->iop
.csParam
.receive
.rcvBuff
);
713 PyErr_Mac(ErrorObject
, err
);
721 udps_Write(self
, args
)
732 if (!newgetargs(args
, "lhs#", &host
, &port
, &buf
, &bufsize
))
734 wds
.length
= bufsize
;
737 err
= xUDPWrite(&self
->iop
, host
, port
, &wds
, (UDPIOCompletionUPP
)0);
739 PyErr_Mac(ErrorObject
, err
);
745 static struct methodlist udps_methods
[] = {
746 {"Read", (method
)udps_Read
, 1},
747 {"Write", (method
)udps_Write
, 1},
749 {NULL
, NULL
} /* sentinel */
755 udps_getattr(self
, name
)
759 if ( strcmp(name
, "asr") == 0 ) {
763 if ( strcmp(name
, "port") == 0 )
764 return newintobject((int)self
->port
);
765 return findmethod(udps_methods
, (object
*)self
, name
);
769 udps_setattr(self
, name
, value
)
774 if ( strcmp(name
, "asr") != 0 || value
== NULL
)
776 self
->asr
= value
; /* XXXX Assuming I don't have to incref */
781 newudpsobject(bufsize
, port
)
788 self
= NEWOBJ(udpsobject
, &Udpstype
);
791 memset((char *)&self
->iop
, 0, sizeof(self
->iop
));
793 err
= xUDPCreate(&self
->iop
, bufsize
, &self
->port
, upp_udp_asr
,
797 PyErr_Mac(ErrorObject
, err
);
809 xUDPRelease(&self
->iop
);
813 static typeobject Udpstype
= {
814 OB_HEAD_INIT(&Typetype
)
816 "MacTCP UDP stream", /*tp_name*/
817 sizeof(udpsobject
), /*tp_basicsize*/
820 (destructor
)udps_dealloc
, /*tp_dealloc*/
821 (printfunc
)0, /*tp_print*/
822 (getattrfunc
)udps_getattr
, /*tp_getattr*/
823 (setattrfunc
)udps_setattr
, /*tp_setattr*/
824 (cmpfunc
)0, /*tp_compare*/
825 (reprfunc
)0, /*tp_repr*/
827 0, /*tp_as_sequence*/
829 (hashfunc
)0, /*tp_hash*/
832 /* End of code for MacTCP UDP stream objects */
833 /* -------------------------------------------------------- */
836 mactcp_TCPCreate(self
, args
)
837 object
*self
; /* Not used */
844 if (!newgetargs(args
, "i", &bufsize
))
846 if ( (err
= xOpenDriver()) != noErr
) {
847 PyErr_Mac(ErrorObject
, err
);
850 rv
= (object
*)newtcpsobject(bufsize
);
855 mactcp_UDPCreate(self
, args
)
856 object
*self
; /* Not used */
863 if (!newgetargs(args
, "ii", &bufsize
, &port
))
865 if ( (err
= xOpenDriver()) != noErr
) {
866 PyErr_Mac(ErrorObject
, err
);
869 rv
= (object
*)newudpsobject(bufsize
, port
);
874 mactcp_MTU(self
, args
)
875 object
*self
; /* Not used */
881 if (!newgetargs(args
, ""))
883 if ( (err
= xOpenDriver()) != noErr
) {
884 PyErr_Mac(ErrorObject
, err
);
888 return newintobject((int)mtu
);
892 mactcp_IPAddr(self
, args
)
893 object
*self
; /* Not used */
899 if (!newgetargs(args
, ""))
901 if ( (err
= xOpenDriver()) != noErr
) {
902 PyErr_Mac(ErrorObject
, err
);
906 return newintobject((int)rv
);
910 mactcp_NetMask(self
, args
)
911 object
*self
; /* Not used */
917 if (!newgetargs(args
, ""))
919 if ( (err
= xOpenDriver()) != noErr
) {
920 PyErr_Mac(ErrorObject
, err
);
924 return newintobject((int)rv
);
929 mactcp_GlobalInfo(self
, args
)
930 object
*self
; /* Not used */
935 if (!newgetargs(args
, ""))
937 if ( (err
= xOpenDriver()) != noErr
) {
938 PyErr_Mac(ErrorObject
, err
);
941 /* XXXX Allocate, fill */
947 /* List of methods defined in the module */
949 static struct methodlist mactcp_methods
[] = {
950 {"TCPCreate", mactcp_TCPCreate
, 1},
951 {"UDPCreate", mactcp_UDPCreate
, 1},
952 {"MTU", mactcp_MTU
, 1},
953 {"IPAddr", mactcp_IPAddr
, 1},
954 {"NetMask", mactcp_NetMask
, 1},
956 {"GlobalInfo", mactcp_GlobalInfo
, 1},
959 {NULL
, NULL
} /* sentinel */
963 /* Initialization function for the module (*must* be called initmactcp) */
970 /* Create the module and add the functions */
971 m
= initmodule("mactcp", mactcp_methods
);
973 /* Add some symbolic constants to the module */
974 d
= getmoduledict(m
);
975 ErrorObject
= newstringobject("mactcp.error");
976 dictinsert(d
, "error", ErrorObject
);
978 upp_tcp_done
= NewTCPIOCompletionProc(tcps_done
);
979 upp_tcp_asr
= NewTCPNotifyProc(tcps_asr
);
981 upp_udp_done
= NewUDPIOCompletionProc(udps_done
);
983 upp_udp_asr
= NewUDPNotifyProc(udps_asr
);
985 /* XXXX Add constants here */
987 /* Check for errors */
989 fatal("can't initialize module mactcp");