435 Socket debug:true |
459 Socket debug:true |
436 Socket debug:false |
460 Socket debug:false |
437 " |
461 " |
438 ! ! |
462 ! ! |
439 |
463 |
|
464 !Socket class methodsFor:'easy tcp/ip instance creation'! |
|
465 |
|
466 connectTo:service on:host |
|
467 "standard & easy client setup: |
|
468 create new client tcp socket, bind and connect; |
|
469 return the socket. |
|
470 The system may block (interruptable), until the connection is |
|
471 established." |
|
472 |
|
473 ^ (self new) for:host port:(self portOfService:service). |
|
474 |
|
475 " |
|
476 Socket connectTo:9995 on:'clam' |
|
477 Socket connectTo:'finger' on:'clam' |
|
478 Socket connectTo:'ftp' on:'clam' |
|
479 Socket connectTo:'nntp' on:(OperatingSystem getEnvironment:'NNTPSERVER') |
|
480 " |
|
481 ! |
|
482 |
|
483 provide:service |
|
484 "standard & easy server setup: |
|
485 create a new TCP server socket providing a service." |
|
486 |
|
487 |newSock| |
|
488 |
|
489 newSock := (self new) for:nil port:(self portOfService:service). |
|
490 newSock notNil ifTrue:[ |
|
491 newSock listenFor:5. |
|
492 ]. |
|
493 ^ newSock |
|
494 |
|
495 " |
|
496 Socket provide:9995 |
|
497 (Socket provide:9996) accept |
|
498 Socket provide:'nntp' |
|
499 " |
|
500 ! ! |
|
501 |
|
502 !Socket class methodsFor:'general instance creation'! |
|
503 |
|
504 domain:domainSymbol type:type |
|
505 "create a socket for domain and type - |
|
506 neither any connect nor binding is done. |
|
507 Domain must be one of the symbols: #inet, #unix, #ns, #appletalk or #ns; |
|
508 Type must be #stream, #datagram or #raw |
|
509 |
|
510 XXX: currently only the #inet domain is supported" |
|
511 |
|
512 ^ self new domain:domainSymbol type:type |
|
513 |
|
514 " |
|
515 Socket domain:#inet type:#stream |
|
516 Socket domain:#inet type:#datagram |
|
517 Socket domain:#unix type:#stream |
|
518 Socket domain:#appletalk type:#stream |
|
519 Socket domain:#DECnet type:#stream |
|
520 " |
|
521 ! |
|
522 |
|
523 newTCP |
|
524 "create a TCP socket - no binding or other setup is done, |
|
525 neither connect nor connect-wait is done." |
|
526 |
|
527 ^ self new domain:#inet type:#stream |
|
528 |
|
529 "Socket newUDP" |
|
530 ! |
|
531 |
|
532 newTCP:aServiceOrNil |
|
533 "create a TCP socket for a service - |
|
534 neither connect nor connect-wait is done." |
|
535 |
|
536 |newSock| |
|
537 |
|
538 newSock := self newTCP. |
|
539 (newSock notNil and:[aServiceOrNil notNil]) ifTrue:[ |
|
540 newSock bindTo:(self portOfService:aServiceOrNil) address:nil |
|
541 ]. |
|
542 ^ newSock |
|
543 |
|
544 |
|
545 "Socket newTCP:'nntp'" |
|
546 "Socket newTCP:9995" |
|
547 ! |
|
548 |
|
549 newTCPclientToHost:hostname port:aService |
|
550 "create a new TCP client socket connecting to a service. |
|
551 Return a socket instance if ok, nil on failure. |
|
552 Block until a connection is established (but only the current thread; |
|
553 not the whole smalltalk). |
|
554 See also: #newTCPclientToHost:port:withTimeout:" |
|
555 |
|
556 ^ self newTCPclientToHost:hostname port:aService withTimeout:nil |
|
557 |
|
558 " |
|
559 Socket newTCPclientToHost:'localhost' port:'nntp' |
|
560 " |
|
561 |
|
562 "Created: 31.10.1995 / 18:54:11 / cg" |
|
563 ! |
|
564 |
|
565 newTCPclientToHost:hostname port:aService withTimeout:millis |
|
566 "create a new TCP client socket connecting to a service. |
|
567 Return a socket instance if ok, nil on failure. |
|
568 If the millis arg is nonNil, stop trying to connect after that many milliseconds |
|
569 and return nil.." |
|
570 |
|
571 |newSock| |
|
572 |
|
573 newSock := self newTCP. |
|
574 newSock notNil ifTrue:[ |
|
575 (newSock connectTo:hostname port:(self portOfService:aService) withTimeout:millis) ifFalse:[ |
|
576 newSock close. |
|
577 ^ nil |
|
578 ] |
|
579 ]. |
|
580 ^ newSock |
|
581 " |
|
582 same as: |
|
583 ^ (self new) for:hostname port:(self portOfService:aPort). |
|
584 " |
|
585 " |
|
586 Socket newTCPclientToHost:'slsv6bt' port:'nntp' |
|
587 Socket newTCPclientToHost:'localhost' port:'nntp' withTimeout:1000 |
|
588 " |
|
589 ! |
|
590 |
|
591 newTCPserverAtPort:aService |
|
592 "create a new TCP server socket providing service." |
|
593 |
|
594 |newSock| |
|
595 |
|
596 newSock := self newTCP. |
|
597 newSock notNil ifTrue:[ |
|
598 (newSock bindTo:(self portOfService:aService) address:nil) ifFalse:[ |
|
599 ^ nil |
|
600 ] |
|
601 ]. |
|
602 ^ newSock |
|
603 " |
|
604 same as: |
|
605 ^ (self new) for:nil port:aPort |
|
606 " |
|
607 ! |
|
608 |
|
609 newUDP |
|
610 "create a UDP socket - no binding or other setup is done, |
|
611 neither connect nor connect-wait is done." |
|
612 |
|
613 ^ self new domain:#inet type:#datagram |
|
614 |
|
615 "Socket newUDP" |
|
616 ! |
|
617 |
|
618 newUDP:aServiceOrNil |
|
619 "create a UDP socket for a service - |
|
620 neither connect nor connect-wait is done." |
|
621 |
|
622 |newSock| |
|
623 |
|
624 newSock := self newUDP. |
|
625 (newSock notNil and:[aServiceOrNil notNil]) ifTrue:[ |
|
626 newSock bindTo:(self portOfService:aServiceOrNil) address:nil |
|
627 ]. |
|
628 ^ newSock |
|
629 |
|
630 "Socket newUDP:nil" |
|
631 ! |
|
632 |
|
633 newUDPserverAtPort:aService |
|
634 "create a new UDP server socket providing service." |
|
635 |
|
636 |newSock| |
|
637 |
|
638 newSock := self newUDP. |
|
639 newSock notNil ifTrue:[ |
|
640 (newSock bindTo:(self portOfService:aService) address:nil) ifFalse:[ |
|
641 ^ nil |
|
642 ] |
|
643 ]. |
|
644 ^ newSock |
|
645 " |
|
646 same as: |
|
647 ^ (self new) for:nil udpPort:aPort |
|
648 " |
|
649 ! |
|
650 |
|
651 newUNIX |
|
652 "create a UNIX domain socket - no binding or other setup is done, |
|
653 neither connect nor connect-wait is done." |
|
654 |
|
655 ^ self new domain:#unix type:#stream |
|
656 |
|
657 " |
|
658 Socket newUNIX |
|
659 " |
|
660 ! |
|
661 |
|
662 newUNIXclientTo:pathName |
|
663 "create a new UNIX client socket connecting to a pathname. |
|
664 Return a socket instance if ok, nil on failure. |
|
665 Block until a connection is established (but only the current thread; |
|
666 not the whole smalltalk). |
|
667 See also: #newUNIXclientTo:withTimeout:" |
|
668 |
|
669 ^ self newUNIXclientTo:pathName withTimeout:nil |
|
670 |
|
671 ! |
|
672 |
|
673 newUNIXclientTo:pathName withTimeout:millis |
|
674 "create a new UNIX client socket connecting to a pathname. |
|
675 Return a socket instance if ok, nil on failure. |
|
676 If the millis arg is nonNil, stop trying to connect after that many milliseconds |
|
677 and return nil.." |
|
678 |
|
679 |newSock| |
|
680 |
|
681 newSock := self newUNIX. |
|
682 newSock notNil ifTrue:[ |
|
683 (newSock connectTo:pathName port:nil withTimeout:millis) ifFalse:[ |
|
684 newSock close. |
|
685 ^ nil |
|
686 ] |
|
687 ]. |
|
688 ^ newSock |
|
689 |
|
690 " |
|
691 |s| |
|
692 |
|
693 s := Socket newUNIXclientTo:'/tmp/foo' |
|
694 " |
|
695 ! |
|
696 |
|
697 newUNIXserverAt:pathName |
|
698 "create a new UNIX server socket providing service at a pathname." |
|
699 |
|
700 |newSock| |
|
701 |
|
702 newSock := self newUNIX. |
|
703 newSock notNil ifTrue:[ |
|
704 (newSock bindTo:pathName address:nil) ifFalse:[ |
|
705 ^ nil |
|
706 ] |
|
707 ]. |
|
708 ^ newSock |
|
709 |
|
710 " |
|
711 |s s2| |
|
712 |
|
713 s := Socket newUNIXserverAt:'/tmp/foo'. |
|
714 s listenFor:5. |
|
715 s2 := s accept. |
|
716 " |
|
717 ! ! |
|
718 |
440 !Socket class methodsFor:'queries'! |
719 !Socket class methodsFor:'queries'! |
441 |
720 |
442 ipAddressOfHost:aHostName |
721 domainOfProtocol:aProtocol |
443 "return the IP (internet-) number for a hostname as a byteArray, |
722 "given a protocols name (i.e. tcp, udp etc) return the domain. |
444 where the network bytes come first (no matter what the cpus byteOrder is). |
723 This method needs more ... - or is there a way to get this from the system ?" |
445 If the host is unknown, return nil. |
724 |
446 This is the reverse operation to #hostWithIpAddress:." |
725 " |
447 |
726 tcp/ip stuff |
448 |b1 b2 b3 b4| |
727 " |
449 |
728 (aProtocol = 'tcp') ifTrue:[^ #inet]. |
450 %{ |
729 (aProtocol = 'udp') ifTrue:[^ #inet]. |
451 struct sockaddr_in sa ; |
730 (aProtocol = 'ip') ifTrue:[^ #inet]. |
452 struct hostent *hp ; |
731 " |
453 long addr; |
732 unix domain |
454 |
733 " |
455 if (__isString(aHostName)) { |
734 (aProtocol = 'ud') ifTrue:[^ #unix]. |
456 bzero(&sa, sizeof(sa)) ; |
735 |
457 if ((addr = inet_addr((char *) _stringVal(aHostName))) != -1) { |
736 " |
458 /* is Internet addr in octet notation */ |
737 add x25 stuff (if any) here ... |
459 bcopy(&addr, (char *) &sa.sin_addr, sizeof(addr)); |
738 " |
460 sa.sin_family = AF_INET; |
739 " |
461 } else { |
740 add appletalk stuff (if any) here ... |
462 /* do we know the host's address? */ |
741 " |
463 if ((hp = gethostbyname((char *) _stringVal(aHostName))) == NULL) { |
742 " |
464 DBGPRINTF(("SOCKET: unknown host\n")); |
743 add other stuff (if any) here ... |
465 RETURN ( nil ); |
744 " |
466 } |
745 ^ nil |
467 bcopy(hp->h_addr, (char *) &sa.sin_addr, hp->h_length) ; |
746 |
468 sa.sin_family = hp->h_addrtype; |
747 " |
469 } |
748 Socket domainOfProtocol:'tcp' |
470 } |
749 Socket domainOfProtocol:'ucp' |
471 /* if the addressing family is not AF_INET, return nil */ |
750 Socket domainOfProtocol:(Socket protocolOfService:'nntp') |
472 if (sa.sin_family != AF_INET) { |
751 Socket domainOfProtocol:(Socket protocolOfService:'echo') |
473 RETURN ( nil ); |
|
474 } |
|
475 |
|
476 sa.sin_addr.s_addr = ntohl(sa.sin_addr.s_addr); |
|
477 b1 = _MKSMALLINT((sa.sin_addr.s_addr >> 24) & 0xFF); |
|
478 b2 = _MKSMALLINT((sa.sin_addr.s_addr >> 16) & 0xFF); |
|
479 b3 = _MKSMALLINT((sa.sin_addr.s_addr >> 8) & 0xFF); |
|
480 b4 = _MKSMALLINT((sa.sin_addr.s_addr >> 0) & 0xFF); |
|
481 %} |
|
482 . |
|
483 ^ ByteArray with:b1 with:b2 with:b3 with:b4 |
|
484 |
|
485 " |
|
486 Socket ipAddressOfHost:'clam' |
|
487 Socket ipAddressOfHost:'porty' |
|
488 Socket ipAddressOfHost:'axept' |
|
489 Socket ipAddressOfHost:'axept' |
|
490 Socket ipAddressOfHost:'1.2.3.4' |
|
491 Socket ipAddressOfHost:'193.15.16.17' |
|
492 Socket ipAddressOfHost:'josef' |
|
493 Socket ipAddressOfHost:'styx.com' |
|
494 Socket hostWithIpAddress:(Socket ipAddressOfHost:'localhost') |
|
495 Socket ipAddressOfHost:(Socket hostWithIpAddress:'127.0.0.1') |
|
496 " |
752 " |
497 ! |
753 ! |
498 |
754 |
499 hostWithIpAddress:anAddress |
755 hostWithIpAddress:anAddress |
500 "return the hostname for an IP (internet-) address. |
756 "return the hostname for an IP (internet-) address. |
717 Socket typeOfProtocol:(Socket protocolOfService:'nntp') |
996 Socket typeOfProtocol:(Socket protocolOfService:'nntp') |
718 Socket typeOfProtocol:(Socket protocolOfService:'echo') |
997 Socket typeOfProtocol:(Socket protocolOfService:'echo') |
719 " |
998 " |
720 ! ! |
999 ! ! |
721 |
1000 |
722 !Socket class methodsFor:'easy tcp/ip instance creation'! |
1001 !Socket methodsFor:'ST-80 mimicri'! |
723 |
1002 |
724 connectTo:service on:host |
1003 errorReporter |
725 "standard & easy client setup: |
1004 ^ self |
726 create new client tcp socket, bind and connect; |
1005 ! |
727 return the socket. |
1006 |
728 The system may block (interruptable), until the connection is |
1007 notReadySignal |
729 established." |
1008 "for now - this is not yet raised" |
730 |
1009 |
731 ^ (self new) for:host port:(self portOfService:service). |
1010 ^ Signal new |
732 |
1011 ! ! |
733 " |
1012 |
734 Socket connectTo:9995 on:'clam' |
1013 !Socket methodsFor:'datagram transmission'! |
735 Socket connectTo:'finger' on:'clam' |
1014 |
736 Socket connectTo:'ftp' on:'clam' |
1015 receiveFrom:anAddressBuffer buffer:aDataBuffer |
737 Socket connectTo:'nntp' on:(OperatingSystem getEnvironment:'NNTPSERVER') |
1016 "receive datagramm data - put address of originating host into |
738 " |
1017 anAddressBuffer, data into aBuffer. |
739 ! |
1018 Both must be ByteArray-like. The addressBuffer must |
740 |
1019 provide space for a valid address for my domain (i.e. for inet, a 4-byte byteArray). |
741 provide:service |
1020 Return the number of bytes received, or a negative number on error. |
742 "standard & easy server setup: |
1021 On error, the unix error code is left in the lastErrorNumber |
743 create a new TCP server socket providing a service." |
1022 instance variable." |
|
1023 |
|
1024 ^ self receiveFrom:anAddressBuffer buffer:aDataBuffer start:1 for:(aDataBuffer size) |
|
1025 ! |
|
1026 |
|
1027 receiveFrom:anAddressBuffer buffer:aDataBuffer start:startIndex for:nBytes |
|
1028 "receive datagramm data - put address of originating host into |
|
1029 anAddressBuffer, data into aBuffer. For ST-80 compatibility, |
|
1030 the addressBuffer may be a non-ByteArray; then, it must understand |
|
1031 the addressBytes-message (i.e. be a SocketAddress instance). |
|
1032 Return the number of bytes received, or a negative number on error. |
|
1033 On error, the unix error code is left in the lastErrorNumber |
|
1034 instance variable." |
|
1035 |
|
1036 |addrBytes addrLen nReceived| |
|
1037 |
|
1038 addrBytes := ByteArray new:100. |
|
1039 %{ |
|
1040 OBJ oClass; |
|
1041 OBJ fp = _INST(filePointer); |
|
1042 int nInstVars, nInstBytes, objSize; |
|
1043 int sock; |
|
1044 struct sockaddr_in sa ; |
|
1045 int alen; |
|
1046 int n; |
|
1047 char *cp; |
|
1048 int flags = 0; |
|
1049 |
|
1050 if (fp != nil) { |
|
1051 sock = fileno(__FILEVal(fp)); |
|
1052 |
|
1053 oClass = __Class(aDataBuffer); |
|
1054 switch (_intVal(_ClassInstPtr(oClass)->c_flags) & ARRAYMASK) { |
|
1055 case BYTEARRAY: |
|
1056 case WORDARRAY: |
|
1057 case LONGARRAY: |
|
1058 case FLOATARRAY: |
|
1059 case DOUBLEARRAY: |
|
1060 break; |
|
1061 default: |
|
1062 goto bad; |
|
1063 } |
|
1064 |
|
1065 nInstVars = _intVal(_ClassInstPtr(oClass)->c_ninstvars); |
|
1066 nInstBytes = OHDR_SIZE + nInstVars * sizeof(OBJ); |
|
1067 objSize = _Size(aDataBuffer) - nInstBytes; |
|
1068 cp = (char *)_InstPtr(aDataBuffer) + nInstBytes; |
|
1069 if (__isSmallInteger(startIndex)) { |
|
1070 cp += __intVal(startIndex); |
|
1071 objSize -= __intVal(startIndex); |
|
1072 } |
|
1073 if (__isSmallInteger(nBytes)) { |
|
1074 if (__intVal(nBytes) < objSize) { |
|
1075 objSize = __intVal(nBytes); |
|
1076 } |
|
1077 } |
|
1078 |
|
1079 __BEGIN_INTERRUPTABLE__ |
|
1080 do { |
|
1081 if (addrBytes == nil) { |
|
1082 n = recvfrom(sock, cp, objSize, flags, (struct sockaddr *) 0, 0); |
|
1083 } else { |
|
1084 n = recvfrom(sock, cp, objSize, flags, (struct sockaddr *) &sa, &alen); |
|
1085 } |
|
1086 } while ((n < 0) && (errno == EINTR)); |
|
1087 __END_INTERRUPTABLE__ |
|
1088 |
|
1089 if (n >= 0) { |
|
1090 if (addrBytes != nil) { |
|
1091 oClass = __Class(addrBytes); |
|
1092 if ((_intVal(_ClassInstPtr(oClass)->c_flags) & ARRAYMASK) != BYTEARRAY) |
|
1093 goto bad; |
|
1094 nInstVars = _intVal(_ClassInstPtr(oClass)->c_ninstvars); |
|
1095 nInstBytes = OHDR_SIZE + nInstVars * sizeof(OBJ); |
|
1096 objSize = _Size(addrBytes) - nInstBytes; |
|
1097 cp = (char *)_InstPtr(addrBytes) + nInstBytes; |
|
1098 if (objSize < alen) |
|
1099 goto bad; |
|
1100 bcopy((char *)&sa, cp, alen); |
|
1101 addrLen = _MKSMALLINT(alen); |
|
1102 } |
|
1103 } |
|
1104 if (n < 0) { |
|
1105 _INST(lastErrorNumber) = _MKSMALLINT(errno); |
|
1106 } |
|
1107 nReceived = _MKSMALLINT(n); |
|
1108 } |
|
1109 bad: ; |
|
1110 %}. |
|
1111 nReceived notNil ifTrue:[ |
|
1112 nReceived < 0 ifTrue:[ |
|
1113 (OperatingSystem errorTextForNumber:lastErrorNumber) printNL. |
|
1114 ]. |
|
1115 addrLen notNil ifTrue:[ |
|
1116 anAddressBuffer class isBytes ifTrue:[ |
|
1117 anAddressBuffer replaceFrom:1 to:addrLen with:addrBytes |
|
1118 ] ifFalse:[ |
|
1119 "/ can be SocketAddress for ST-80 compatibility |
|
1120 anAddressBuffer addressBytes:(addrBytes copyTo:addrLen) |
|
1121 ]. |
|
1122 ]. |
|
1123 ^ nReceived |
|
1124 ]. |
|
1125 " |
|
1126 arrive here if you try to receive into an invalid buffer |
|
1127 (i.e. not ByteArray-like), |
|
1128 or if the addressBuffer is nonNil AND not a ByteArray/String |
|
1129 or if the addressBuffer is nonNil AND too small. |
|
1130 " |
|
1131 self primitiveFailed |
|
1132 ! |
|
1133 |
|
1134 sendTo:anAddressBuffer buffer:buffer |
|
1135 "send datagramm data - fetch address of destination host from |
|
1136 anAddressBuffer, data from aDataBuffer. |
|
1137 Both must be ByteArray-like. The bytes in the addressBuffer must |
|
1138 be a valid address for my domain (i.e. for inet, a 4-byte byteArray). |
|
1139 Return the number of bytes transmitted, or a negative number on error. |
|
1140 On error, the unix error code is left in the lastErrorNumber |
|
1141 instance variable. |
|
1142 Flags is currently ignored; it is there for ST-80 compatibility." |
|
1143 |
|
1144 ^ self sendTo:anAddressBuffer buffer:buffer start:1 for:buffer size flags:0 |
|
1145 ! |
|
1146 |
|
1147 sendTo:anAddressBuffer buffer:aDataBuffer start:startIndex for:count flags:flags |
|
1148 "send datagramm data - fetch address of destination host from |
|
1149 anAddressBuffer, data from aDataBuffer starting at startIndex, |
|
1150 sending count bytes. |
|
1151 Both must be ByteArray-like. The bytes in the addressBuffer must |
|
1152 be a valid address for my domain (i.e. for inet, a 4-byte byteArray). |
|
1153 Return the number of bytes transmitted, or a negative number on error. |
|
1154 On error, the unix error code is left in the lastErrorNumber |
|
1155 instance variable." |
|
1156 |
|
1157 |addrBytes addrLen nReceived portNo| |
|
1158 |
|
1159 "/ addressBuffer can be a 6-byte byteArray (last 2 bytes are portNo, msb-first) |
|
1160 "/ or an instance of IPSocketAddress |
|
1161 "/ |
|
1162 anAddressBuffer class isBytes ifTrue:[ |
|
1163 addrBytes := anAddressBuffer copyFrom:1 to:4. |
|
1164 portNo := ((anAddressBuffer at:5) bitShift:8) |
|
1165 + (anAddressBuffer at:6). |
|
1166 ] ifFalse:[ |
|
1167 addrBytes := anAddressBuffer hostAddress. |
|
1168 portNo := anAddressBuffer port. |
|
1169 ]. |
|
1170 %{ |
|
1171 OBJ oClass; |
|
1172 OBJ fp = _INST(filePointer); |
|
1173 int nInstVars, nInstBytes, objSize; |
|
1174 int sock; |
|
1175 struct sockaddr_in sa; |
|
1176 struct sockaddr *saPtr = (struct sockaddr *)&sa; |
|
1177 int alen = sizeof(sa); |
|
1178 int n; |
|
1179 char *cp; |
|
1180 int _flags = 0; |
|
1181 int offs, nBytes; |
|
1182 unsigned long norder; |
|
1183 |
|
1184 _flags = __longIntVal(flags); |
|
1185 |
|
1186 if ((fp != nil) |
|
1187 && __isSmallInteger(startIndex) |
|
1188 && __isSmallInteger(count)) { |
|
1189 sock = fileno(__FILEVal(fp)); |
|
1190 |
|
1191 if (addrBytes != nil) { |
|
1192 if (! __isByteArray(addrBytes)) goto bad; |
|
1193 cp = __ByteArrayInstPtr(addrBytes)->ba_element; |
|
1194 n = __byteArraySize(addrBytes); |
|
1195 if (alen < n) n = alen; |
|
1196 /* |
|
1197 printf("address is %d bytes ... %d.%d.%d.%d", n, cp[0], cp[1], cp[2], cp[3]); |
|
1198 */ |
|
1199 bcopy(cp, &sa.sin_addr.s_addr, n); |
|
1200 sa.sin_family = AF_INET; |
|
1201 sa.sin_port = htons((u_short) __intVal(portNo)); |
|
1202 } else { |
|
1203 alen = 0; |
|
1204 saPtr = (struct sockaddr *)0; |
|
1205 } |
|
1206 |
|
1207 oClass = __Class(aDataBuffer); |
|
1208 switch (_intVal(_ClassInstPtr(oClass)->c_flags) & ARRAYMASK) { |
|
1209 case BYTEARRAY: |
|
1210 offs = __intVal(startIndex) - 1; |
|
1211 break; |
|
1212 case WORDARRAY: |
|
1213 offs = (__intVal(startIndex) - 1) * sizeof(short); |
|
1214 break; |
|
1215 case LONGARRAY: |
|
1216 offs = (__intVal(startIndex) - 1) * sizeof(long); |
|
1217 break; |
|
1218 case FLOATARRAY: |
|
1219 offs = (__intVal(startIndex) - 1) * sizeof(float); |
|
1220 break; |
|
1221 case DOUBLEARRAY: |
|
1222 offs = (__intVal(startIndex) - 1) * sizeof(double); |
|
1223 #ifdef NEED_DOUBLE_ALIGN |
|
1224 offs += sizeof(long); |
|
1225 #endif |
|
1226 break; |
|
1227 default: |
|
1228 goto bad; |
|
1229 } |
|
1230 nBytes = __intVal(count); |
|
1231 |
|
1232 nInstVars = _intVal(_ClassInstPtr(oClass)->c_ninstvars); |
|
1233 nInstBytes = OHDR_SIZE + nInstVars * sizeof(OBJ); |
|
1234 objSize = __qSize(aDataBuffer) - nInstBytes; |
|
1235 cp = (char *)_InstPtr(aDataBuffer) + nInstBytes; |
|
1236 cp += offs; |
|
1237 if ((offs + nBytes) > objSize) { |
|
1238 /* |
|
1239 printf("cut off ...\n"); |
|
1240 */ |
|
1241 nBytes = objSize - offs; |
|
1242 } |
|
1243 |
|
1244 norder = htonl(sa.sin_addr.s_addr); |
|
1245 /* |
|
1246 printf("sending %d bytes ... to ", nBytes); |
|
1247 printf("%d.%d.%d.%d\n", |
|
1248 (norder >> 24) & 0xFF, |
|
1249 (norder >> 16) & 0xFF, |
|
1250 (norder >> 8) & 0xFF, |
|
1251 norder & 0xFF); |
|
1252 */ |
|
1253 |
|
1254 __BEGIN_INTERRUPTABLE__ |
|
1255 do { |
|
1256 n = sendto(sock, cp, nBytes, _flags, saPtr, alen); |
|
1257 } while ((n < 0) && (errno == EINTR)); |
|
1258 __END_INTERRUPTABLE__ |
|
1259 |
|
1260 if (n < 0) { |
|
1261 _INST(lastErrorNumber) = _MKSMALLINT(errno); |
|
1262 } |
|
1263 RETURN (_MKSMALLINT(n)); |
|
1264 } |
|
1265 bad: ; |
|
1266 %}. |
|
1267 " |
|
1268 arrive here if you try to send from an invalid buffer |
|
1269 (i.e. not ByteArray-like), |
|
1270 or if the addressBuffer is nonNil AND not a ByteArray/String |
|
1271 or if the addressBuffer is nonNil AND too small. |
|
1272 " |
|
1273 self primitiveFailed |
|
1274 ! ! |
|
1275 |
|
1276 !Socket methodsFor:'low level'! |
|
1277 |
|
1278 accept |
|
1279 "create a new TCP socket from accepting on the receiver. |
|
1280 This method will suspend the current process if no connection is waiting. |
|
1281 For ST-80 compatibility" |
744 |
1282 |
745 |newSock| |
1283 |newSock| |
746 |
1284 |
747 newSock := (self new) for:nil port:(self portOfService:service). |
1285 "/ self readWait. |
748 newSock notNil ifTrue:[ |
1286 newSock := self class new. |
749 newSock listenFor:5. |
1287 (newSock acceptOn:self) ifFalse:[^ nil]. |
750 ]. |
|
751 ^ newSock |
1288 ^ newSock |
752 |
1289 |
753 " |
1290 " |
754 Socket provide:9995 |
1291 |sock newSock| |
755 (Socket provide:9996) accept |
1292 |
756 Socket provide:'nntp' |
1293 sock := Socket provide:8004. |
757 " |
1294 sock listenFor:5. |
|
1295 newSock := sock accept. |
|
1296 " |
|
1297 ! |
|
1298 |
|
1299 acceptOn:aSocket |
|
1300 "accept a connection on a server port (created with:'Socket>>onIPPort:') |
|
1301 usage is: (Socket basicNew acceptOn:(Socket onIPPort:9999)). |
|
1302 Return the true if ok; false if not. |
|
1303 |
|
1304 NOTICE: this method will block, if no connection is already pending. |
|
1305 use readWait or Socket>>accept." |
|
1306 |
|
1307 |serverSocketFd| |
|
1308 |
|
1309 filePointer notNil ifTrue:[ |
|
1310 ^ self error:'already connected' |
|
1311 ]. |
|
1312 |
|
1313 domain := aSocket domain. |
|
1314 socketType := aSocket type. |
|
1315 serverSocketFd := aSocket fileDescriptor. |
|
1316 serverSocketFd isNil ifTrue:[ |
|
1317 ^ self error:'invalid server socket' |
|
1318 ]. |
|
1319 (serverSocketFd isMemberOf:SmallInteger) ifFalse:[ |
|
1320 ^ self error:'invalid server socket' |
|
1321 ]. |
|
1322 %{ |
|
1323 FILE *fp; |
|
1324 int flags; |
|
1325 int sock, newSock; |
|
1326 union { |
|
1327 struct sockaddr_in in ; |
|
1328 struct sockaddr_un un ; |
|
1329 } sa; |
|
1330 int alen; |
|
1331 struct hostent *he ; |
|
1332 char dotted[20] ; |
|
1333 |
|
1334 sock = _intVal(serverSocketFd); |
|
1335 |
|
1336 #if defined(O_NDELAY) && defined(SET_NDELAY) |
|
1337 flags = ioctl(sock, F_GETFL, 0); |
|
1338 ioctl(sock, F_SETFL, flags | O_NDELAY); |
|
1339 #endif |
|
1340 __BEGIN_INTERRUPTABLE__ |
|
1341 do { |
|
1342 alen = sizeof(sa) ; |
|
1343 newSock = accept(sock, (struct sockaddr *) &sa, &alen); |
|
1344 } while ((newSock < 0) && (errno == EINTR)); |
|
1345 __END_INTERRUPTABLE__ |
|
1346 |
|
1347 #if defined(O_NDELAY) && defined(SET_NDELAY) |
|
1348 ioctl(sock, F_SETFL, flags); |
|
1349 #endif |
|
1350 |
|
1351 if (newSock < 0) { |
|
1352 DBGPRINTF(("SOCKET: accept call failed errno=%d\n", errno)); |
|
1353 _INST(lastErrorNumber) = _MKSMALLINT(errno); |
|
1354 RETURN (false); |
|
1355 } |
|
1356 |
|
1357 /* |
|
1358 * extract the partners address |
|
1359 */ |
|
1360 #ifdef AF_INET |
|
1361 if (_INST(domain) == @symbol(inet)) { |
|
1362 he = gethostbyaddr((char *) &sa.in.sin_addr.s_addr, alen, AF_INET) ; |
|
1363 if (! he) { |
|
1364 unsigned long norder; |
|
1365 |
|
1366 norder = htonl(sa.in.sin_addr.s_addr) ; |
|
1367 sprintf(dotted, "%d.%d.%d.%d", |
|
1368 (norder >> 24) & 0xFF, |
|
1369 (norder >> 16) & 0xFF, |
|
1370 (norder >> 8) & 0xFF, |
|
1371 norder & 0xFF); |
|
1372 } |
|
1373 DBGPRINTF(("SOCKET: accepted connection from host %s\n", (he ? he->h_name : dotted))) ; |
|
1374 _INST(peerName) = _MKSTRING((he ? he->h_name : dotted) COMMA_CON); |
|
1375 } |
|
1376 #endif |
|
1377 #ifdef AF_UNIX |
|
1378 if (_INST(domain) == @symbol(unix)) { |
|
1379 DBGPRINTF(("SOCKET: accepted connection on unix socket\n")) ; |
|
1380 /* nothing to be done here */ |
|
1381 } |
|
1382 #endif |
|
1383 |
|
1384 /* |
|
1385 * make it a FILE * |
|
1386 */ |
|
1387 fp = fdopen(newSock, "r+"); |
|
1388 if (! fp) { |
|
1389 DBGPRINTF(("SOCKET: fdopen call failed\n")); |
|
1390 _INST(lastErrorNumber) = _MKSMALLINT(errno); |
|
1391 close(newSock); |
|
1392 RETURN (false); |
|
1393 } else { |
|
1394 #ifdef NO_BUFFER |
|
1395 setbuf(fp, NULL); |
|
1396 _INST(buffered) = false; |
|
1397 #endif |
|
1398 _INST(filePointer) = __MKOBJ(fp); |
|
1399 } |
|
1400 %}. |
|
1401 mode := #readwrite. |
|
1402 binary := false. |
|
1403 port := aSocket port. |
|
1404 ^ true |
|
1405 ! |
|
1406 |
|
1407 bindTo:aSocketAddress |
|
1408 "ST80 compatible bind: |
|
1409 the socketAddress object is supposed to respond to |
|
1410 portOrName and address requests." |
|
1411 |
|
1412 ^ self bindTo:(aSocketAddress portOrName) |
|
1413 address:(aSocketAddress address) |
|
1414 ! |
|
1415 |
|
1416 bindTo:portNrOrName address:address |
|
1417 "low level bind - returns true if ok, false otherwise. |
|
1418 Currently only non-address binding is supported; |
|
1419 i.e. address must always be nil. |
|
1420 |
|
1421 The interpretation of portNrOrName depends on the domain: |
|
1422 inet domain uses (4byte) byteArray like internet numbers, |
|
1423 unix domain uses pathname strings, |
|
1424 others use whatever will come up in the future |
|
1425 " |
|
1426 |
|
1427 ^ self bindTo:portNrOrName address:address reuseAddress:true |
|
1428 ! |
|
1429 |
|
1430 bindTo:portNrOrName address:address reuseAddress:reuse |
|
1431 "low level bind - returns true if ok, false otherwise. |
|
1432 Currently only non-address binding is supported; |
|
1433 i.e. address must always be nil. |
|
1434 |
|
1435 The interpretation of portNrOrName depends on the domain: |
|
1436 inet domain uses (4byte) byteArray like internet numbers, |
|
1437 unix domain uses pathname strings, |
|
1438 others use whatever will come up in the future |
|
1439 " |
|
1440 |
|
1441 filePointer isNil ifTrue:[ |
|
1442 ^ self error:'not a valid socket' |
|
1443 ]. |
|
1444 %{ |
|
1445 OBJ t = _INST(filePointer); |
|
1446 OBJ myDomain; |
|
1447 int sock; |
|
1448 union { |
|
1449 struct sockaddr_in in; |
|
1450 struct sockaddr_un un; |
|
1451 } sa; |
|
1452 int sockaddr_size; |
|
1453 int ret; |
|
1454 int on = 1; |
|
1455 int ok; |
|
1456 extern OBJ LargeInteger; |
|
1457 |
|
1458 if (!__isString(_INST(domain)) && !__isSymbol(_INST(domain))) { |
|
1459 DBGPRINTF(("SOCKET: invalid domain arg\n")); |
|
1460 RETURN (false); |
|
1461 } |
|
1462 |
|
1463 ok = 0; |
|
1464 myDomain = _INST(domain); |
|
1465 #ifdef AF_INET |
|
1466 if (myDomain == @symbol(inet)) { |
|
1467 /* |
|
1468 * INET addresses - port must be a smallinteger |
|
1469 */ |
|
1470 sa.in.sin_family = AF_INET; |
|
1471 if (! __isSmallInteger(portNrOrName)) { |
|
1472 DBGPRINTF(("SOCKET: invalid port arg\n")); |
|
1473 RETURN (false); |
|
1474 } |
|
1475 sa.in.sin_port = htons((u_short) _intVal(portNrOrName)); |
|
1476 if (address == nil) { |
|
1477 sa.in.sin_addr.s_addr = htonl(INADDR_ANY); |
|
1478 } else { |
|
1479 if (__isInteger(address)) { |
|
1480 sa.in.sin_addr.s_addr = htonl(__longIntVal(address)); |
|
1481 } else { |
|
1482 printf("SOCKET: address bind not yet supported\n"); |
|
1483 RETURN (false); |
|
1484 } |
|
1485 } |
|
1486 sockaddr_size = sizeof(struct sockaddr_in); |
|
1487 ok = 1; |
|
1488 } |
|
1489 #endif |
|
1490 #ifdef AF_UNIX |
|
1491 if (myDomain == @symbol(unix)) { |
|
1492 char *pathName; |
|
1493 int l; |
|
1494 |
|
1495 if (! __isString(portNrOrName)) { |
|
1496 DBGPRINTF(("SOCKET: invalid port (pathname) arg\n")); |
|
1497 RETURN (false); |
|
1498 } |
|
1499 pathName = __stringVal(portNrOrName); |
|
1500 l = strlen(pathName); |
|
1501 if ((l + sizeof ( sa.un.sun_family )) > sizeof(struct sockaddr_un)) { |
|
1502 DBGPRINTF(("SOCKET: pathname too long\n")); |
|
1503 RETURN (false); |
|
1504 } |
|
1505 |
|
1506 strcpy(sa.un.sun_path, pathName); |
|
1507 sa.un.sun_family = AF_UNIX; |
|
1508 sockaddr_size = l + sizeof ( sa.un.sun_family ); |
|
1509 ok = 1; |
|
1510 } |
|
1511 #endif |
|
1512 /* |
|
1513 * XXXX add addressing stuff for other domains here ... |
|
1514 */ |
|
1515 #ifdef AF_X25 |
|
1516 if (myDomain == @symbol(x25)) { |
|
1517 } |
|
1518 #endif |
|
1519 #ifdef AF_NS |
|
1520 if (myDomain == @symbol(ns)) { |
|
1521 } |
|
1522 #endif |
|
1523 #ifdef AF_APPLETALK |
|
1524 if (myDomain == @symbol(appletalk)) { |
|
1525 } |
|
1526 #endif |
|
1527 #ifdef AF_SNA |
|
1528 if (myDomain == @symbol(sna)) { |
|
1529 } |
|
1530 #endif |
|
1531 #ifdef AF_NS |
|
1532 if (myDomain == @symbol(xns)) { |
|
1533 } |
|
1534 #endif |
|
1535 #ifdef AF_RAW |
|
1536 if (myDomain == @symbol(raw)) { |
|
1537 } |
|
1538 #endif |
|
1539 |
|
1540 if (! ok) { |
|
1541 DBGPRINTF(("SOCKET: unsupported domain\n")); |
|
1542 RETURN (false); |
|
1543 } |
|
1544 |
|
1545 sock = fileno(__FILEVal(t)); |
|
1546 |
|
1547 #ifdef SO_REUSEADDR |
|
1548 if (reuse == true) { |
|
1549 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof (on)) < 0) { |
|
1550 DBGPRINTF(("SOCKET: setsockopt - SO_REUSEADDR failed\n")); |
|
1551 } |
|
1552 } |
|
1553 #endif /* SO_REUSEADDR */ |
|
1554 |
|
1555 __BEGIN_INTERRUPTABLE__ |
|
1556 do { |
|
1557 ret = bind(sock, (struct sockaddr *)&sa, sockaddr_size); |
|
1558 } while ((ret < 0) && (errno == EINTR)); |
|
1559 __END_INTERRUPTABLE__ |
|
1560 |
|
1561 if (ret < 0) { |
|
1562 DBGPRINTF(("SOCKET: bind failed errno=%d\n", errno)); |
|
1563 _INST(lastErrorNumber) = _MKSMALLINT(errno); |
|
1564 RETURN (false); |
|
1565 } |
|
1566 %}. |
|
1567 |
|
1568 port := portNrOrName. |
|
1569 ^ true |
|
1570 |
|
1571 " |
|
1572 (Socket domain:#inet type:#stream) |
|
1573 bindTo:9999 |
|
1574 address:nil |
|
1575 " |
|
1576 ! |
|
1577 |
|
1578 closeFile |
|
1579 "low level close" |
|
1580 |
|
1581 %{ /* NOCONTEXT */ |
|
1582 |
|
1583 OBJ t; |
|
1584 |
|
1585 t = _INST(filePointer); |
|
1586 if (t != nil) { |
|
1587 FILE *fp; |
|
1588 |
|
1589 fp = __FILEVal(t); |
|
1590 fflush(fp); |
|
1591 shutdown(fileno(fp), 2); |
|
1592 fclose(fp); |
|
1593 _INST(filePointer) = nil; |
|
1594 } |
|
1595 %} |
|
1596 ! |
|
1597 |
|
1598 connectTo:hostOrPathName port:portNrOrName |
|
1599 "low level connect; connect to port, portNrOrName on host, hostName. |
|
1600 For unix-domain sockets, the port argument is ignored and pathName is taken. |
|
1601 Other sockets are not yet implemented. |
|
1602 Return true if ok, false otherwise. |
|
1603 Hostname must be a string, portNrOrName an integer port number (in inet domain). |
|
1604 The current process will block (but not the whole Smalltalk) until the connection |
|
1605 is established. |
|
1606 See also: #connectTo:port:withTimeout: for a somewhat nicer interface." |
|
1607 |
|
1608 filePointer isNil ifTrue:[ |
|
1609 ^ self error:'not a valid socket' |
|
1610 ]. |
|
1611 %{ |
|
1612 OBJ t = _INST(filePointer); |
|
1613 OBJ myDomain; |
|
1614 union { |
|
1615 struct sockaddr_in in ; |
|
1616 struct sockaddr_un un; |
|
1617 } sa; |
|
1618 struct hostent *hp ; |
|
1619 int a, sock ; |
|
1620 long addr; |
|
1621 FILE *fp; |
|
1622 int ret; |
|
1623 int on = 1; |
|
1624 int ok; |
|
1625 int sockaddr_size; |
|
1626 |
|
1627 if (!__isString(_INST(domain)) && !__isSymbol(_INST(domain))) { |
|
1628 DBGPRINTF(("SOCKET: invalid domain arg\n")); |
|
1629 RETURN (false); |
|
1630 } |
|
1631 |
|
1632 ok = 0; |
|
1633 myDomain = _INST(domain); |
|
1634 bzero((char *) &sa, sizeof(sa)) ; |
|
1635 #ifdef AF_INET |
|
1636 if (myDomain == @symbol(inet)) { |
|
1637 char *hostName; |
|
1638 |
|
1639 if (! __isString(hostOrPathName)) { |
|
1640 DBGPRINTF(("SOCKET: invalid hostname arg\n")); |
|
1641 RETURN (false); |
|
1642 } |
|
1643 hostName = (char *) _stringVal(hostOrPathName); |
|
1644 |
|
1645 if (! __isSmallInteger(portNrOrName)) { |
|
1646 DBGPRINTF(("SOCKET: invalid port arg\n")); |
|
1647 RETURN (false); |
|
1648 } |
|
1649 |
|
1650 sa.in.sin_family = AF_INET; |
|
1651 sa.in.sin_port = htons((u_short) _intVal(portNrOrName)) ; |
|
1652 |
|
1653 if ((addr = inet_addr(hostName)) != -1) { |
|
1654 /* |
|
1655 * is Internet addr in octet notation |
|
1656 */ |
|
1657 bcopy(&addr, (char *) &sa.in.sin_addr, sizeof(addr)) ; /* set address */ |
|
1658 } else { |
|
1659 /* |
|
1660 * do we know the host's address? |
|
1661 */ |
|
1662 if ((hp = gethostbyname(hostName)) == NULL) { |
|
1663 DBGPRINTF(("SOCKET: unknown host:%s\n", hostName)); |
|
1664 RETURN (false); |
|
1665 } |
|
1666 bcopy(hp->h_addr, (char *) &sa.in.sin_addr, hp->h_length) ; |
|
1667 sa.in.sin_family = hp->h_addrtype; |
|
1668 } |
|
1669 sockaddr_size = sizeof(struct sockaddr_in); |
|
1670 ok = 1; |
|
1671 } |
|
1672 #endif |
|
1673 #ifdef AF_UNIX |
|
1674 if (myDomain == @symbol(unix)) { |
|
1675 char *pathName; |
|
1676 int l; |
|
1677 |
|
1678 if (! __isString(hostOrPathName)) { |
|
1679 DBGPRINTF(("SOCKET: invalid port (pathname) arg\n")); |
|
1680 RETURN (false); |
|
1681 } |
|
1682 pathName = (char *) __stringVal(hostOrPathName); |
|
1683 l = strlen(pathName); |
|
1684 if ((l + sizeof ( sa.un.sun_family )) > sizeof(struct sockaddr_un)) { |
|
1685 DBGPRINTF(("SOCKET: pathname too long\n")); |
|
1686 RETURN (false); |
|
1687 } |
|
1688 |
|
1689 strcpy(sa.un.sun_path, pathName); |
|
1690 sa.un.sun_family = AF_UNIX; |
|
1691 sockaddr_size = l + sizeof ( sa.un.sun_family ); |
|
1692 ok = 1; |
|
1693 } |
|
1694 #endif |
|
1695 /* |
|
1696 * XXXX add addressing stuff for other domains here ... |
|
1697 */ |
|
1698 #ifdef AF_X25 |
|
1699 if (myDomain == @symbol(x25)) { |
|
1700 } |
|
1701 #endif |
|
1702 #ifdef AF_NS |
|
1703 if (myDomain == @symbol(ns)) { |
|
1704 } |
|
1705 #endif |
|
1706 #ifdef AF_APPLETALK |
|
1707 if (myDomain == @symbol(appletalk)) { |
|
1708 } |
|
1709 #endif |
|
1710 #ifdef AF_NS |
|
1711 if (myDomain == @symbol(xns)) { |
|
1712 } |
|
1713 #endif |
|
1714 #ifdef AF_SNA |
|
1715 if (myDomain == @symbol(sna)) { |
|
1716 } |
|
1717 #endif |
|
1718 #ifdef AF_RAW |
|
1719 if (myDomain == @symbol(raw)) { |
|
1720 } |
|
1721 #endif |
|
1722 |
|
1723 if (! ok) { |
|
1724 DBGPRINTF(("SOCKET: unsupported domain\n")); |
|
1725 RETURN (false); |
|
1726 } |
|
1727 |
|
1728 sock = fileno(__FILEVal(t)); |
|
1729 |
|
1730 /* |
|
1731 * connect |
|
1732 */ |
|
1733 __BEGIN_INTERRUPTABLE__ |
|
1734 |
|
1735 do { |
|
1736 ret = connect(sock, (struct sockaddr *)&sa, sockaddr_size); |
|
1737 } while ((ret < 0) |
|
1738 && ((errno == EINTR) |
|
1739 #ifdef EAGAIN |
|
1740 || (errno == EAGAIN) |
|
1741 #endif |
|
1742 #ifdef EINPROGRESS |
|
1743 || (errno == EINPROGRESS) |
|
1744 #endif |
|
1745 )); |
|
1746 __END_INTERRUPTABLE__ |
|
1747 |
|
1748 if (ret < 0) { |
|
1749 DBGPRINTF(("SOCKET: connect failed errno=%d\n", errno)); |
|
1750 #ifdef DUMP_ADDRESS |
|
1751 { |
|
1752 char *cp = (char *)(&sa); |
|
1753 int i; |
|
1754 |
|
1755 printf("address data:\n"); |
|
1756 for (i=0; i<sockaddr_size; i++) { |
|
1757 printf(" %02x\n", *cp++); |
|
1758 } |
|
1759 } |
|
1760 #endif |
|
1761 _INST(lastErrorNumber) = _MKSMALLINT(errno); |
|
1762 RETURN (false); |
|
1763 } |
|
1764 %}. |
|
1765 port := portNrOrName. |
|
1766 peerName := hostOrPathName. |
|
1767 ^ true |
|
1768 ! |
|
1769 |
|
1770 connectTo:hostOrPathName port:portNrOrName withTimeout:millis |
|
1771 "connect to port, portNrOrName on host, hostName. |
|
1772 Or path (UNIX socket), where portNrOrName is ignored. |
|
1773 Return true if ok, false otherwise. |
|
1774 Hostname must be a string, portNrOrName an integer port number (in inet domain). |
|
1775 If a non-nil timeout is given, stop trying after that time and return false as well." |
|
1776 |
|
1777 |stopSignal stopMe connection| |
|
1778 |
|
1779 millis isNil ifTrue:[ |
|
1780 ^ self connectTo:hostOrPathName port:portNrOrName |
|
1781 ]. |
|
1782 stopSignal := Signal new. |
|
1783 stopMe := [stopSignal raise]. |
|
1784 stopSignal handle:[:ex | |
|
1785 "/ 'timeout on connect' infoPrintNL. |
|
1786 ^ false |
|
1787 ] do:[ |
|
1788 Processor addTimedBlock:stopMe afterMilliseconds:millis. |
|
1789 connection := self connectTo:hostOrPathName port:portNrOrName. |
|
1790 Processor removeTimedBlock:stopMe. |
|
1791 ]. |
|
1792 ^ connection |
|
1793 |
|
1794 "Created: 31.10.1995 / 18:52:49 / cg" |
|
1795 ! |
|
1796 |
|
1797 listenFor:aNumber |
|
1798 "same as listenWithBacklog: - for ST-80 compatibility" |
|
1799 |
|
1800 ^ self listenWithBacklog:aNumber |
|
1801 ! |
|
1802 |
|
1803 listenWithBacklog:aNumber |
|
1804 "start listening; return true if ok, false on error" |
|
1805 |
|
1806 filePointer isNil ifTrue:[ |
|
1807 ^ self error:'not a valid socket' |
|
1808 ]. |
|
1809 %{ |
|
1810 OBJ fp = _INST(filePointer); |
|
1811 int sock; |
|
1812 int ret; |
|
1813 |
|
1814 if (! __isSmallInteger(aNumber)) { |
|
1815 DBGPRINTF(("SOCKET: invalid arg\n")); |
|
1816 RETURN (false); |
|
1817 } |
|
1818 |
|
1819 sock = fileno(__FILEVal(fp)); |
|
1820 |
|
1821 __BEGIN_INTERRUPTABLE__ |
|
1822 do { |
|
1823 ret = listen(sock, _intVal(aNumber)); |
|
1824 } while ((ret < 0) && (errno == EINTR)); |
|
1825 __END_INTERRUPTABLE__ |
|
1826 |
|
1827 if (ret < 0) { |
|
1828 DBGPRINTF(("SOCKET: listen call failed errno=%d\n", errno)); |
|
1829 _INST(lastErrorNumber) = _MKSMALLINT(errno); |
|
1830 RETURN (false); |
|
1831 } |
|
1832 %}. |
|
1833 ^ true |
758 ! ! |
1834 ! ! |
759 |
1835 |
760 !Socket class methodsFor:'ST80 queries'! |
1836 !Socket methodsFor:'queries'! |
761 |
1837 |
762 sockStream |
1838 domain |
763 "return the type code for stream sockets" |
1839 "return the sockets addressing domain (i.e. #inet, #unix, #x25, #appletalk)" |
764 |
1840 |
765 ^ #stream |
1841 ^ domain |
766 ! ! |
1842 ! |
767 |
1843 |
768 !Socket class methodsFor:'ST80 instance creation'! |
1844 getName |
769 |
1845 "return the name; here, we return the ports name" |
770 family:domainSymbol type:typeSymbol |
1846 |
771 "create a socket for domain and type - ST80 simply uses a different name. |
1847 ^ port printString |
772 Domain must be one of the symbols: #inet, #unix, #ns, #appletalk or #ns; |
1848 ! |
773 Type must be #stream, #datagram or #raw |
1849 |
774 |
1850 getPeer |
775 XXX: currently only the #inet domain is supported" |
1851 "ST-80 compatibility: return an IPSocketAddress instance representing |
776 |
1852 my hostname/port combination. |
777 ^ self domain:domainSymbol type:typeSymbol |
1853 If you are interrested in the hostname, use getPeerName directly." |
778 |
1854 |
779 " |
1855 domain == #unix ifTrue:[ |
780 Socket family:#inet type:#stream |
1856 ^ UDSocketAddress name:peerName |
781 Socket family:#inet type:#datagram |
1857 ]. |
782 Socket family:#unix type:#stream |
1858 ^ IPSocketAddress hostAddress:(self class ipAddressOfHost:peerName) port:port |
783 " |
1859 |
784 ! ! |
1860 "Created: 2.11.1995 / 11:22:39 / cg" |
785 |
1861 ! |
786 !Socket class methodsFor:'general instance creation'! |
1862 |
787 |
1863 getPeerName |
788 domain:domainSymbol type:type |
1864 "return the peer name; thats the hostname (or dotted name) of the |
789 "create a socket for domain and type - |
1865 partners host after an accept." |
790 neither any connect nor binding is done. |
1866 |
791 Domain must be one of the symbols: #inet, #unix, #ns, #appletalk or #ns; |
1867 ^ peerName |
792 Type must be #stream, #datagram or #raw |
1868 ! |
793 |
1869 |
794 XXX: currently only the #inet domain is supported" |
1870 isActive |
795 |
1871 "return true, if the receiver has a connection" |
796 ^ self new domain:domainSymbol type:type |
1872 |
797 |
1873 ^ filePointer notNil |
798 " |
1874 ! |
799 Socket domain:#inet type:#stream |
1875 |
800 Socket domain:#inet type:#datagram |
1876 port |
801 Socket domain:#unix type:#stream |
1877 "return the port number (or name for unix-sockets) to which the socket is bound" |
802 Socket domain:#appletalk type:#stream |
1878 |
803 Socket domain:#DECnet type:#stream |
1879 ^ port |
804 " |
1880 ! |
805 ! |
1881 |
806 |
1882 type |
807 newUDP |
1883 "return the sockets connection type (i.e. #datagram, #stream etc)" |
808 "create a UDP socket - no binding or other setup is done, |
1884 |
809 neither connect nor connect-wait is done." |
1885 ^ socketType |
810 |
|
811 ^ self new domain:#inet type:#datagram |
|
812 |
|
813 "Socket newUDP" |
|
814 ! |
|
815 |
|
816 newUDP:aServiceOrNil |
|
817 "create a UDP socket for a service - |
|
818 neither connect nor connect-wait is done." |
|
819 |
|
820 |newSock| |
|
821 |
|
822 newSock := self newUDP. |
|
823 (newSock notNil and:[aServiceOrNil notNil]) ifTrue:[ |
|
824 newSock bindTo:(self portOfService:aServiceOrNil) address:nil |
|
825 ]. |
|
826 ^ newSock |
|
827 |
|
828 "Socket newUDP:nil" |
|
829 ! |
|
830 |
|
831 newTCP |
|
832 "create a TCP socket - no binding or other setup is done, |
|
833 neither connect nor connect-wait is done." |
|
834 |
|
835 ^ self new domain:#inet type:#stream |
|
836 |
|
837 "Socket newUDP" |
|
838 ! |
|
839 |
|
840 newTCP:aServiceOrNil |
|
841 "create a TCP socket for a service - |
|
842 neither connect nor connect-wait is done." |
|
843 |
|
844 |newSock| |
|
845 |
|
846 newSock := self newTCP. |
|
847 (newSock notNil and:[aServiceOrNil notNil]) ifTrue:[ |
|
848 newSock bindTo:(self portOfService:aServiceOrNil) address:nil |
|
849 ]. |
|
850 ^ newSock |
|
851 |
|
852 |
|
853 "Socket newTCP:'nntp'" |
|
854 "Socket newTCP:9995" |
|
855 ! |
|
856 |
|
857 newTCPclientToHost:hostname port:aService |
|
858 "create a new TCP client socket connecting to a service. |
|
859 Return a socket instance if ok, nil on failure. |
|
860 Block until a connection is established (but only the current thread; |
|
861 not the whole smalltalk). |
|
862 See also: #newTCPclientToHost:port:withTimeout:" |
|
863 |
|
864 ^ self newTCPclientToHost:hostname port:aService withTimeout:nil |
|
865 |
|
866 " |
|
867 Socket newTCPclientToHost:'localhost' port:'nntp' |
|
868 " |
|
869 |
|
870 "Created: 31.10.1995 / 18:54:11 / cg" |
|
871 ! |
|
872 |
|
873 newTCPclientToHost:hostname port:aService withTimeout:millis |
|
874 "create a new TCP client socket connecting to a service. |
|
875 Return a socket instance if ok, nil on failure. |
|
876 If the millis arg is nonNil, stop trying to connect after that many milliseconds |
|
877 and return nil.." |
|
878 |
|
879 |newSock| |
|
880 |
|
881 newSock := self newTCP. |
|
882 newSock notNil ifTrue:[ |
|
883 (newSock connectTo:hostname port:(self portOfService:aService) withTimeout:millis) ifFalse:[ |
|
884 newSock close. |
|
885 ^ nil |
|
886 ] |
|
887 ]. |
|
888 ^ newSock |
|
889 " |
|
890 same as: |
|
891 ^ (self new) for:hostname port:(self portOfService:aPort). |
|
892 " |
|
893 " |
|
894 Socket newTCPclientToHost:'slsv6bt' port:'nntp' |
|
895 Socket newTCPclientToHost:'localhost' port:'nntp' withTimeout:1000 |
|
896 " |
|
897 ! |
|
898 |
|
899 newTCPserverAtPort:aService |
|
900 "create a new TCP server socket providing service." |
|
901 |
|
902 |newSock| |
|
903 |
|
904 newSock := self newTCP. |
|
905 newSock notNil ifTrue:[ |
|
906 (newSock bindTo:(self portOfService:aService) address:nil) ifFalse:[ |
|
907 ^ nil |
|
908 ] |
|
909 ]. |
|
910 ^ newSock |
|
911 " |
|
912 same as: |
|
913 ^ (self new) for:nil port:aPort |
|
914 " |
|
915 ! |
|
916 |
|
917 newUDPserverAtPort:aService |
|
918 "create a new UDP server socket providing service." |
|
919 |
|
920 |newSock| |
|
921 |
|
922 newSock := self newUDP. |
|
923 newSock notNil ifTrue:[ |
|
924 (newSock bindTo:(self portOfService:aService) address:nil) ifFalse:[ |
|
925 ^ nil |
|
926 ] |
|
927 ]. |
|
928 ^ newSock |
|
929 " |
|
930 same as: |
|
931 ^ (self new) for:nil udpPort:aPort |
|
932 " |
|
933 ! |
|
934 |
|
935 newUNIX |
|
936 "create a UNIX domain socket - no binding or other setup is done, |
|
937 neither connect nor connect-wait is done." |
|
938 |
|
939 ^ self new domain:#unix type:#stream |
|
940 |
|
941 " |
|
942 Socket newUNIX |
|
943 " |
|
944 ! |
|
945 |
|
946 newUNIXclientTo:pathName |
|
947 "create a new UNIX client socket connecting to a pathname. |
|
948 Return a socket instance if ok, nil on failure. |
|
949 Block until a connection is established (but only the current thread; |
|
950 not the whole smalltalk). |
|
951 See also: #newUNIXclientTo:withTimeout:" |
|
952 |
|
953 ^ self newUNIXclientTo:pathName withTimeout:nil |
|
954 |
|
955 ! |
|
956 |
|
957 newUNIXclientTo:pathName withTimeout:millis |
|
958 "create a new UNIX client socket connecting to a pathname. |
|
959 Return a socket instance if ok, nil on failure. |
|
960 If the millis arg is nonNil, stop trying to connect after that many milliseconds |
|
961 and return nil.." |
|
962 |
|
963 |newSock| |
|
964 |
|
965 newSock := self newUNIX. |
|
966 newSock notNil ifTrue:[ |
|
967 (newSock connectTo:pathName port:nil withTimeout:millis) ifFalse:[ |
|
968 newSock close. |
|
969 ^ nil |
|
970 ] |
|
971 ]. |
|
972 ^ newSock |
|
973 |
|
974 " |
|
975 |s| |
|
976 |
|
977 s := Socket newUNIXclientTo:'/tmp/foo' |
|
978 " |
|
979 ! |
|
980 |
|
981 newUNIXserverAt:pathName |
|
982 "create a new UNIX server socket providing service at a pathname." |
|
983 |
|
984 |newSock| |
|
985 |
|
986 newSock := self newUNIX. |
|
987 newSock notNil ifTrue:[ |
|
988 (newSock bindTo:pathName address:nil) ifFalse:[ |
|
989 ^ nil |
|
990 ] |
|
991 ]. |
|
992 ^ newSock |
|
993 |
|
994 " |
|
995 |s s2| |
|
996 |
|
997 s := Socket newUNIXserverAt:'/tmp/foo'. |
|
998 s listenFor:5. |
|
999 s2 := s accept. |
|
1000 " |
|
1001 ! ! |
1886 ! ! |
1002 |
1887 |
1003 !Socket methodsFor:'socket setup'! |
1888 !Socket methodsFor:'socket setup'! |
1004 |
1889 |
1005 domain:domainArg type:typeArg |
1890 domain:domainArg type:typeArg |
1283 peerName := hostName. |
2303 peerName := hostName. |
1284 |
2304 |
1285 " |
2305 " |
1286 Socket new for:'clam' udpPort:(Socket portOfService:'echo') |
2306 Socket new for:'clam' udpPort:(Socket portOfService:'echo') |
1287 " |
2307 " |
1288 ! |
|
1289 |
|
1290 for:hostName port:portNr |
|
1291 "setup for a TCP socket (i.e. inet domain, stream type) |
|
1292 If hostname is nil, a server port is opened, |
|
1293 otherwise a client port to the server on host. |
|
1294 |
|
1295 HISTORIC LEFTOVER: |
|
1296 This method will vanish, as soon as the low level |
|
1297 connect/bind works," |
|
1298 |
|
1299 self obsoleteMethodWarning. |
|
1300 |
|
1301 filePointer notNil ifTrue:[ |
|
1302 ^ self error:'already created' |
|
1303 ]. |
|
1304 (portNr isMemberOf:SmallInteger) ifFalse:[ |
|
1305 ^ self error:'invalid portNr' |
|
1306 ]. |
|
1307 %{ |
|
1308 struct sockaddr_in sa ; |
|
1309 struct hostent *hp ; |
|
1310 int a, sock ; |
|
1311 long addr; |
|
1312 FILE *fp; |
|
1313 int ret; |
|
1314 int on = 1; |
|
1315 |
|
1316 bzero((char *) &sa, sizeof(sa)) ; |
|
1317 sa.sin_family = AF_INET; |
|
1318 sa.sin_addr.s_addr = htonl(INADDR_ANY); |
|
1319 |
|
1320 if ((hostName != nil) && __isString(hostName)){ |
|
1321 bzero(&sa, sizeof(sa)) ; |
|
1322 if ((addr = inet_addr((char *) _stringVal(hostName))) != -1) { |
|
1323 /* |
|
1324 * is Internet addr in octet notation |
|
1325 */ |
|
1326 bcopy(&addr, (char *) &sa.sin_addr, sizeof(addr)) ; /* set address */ |
|
1327 } else { |
|
1328 /* |
|
1329 * do we know the host's address? |
|
1330 */ |
|
1331 if ((hp = gethostbyname((char *) _stringVal(hostName))) == NULL) { |
|
1332 DBGPRINTF(("SOCKET: unknown host\n")); |
|
1333 RETURN ( nil ); |
|
1334 } |
|
1335 bcopy(hp->h_addr, (char *) &sa.sin_addr, hp->h_length) ; |
|
1336 sa.sin_family = hp->h_addrtype; |
|
1337 } |
|
1338 } |
|
1339 |
|
1340 /* |
|
1341 * create the socket |
|
1342 */ |
|
1343 __BEGIN_INTERRUPTABLE__ |
|
1344 do { |
|
1345 sock = socket(sa.sin_family, SOCK_STREAM, 0); |
|
1346 } while ((sock < 0) && (errno == EINTR)); |
|
1347 __END_INTERRUPTABLE__ |
|
1348 |
|
1349 if (sock < 0) { |
|
1350 DBGPRINTF(("SOCKET: socket(dom=%d typ=%d proto=0) call failed errno=%d\n", sa.sin_family, SOCK_STREAM, errno)); |
|
1351 _INST(lastErrorNumber) = _MKSMALLINT(errno); |
|
1352 } else { |
|
1353 /* |
|
1354 * connect/bind |
|
1355 */ |
|
1356 sa.sin_port = htons((u_short) _intVal(portNr)) ; |
|
1357 |
|
1358 __BEGIN_INTERRUPTABLE__ |
|
1359 if (hostName != nil) { |
|
1360 do { |
|
1361 ret = connect(sock, (struct sockaddr *)&sa, sizeof(sa)); |
|
1362 } while ((ret < 0) && (errno == EINTR)); |
|
1363 } else { |
|
1364 #ifdef SO_REUSEADDR |
|
1365 /* |
|
1366 * should I also do this for DGRAM sockets ? |
|
1367 */ |
|
1368 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof (on)) < 0) { |
|
1369 DBGPRINTF(("SOCKET: setsockopt - SO_REUSEADDR failed\n")); |
|
1370 } |
|
1371 #endif /* SO_REUSEADDR */ |
|
1372 sa.sin_addr.s_addr = htonl(INADDR_ANY); |
|
1373 do { |
|
1374 ret = bind(sock, (struct sockaddr *)&sa, sizeof(sa)); |
|
1375 } while ((ret < 0) && (errno == EINTR)); |
|
1376 } |
|
1377 __END_INTERRUPTABLE__ |
|
1378 |
|
1379 if (ret < 0) { |
|
1380 DBGPRINTF(("SOCKET: bind/connect call failed errno=%d\n", errno)); |
|
1381 _INST(lastErrorNumber) = _MKSMALLINT(errno); |
|
1382 __BEGIN_INTERRUPTABLE__ |
|
1383 close(sock) ; |
|
1384 __END_INTERRUPTABLE__ |
|
1385 } else { |
|
1386 /* |
|
1387 * make it a FILE * |
|
1388 */ |
|
1389 fp = fdopen(sock, "r+"); |
|
1390 if (! fp) { |
|
1391 DBGPRINTF(("SOCKET: fdopen failed\n")); |
|
1392 _INST(lastErrorNumber) = _MKSMALLINT(errno); |
|
1393 __BEGIN_INTERRUPTABLE__ |
|
1394 close(sock); |
|
1395 __END_INTERRUPTABLE__ |
|
1396 } else { |
|
1397 #ifdef NO_BUFFER |
|
1398 setbuf(fp, NULL); |
|
1399 _INST(buffered) = false; |
|
1400 #endif |
|
1401 _INST(filePointer) = __MKOBJ(fp); |
|
1402 } |
|
1403 } |
|
1404 } |
|
1405 %}. |
|
1406 filePointer isNil ifTrue:[ |
|
1407 ^ nil |
|
1408 ]. |
|
1409 mode := #readwrite. |
|
1410 binary := false. |
|
1411 |
|
1412 domain := #inet. |
|
1413 socketType := #stream. |
|
1414 protocol := portNr. |
|
1415 peerName := hostName. |
|
1416 |
|
1417 " |
|
1418 Socket new for:'clam' port:(Socket portOfService:'echo') |
|
1419 |
|
1420 Socket new for:nil port:9999 |
|
1421 Socket new for:(OperatingSystem getHostName) port:9999 |
|
1422 " |
|
1423 ! ! |
2308 ! ! |
1424 |
2309 |
1425 !Socket methodsFor:'low level'! |
2310 !Socket methodsFor:'specials'! |
1426 |
2311 |
1427 closeFile |
2312 receiveTimeout:seconds |
1428 "low level close" |
2313 "set the receive timeout - for special applications only. |
1429 |
2314 Not all operatingSystems offer this functionality |
1430 %{ /* NOCONTEXT */ |
2315 (returns false, if unsupported)" |
1431 |
2316 |
1432 OBJ t; |
2317 |millis| |
1433 |
|
1434 t = _INST(filePointer); |
|
1435 if (t != nil) { |
|
1436 FILE *fp; |
|
1437 |
|
1438 fp = __FILEVal(t); |
|
1439 fflush(fp); |
|
1440 shutdown(fileno(fp), 2); |
|
1441 fclose(fp); |
|
1442 _INST(filePointer) = nil; |
|
1443 } |
|
1444 %} |
|
1445 ! |
|
1446 |
|
1447 bindTo:aSocketAddress |
|
1448 "ST80 compatible bind: |
|
1449 the socketAddress object is supposed to respond to |
|
1450 portOrName and address requests." |
|
1451 |
|
1452 ^ self bindTo:(aSocketAddress portOrName) |
|
1453 address:(aSocketAddress address) |
|
1454 ! |
|
1455 |
|
1456 bindTo:portNrOrName address:address |
|
1457 "low level bind - returns true if ok, false otherwise. |
|
1458 Currently only non-address binding is supported; |
|
1459 i.e. address must always be nil. |
|
1460 |
|
1461 The interpretation of portNrOrName depends on the domain: |
|
1462 inet domain uses (4byte) byteArray like internet numbers, |
|
1463 unix domain uses pathname strings, |
|
1464 others use whatever will come up in the future |
|
1465 " |
|
1466 |
|
1467 ^ self bindTo:portNrOrName address:address reuseAddress:true |
|
1468 ! |
|
1469 |
|
1470 bindTo:portNrOrName address:address reuseAddress:reuse |
|
1471 "low level bind - returns true if ok, false otherwise. |
|
1472 Currently only non-address binding is supported; |
|
1473 i.e. address must always be nil. |
|
1474 |
|
1475 The interpretation of portNrOrName depends on the domain: |
|
1476 inet domain uses (4byte) byteArray like internet numbers, |
|
1477 unix domain uses pathname strings, |
|
1478 others use whatever will come up in the future |
|
1479 " |
|
1480 |
2318 |
1481 filePointer isNil ifTrue:[ |
2319 filePointer isNil ifTrue:[ |
1482 ^ self error:'not a valid socket' |
2320 ^ self error:'not a valid socket' |
1483 ]. |
2321 ]. |
|
2322 millis := (seconds * 1000) rounded. |
1484 %{ |
2323 %{ |
1485 OBJ t = _INST(filePointer); |
2324 #if defined(SO_RCVTIMEO) && defined(SOL_SOCKET) && defined(HZ) |
1486 OBJ myDomain; |
2325 if (__isSmallInteger(millis)) { |
1487 int sock; |
2326 OBJ fp = _INST(filePointer); |
1488 union { |
2327 int sock; |
1489 struct sockaddr_in in; |
2328 int opt; |
1490 struct sockaddr_un un; |
2329 |
1491 } sa; |
2330 sock = fileno(__FILEVal(fp)); |
1492 int sockaddr_size; |
2331 opt = _intVal(millis) / (1000 / HZ); |
1493 int ret; |
2332 setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&opt, sizeof(int)); |
1494 int on = 1; |
2333 RETURN(true); |
1495 int ok; |
2334 } |
1496 extern OBJ LargeInteger; |
2335 #endif |
1497 |
|
1498 if (!__isString(_INST(domain)) && !__isSymbol(_INST(domain))) { |
|
1499 DBGPRINTF(("SOCKET: invalid domain arg\n")); |
|
1500 RETURN (false); |
|
1501 } |
|
1502 |
|
1503 ok = 0; |
|
1504 myDomain = _INST(domain); |
|
1505 #ifdef AF_INET |
|
1506 if (myDomain == @symbol(inet)) { |
|
1507 /* |
|
1508 * INET addresses - port must be a smallinteger |
|
1509 */ |
|
1510 sa.in.sin_family = AF_INET; |
|
1511 if (! __isSmallInteger(portNrOrName)) { |
|
1512 DBGPRINTF(("SOCKET: invalid port arg\n")); |
|
1513 RETURN (false); |
|
1514 } |
|
1515 sa.in.sin_port = htons((u_short) _intVal(portNrOrName)); |
|
1516 if (address == nil) { |
|
1517 sa.in.sin_addr.s_addr = htonl(INADDR_ANY); |
|
1518 } else { |
|
1519 if (__isInteger(address)) { |
|
1520 sa.in.sin_addr.s_addr = htonl(__longIntVal(address)); |
|
1521 } else { |
|
1522 printf("SOCKET: address bind not yet supported\n"); |
|
1523 RETURN (false); |
|
1524 } |
|
1525 } |
|
1526 sockaddr_size = sizeof(struct sockaddr_in); |
|
1527 ok = 1; |
|
1528 } |
|
1529 #endif |
|
1530 #ifdef AF_UNIX |
|
1531 if (myDomain == @symbol(unix)) { |
|
1532 char *pathName; |
|
1533 int l; |
|
1534 |
|
1535 if (! __isString(portNrOrName)) { |
|
1536 DBGPRINTF(("SOCKET: invalid port (pathname) arg\n")); |
|
1537 RETURN (false); |
|
1538 } |
|
1539 pathName = __stringVal(portNrOrName); |
|
1540 l = strlen(pathName); |
|
1541 if ((l + sizeof ( sa.un.sun_family )) > sizeof(struct sockaddr_un)) { |
|
1542 DBGPRINTF(("SOCKET: pathname too long\n")); |
|
1543 RETURN (false); |
|
1544 } |
|
1545 |
|
1546 strcpy(sa.un.sun_path, pathName); |
|
1547 sa.un.sun_family = AF_UNIX; |
|
1548 sockaddr_size = l + sizeof ( sa.un.sun_family ); |
|
1549 ok = 1; |
|
1550 } |
|
1551 #endif |
|
1552 /* |
|
1553 * XXXX add addressing stuff for other domains here ... |
|
1554 */ |
|
1555 #ifdef AF_X25 |
|
1556 if (myDomain == @symbol(x25)) { |
|
1557 } |
|
1558 #endif |
|
1559 #ifdef AF_NS |
|
1560 if (myDomain == @symbol(ns)) { |
|
1561 } |
|
1562 #endif |
|
1563 #ifdef AF_APPLETALK |
|
1564 if (myDomain == @symbol(appletalk)) { |
|
1565 } |
|
1566 #endif |
|
1567 #ifdef AF_SNA |
|
1568 if (myDomain == @symbol(sna)) { |
|
1569 } |
|
1570 #endif |
|
1571 #ifdef AF_NS |
|
1572 if (myDomain == @symbol(xns)) { |
|
1573 } |
|
1574 #endif |
|
1575 #ifdef AF_RAW |
|
1576 if (myDomain == @symbol(raw)) { |
|
1577 } |
|
1578 #endif |
|
1579 |
|
1580 if (! ok) { |
|
1581 DBGPRINTF(("SOCKET: unsupported domain\n")); |
|
1582 RETURN (false); |
|
1583 } |
|
1584 |
|
1585 sock = fileno(__FILEVal(t)); |
|
1586 |
|
1587 #ifdef SO_REUSEADDR |
|
1588 if (reuse == true) { |
|
1589 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof (on)) < 0) { |
|
1590 DBGPRINTF(("SOCKET: setsockopt - SO_REUSEADDR failed\n")); |
|
1591 } |
|
1592 } |
|
1593 #endif /* SO_REUSEADDR */ |
|
1594 |
|
1595 __BEGIN_INTERRUPTABLE__ |
|
1596 do { |
|
1597 ret = bind(sock, (struct sockaddr *)&sa, sockaddr_size); |
|
1598 } while ((ret < 0) && (errno == EINTR)); |
|
1599 __END_INTERRUPTABLE__ |
|
1600 |
|
1601 if (ret < 0) { |
|
1602 DBGPRINTF(("SOCKET: bind failed errno=%d\n", errno)); |
|
1603 _INST(lastErrorNumber) = _MKSMALLINT(errno); |
|
1604 RETURN (false); |
|
1605 } |
|
1606 %}. |
2336 %}. |
1607 |
2337 ^ false |
1608 port := portNrOrName. |
2338 ! |
1609 ^ true |
|
1610 |
|
1611 " |
|
1612 (Socket domain:#inet type:#stream) |
|
1613 bindTo:9999 |
|
1614 address:nil |
|
1615 " |
|
1616 ! |
|
1617 |
|
1618 connectTo:hostOrPathName port:portNrOrName withTimeout:millis |
|
1619 "connect to port, portNrOrName on host, hostName. |
|
1620 Or path (UNIX socket), where portNrOrName is ignored. |
|
1621 Return true if ok, false otherwise. |
|
1622 Hostname must be a string, portNrOrName an integer port number (in inet domain). |
|
1623 If a non-nil timeout is given, stop trying after that time and return false as well." |
|
1624 |
|
1625 |stopSignal stopMe connection| |
|
1626 |
|
1627 millis isNil ifTrue:[ |
|
1628 ^ self connectTo:hostOrPathName port:portNrOrName |
|
1629 ]. |
|
1630 stopSignal := Signal new. |
|
1631 stopMe := [stopSignal raise]. |
|
1632 stopSignal handle:[:ex | |
|
1633 "/ 'timeout on connect' infoPrintNL. |
|
1634 ^ false |
|
1635 ] do:[ |
|
1636 Processor addTimedBlock:stopMe afterMilliseconds:millis. |
|
1637 connection := self connectTo:hostOrPathName port:portNrOrName. |
|
1638 Processor removeTimedBlock:stopMe. |
|
1639 ]. |
|
1640 ^ connection |
|
1641 |
|
1642 "Created: 31.10.1995 / 18:52:49 / cg" |
|
1643 ! |
|
1644 |
|
1645 connectTo:hostOrPathName port:portNrOrName |
|
1646 "low level connect; connect to port, portNrOrName on host, hostName. |
|
1647 For unix-domain sockets, the port argument is ignored and pathName is taken. |
|
1648 Other sockets are not yet implemented. |
|
1649 Return true if ok, false otherwise. |
|
1650 Hostname must be a string, portNrOrName an integer port number (in inet domain). |
|
1651 The current process will block (but not the whole Smalltalk) until the connection |
|
1652 is established. |
|
1653 See also: #connectTo:port:withTimeout: for a somewhat nicer interface." |
|
1654 |
|
1655 filePointer isNil ifTrue:[ |
|
1656 ^ self error:'not a valid socket' |
|
1657 ]. |
|
1658 %{ |
|
1659 OBJ t = _INST(filePointer); |
|
1660 OBJ myDomain; |
|
1661 union { |
|
1662 struct sockaddr_in in ; |
|
1663 struct sockaddr_un un; |
|
1664 } sa; |
|
1665 struct hostent *hp ; |
|
1666 int a, sock ; |
|
1667 long addr; |
|
1668 FILE *fp; |
|
1669 int ret; |
|
1670 int on = 1; |
|
1671 int ok; |
|
1672 int sockaddr_size; |
|
1673 |
|
1674 if (!__isString(_INST(domain)) && !__isSymbol(_INST(domain))) { |
|
1675 DBGPRINTF(("SOCKET: invalid domain arg\n")); |
|
1676 RETURN (false); |
|
1677 } |
|
1678 |
|
1679 ok = 0; |
|
1680 myDomain = _INST(domain); |
|
1681 bzero((char *) &sa, sizeof(sa)) ; |
|
1682 #ifdef AF_INET |
|
1683 if (myDomain == @symbol(inet)) { |
|
1684 char *hostName; |
|
1685 |
|
1686 if (! __isString(hostOrPathName)) { |
|
1687 DBGPRINTF(("SOCKET: invalid hostname arg\n")); |
|
1688 RETURN (false); |
|
1689 } |
|
1690 hostName = (char *) _stringVal(hostOrPathName); |
|
1691 |
|
1692 if (! __isSmallInteger(portNrOrName)) { |
|
1693 DBGPRINTF(("SOCKET: invalid port arg\n")); |
|
1694 RETURN (false); |
|
1695 } |
|
1696 |
|
1697 sa.in.sin_family = AF_INET; |
|
1698 sa.in.sin_port = htons((u_short) _intVal(portNrOrName)) ; |
|
1699 |
|
1700 if ((addr = inet_addr(hostName)) != -1) { |
|
1701 /* |
|
1702 * is Internet addr in octet notation |
|
1703 */ |
|
1704 bcopy(&addr, (char *) &sa.in.sin_addr, sizeof(addr)) ; /* set address */ |
|
1705 } else { |
|
1706 /* |
|
1707 * do we know the host's address? |
|
1708 */ |
|
1709 if ((hp = gethostbyname(hostName)) == NULL) { |
|
1710 DBGPRINTF(("SOCKET: unknown host:%s\n", hostName)); |
|
1711 RETURN (false); |
|
1712 } |
|
1713 bcopy(hp->h_addr, (char *) &sa.in.sin_addr, hp->h_length) ; |
|
1714 sa.in.sin_family = hp->h_addrtype; |
|
1715 } |
|
1716 sockaddr_size = sizeof(struct sockaddr_in); |
|
1717 ok = 1; |
|
1718 } |
|
1719 #endif |
|
1720 #ifdef AF_UNIX |
|
1721 if (myDomain == @symbol(unix)) { |
|
1722 char *pathName; |
|
1723 int l; |
|
1724 |
|
1725 if (! __isString(hostOrPathName)) { |
|
1726 DBGPRINTF(("SOCKET: invalid port (pathname) arg\n")); |
|
1727 RETURN (false); |
|
1728 } |
|
1729 pathName = (char *) __stringVal(hostOrPathName); |
|
1730 l = strlen(pathName); |
|
1731 if ((l + sizeof ( sa.un.sun_family )) > sizeof(struct sockaddr_un)) { |
|
1732 DBGPRINTF(("SOCKET: pathname too long\n")); |
|
1733 RETURN (false); |
|
1734 } |
|
1735 |
|
1736 strcpy(sa.un.sun_path, pathName); |
|
1737 sa.un.sun_family = AF_UNIX; |
|
1738 sockaddr_size = l + sizeof ( sa.un.sun_family ); |
|
1739 ok = 1; |
|
1740 } |
|
1741 #endif |
|
1742 /* |
|
1743 * XXXX add addressing stuff for other domains here ... |
|
1744 */ |
|
1745 #ifdef AF_X25 |
|
1746 if (myDomain == @symbol(x25)) { |
|
1747 } |
|
1748 #endif |
|
1749 #ifdef AF_NS |
|
1750 if (myDomain == @symbol(ns)) { |
|
1751 } |
|
1752 #endif |
|
1753 #ifdef AF_APPLETALK |
|
1754 if (myDomain == @symbol(appletalk)) { |
|
1755 } |
|
1756 #endif |
|
1757 #ifdef AF_NS |
|
1758 if (myDomain == @symbol(xns)) { |
|
1759 } |
|
1760 #endif |
|
1761 #ifdef AF_SNA |
|
1762 if (myDomain == @symbol(sna)) { |
|
1763 } |
|
1764 #endif |
|
1765 #ifdef AF_RAW |
|
1766 if (myDomain == @symbol(raw)) { |
|
1767 } |
|
1768 #endif |
|
1769 |
|
1770 if (! ok) { |
|
1771 DBGPRINTF(("SOCKET: unsupported domain\n")); |
|
1772 RETURN (false); |
|
1773 } |
|
1774 |
|
1775 sock = fileno(__FILEVal(t)); |
|
1776 |
|
1777 /* |
|
1778 * connect |
|
1779 */ |
|
1780 __BEGIN_INTERRUPTABLE__ |
|
1781 |
|
1782 do { |
|
1783 ret = connect(sock, (struct sockaddr *)&sa, sockaddr_size); |
|
1784 } while ((ret < 0) |
|
1785 && ((errno == EINTR) |
|
1786 #ifdef EAGAIN |
|
1787 || (errno == EAGAIN) |
|
1788 #endif |
|
1789 #ifdef EINPROGRESS |
|
1790 || (errno == EINPROGRESS) |
|
1791 #endif |
|
1792 )); |
|
1793 __END_INTERRUPTABLE__ |
|
1794 |
|
1795 if (ret < 0) { |
|
1796 DBGPRINTF(("SOCKET: connect failed errno=%d\n", errno)); |
|
1797 #ifdef DUMP_ADDRESS |
|
1798 { |
|
1799 char *cp = (char *)(&sa); |
|
1800 int i; |
|
1801 |
|
1802 printf("address data:\n"); |
|
1803 for (i=0; i<sockaddr_size; i++) { |
|
1804 printf(" %02x\n", *cp++); |
|
1805 } |
|
1806 } |
|
1807 #endif |
|
1808 _INST(lastErrorNumber) = _MKSMALLINT(errno); |
|
1809 RETURN (false); |
|
1810 } |
|
1811 %}. |
|
1812 port := portNrOrName. |
|
1813 peerName := hostOrPathName. |
|
1814 ^ true |
|
1815 ! |
|
1816 |
|
1817 listenWithBacklog:aNumber |
|
1818 "start listening; return true if ok, false on error" |
|
1819 |
|
1820 filePointer isNil ifTrue:[ |
|
1821 ^ self error:'not a valid socket' |
|
1822 ]. |
|
1823 %{ |
|
1824 OBJ fp = _INST(filePointer); |
|
1825 int sock; |
|
1826 int ret; |
|
1827 |
|
1828 if (! __isSmallInteger(aNumber)) { |
|
1829 DBGPRINTF(("SOCKET: invalid arg\n")); |
|
1830 RETURN (false); |
|
1831 } |
|
1832 |
|
1833 sock = fileno(__FILEVal(fp)); |
|
1834 |
|
1835 __BEGIN_INTERRUPTABLE__ |
|
1836 do { |
|
1837 ret = listen(sock, _intVal(aNumber)); |
|
1838 } while ((ret < 0) && (errno == EINTR)); |
|
1839 __END_INTERRUPTABLE__ |
|
1840 |
|
1841 if (ret < 0) { |
|
1842 DBGPRINTF(("SOCKET: listen call failed errno=%d\n", errno)); |
|
1843 _INST(lastErrorNumber) = _MKSMALLINT(errno); |
|
1844 RETURN (false); |
|
1845 } |
|
1846 %}. |
|
1847 ^ true |
|
1848 ! |
|
1849 |
|
1850 listenFor:aNumber |
|
1851 "same as listenWithBacklog: - for ST-80 compatibility" |
|
1852 |
|
1853 ^ self listenWithBacklog:aNumber |
|
1854 ! |
|
1855 |
|
1856 acceptOn:aSocket |
|
1857 "accept a connection on a server port (created with:'Socket>>onIPPort:') |
|
1858 usage is: (Socket basicNew acceptOn:(Socket onIPPort:9999)). |
|
1859 Return the true if ok; false if not. |
|
1860 |
|
1861 NOTICE: this method will block, if no connection is already pending. |
|
1862 use readWait or Socket>>accept." |
|
1863 |
|
1864 |serverSocketFd| |
|
1865 |
|
1866 filePointer notNil ifTrue:[ |
|
1867 ^ self error:'already connected' |
|
1868 ]. |
|
1869 |
|
1870 domain := aSocket domain. |
|
1871 socketType := aSocket type. |
|
1872 serverSocketFd := aSocket fileDescriptor. |
|
1873 serverSocketFd isNil ifTrue:[ |
|
1874 ^ self error:'invalid server socket' |
|
1875 ]. |
|
1876 (serverSocketFd isMemberOf:SmallInteger) ifFalse:[ |
|
1877 ^ self error:'invalid server socket' |
|
1878 ]. |
|
1879 %{ |
|
1880 FILE *fp; |
|
1881 int flags; |
|
1882 int sock, newSock; |
|
1883 union { |
|
1884 struct sockaddr_in in ; |
|
1885 struct sockaddr_un un ; |
|
1886 } sa; |
|
1887 int alen; |
|
1888 struct hostent *he ; |
|
1889 char dotted[20] ; |
|
1890 |
|
1891 sock = _intVal(serverSocketFd); |
|
1892 |
|
1893 #if defined(O_NDELAY) && defined(SET_NDELAY) |
|
1894 flags = ioctl(sock, F_GETFL, 0); |
|
1895 ioctl(sock, F_SETFL, flags | O_NDELAY); |
|
1896 #endif |
|
1897 __BEGIN_INTERRUPTABLE__ |
|
1898 do { |
|
1899 alen = sizeof(sa) ; |
|
1900 newSock = accept(sock, (struct sockaddr *) &sa, &alen); |
|
1901 } while ((newSock < 0) && (errno == EINTR)); |
|
1902 __END_INTERRUPTABLE__ |
|
1903 |
|
1904 #if defined(O_NDELAY) && defined(SET_NDELAY) |
|
1905 ioctl(sock, F_SETFL, flags); |
|
1906 #endif |
|
1907 |
|
1908 if (newSock < 0) { |
|
1909 DBGPRINTF(("SOCKET: accept call failed errno=%d\n", errno)); |
|
1910 _INST(lastErrorNumber) = _MKSMALLINT(errno); |
|
1911 RETURN (false); |
|
1912 } |
|
1913 |
|
1914 /* |
|
1915 * extract the partners address |
|
1916 */ |
|
1917 #ifdef AF_INET |
|
1918 if (_INST(domain) == @symbol(inet)) { |
|
1919 he = gethostbyaddr((char *) &sa.in.sin_addr.s_addr, alen, AF_INET) ; |
|
1920 if (! he) { |
|
1921 unsigned long norder; |
|
1922 |
|
1923 norder = htonl(sa.in.sin_addr.s_addr) ; |
|
1924 sprintf(dotted, "%d.%d.%d.%d", |
|
1925 (norder >> 24) & 0xFF, |
|
1926 (norder >> 16) & 0xFF, |
|
1927 (norder >> 8) & 0xFF, |
|
1928 norder & 0xFF); |
|
1929 } |
|
1930 DBGPRINTF(("SOCKET: accepted connection from host %s\n", (he ? he->h_name : dotted))) ; |
|
1931 _INST(peerName) = _MKSTRING((he ? he->h_name : dotted) COMMA_CON); |
|
1932 } |
|
1933 #endif |
|
1934 #ifdef AF_UNIX |
|
1935 if (_INST(domain) == @symbol(unix)) { |
|
1936 DBGPRINTF(("SOCKET: accepted connection on unix socket\n")) ; |
|
1937 /* nothing to be done here */ |
|
1938 } |
|
1939 #endif |
|
1940 |
|
1941 /* |
|
1942 * make it a FILE * |
|
1943 */ |
|
1944 fp = fdopen(newSock, "r+"); |
|
1945 if (! fp) { |
|
1946 DBGPRINTF(("SOCKET: fdopen call failed\n")); |
|
1947 _INST(lastErrorNumber) = _MKSMALLINT(errno); |
|
1948 close(newSock); |
|
1949 RETURN (false); |
|
1950 } else { |
|
1951 #ifdef NO_BUFFER |
|
1952 setbuf(fp, NULL); |
|
1953 _INST(buffered) = false; |
|
1954 #endif |
|
1955 _INST(filePointer) = __MKOBJ(fp); |
|
1956 } |
|
1957 %}. |
|
1958 mode := #readwrite. |
|
1959 binary := false. |
|
1960 port := aSocket port. |
|
1961 ^ true |
|
1962 ! |
|
1963 |
|
1964 accept |
|
1965 "create a new TCP socket from accepting on the receiver. |
|
1966 This method will suspend the current process if no connection is waiting. |
|
1967 For ST-80 compatibility" |
|
1968 |
|
1969 |newSock| |
|
1970 |
|
1971 "/ self readWait. |
|
1972 newSock := self class new. |
|
1973 (newSock acceptOn:self) ifFalse:[^ nil]. |
|
1974 ^ newSock |
|
1975 |
|
1976 " |
|
1977 |sock newSock| |
|
1978 |
|
1979 sock := Socket provide:8004. |
|
1980 sock listenFor:5. |
|
1981 newSock := sock accept. |
|
1982 " |
|
1983 ! ! |
|
1984 |
|
1985 !Socket methodsFor:'queries'! |
|
1986 |
|
1987 getPeer |
|
1988 "ST-80 compatibility: return an IPSocketAddress instance representing |
|
1989 my hostname/port combination. |
|
1990 If you are interrested in the hostname, use getPeerName directly." |
|
1991 |
|
1992 domain == #unix ifTrue:[ |
|
1993 ^ UDSocketAddress name:peerName |
|
1994 ]. |
|
1995 ^ IPSocketAddress hostAddress:(self class ipAddressOfHost:peerName) port:port |
|
1996 |
|
1997 "Created: 2.11.1995 / 11:22:39 / cg" |
|
1998 ! |
|
1999 |
|
2000 getPeerName |
|
2001 "return the peer name; thats the hostname (or dotted name) of the |
|
2002 partners host after an accept." |
|
2003 |
|
2004 ^ peerName |
|
2005 ! |
|
2006 |
|
2007 getName |
|
2008 "return the name; here, we return the ports name" |
|
2009 |
|
2010 ^ port printString |
|
2011 ! |
|
2012 |
|
2013 port |
|
2014 "return the port number (or name for unix-sockets) to which the socket is bound" |
|
2015 |
|
2016 ^ port |
|
2017 ! |
|
2018 |
|
2019 domain |
|
2020 "return the sockets addressing domain (i.e. #inet, #unix, #x25, #appletalk)" |
|
2021 |
|
2022 ^ domain |
|
2023 ! |
|
2024 |
|
2025 type |
|
2026 "return the sockets connection type (i.e. #datagram, #stream etc)" |
|
2027 |
|
2028 ^ socketType |
|
2029 ! |
|
2030 |
|
2031 isActive |
|
2032 "return true, if the receiver has a connection" |
|
2033 |
|
2034 ^ filePointer notNil |
|
2035 ! ! |
|
2036 |
|
2037 !Socket methodsFor:'ST-80 mimicri'! |
|
2038 |
|
2039 errorReporter |
|
2040 ^ self |
|
2041 ! |
|
2042 |
|
2043 notReadySignal |
|
2044 "for now - this is not yet raised" |
|
2045 |
|
2046 ^ Signal new |
|
2047 ! ! |
|
2048 |
|
2049 !Socket methodsFor:'specials'! |
|
2050 |
2339 |
2051 sendTimeout:seconds |
2340 sendTimeout:seconds |
2052 "set the send timeout - for special applications only. |
2341 "set the send timeout - for special applications only. |
2053 Not all operatingSystems offer this functionality |
2342 Not all operatingSystems offer this functionality |
2054 (returns false, if unsupported)" |
2343 (returns false, if unsupported)" |
2072 RETURN(true); |
2361 RETURN(true); |
2073 } |
2362 } |
2074 #endif |
2363 #endif |
2075 %}. |
2364 %}. |
2076 ^ false |
2365 ^ false |
2077 ! |
|
2078 |
|
2079 receiveTimeout:seconds |
|
2080 "set the receive timeout - for special applications only. |
|
2081 Not all operatingSystems offer this functionality |
|
2082 (returns false, if unsupported)" |
|
2083 |
|
2084 |millis| |
|
2085 |
|
2086 filePointer isNil ifTrue:[ |
|
2087 ^ self error:'not a valid socket' |
|
2088 ]. |
|
2089 millis := (seconds * 1000) rounded. |
|
2090 %{ |
|
2091 #if defined(SO_RCVTIMEO) && defined(SOL_SOCKET) && defined(HZ) |
|
2092 if (__isSmallInteger(millis)) { |
|
2093 OBJ fp = _INST(filePointer); |
|
2094 int sock; |
|
2095 int opt; |
|
2096 |
|
2097 sock = fileno(__FILEVal(fp)); |
|
2098 opt = _intVal(millis) / (1000 / HZ); |
|
2099 setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&opt, sizeof(int)); |
|
2100 RETURN(true); |
|
2101 } |
|
2102 #endif |
|
2103 %}. |
|
2104 ^ false |
|
2105 ! ! |
2366 ! ! |
2106 |
2367 |
2107 !Socket methodsFor:'datagram transmission'! |
|
2108 |
|
2109 receiveFrom:anAddressBuffer buffer:aDataBuffer start:startIndex for:nBytes |
|
2110 "receive datagramm data - put address of originating host into |
|
2111 anAddressBuffer, data into aBuffer. For ST-80 compatibility, |
|
2112 the addressBuffer may be a non-ByteArray; then, it must understand |
|
2113 the addressBytes-message (i.e. be a SocketAddress instance). |
|
2114 Return the number of bytes received, or a negative number on error. |
|
2115 On error, the unix error code is left in the lastErrorNumber |
|
2116 instance variable." |
|
2117 |
|
2118 |addrBytes addrLen nReceived| |
|
2119 |
|
2120 addrBytes := ByteArray new:100. |
|
2121 %{ |
|
2122 OBJ oClass; |
|
2123 OBJ fp = _INST(filePointer); |
|
2124 int nInstVars, nInstBytes, objSize; |
|
2125 int sock; |
|
2126 struct sockaddr_in sa ; |
|
2127 int alen; |
|
2128 int n; |
|
2129 char *cp; |
|
2130 int flags = 0; |
|
2131 |
|
2132 if (fp != nil) { |
|
2133 sock = fileno(__FILEVal(fp)); |
|
2134 |
|
2135 oClass = __Class(aDataBuffer); |
|
2136 switch (_intVal(_ClassInstPtr(oClass)->c_flags) & ARRAYMASK) { |
|
2137 case BYTEARRAY: |
|
2138 case WORDARRAY: |
|
2139 case LONGARRAY: |
|
2140 case FLOATARRAY: |
|
2141 case DOUBLEARRAY: |
|
2142 break; |
|
2143 default: |
|
2144 goto bad; |
|
2145 } |
|
2146 |
|
2147 nInstVars = _intVal(_ClassInstPtr(oClass)->c_ninstvars); |
|
2148 nInstBytes = OHDR_SIZE + nInstVars * sizeof(OBJ); |
|
2149 objSize = _Size(aDataBuffer) - nInstBytes; |
|
2150 cp = (char *)_InstPtr(aDataBuffer) + nInstBytes; |
|
2151 if (__isSmallInteger(startIndex)) { |
|
2152 cp += __intVal(startIndex); |
|
2153 objSize -= __intVal(startIndex); |
|
2154 } |
|
2155 if (__isSmallInteger(nBytes)) { |
|
2156 if (__intVal(nBytes) < objSize) { |
|
2157 objSize = __intVal(nBytes); |
|
2158 } |
|
2159 } |
|
2160 |
|
2161 __BEGIN_INTERRUPTABLE__ |
|
2162 do { |
|
2163 if (addrBytes == nil) { |
|
2164 n = recvfrom(sock, cp, objSize, flags, (struct sockaddr *) 0, 0); |
|
2165 } else { |
|
2166 n = recvfrom(sock, cp, objSize, flags, (struct sockaddr *) &sa, &alen); |
|
2167 } |
|
2168 } while ((n < 0) && (errno == EINTR)); |
|
2169 __END_INTERRUPTABLE__ |
|
2170 |
|
2171 if (n >= 0) { |
|
2172 if (addrBytes != nil) { |
|
2173 oClass = __Class(addrBytes); |
|
2174 if ((_intVal(_ClassInstPtr(oClass)->c_flags) & ARRAYMASK) != BYTEARRAY) |
|
2175 goto bad; |
|
2176 nInstVars = _intVal(_ClassInstPtr(oClass)->c_ninstvars); |
|
2177 nInstBytes = OHDR_SIZE + nInstVars * sizeof(OBJ); |
|
2178 objSize = _Size(addrBytes) - nInstBytes; |
|
2179 cp = (char *)_InstPtr(addrBytes) + nInstBytes; |
|
2180 if (objSize < alen) |
|
2181 goto bad; |
|
2182 bcopy((char *)&sa, cp, alen); |
|
2183 addrLen = _MKSMALLINT(alen); |
|
2184 } |
|
2185 } |
|
2186 if (n < 0) { |
|
2187 _INST(lastErrorNumber) = _MKSMALLINT(errno); |
|
2188 } |
|
2189 nReceived = _MKSMALLINT(n); |
|
2190 } |
|
2191 bad: ; |
|
2192 %}. |
|
2193 nReceived notNil ifTrue:[ |
|
2194 nReceived < 0 ifTrue:[ |
|
2195 (OperatingSystem errorTextForNumber:lastErrorNumber) printNL. |
|
2196 ]. |
|
2197 addrLen notNil ifTrue:[ |
|
2198 anAddressBuffer class isBytes ifTrue:[ |
|
2199 anAddressBuffer replaceFrom:1 to:addrLen with:addrBytes |
|
2200 ] ifFalse:[ |
|
2201 "/ can be SocketAddress for ST-80 compatibility |
|
2202 anAddressBuffer addressBytes:(addrBytes copyTo:addrLen) |
|
2203 ]. |
|
2204 ]. |
|
2205 ^ nReceived |
|
2206 ]. |
|
2207 " |
|
2208 arrive here if you try to receive into an invalid buffer |
|
2209 (i.e. not ByteArray-like), |
|
2210 or if the addressBuffer is nonNil AND not a ByteArray/String |
|
2211 or if the addressBuffer is nonNil AND too small. |
|
2212 " |
|
2213 self primitiveFailed |
|
2214 ! |
|
2215 |
|
2216 receiveFrom:anAddressBuffer buffer:aDataBuffer |
|
2217 "receive datagramm data - put address of originating host into |
|
2218 anAddressBuffer, data into aBuffer. |
|
2219 Both must be ByteArray-like. The addressBuffer must |
|
2220 provide space for a valid address for my domain (i.e. for inet, a 4-byte byteArray). |
|
2221 Return the number of bytes received, or a negative number on error. |
|
2222 On error, the unix error code is left in the lastErrorNumber |
|
2223 instance variable." |
|
2224 |
|
2225 ^ self receiveFrom:anAddressBuffer buffer:aDataBuffer start:1 for:(aDataBuffer size) |
|
2226 ! |
|
2227 |
|
2228 sendTo:anAddressBuffer buffer:buffer |
|
2229 "send datagramm data - fetch address of destination host from |
|
2230 anAddressBuffer, data from aDataBuffer. |
|
2231 Both must be ByteArray-like. The bytes in the addressBuffer must |
|
2232 be a valid address for my domain (i.e. for inet, a 4-byte byteArray). |
|
2233 Return the number of bytes transmitted, or a negative number on error. |
|
2234 On error, the unix error code is left in the lastErrorNumber |
|
2235 instance variable. |
|
2236 Flags is currently ignored; it is there for ST-80 compatibility." |
|
2237 |
|
2238 ^ self sendTo:anAddressBuffer buffer:buffer start:1 for:buffer size flags:0 |
|
2239 ! |
|
2240 |
|
2241 sendTo:anAddressBuffer buffer:aDataBuffer start:startIndex for:count flags:flags |
|
2242 "send datagramm data - fetch address of destination host from |
|
2243 anAddressBuffer, data from aDataBuffer starting at startIndex, |
|
2244 sending count bytes. |
|
2245 Both must be ByteArray-like. The bytes in the addressBuffer must |
|
2246 be a valid address for my domain (i.e. for inet, a 4-byte byteArray). |
|
2247 Return the number of bytes transmitted, or a negative number on error. |
|
2248 On error, the unix error code is left in the lastErrorNumber |
|
2249 instance variable." |
|
2250 |
|
2251 |addrBytes addrLen nReceived portNo| |
|
2252 |
|
2253 "/ addressBuffer can be a 6-byte byteArray (last 2 bytes are portNo, msb-first) |
|
2254 "/ or an instance of IPSocketAddress |
|
2255 "/ |
|
2256 anAddressBuffer class isBytes ifTrue:[ |
|
2257 addrBytes := anAddressBuffer copyFrom:1 to:4. |
|
2258 portNo := ((anAddressBuffer at:5) bitShift:8) |
|
2259 + (anAddressBuffer at:6). |
|
2260 ] ifFalse:[ |
|
2261 addrBytes := anAddressBuffer hostAddress. |
|
2262 portNo := anAddressBuffer port. |
|
2263 ]. |
|
2264 %{ |
|
2265 OBJ oClass; |
|
2266 OBJ fp = _INST(filePointer); |
|
2267 int nInstVars, nInstBytes, objSize; |
|
2268 int sock; |
|
2269 struct sockaddr_in sa; |
|
2270 struct sockaddr *saPtr = (struct sockaddr *)&sa; |
|
2271 int alen = sizeof(sa); |
|
2272 int n; |
|
2273 char *cp; |
|
2274 int _flags = 0; |
|
2275 int offs, nBytes; |
|
2276 unsigned long norder; |
|
2277 |
|
2278 _flags = __longIntVal(flags); |
|
2279 |
|
2280 if ((fp != nil) |
|
2281 && __isSmallInteger(startIndex) |
|
2282 && __isSmallInteger(count)) { |
|
2283 sock = fileno(__FILEVal(fp)); |
|
2284 |
|
2285 if (addrBytes != nil) { |
|
2286 if (! __isByteArray(addrBytes)) goto bad; |
|
2287 cp = __ByteArrayInstPtr(addrBytes)->ba_element; |
|
2288 n = __byteArraySize(addrBytes); |
|
2289 if (alen < n) n = alen; |
|
2290 /* |
|
2291 printf("address is %d bytes ... %d.%d.%d.%d", n, cp[0], cp[1], cp[2], cp[3]); |
|
2292 */ |
|
2293 bcopy(cp, &sa.sin_addr.s_addr, n); |
|
2294 sa.sin_family = AF_INET; |
|
2295 sa.sin_port = htons((u_short) __intVal(portNo)); |
|
2296 } else { |
|
2297 alen = 0; |
|
2298 saPtr = (struct sockaddr *)0; |
|
2299 } |
|
2300 |
|
2301 oClass = __Class(aDataBuffer); |
|
2302 switch (_intVal(_ClassInstPtr(oClass)->c_flags) & ARRAYMASK) { |
|
2303 case BYTEARRAY: |
|
2304 offs = __intVal(startIndex) - 1; |
|
2305 break; |
|
2306 case WORDARRAY: |
|
2307 offs = (__intVal(startIndex) - 1) * sizeof(short); |
|
2308 break; |
|
2309 case LONGARRAY: |
|
2310 offs = (__intVal(startIndex) - 1) * sizeof(long); |
|
2311 break; |
|
2312 case FLOATARRAY: |
|
2313 offs = (__intVal(startIndex) - 1) * sizeof(float); |
|
2314 break; |
|
2315 case DOUBLEARRAY: |
|
2316 offs = (__intVal(startIndex) - 1) * sizeof(double); |
|
2317 #ifdef NEED_DOUBLE_ALIGN |
|
2318 offs += sizeof(long); |
|
2319 #endif |
|
2320 break; |
|
2321 default: |
|
2322 goto bad; |
|
2323 } |
|
2324 nBytes = __intVal(count); |
|
2325 |
|
2326 nInstVars = _intVal(_ClassInstPtr(oClass)->c_ninstvars); |
|
2327 nInstBytes = OHDR_SIZE + nInstVars * sizeof(OBJ); |
|
2328 objSize = __qSize(aDataBuffer) - nInstBytes; |
|
2329 cp = (char *)_InstPtr(aDataBuffer) + nInstBytes; |
|
2330 cp += offs; |
|
2331 if ((offs + nBytes) > objSize) { |
|
2332 /* |
|
2333 printf("cut off ...\n"); |
|
2334 */ |
|
2335 nBytes = objSize - offs; |
|
2336 } |
|
2337 |
|
2338 norder = htonl(sa.sin_addr.s_addr); |
|
2339 /* |
|
2340 printf("sending %d bytes ... to ", nBytes); |
|
2341 printf("%d.%d.%d.%d\n", |
|
2342 (norder >> 24) & 0xFF, |
|
2343 (norder >> 16) & 0xFF, |
|
2344 (norder >> 8) & 0xFF, |
|
2345 norder & 0xFF); |
|
2346 */ |
|
2347 |
|
2348 __BEGIN_INTERRUPTABLE__ |
|
2349 do { |
|
2350 n = sendto(sock, cp, nBytes, _flags, saPtr, alen); |
|
2351 } while ((n < 0) && (errno == EINTR)); |
|
2352 __END_INTERRUPTABLE__ |
|
2353 |
|
2354 if (n < 0) { |
|
2355 _INST(lastErrorNumber) = _MKSMALLINT(errno); |
|
2356 } |
|
2357 RETURN (_MKSMALLINT(n)); |
|
2358 } |
|
2359 bad: ; |
|
2360 %}. |
|
2361 " |
|
2362 arrive here if you try to send from an invalid buffer |
|
2363 (i.e. not ByteArray-like), |
|
2364 or if the addressBuffer is nonNil AND not a ByteArray/String |
|
2365 or if the addressBuffer is nonNil AND too small. |
|
2366 " |
|
2367 self primitiveFailed |
|
2368 ! ! |
|