1586 self readWait |
1586 self readWait |
1587 |
1587 |
1588 "Created: / 04-06-2007 / 21:28:40 / cg" |
1588 "Created: / 04-06-2007 / 21:28:40 / cg" |
1589 ! ! |
1589 ! ! |
1590 |
1590 |
1591 !Socket methodsFor:'closing'! |
1591 !Socket methodsFor:'accepting connections'! |
1592 |
1592 |
1593 shutDown |
1593 accept |
1594 "shutDown and close the socket" |
1594 "create a new TCP socket from accepting on the receiver. |
1595 |
1595 This method will suspend the current process if no connection is waiting. |
1596 self shutdown:2. |
1596 For ST-80 compatibility" |
1597 self close |
1597 |
1598 ! |
1598 |newSock| |
1599 |
1599 |
1600 shutDownInput |
1600 self readWait. |
1601 "shutDown the input side of the socket. |
1601 newSock := self class new. |
1602 Any read on the socket will signal end-of-file from now on. |
1602 (newSock primAcceptOn:self blocking:false) ifFalse:[ |
1603 The other side MAY be informed, that no more data will be accepted |
1603 "should raise an error here" |
1604 (e.g. setting the TCP-Windowsize to 0)" |
1604 ^ nil |
1605 |
1605 ]. |
1606 self shutdown:0. |
1606 ^ newSock |
1607 ! |
1607 |
1608 |
1608 " |
1609 shutDownOutput |
1609 |sock newSock| |
1610 "shutDown the output side of the socket. |
1610 |
1611 Any write to the socket will signal end-of-file from now on. |
1611 sock := Socket provide:8004. |
1612 The other side will get a end-of-file condition, |
1612 sock listenFor:5. |
1613 after the last buffered data has been read" |
1613 newSock := sock accept. |
1614 |
1614 " |
1615 self shutdown:1. |
1615 ! |
|
1616 |
|
1617 blockingAccept |
|
1618 "create a new TCP socket from accepting on the receiver. |
|
1619 This method will suspend the smalltalk image with all smalltalk processes if no connection is waiting. |
|
1620 For ST-80 compatibility" |
|
1621 |
|
1622 |newSock| |
|
1623 |
|
1624 newSock := self class new. |
|
1625 (newSock primAcceptOn:self blocking:true) ifFalse:[ |
|
1626 "should raise an error here" |
|
1627 ^ nil |
|
1628 ]. |
|
1629 ^ newSock |
1616 ! ! |
1630 ! ! |
1617 |
1631 |
1618 !Socket methodsFor:'datagram transmission'! |
1632 !Socket methodsFor:'binding'! |
1619 |
|
1620 receiveBuffer:aDataBuffer start:startIndex for:nBytes |
|
1621 "receive data |
|
1622 Return the number of bytes received, or a negative number on error. |
|
1623 On error, the unix error code is left in the lastErrorNumber |
|
1624 instance variable. |
|
1625 The thread blocks until data arrives - you may want to wait before |
|
1626 receiving, using #readWait or #readWaitWithTimeout:." |
|
1627 |
|
1628 |nReceived| |
|
1629 |
|
1630 %{ |
|
1631 #ifndef NO_SOCKET |
|
1632 OBJ fp = __INST(filePointer); |
|
1633 |
|
1634 if (fp != nil) { |
|
1635 SOCKET sock; |
|
1636 int objSize, offs; |
|
1637 int n; |
|
1638 char *extPtr; |
|
1639 unsigned char *buffer; |
|
1640 unsigned char *allocatedBuffer; |
|
1641 int flags = 0; |
|
1642 |
|
1643 sock = SOCKET_FROM_FILE_OBJECT(fp); |
|
1644 |
|
1645 if (! setupBufferParameters(aDataBuffer, startIndex, &extPtr, &offs, &objSize)) goto bad; |
|
1646 if (__isSmallInteger(nBytes)) { |
|
1647 if (__intVal(nBytes) < objSize) { |
|
1648 objSize = __intVal(nBytes); |
|
1649 } |
|
1650 } |
|
1651 |
|
1652 # ifdef DO_WRAP_CALLS |
|
1653 if (extPtr) { |
|
1654 buffer = extPtr + offs; |
|
1655 } else { |
|
1656 allocatedBuffer = buffer = (char *)malloc(objSize); |
|
1657 } |
|
1658 |
|
1659 do { |
|
1660 __threadErrno = 0; |
|
1661 n = STX_WSA_CALL4("recv", recv, sock, buffer, objSize, flags); |
|
1662 } while ((n < 0) && (__threadErrno == EINTR)); |
|
1663 |
|
1664 if (allocatedBuffer) { |
|
1665 if (n > 0) { |
|
1666 bcopy(allocatedBuffer, (char *)__InstPtr(aDataBuffer) + offs, n); |
|
1667 } |
|
1668 free(allocatedBuffer); |
|
1669 } |
|
1670 # else |
|
1671 __BEGIN_INTERRUPTABLE__ |
|
1672 do { |
|
1673 if (extPtr) { |
|
1674 n = recv(sock, extPtr + offs, objSize, flags); |
|
1675 } else { |
|
1676 n = recv(sock, (char *)__InstPtr(aDataBuffer) + offs, objSize, flags); |
|
1677 } |
|
1678 } while ((n < 0) && (errno == EINTR)); |
|
1679 __END_INTERRUPTABLE__ |
|
1680 # endif |
|
1681 |
|
1682 if (n < 0) { |
|
1683 __INST(lastErrorNumber) = __MKSMALLINT(errno); |
|
1684 } |
|
1685 nReceived = __MKSMALLINT(n); |
|
1686 } |
|
1687 #endif |
|
1688 bad: ; |
|
1689 %}. |
|
1690 nReceived notNil ifTrue:[ |
|
1691 nReceived < 0 ifTrue:[ |
|
1692 'Socket [warning]: ' infoPrint. |
|
1693 (OperatingSystem errorTextForNumber:lastErrorNumber) infoPrintCR. |
|
1694 ]. |
|
1695 ^ nReceived |
|
1696 ]. |
|
1697 " |
|
1698 arrive here if you try to receive into an invalid buffer (i.e. not ByteArray-like) |
|
1699 " |
|
1700 self primitiveFailed |
|
1701 ! |
|
1702 |
|
1703 receiveFrom:anAddressBuffer buffer:aDataBuffer |
|
1704 "receive datagramm data - put address of originating host into |
|
1705 anAddressBuffer, data into aBuffer. |
|
1706 Both must be ByteArray-like. The addressBuffer must |
|
1707 provide space for a valid address for my domain (i.e. for inet, a 4-byte byteArray). |
|
1708 Return the number of bytes received, or a negative number on error. |
|
1709 On error, the unix error code is left in the lastErrorNumber |
|
1710 instance variable." |
|
1711 |
|
1712 ^ self receiveFrom:anAddressBuffer buffer:aDataBuffer start:1 for:(aDataBuffer size) |
|
1713 ! |
|
1714 |
|
1715 receiveFrom:anAddressBuffer buffer:aDataBuffer start:startIndex for:nBytes |
|
1716 "receive datagramm data |
|
1717 - put address of originating host into anAddressBuffer, data into aBuffer. |
|
1718 For backward compatibility, the addressBuffer may be a non-SocketAddress; |
|
1719 then, it must be a byteArray with appropriate size for the addressBytes. |
|
1720 |
|
1721 Return the number of bytes received, or a negative number on error. |
|
1722 On error, the unix error code is left in the lastErrorNumber |
|
1723 instance variable. |
|
1724 The thread blocks until data arrives - you may want to wait before |
|
1725 receiving, using #readWait or #readWaitWithTimeout:." |
|
1726 |
|
1727 |domainClass addr addrLen nReceived| |
|
1728 |
|
1729 domainClass := self class socketAddressClassForDomain:domain. |
|
1730 domainClass isNil ifTrue:[ |
|
1731 ^ self error:'invalid (unsupported) domain'. |
|
1732 ]. |
|
1733 (anAddressBuffer isKindOf:SocketAddress) ifTrue:[ |
|
1734 anAddressBuffer class == domainClass ifFalse:[ |
|
1735 ^ self error:'addressBuffer class mismatch (domain)'. |
|
1736 ]. |
|
1737 addr := anAddressBuffer. |
|
1738 ] ifFalse:[ |
|
1739 anAddressBuffer notNil ifTrue:[ |
|
1740 addr := domainClass new. |
|
1741 ]. |
|
1742 ]. |
|
1743 |
|
1744 %{ |
|
1745 #ifndef NO_SOCKET |
|
1746 OBJ fp = __INST(filePointer); |
|
1747 |
|
1748 if (fp != nil) { |
|
1749 SOCKET sock; |
|
1750 int objSize; |
|
1751 union sockaddr_u sa; |
|
1752 unsigned int alen = 0; |
|
1753 int n, offs; |
|
1754 int flags = 0; |
|
1755 char *extPtr; |
|
1756 unsigned char *allocatedBuffer = NULL; |
|
1757 unsigned char *buffer = NULL; |
|
1758 |
|
1759 sock = SOCKET_FROM_FILE_OBJECT(fp); |
|
1760 |
|
1761 if (! setupBufferParameters(aDataBuffer, startIndex, &extPtr, &offs, &objSize)) goto bad; |
|
1762 if (__isSmallInteger(nBytes)) { |
|
1763 if (__intVal(nBytes) < objSize) { |
|
1764 objSize = __intVal(nBytes); |
|
1765 } |
|
1766 } |
|
1767 # ifdef DO_WRAP_CALLS |
|
1768 if (extPtr) { |
|
1769 buffer = extPtr + offs; |
|
1770 } else { |
|
1771 allocatedBuffer = buffer = (char *)malloc(objSize); |
|
1772 } |
|
1773 |
|
1774 do { |
|
1775 __threadErrno = 0; |
|
1776 alen = sizeof(sa); |
|
1777 n = STX_WSA_CALL6("recvfrom", recvfrom, sock, buffer, objSize, flags, (struct sockaddr *)&sa, &alen); |
|
1778 } while ((n < 0) && (__threadErrno == EINTR)); |
|
1779 |
|
1780 if (allocatedBuffer) { |
|
1781 if (n > 0) { |
|
1782 bcopy(allocatedBuffer, (char *)__InstPtr(aDataBuffer) + offs, n); |
|
1783 } |
|
1784 free(allocatedBuffer); |
|
1785 } |
|
1786 # else |
|
1787 __BEGIN_INTERRUPTABLE__ |
|
1788 do { |
|
1789 alen = sizeof(sa); |
|
1790 if (extPtr) { |
|
1791 n = recvfrom(sock, extPtr + offs, objSize, flags, (struct sockaddr *) &sa, &alen); |
|
1792 } else { |
|
1793 n = recvfrom(sock, (char *)__InstPtr(aDataBuffer) + offs, objSize, flags, (struct sockaddr *) &sa, &alen); |
|
1794 } |
|
1795 } while ((n < 0) && (errno == EINTR)); |
|
1796 __END_INTERRUPTABLE__ |
|
1797 # endif |
|
1798 |
|
1799 if (n >= 0) { |
|
1800 if (__isNonNilObject(addr)) { |
|
1801 char *addrPtr; |
|
1802 OBJ oClass; |
|
1803 int nInstVars, nInstBytes, objSize; |
|
1804 |
|
1805 oClass = __qClass(addr); |
|
1806 if (! __isBytes(addr) ) |
|
1807 goto bad; |
|
1808 nInstVars = __intVal(__ClassInstPtr(oClass)->c_ninstvars); |
|
1809 nInstBytes = OHDR_SIZE + (nInstVars * sizeof(OBJ)); |
|
1810 objSize = __qSize(addr) - nInstBytes; |
|
1811 addrPtr = (char *)__InstPtr(addr) + nInstBytes; |
|
1812 if (objSize < alen) |
|
1813 goto bad; |
|
1814 |
|
1815 /* |
|
1816 * extract the datagrams address |
|
1817 */ |
|
1818 bcopy((char *)&sa, addrPtr, alen); |
|
1819 addrLen = __MKSMALLINT(alen); |
|
1820 } |
|
1821 } |
|
1822 if (n < 0) { |
|
1823 __INST(lastErrorNumber) = __MKSMALLINT(errno); |
|
1824 } |
|
1825 nReceived = __MKSMALLINT(n); |
|
1826 } |
|
1827 #endif |
|
1828 bad: ; |
|
1829 %}. |
|
1830 nReceived notNil ifTrue:[ |
|
1831 nReceived < 0 ifTrue:[ |
|
1832 'Socket [warning]: ' infoPrint. |
|
1833 (OperatingSystem errorTextForNumber:lastErrorNumber) infoPrintCR. |
|
1834 ]. |
|
1835 addrLen notNil ifTrue:[ |
|
1836 (addr == anAddressBuffer) ifFalse:[ |
|
1837 self obsoleteFeatureWarning:'please use a socketAddress argument'. |
|
1838 |
|
1839 " can be a ByteArray for backward compatibility " |
|
1840 anAddressBuffer replaceFrom:1 to:addrLen with:(addr hostAddress). |
|
1841 ]. |
|
1842 ]. |
|
1843 ^ nReceived |
|
1844 ]. |
|
1845 " |
|
1846 arrive here if you try to receive into an invalid buffer |
|
1847 (i.e. not ByteArray-like), |
|
1848 or if the addressBuffer is nonNil AND not a SocketAddress/ByteArray |
|
1849 or if the addressBuffer is nonNil AND too small. |
|
1850 " |
|
1851 self primitiveFailed |
|
1852 ! |
|
1853 |
|
1854 sendBuffer:aDataBuffer start:startIndex for:nBytes flags:flags |
|
1855 "send data. |
|
1856 Both must be ByteArray-like. The bytes in the addressBuffer must |
|
1857 be a valid address for my domain (i.e. for inet, a 4-byte byteArray). |
|
1858 Return the number of bytes transmitted, or a negative number on error. |
|
1859 On error, the unix error code is left in the lastErrorNumber |
|
1860 instance variable." |
|
1861 |
|
1862 |nReceived portNo| |
|
1863 |
|
1864 %{ |
|
1865 #ifndef NO_SOCKET |
|
1866 OBJ fp = __INST(filePointer); |
|
1867 |
|
1868 if ((fp != nil) |
|
1869 && __isSmallInteger(startIndex) |
|
1870 && __isSmallInteger(nBytes)) { |
|
1871 SOCKET sock; |
|
1872 int objSize; |
|
1873 int n; |
|
1874 char *extPtr; |
|
1875 int _flags = 0; |
|
1876 int offs; |
|
1877 unsigned long norder; |
|
1878 unsigned char *buffer; |
|
1879 unsigned char *allocatedBuffer; |
|
1880 |
|
1881 _flags = __longIntVal(flags); |
|
1882 |
|
1883 sock = SOCKET_FROM_FILE_OBJECT(fp); |
|
1884 |
|
1885 if (! setupBufferParameters(aDataBuffer, startIndex, &extPtr, &offs, &objSize)) goto bad; |
|
1886 if (__isSmallInteger(nBytes)) { |
|
1887 if (__intVal(nBytes) < objSize) { |
|
1888 objSize = __intVal(nBytes); |
|
1889 } |
|
1890 } |
|
1891 |
|
1892 # ifdef DGRAM_DEBUG |
|
1893 console_printf("sending %d bytes ...\n", nBytes); |
|
1894 # endif |
|
1895 |
|
1896 #ifdef DO_WRAP_CALLS |
|
1897 if (extPtr) { |
|
1898 buffer = extPtr + offs; |
|
1899 } else { |
|
1900 allocatedBuffer = buffer = (char *)malloc(objSize); |
|
1901 bcopy((char *)__InstPtr(aDataBuffer) + offs, allocatedBuffer, objSize); |
|
1902 } |
|
1903 |
|
1904 do { |
|
1905 __threadErrno = 0; |
|
1906 n = STX_WSA_CALL4("send", send, sock, buffer, objSize, _flags); |
|
1907 } while ((n < 0) && (__threadErrno == EINTR)); |
|
1908 |
|
1909 if (allocatedBuffer) { |
|
1910 free(allocatedBuffer); |
|
1911 } |
|
1912 #else |
|
1913 __BEGIN_INTERRUPTABLE__ |
|
1914 do { |
|
1915 if (extPtr) { |
|
1916 n = send(sock, extPtr + offs, objSize, _flags); |
|
1917 } else { |
|
1918 n = send(sock, (char *)__InstPtr(aDataBuffer) + offs, objSize, _flags); |
|
1919 } |
|
1920 } while ((n < 0) && (errno == EINTR)); |
|
1921 __END_INTERRUPTABLE__ |
|
1922 #endif |
|
1923 |
|
1924 if (n < 0) { |
|
1925 __INST(lastErrorNumber) = __MKSMALLINT(errno); |
|
1926 } |
|
1927 RETURN (__MKSMALLINT(n)); |
|
1928 } |
|
1929 #endif |
|
1930 bad: ; |
|
1931 %}. |
|
1932 " |
|
1933 arrive here if you try to send from an invalid buffer (i.e. not ByteArray-like), |
|
1934 " |
|
1935 self primitiveFailed |
|
1936 ! |
|
1937 |
|
1938 sendTo:anAddressBuffer buffer:buffer |
|
1939 "send datagramm data - fetch address of destination host from |
|
1940 anAddressBuffer, data from aDataBuffer. |
|
1941 Both must be ByteArray-like. The bytes in the addressBuffer must |
|
1942 be a valid address for my domain (i.e. for inet, a 4-byte byteArray). |
|
1943 Return the number of bytes transmitted, or a negative number on error. |
|
1944 On error, the unix error code is left in the lastErrorNumber |
|
1945 instance variable. |
|
1946 Flags is currently ignored; it is there for ST-80 compatibility." |
|
1947 |
|
1948 ^ self sendTo:anAddressBuffer buffer:buffer start:1 for:buffer size flags:0 |
|
1949 ! |
|
1950 |
|
1951 sendTo:anAddressBuffer buffer:buffer start:startIndex for:count |
|
1952 "send datagramm data - fetch address of destination host from |
|
1953 anAddressBuffer, data from aDataBuffer. |
|
1954 Both must be ByteArray-like. The bytes in the addressBuffer must |
|
1955 be a valid address for my domain (i.e. for inet, a 4-byte byteArray). |
|
1956 Return the number of bytes transmitted, or a negative number on error. |
|
1957 On error, the unix error code is left in the lastErrorNumber |
|
1958 instance variable. |
|
1959 Flags is currently ignored; it is there for ST-80 compatibility." |
|
1960 |
|
1961 ^ self sendTo:anAddressBuffer buffer:buffer start:startIndex for:count flags:0 |
|
1962 ! |
|
1963 |
|
1964 sendTo:anAddressBuffer buffer:aDataBuffer start:startIndex for:nBytes flags:flags |
|
1965 "send datagramm data - fetch address of destination host from |
|
1966 anAddressBuffer, data from aDataBuffer starting at startIndex, |
|
1967 sending count bytes. |
|
1968 Both must be ByteArray-like. The bytes in the addressBuffer must |
|
1969 be a valid address for my domain (i.e. for inet, a 4-byte byteArray). |
|
1970 Return the number of bytes transmitted, or a negative number on error. |
|
1971 On error, the unix error code is left in the lastErrorNumber |
|
1972 instance variable." |
|
1973 |
|
1974 |domainClass addr| |
|
1975 |
|
1976 domainClass := self class socketAddressClassForDomain:domain. |
|
1977 domainClass isNil ifTrue:[ |
|
1978 ^ self error:'invalid (unsupported) domain'. |
|
1979 ]. |
|
1980 |
|
1981 (anAddressBuffer isKindOf:SocketAddress) ifTrue:[ |
|
1982 addr := anAddressBuffer. |
|
1983 ] ifFalse:[ |
|
1984 anAddressBuffer isByteArray ifFalse:[ |
|
1985 ^ self error:'bad socketAddress argument' |
|
1986 ]. |
|
1987 addr := domainClass hostAddress:anAddressBuffer. |
|
1988 ]. |
|
1989 %{ |
|
1990 #ifndef NO_SOCKET |
|
1991 OBJ fp = __INST(filePointer); |
|
1992 |
|
1993 if ((fp != nil) |
|
1994 && __isSmallInteger(startIndex) |
|
1995 && __isSmallInteger(nBytes)) { |
|
1996 SOCKET sock; |
|
1997 int objSize; |
|
1998 struct sockaddr *sockaddr_ptr; |
|
1999 union sockaddr_u sa; |
|
2000 int alen = 0; |
|
2001 int sockAddrOffs, sockaddr_size; |
|
2002 int n; |
|
2003 char *extPtr; |
|
2004 int _flags = 0; |
|
2005 int offs; |
|
2006 unsigned long norder; |
|
2007 unsigned char *buffer; |
|
2008 unsigned char *allocatedBuffer; |
|
2009 |
|
2010 _flags = __longIntVal(flags); |
|
2011 sock = SOCKET_FROM_FILE_OBJECT(fp); |
|
2012 |
|
2013 if (! __isBytes(addr)) { |
|
2014 sockaddr_size = 0; |
|
2015 sockaddr_ptr = (struct sockaddr *)0; |
|
2016 } else { |
|
2017 int nIndex; |
|
2018 OBJ cls; |
|
2019 |
|
2020 sockAddrOffs = 0; |
|
2021 if ((cls = __qClass(addr)) != @global(ByteArray)) |
|
2022 sockAddrOffs += __OBJS2BYTES__(__intVal(__ClassInstPtr(cls)->c_ninstvars)); |
|
2023 nIndex = __qSize(addr) - OHDR_SIZE; |
|
2024 sockaddr_size = nIndex - sockAddrOffs; |
|
2025 if (sockaddr_size > sizeof(sa)) { |
|
2026 console_fprintf(stderr, "Socket [warning]: bad socketAddr\n"); |
|
2027 goto bad; |
|
2028 } |
|
2029 bcopy((__byteArrayVal(addr) + sockAddrOffs), &sa, sockaddr_size); |
|
2030 sockaddr_ptr = (struct sockaddr *)(&sa); |
|
2031 } |
|
2032 |
|
2033 if (! setupBufferParameters(aDataBuffer, startIndex, &extPtr, &offs, &objSize)) goto bad; |
|
2034 if (__isSmallInteger(nBytes)) { |
|
2035 if (__intVal(nBytes) < objSize) { |
|
2036 objSize = __intVal(nBytes); |
|
2037 } |
|
2038 } |
|
2039 |
|
2040 #ifdef DO_WRAP_CALLS |
|
2041 if (extPtr) { |
|
2042 buffer = extPtr + offs; |
|
2043 } else { |
|
2044 allocatedBuffer = buffer = (char *)malloc(objSize); |
|
2045 bcopy((char *)__InstPtr(aDataBuffer) + offs, allocatedBuffer, objSize); |
|
2046 } |
|
2047 |
|
2048 do { |
|
2049 __threadErrno = 0; |
|
2050 n = STX_WSA_CALL6("sendto", sendto, sock, buffer, objSize, _flags, sockaddr_ptr, sockaddr_size); |
|
2051 } while ((n < 0) && (__threadErrno == EINTR)); |
|
2052 |
|
2053 if (allocatedBuffer) { |
|
2054 free(allocatedBuffer); |
|
2055 } |
|
2056 #else |
|
2057 __BEGIN_INTERRUPTABLE__ |
|
2058 do { |
|
2059 if (extPtr) { |
|
2060 n = sendto(sock, extPtr + offs, objSize, _flags, sockaddr_ptr, sockaddr_size); |
|
2061 } else { |
|
2062 n = sendto(sock, (char *)__InstPtr(aDataBuffer) + offs, objSize, _flags, sockaddr_ptr, sockaddr_size); |
|
2063 } |
|
2064 } while ((n < 0) && (errno == EINTR)); |
|
2065 __END_INTERRUPTABLE__ |
|
2066 #endif |
|
2067 |
|
2068 if (n < 0) { |
|
2069 __INST(lastErrorNumber) = __MKSMALLINT(errno); |
|
2070 } |
|
2071 RETURN (__MKSMALLINT(n)); |
|
2072 } |
|
2073 #endif |
|
2074 bad: ; |
|
2075 %}. |
|
2076 " |
|
2077 arrive here if you try to send from an invalid buffer |
|
2078 (i.e. not ByteArray-like), |
|
2079 or if the addressBuffer is nonNil AND not a ByteArray/String |
|
2080 or if the addressBuffer is nonNil AND too small. |
|
2081 " |
|
2082 self primitiveFailed |
|
2083 ! ! |
|
2084 |
|
2085 !Socket methodsFor:'low level'! |
|
2086 |
1633 |
2087 bindAnonymously |
1634 bindAnonymously |
2088 "bind to any address. A free port will be allocated. |
1635 "bind to any address. A free port will be allocated. |
2089 Our own socket address will be determined after conection set up. |
1636 Our own socket address will be determined after conection set up. |
2090 This is the default after the socket has been created" |
1637 This is the default after the socket has been created" |
2277 with:hostOrPathNameOrSocketAddrOrNil |
1824 with:hostOrPathNameOrSocketAddrOrNil |
2278 with:error). |
1825 with:error). |
2279 ^ true. |
1826 ^ true. |
2280 ]. |
1827 ]. |
2281 |
1828 |
2282 peer := addr. |
|
2283 port := addr port. |
1829 port := addr port. |
2284 peerName := addrName. |
|
2285 |
1830 |
2286 ^ true |
1831 ^ true |
2287 |
1832 |
2288 " |
1833 " |
2289 (Socket domain:#inet type:#stream) |
1834 (Socket domain:#inet type:#stream) |
2290 bindTo:21 |
1835 bindTo:21 |
2291 address:nil |
1836 address:nil |
2292 " |
1837 " |
2293 ! ! |
|
2294 |
|
2295 !Socket protectedMethodsFor:'low level'! |
|
2296 |
|
2297 closeFile |
|
2298 "low level close" |
|
2299 |
|
2300 %{ /* NOCONTEXT */ |
|
2301 #ifndef NO_SOCKET |
|
2302 OBJ t; |
|
2303 |
|
2304 t = __INST(filePointer); |
|
2305 if (t != nil) { |
|
2306 FILE *fp; |
|
2307 SOCKET sock; |
|
2308 int fd; |
|
2309 |
|
2310 __INST(filePointer) = nil; |
|
2311 fp = __FILEVal(t); |
|
2312 fd = fileno(fp); |
|
2313 sock = SOCKET_FROM_FD(fd); |
|
2314 |
|
2315 # ifdef xxDO_WRAP_CALLS |
|
2316 { int ret; |
|
2317 |
|
2318 do { |
|
2319 __threadErrno = 0; |
|
2320 ret = STX_C_CALL1("fclose", fclose, fp); |
|
2321 } while ((ret < 0) && (__threadErrno == EINTR)); |
|
2322 |
|
2323 # ifdef WIN32 |
|
2324 do { |
|
2325 __threadErrno = 0; |
|
2326 ret = STX_WSA_CALL1("closesocket", closesocket, sock); |
|
2327 } while ((ret < 0) && (__threadErrno == EINTR)); |
|
2328 closesocket(sock); |
|
2329 # endif |
|
2330 } |
|
2331 # else /* !DO_WRAP_CALLS */ |
|
2332 |
|
2333 DBGFPRINTF((stderr, "SOCKET: fflush %x (%d %d)\n", fp, fileno(fp), sock)); |
|
2334 fflush(fp); |
|
2335 |
|
2336 # if defined(CLOSESOCKET_BEFORE_FCLOSE) |
|
2337 DBGFPRINTF((stderr, "SOCKET: closesocket (%d)\n", sock)); |
|
2338 closesocket(sock); |
|
2339 # endif |
|
2340 if ((@global(FileOpenTrace) == true) || __debugging__) { |
|
2341 console_fprintf(stderr, "SOCKET: fclose %x (%d %d)\n", fp, fileno(fp), sock); |
|
2342 } |
|
2343 fclose(fp); |
|
2344 |
|
2345 # if defined(CLOSESOCKET_AFTER_FCLOSE) |
|
2346 DBGFPRINTF((stderr, "SOCKET: closesocket (%d)\n", sock)); |
|
2347 closesocket(sock); |
|
2348 # endif |
|
2349 # endif /* !DO_WRAP_CALLS */ |
|
2350 } |
|
2351 #endif /* NO_SOCKET */ |
|
2352 %} |
|
2353 ! ! |
|
2354 |
|
2355 !Socket methodsFor:'low level'! |
|
2356 |
|
2357 getSocketError |
|
2358 "get the SO_ERROR form the socket, which indicates the |
|
2359 result of an asynchronous operation" |
|
2360 |
|
2361 %{ |
|
2362 #ifndef NO_SOCKET |
|
2363 OBJ fp; |
|
2364 int err; |
|
2365 |
|
2366 fp = __INST(filePointer); |
|
2367 if (fp == nil) { |
|
2368 err = EBADF; |
|
2369 } else { |
|
2370 unsigned int sz; |
|
2371 SOCKET sock; |
|
2372 |
|
2373 sock = SOCKET_FROM_FILE_OBJECT(fp); |
|
2374 sz = sizeof(err); |
|
2375 if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &err, &sz) < 0) { |
|
2376 # ifdef WIN32 |
|
2377 errno = WSAGetLastError(); |
|
2378 # endif |
|
2379 err = errno; |
|
2380 } |
|
2381 } |
|
2382 |
|
2383 RETURN(__MKSMALLINT(err)); |
|
2384 #endif |
|
2385 %} |
|
2386 ! |
1838 ! |
2387 |
1839 |
2388 listenFor:aNumber |
1840 listenFor:aNumber |
2389 "same as listenWithBacklog: - for ST-80 compatibility" |
1841 "start listening; return true if ok, false on error |
2390 |
1842 aNumber is the number of connect requests, that may be queued on the socket" |
2391 ^ self listenWithBacklog:aNumber |
|
2392 ! |
|
2393 |
|
2394 listenWithBacklog:aNumber |
|
2395 "start listening; return true if ok, false on error" |
|
2396 |
1843 |
2397 filePointer isNil ifTrue:[ |
1844 filePointer isNil ifTrue:[ |
2398 ^ self errorNotOpen |
1845 ^ self errorNotOpen |
2399 ]. |
1846 ]. |
2400 %{ |
1847 %{ |
2401 #ifndef NO_SOCKET |
1848 #ifndef NO_SOCKET |
2402 OBJ fp = __INST(filePointer); |
1849 OBJ fp = __INST(filePointer); |
2403 SOCKET sock; |
1850 SOCKET sock; |
2404 int ret; |
1851 int ret; |
2405 |
1852 |
2406 if (! __isSmallInteger(aNumber)) { |
1853 if (! __isSmallInteger(aNumber)) { |
2407 DBGPRINTF(("SOCKET: invalid arg\n")); |
1854 DBGPRINTF(("SOCKET: invalid arg\n")); |
2408 RETURN (false); |
1855 RETURN (false); |
2409 } |
1856 } |
2410 |
1857 |
2411 sock = SOCKET_FROM_FILE_OBJECT(fp); |
1858 sock = SOCKET_FROM_FILE_OBJECT(fp); |
2412 |
1859 |
2413 #ifdef LISTEN_BLOCKS |
1860 #ifdef LISTEN_BLOCKS |
2414 # ifdef DO_WRAP_CALLS |
1861 # ifdef DO_WRAP_CALLS |
2415 do { |
1862 do { |
2416 __threadErrno = 0; |
1863 __threadErrno = 0; |
2417 ret = STX_WSA_CALL2("listen", listen, sock, __intVal(aNumber)); |
1864 ret = STX_WSA_CALL2("listen", listen, sock, __intVal(aNumber)); |
2418 } while ((ret < 0) && (__threadErrno == EINTR)); |
1865 } while ((ret < 0) && (__threadErrno == EINTR)); |
2419 # else |
1866 # else |
2420 __BEGIN_INTERRUPTABLE__ |
1867 __BEGIN_INTERRUPTABLE__ |
2421 do { |
1868 do { |
2422 ret = listen(sock, __intVal(aNumber)); |
1869 ret = listen(sock, __intVal(aNumber)); |
2423 } while ((ret < 0) && (errno == EINTR)); |
1870 } while ((ret < 0) && (errno == EINTR)); |
2424 __END_INTERRUPTABLE__ |
1871 __END_INTERRUPTABLE__ |
2425 # endif |
1872 # endif |
2426 #else |
1873 #else |
2427 ret = listen(sock, __intVal(aNumber)); |
1874 ret = listen(sock, __intVal(aNumber)); |
2428 #endif |
1875 #endif |
2429 |
1876 |
2430 if (ret < 0) { |
1877 if (ret < 0) { |
2431 DBGPRINTF(("SOCKET: listen call failed errno=%d\n", errno)); |
1878 DBGPRINTF(("SOCKET: listen call failed errno=%d\n", errno)); |
2432 __INST(lastErrorNumber) = __MKSMALLINT(errno); |
1879 __INST(lastErrorNumber) = __MKSMALLINT(errno); |
2433 RETURN (false); |
1880 RETURN (false); |
2434 } |
1881 } |
2435 #else |
1882 #else |
2436 RETURN (false); |
1883 RETURN (false); |
2437 #endif |
1884 #endif |
2438 %}. |
1885 %}. |
2439 listening := true. |
1886 listening := true. |
2440 ^ true |
1887 ^ true |
2441 ! ! |
1888 ! ! |
2442 |
1889 |
2443 !Socket protectedMethodsFor:'low level'! |
1890 !Socket methodsFor:'closing'! |
2444 |
1891 |
2445 setSocketOption:option argument:arg1 argument:arg2 |
1892 shutDown |
2446 |ok| |
1893 "shutDown and close the socket" |
2447 |
1894 |
2448 %{ /* STACK: 32000 */ |
1895 self shutdown:2. |
2449 OBJ fp = __INST(filePointer); |
1896 self close |
2450 |
1897 ! |
2451 if (fp != nil) { |
1898 |
2452 SOCKET sock; |
1899 shutDownInput |
2453 int opt = -1; |
1900 "shutDown the input side of the socket. |
2454 int level = -1; |
1901 Any read on the socket will signal end-of-file from now on. |
2455 int usize = -1; |
1902 The other side MAY be informed, that no more data will be accepted |
2456 int ret; |
1903 (e.g. setting the TCP-Windowsize to 0)" |
2457 union u { |
1904 |
2458 BOOL u_bool; |
1905 self shutdown:0. |
2459 int u_int; |
1906 ! |
2460 struct linger u_linger; |
1907 |
2461 } u; |
1908 shutDownOutput |
2462 |
1909 "shutDown the output side of the socket. |
2463 sock = SOCKET_FROM_FILE_OBJECT(fp); |
1910 Any write to the socket will signal end-of-file from now on. |
2464 |
1911 The other side will get a end-of-file condition, |
2465 # ifdef SO_BROADCAST |
1912 after the last buffered data has been read" |
2466 if (option == @symbol(SO_BROADCAST)) { |
1913 |
2467 /* Enables transmission and receipt of broadcast messages on the socket. */ |
1914 self shutdown:1. |
2468 opt = SO_BROADCAST; |
|
2469 level = SOL_SOCKET; |
|
2470 usize = sizeof(u.u_bool); |
|
2471 if (arg1 == true) u.u_bool = TRUE; |
|
2472 else if (arg1 == false) u.u_bool = FALSE; |
|
2473 else goto argError; |
|
2474 } |
|
2475 # endif /* SO_BROADCAST */ |
|
2476 |
|
2477 # ifdef SO_CONDITIONAL |
|
2478 # if 0 |
|
2479 if (option == @symbol(SO_CONDITIONAL)) { |
|
2480 /* Enables sockets to delay the acknowledgment of a connection until after the WSAAccept condition function is called. */ |
|
2481 opt = SO_CONDITIONAL; |
|
2482 level = SOL_SOCKET; |
|
2483 usize = sizeof(u.u_bool); |
|
2484 if (arg1 == true) u.u_bool = TRUE; |
|
2485 else if (arg1 == false) u.u_bool = FALSE; |
|
2486 else goto argError; |
|
2487 } |
|
2488 # endif |
|
2489 # endif /* SO_CONDITIONAL */ |
|
2490 |
|
2491 # ifdef SO_DEBUG |
|
2492 if (option == @symbol(SO_DEBUG)) { |
|
2493 /* Records debugging information. */ |
|
2494 opt = SO_DEBUG; |
|
2495 level = SOL_SOCKET; |
|
2496 usize = sizeof(u.u_bool); |
|
2497 if (arg1 == true) u.u_bool = TRUE; |
|
2498 else if (arg1 == false) u.u_bool = FALSE; |
|
2499 else goto argError; |
|
2500 } |
|
2501 # endif /* SO_DEBUG */ |
|
2502 |
|
2503 # ifdef SO_DONTLINGER |
|
2504 if (option == @symbol(SO_DONTLINGER)) { |
|
2505 /* Does not block close waiting for unsent data to be sent. |
|
2506 Setting this option is equivalent to setting SO_LINGER with l_onoff set to zero. */ |
|
2507 opt = SO_DONTLINGER; |
|
2508 level = SOL_SOCKET; |
|
2509 usize = sizeof(u.u_bool); |
|
2510 if (arg1 == true) u.u_bool = TRUE; |
|
2511 else if (arg1 == false) u.u_bool = FALSE; |
|
2512 else goto argError; |
|
2513 } |
|
2514 # endif /* SO_DONTLINGER */ |
|
2515 |
|
2516 # ifdef SO_DONTROUTE |
|
2517 if (option == @symbol(SO_DONTROUTE)) { |
|
2518 /* Does not route: sends directly to interface. |
|
2519 Succeeds but is ignored on AF_INET sockets; |
|
2520 fails on AF_INET6 sockets with WSAENOPROTOOPT. |
|
2521 Not supported on ATM sockets (results in an error). */ |
|
2522 opt = SO_DONTROUTE; |
|
2523 level = SOL_SOCKET; |
|
2524 usize = sizeof(u.u_bool); |
|
2525 if (arg1 == true) u.u_bool = TRUE; |
|
2526 else if (arg1 == false) u.u_bool = FALSE; |
|
2527 else goto argError; |
|
2528 } |
|
2529 # endif /* SO_DONTROUTE */ |
|
2530 |
|
2531 # ifdef SO_KEEPALIVE |
|
2532 if (option == @symbol(SO_KEEPALIVE)) { |
|
2533 /* Sends keep-alives. Not supported on ATM sockets (results in an error). */ |
|
2534 opt = SO_KEEPALIVE; |
|
2535 level = SOL_SOCKET; |
|
2536 usize = sizeof(u.u_bool); |
|
2537 if (arg1 == true) u.u_bool = TRUE; |
|
2538 else if (arg1 == false) u.u_bool = FALSE; |
|
2539 else goto argError; |
|
2540 } |
|
2541 # endif /* SO_KEEPALIVE */ |
|
2542 |
|
2543 # ifdef SO_LINGER |
|
2544 if (option == @symbol(SO_LINGER)) { |
|
2545 /* Lingers on close if unsent data is present. */ |
|
2546 opt = SO_LINGER; |
|
2547 level = SOL_SOCKET; |
|
2548 usize = sizeof(u.u_linger); |
|
2549 if (arg1 == true) u.u_linger.l_onoff = TRUE; |
|
2550 else if (arg1 == false) u.u_linger.l_onoff = FALSE; |
|
2551 else goto argError; |
|
2552 if (arg2 == nil) u.u_linger.l_linger = 0; |
|
2553 else if (__isSmallInteger(arg2))u.u_linger.l_linger = __intVal(arg2); |
|
2554 else goto argError; |
|
2555 DBGPRINTF(("SOCKET: SO_LINGER %d %d\n", u.u_linger.l_onoff, u.u_linger.l_linger)); |
|
2556 } |
|
2557 # endif /* SO_LINGER */ |
|
2558 |
|
2559 # ifdef SO_OOBINLINE |
|
2560 if (option == @symbol(SO_OOBINLINE)) { |
|
2561 /* Receives OOB data in the normal data stream. */ |
|
2562 opt = SO_OOBINLINE; |
|
2563 level = SOL_SOCKET; |
|
2564 usize = sizeof(u.u_bool); |
|
2565 if (arg1 == true) u.u_bool = TRUE; |
|
2566 else if (arg1 == false) u.u_bool = FALSE; |
|
2567 else goto argError; |
|
2568 } |
|
2569 # endif /* SO_OOBINLINE */ |
|
2570 |
|
2571 # ifdef SO_RCVBUF |
|
2572 if (option == @symbol(SO_RCVBUF)) { |
|
2573 /* Specifies the total per-socket buffer space reserved for receives. |
|
2574 This is unrelated to SO_MAX_MSG_SIZE or the size of a TCP window. */ |
|
2575 opt = SO_RCVBUF; |
|
2576 level = SOL_SOCKET; |
|
2577 usize = sizeof(u.u_int); |
|
2578 if (__isSmallInteger(arg1))u.u_int = __intVal(arg1); |
|
2579 else goto argError; |
|
2580 } |
|
2581 # endif /* SO_RCVBUF */ |
|
2582 |
|
2583 # ifdef SO_SNDBUF |
|
2584 if (option == @symbol(SO_SNDBUF)) { |
|
2585 /* Specifies the total per-socket buffer space reserved for sends. |
|
2586 This is unrelated to SO_MAX_MSG_SIZE or the size of a TCP window. */ |
|
2587 opt = SO_SNDBUF; |
|
2588 level = SOL_SOCKET; |
|
2589 usize = sizeof(u.u_int); |
|
2590 if (__isSmallInteger(arg1))u.u_int = __intVal(arg1); |
|
2591 else goto argError; |
|
2592 } |
|
2593 # endif /* SO_SNDBUF */ |
|
2594 |
|
2595 # ifdef SO_REUSEADDR |
|
2596 if (option == @symbol(SO_REUSEADDR)) { |
|
2597 /* Allows the socket to be bound to an address that is already in use. */ |
|
2598 opt = SO_REUSEADDR; |
|
2599 level = SOL_SOCKET; |
|
2600 usize = sizeof(u.u_bool); |
|
2601 if (arg1 == true) u.u_bool = TRUE; |
|
2602 else if (arg1 == false) u.u_bool = FALSE; |
|
2603 else goto argError; |
|
2604 } |
|
2605 # endif /* SO_OOBINLINE */ |
|
2606 |
|
2607 # ifdef SO_EXCLUSIVEADDRUSE |
|
2608 if (option == @symbol(SO_EXCLUSIVEADDRUSE)) { |
|
2609 /* Enables a socket to be bound for exclusive access. |
|
2610 Does not require administrative privilege. */ |
|
2611 opt = SO_EXCLUSIVEADDRUSE; |
|
2612 level = SOL_SOCKET; |
|
2613 usize = sizeof(u.u_bool); |
|
2614 if (arg1 == true) u.u_bool = TRUE; |
|
2615 else if (arg1 == false) u.u_bool = FALSE; |
|
2616 else goto argError; |
|
2617 } |
|
2618 # endif /* SO_OOBINLINE */ |
|
2619 |
|
2620 if (usize == -1) goto argError; |
|
2621 |
|
2622 ok = ( setsockopt( sock, level, opt, &u, usize) >= 0) ? true : false; |
|
2623 } |
|
2624 argError: ; |
|
2625 |
|
2626 %}. |
|
2627 ok isNil ifTrue:[ |
|
2628 self primitiveFailed |
|
2629 ]. |
|
2630 ok ifFalse:[ |
|
2631 'setsocketoption failed' infoPrintCR. |
|
2632 ]. |
|
2633 ! ! |
1915 ! ! |
2634 |
1916 |
2635 !Socket methodsFor:'low level'! |
1917 !Socket methodsFor:'connecting'! |
2636 |
|
2637 shutdown: howNum |
|
2638 "shutDown the socket - inform it that no more I/O will be performed. |
|
2639 0 - read side (no further reads) |
|
2640 1 - write side (no further writes) |
|
2641 2 - both (no further I/O at all) |
|
2642 shutDown:2 |
|
2643 discards any pending data |
|
2644 (as opposed to close, which might wait until data is delivered as set by LINGER)" |
|
2645 |
|
2646 %{ |
|
2647 #ifndef NO_SOCKET |
|
2648 |
|
2649 OBJ fp; |
|
2650 |
|
2651 fp = __INST(filePointer); |
|
2652 if ((fp != nil) && __isSmallInteger(howNum)) { |
|
2653 SOCKET sock; |
|
2654 int ret; |
|
2655 |
|
2656 sock = SOCKET_FROM_FILE_OBJECT(fp); |
|
2657 # ifdef DO_WRAP_CALLS |
|
2658 do { |
|
2659 __threadErrno = 0; |
|
2660 DBGFPRINTF((stderr, "SOCKET: shutDown...\n")); |
|
2661 ret = STX_WSA_CALL2("shutdown", shutdown, sock, __intVal(howNum)); |
|
2662 DBGFPRINTF((stderr, "SOCKET: shutDown -> %d (%d)\n", ret, __threadErrno)); |
|
2663 } while ((ret < 0) && (__threadErrno == EINTR)); |
|
2664 # else |
|
2665 __BEGIN_INTERRUPTABLE__ |
|
2666 shutdown(sock, __intVal(howNum)); |
|
2667 __END_INTERRUPTABLE__ |
|
2668 # endif |
|
2669 } |
|
2670 #endif |
|
2671 %}. |
|
2672 ! ! |
|
2673 |
|
2674 !Socket methodsFor:'low level-accepting'! |
|
2675 |
|
2676 accept |
|
2677 "create a new TCP socket from accepting on the receiver. |
|
2678 This method will suspend the current process if no connection is waiting. |
|
2679 For ST-80 compatibility" |
|
2680 |
|
2681 |newSock| |
|
2682 |
|
2683 newSock := self class new. |
|
2684 (newSock acceptOn:self) ifFalse:[^ nil]. |
|
2685 ^ newSock |
|
2686 |
|
2687 " |
|
2688 |sock newSock| |
|
2689 |
|
2690 sock := Socket provide:8004. |
|
2691 sock listenFor:5. |
|
2692 newSock := sock accept. |
|
2693 " |
|
2694 ! |
|
2695 |
|
2696 acceptOn:aSocket |
|
2697 "accept a connection on a server port (created with:'Socket>>onIPPort:') |
|
2698 usage is: (Socket basicNew acceptOn:(Socket onIPPort:9999)). |
|
2699 This method will suspend the current process if no connection is waiting. |
|
2700 Return the true if ok; false if not." |
|
2701 |
|
2702 aSocket readWait. |
|
2703 ^ self primAcceptOn:aSocket blocking:false. |
|
2704 |
|
2705 "Modified: / 11.3.1996 / 14:21:31 / stefan" |
|
2706 "Modified: / 1.8.1998 / 23:39:10 / cg" |
|
2707 ! |
|
2708 |
|
2709 blockingAccept |
|
2710 "create a new TCP socket from accepting on the receiver. |
|
2711 This method will suspend the current process if no connection is waiting. |
|
2712 For ST-80 compatibility" |
|
2713 |
|
2714 |newSock| |
|
2715 |
|
2716 newSock := self class new. |
|
2717 (newSock blockingAcceptOn:self) ifFalse:[^ nil]. |
|
2718 ^ newSock |
|
2719 ! |
|
2720 |
|
2721 blockingAcceptOn:aSocket |
|
2722 "accept a connection on a server port (created with:'Socket>>onIPPort:') |
|
2723 usage is: (Socket basicNew acceptOn:(Socket onIPPort:9999)). |
|
2724 This method will suspend the current process if no connection is waiting. |
|
2725 Return the true if ok; false if not." |
|
2726 |
|
2727 ^ self primAcceptOn:aSocket blocking:true. |
|
2728 ! |
|
2729 |
|
2730 pollingWaitForNewConnectionOrDataOnAny:otherConnections timeout:timeoutSeconds |
|
2731 <resource: #obsolete> |
|
2732 "stupid MSDOS does not support select on sockets (sigh). |
|
2733 Must poll here." |
|
2734 |
|
2735 |millis newConnection| |
|
2736 |
|
2737 millis := timeoutSeconds * 1000. |
|
2738 [millis > 0] whileTrue:[ |
|
2739 otherConnections size > 0 ifTrue:[ |
|
2740 otherConnections do:[:aConnection | |
|
2741 aConnection canReadWithoutBlocking ifTrue:[ |
|
2742 ^ aConnection |
|
2743 ] |
|
2744 ]. |
|
2745 ]. |
|
2746 newConnection := self blockingAccept. |
|
2747 newConnection notNil ifTrue:[^ newConnection]. |
|
2748 Delay waitForMilliseconds:20. |
|
2749 millis := millis - 20. |
|
2750 ]. |
|
2751 ^ nil. |
|
2752 ! |
|
2753 |
|
2754 pollingWaitForNewConnectionWithTimeout:timeoutSeconds |
|
2755 <resource: #obsolete> |
|
2756 "stupid MSDOS does not support select on sockets (sigh). |
|
2757 Must poll here." |
|
2758 |
|
2759 |millis newConnection| |
|
2760 |
|
2761 timeoutSeconds notNil ifTrue:[ |
|
2762 millis := timeoutSeconds * 1000. |
|
2763 ]. |
|
2764 [millis isNil or:[millis > 0]] whileTrue:[ |
|
2765 newConnection := self blockingAccept. |
|
2766 newConnection notNil ifTrue:[^ newConnection]. |
|
2767 Delay waitForMilliseconds:20. |
|
2768 millis notNil ifTrue:[ |
|
2769 millis := millis - 20. |
|
2770 ] |
|
2771 ]. |
|
2772 ^ nil. |
|
2773 ! |
|
2774 |
|
2775 primAcceptOn:aSocket blocking:blocking |
|
2776 "accept a connection on a server port (created with:'Socket>>onIPPort:') |
|
2777 usage is: (Socket basicNew acceptOn:(Socket onIPPort:9999)). |
|
2778 Return the true if ok; false if not." |
|
2779 |
|
2780 |serverSocketFd addr addrLen domainClass| |
|
2781 |
|
2782 filePointer notNil ifTrue:[ |
|
2783 ^ self errorAlreadyOpen |
|
2784 ]. |
|
2785 |
|
2786 domain := aSocket domain. |
|
2787 socketType := aSocket type. |
|
2788 serverSocketFd := aSocket fileDescriptor. |
|
2789 serverSocketFd isNil ifTrue:[ |
|
2790 ^ self error:'invalid server socket' |
|
2791 ]. |
|
2792 (serverSocketFd isMemberOf:SmallInteger) ifFalse:[ |
|
2793 ^ self error:'invalid server socket' |
|
2794 ]. |
|
2795 |
|
2796 domainClass := self class socketAddressClassForDomain:domain. |
|
2797 domainClass isNil ifTrue:[ |
|
2798 ^ self error:'invalid (unsupported) domain'. |
|
2799 ]. |
|
2800 addrLen := domainClass socketAddressSize. |
|
2801 addr := domainClass new. |
|
2802 |
|
2803 %{ /* STACK: 100000 */ |
|
2804 #ifndef NO_SOCKET |
|
2805 FILE *fp; |
|
2806 int flags; |
|
2807 SOCKET sock, newSock; |
|
2808 union sockaddr_u sa; |
|
2809 unsigned int alen, alen0; |
|
2810 struct hostent *he ; |
|
2811 char dotted[20] ; |
|
2812 |
|
2813 if (!__isSmallInteger(addrLen)) { |
|
2814 DBGPRINTF(("SOCKET: bad addrLen\n")); |
|
2815 RETURN (false); |
|
2816 } |
|
2817 alen0 = __intVal(addrLen); |
|
2818 sock = SOCKET_FROM_FD(__intVal(serverSocketFd)); |
|
2819 |
|
2820 if (blocking == false) { |
|
2821 # if defined(O_NONBLOCK) && defined(SET_NDELAY) |
|
2822 flags = fcntl(sock, F_GETFL); |
|
2823 fcntl(sock, F_SETFL, flags | O_NONBLOCK); |
|
2824 # endif |
|
2825 } |
|
2826 |
|
2827 # ifdef DO_WRAP_CALLS |
|
2828 do { |
|
2829 __threadErrno = 0; |
|
2830 alen = alen0; |
|
2831 newSock = STX_WSA_CALL3("accept", accept, sock, &sa, &alen); |
|
2832 } while ((newSock < 0) && (__threadErrno == EINTR)); |
|
2833 # else |
|
2834 __BEGIN_INTERRUPTABLE__ |
|
2835 do { |
|
2836 alen = alen0; |
|
2837 newSock = accept(sock, (struct sockaddr *) &sa, &alen); |
|
2838 } while ((newSock < 0) && (errno == EINTR)); |
|
2839 __END_INTERRUPTABLE__ |
|
2840 # endif |
|
2841 DBGFPRINTF((stderr, "SOCKET: accept newSock=%d\n", newSock)); |
|
2842 |
|
2843 if (blocking == false) { |
|
2844 # if defined(O_NDELAY) && defined(SET_NDELAY) |
|
2845 fcntl(sock, F_SETFL, flags); |
|
2846 # endif |
|
2847 } |
|
2848 |
|
2849 if (newSock < 0) { |
|
2850 DBGPRINTF(("SOCKET: accept call failed errno=%d\n", errno)); |
|
2851 __INST(lastErrorNumber) = __MKSMALLINT(errno); |
|
2852 RETURN (false); |
|
2853 } |
|
2854 |
|
2855 if (__isNonNilObject(addr)) { |
|
2856 OBJ oClass; |
|
2857 int nInstVars, nInstBytes, objSize; |
|
2858 char *cp; |
|
2859 |
|
2860 oClass = __qClass(addr); |
|
2861 if (! __isBytes(addr) ) { |
|
2862 DBGPRINTF(("SOCKET: bad addr\n")); |
|
2863 closesocket(newSock); |
|
2864 RETURN (false); |
|
2865 } |
|
2866 |
|
2867 nInstVars = __intVal(__ClassInstPtr(oClass)->c_ninstvars); |
|
2868 nInstBytes = OHDR_SIZE + (nInstVars * sizeof(OBJ)); |
|
2869 objSize = __qSize(addr) - nInstBytes; |
|
2870 cp = (char *)__InstPtr(addr) + nInstBytes; |
|
2871 if (objSize < alen) { |
|
2872 DBGPRINTF(("SOCKET: bad addr\n")); |
|
2873 closesocket(newSock); |
|
2874 RETURN (false); |
|
2875 } |
|
2876 |
|
2877 /* |
|
2878 * extract the partners address |
|
2879 */ |
|
2880 bcopy((char *)&sa, cp, alen); |
|
2881 addrLen = __MKSMALLINT(alen); |
|
2882 } |
|
2883 |
|
2884 /* |
|
2885 * make it a FILE * |
|
2886 */ |
|
2887 # ifdef WIN32 |
|
2888 { |
|
2889 int _fd = _open_osfhandle(newSock, 0); |
|
2890 fp = fdopen(_fd, "r+"); |
|
2891 DBGPRINTF(("SOCKET: sock=%d fd=%d fp=%x\n",newSock,_fd, fp)); |
|
2892 } |
|
2893 # else |
|
2894 fp = fdopen(newSock, "r+"); |
|
2895 # endif |
|
2896 |
|
2897 if (! fp) { |
|
2898 DBGPRINTF(("SOCKET: fdopen call failed\n")); |
|
2899 __INST(lastErrorNumber) = __MKSMALLINT(errno); |
|
2900 # ifdef DO_WRAP_CALLS |
|
2901 { |
|
2902 int ret; |
|
2903 do { |
|
2904 __threadErrno = 0; |
|
2905 ret = STX_WSA_CALL1("closesocket", closesocket, newSock); |
|
2906 } while ((ret < 0) && (__threadErrno == EINTR)); |
|
2907 } |
|
2908 # else |
|
2909 closesocket(newSock); |
|
2910 # endif |
|
2911 DBGFPRINTF((stderr, "SOCKET: close (fdopen failed) (%d)\n", newSock)); |
|
2912 RETURN (false); |
|
2913 } |
|
2914 |
|
2915 if ((@global(FileOpenTrace) == true) || __debugging__) { |
|
2916 # ifdef WIN32 |
|
2917 { |
|
2918 HANDLE h; |
|
2919 int _fd = fileno(fp); |
|
2920 h = (HANDLE)_get_osfhandle(_fd); |
|
2921 console_fprintf(stderr, "fdopen [Socket] -> %x (fd: %d) (H: %x)\n", fp, _fd, h); |
|
2922 } |
|
2923 # else |
|
2924 console_fprintf(stderr, "fdopen [Socket] -> %x (fd: %d)\n", fp, newSock); |
|
2925 # endif |
|
2926 } |
|
2927 |
|
2928 # ifdef BUGGY_STDIO_LIB |
|
2929 setbuf(fp, NULL); |
|
2930 __INST(buffered) = false; |
|
2931 # endif |
|
2932 |
|
2933 # if 0 |
|
2934 // The original code was: |
|
2935 __INST(filePointer) = __MKOBJ((INT)fp); __STORESELF(filePointer); |
|
2936 // but for that, gcc generates wrong code, which loads self (volatile) into |
|
2937 // a register (bp), then calls __MKOBJ, then stores indirect bp. |
|
2938 // That is wrong if a scavenge occurs in MKOBJ, as bp is now still pointing to the old |
|
2939 // object. |
|
2940 # endif |
|
2941 { |
|
2942 OBJ t; |
|
2943 |
|
2944 t = __MKOBJ(fp); |
|
2945 __INST(filePointer) = t; |
|
2946 __STORE(self, t); |
|
2947 } |
|
2948 #endif /* not NO_SOCKET */ |
|
2949 %}. |
|
2950 mode := #readwrite. |
|
2951 Lobby register:self. |
|
2952 binary := false. |
|
2953 port := aSocket port. |
|
2954 |
|
2955 addr notNil ifTrue:[ |
|
2956 peer := addr. |
|
2957 ]. |
|
2958 |
|
2959 ^ true |
|
2960 ! |
|
2961 |
|
2962 waitForNewConnectionOrDataOnAny:otherConnections timeout:timeoutSeconds |
|
2963 "suspend the current process, until either a new connection comes |
|
2964 in at the receiver, or data arrives on any of the otherConnections. |
|
2965 For a new connection, an accept is performed and the new socket is returned. |
|
2966 For an old connection, that socket is returned. |
|
2967 In any case, the caller gets a socket to operate on as return value, |
|
2968 or nil, if a timeout occured. |
|
2969 This method implements the inner wait-primitive of a multi-connection |
|
2970 server application." |
|
2971 |
|
2972 |
|
2973 |wasBlocked sema| |
|
2974 |
|
2975 "first, a quick check if data is already available" |
|
2976 self canReadWithoutBlocking ifTrue:[ |
|
2977 ^ self accept. |
|
2978 ]. |
|
2979 otherConnections do:[:aConnection | |
|
2980 aConnection canReadWithoutBlocking ifTrue:[ |
|
2981 ^ aConnection |
|
2982 ] |
|
2983 ]. |
|
2984 |
|
2985 [ |
|
2986 "check again - prevent incoming interrupts from disturbing our setup" |
|
2987 wasBlocked := OperatingSystem blockInterrupts. |
|
2988 |
|
2989 self canReadWithoutBlocking ifTrue:[ |
|
2990 ^ self accept. |
|
2991 ]. |
|
2992 otherConnections do:[:aConnection | |
|
2993 aConnection canReadWithoutBlocking ifTrue:[ |
|
2994 ^ aConnection |
|
2995 ] |
|
2996 ]. |
|
2997 |
|
2998 "nope - must wait" |
|
2999 sema := Semaphore new name:'multiReadWait'. |
|
3000 otherConnections do:[:aConnection | |
|
3001 Processor signal:sema onInput:(aConnection fileDescriptor). |
|
3002 ]. |
|
3003 Processor signal:sema onInput:(self fileDescriptor). |
|
3004 timeoutSeconds notNil ifTrue:[ |
|
3005 Processor signal:sema afterSeconds:timeoutSeconds |
|
3006 ]. |
|
3007 Processor activeProcess state:#ioWait. |
|
3008 sema wait. |
|
3009 ] ensure:[ |
|
3010 sema notNil ifTrue:[Processor disableSemaphore:sema]. |
|
3011 wasBlocked ifFalse:[OperatingSystem unblockInterrupts]. |
|
3012 ]. |
|
3013 |
|
3014 "see who it was ..." |
|
3015 self canReadWithoutBlocking ifTrue:[ |
|
3016 ^ self accept. |
|
3017 ]. |
|
3018 otherConnections do:[:aConnection | |
|
3019 aConnection canReadWithoutBlocking ifTrue:[ |
|
3020 ^ aConnection |
|
3021 ] |
|
3022 ]. |
|
3023 |
|
3024 "none - a timeout" |
|
3025 ^ nil |
|
3026 ! |
|
3027 |
|
3028 waitForNewConnectionWithTimeout:timeoutSeconds |
|
3029 "suspend the current process, until a new connection comes |
|
3030 in at the receiver or a timeout occurs. |
|
3031 For a new connection, an accept is performed and the new socket is returned. |
|
3032 Returns nil, if a timeout occured. |
|
3033 This method implements the inner wait-primitive of a single-connection |
|
3034 server application." |
|
3035 |
|
3036 (self readWaitWithTimeout:timeoutSeconds) ifTrue:[ |
|
3037 "a timeout occurred - no connection within timeout" |
|
3038 ^ nil |
|
3039 ]. |
|
3040 ^ self accept. |
|
3041 ! ! |
|
3042 |
|
3043 !Socket methodsFor:'low level-connecting'! |
|
3044 |
1918 |
3045 connectTo:hostOrPathName port:portNrOrName |
1919 connectTo:hostOrPathName port:portNrOrName |
3046 "low level connect; connect to port, portNrOrNameOrNil on host, hostName. |
1920 "low level connect; connect to port, portNrOrNameOrNil on host, hostName. |
3047 For backward compatibility, host may be also a string or a byteArray, |
1921 For backward compatibility, host may be also a string or a byteArray, |
3048 but it is recommended to pass socketAddress instances. |
1922 but it is recommended to pass socketAddress instances. |
3235 sock connectTo:'localhost' port:9876 withTimeout:2000. |
2114 sock connectTo:'localhost' port:9876 withTimeout:2000. |
3236 sock |
2115 sock |
3237 " |
2116 " |
3238 ! ! |
2117 ! ! |
3239 |
2118 |
|
2119 !Socket methodsFor:'datagram transmission'! |
|
2120 |
|
2121 receiveBuffer:aDataBuffer start:startIndex for:nBytes |
|
2122 "receive data |
|
2123 Return the number of bytes received, or a negative number on error. |
|
2124 On error, the unix error code is left in the lastErrorNumber |
|
2125 instance variable. |
|
2126 The thread blocks until data arrives - you may want to wait before |
|
2127 receiving, using #readWait or #readWaitWithTimeout:." |
|
2128 |
|
2129 |nReceived| |
|
2130 |
|
2131 %{ |
|
2132 #ifndef NO_SOCKET |
|
2133 OBJ fp = __INST(filePointer); |
|
2134 |
|
2135 if (fp != nil) { |
|
2136 SOCKET sock; |
|
2137 int objSize, offs; |
|
2138 int n; |
|
2139 char *extPtr; |
|
2140 unsigned char *buffer; |
|
2141 unsigned char *allocatedBuffer; |
|
2142 int flags = 0; |
|
2143 |
|
2144 sock = SOCKET_FROM_FILE_OBJECT(fp); |
|
2145 |
|
2146 if (! setupBufferParameters(aDataBuffer, startIndex, &extPtr, &offs, &objSize)) goto bad; |
|
2147 if (__isSmallInteger(nBytes)) { |
|
2148 if (__intVal(nBytes) < objSize) { |
|
2149 objSize = __intVal(nBytes); |
|
2150 } |
|
2151 } |
|
2152 |
|
2153 # ifdef DO_WRAP_CALLS |
|
2154 if (extPtr) { |
|
2155 buffer = extPtr + offs; |
|
2156 } else { |
|
2157 allocatedBuffer = buffer = (char *)malloc(objSize); |
|
2158 } |
|
2159 |
|
2160 do { |
|
2161 __threadErrno = 0; |
|
2162 n = STX_WSA_CALL4("recv", recv, sock, buffer, objSize, flags); |
|
2163 } while ((n < 0) && (__threadErrno == EINTR)); |
|
2164 |
|
2165 if (allocatedBuffer) { |
|
2166 if (n > 0) { |
|
2167 bcopy(allocatedBuffer, (char *)__InstPtr(aDataBuffer) + offs, n); |
|
2168 } |
|
2169 free(allocatedBuffer); |
|
2170 } |
|
2171 # else |
|
2172 __BEGIN_INTERRUPTABLE__ |
|
2173 do { |
|
2174 if (extPtr) { |
|
2175 n = recv(sock, extPtr + offs, objSize, flags); |
|
2176 } else { |
|
2177 n = recv(sock, (char *)__InstPtr(aDataBuffer) + offs, objSize, flags); |
|
2178 } |
|
2179 } while ((n < 0) && (errno == EINTR)); |
|
2180 __END_INTERRUPTABLE__ |
|
2181 # endif |
|
2182 |
|
2183 if (n < 0) { |
|
2184 __INST(lastErrorNumber) = __MKSMALLINT(errno); |
|
2185 } |
|
2186 nReceived = __MKSMALLINT(n); |
|
2187 } |
|
2188 #endif |
|
2189 bad: ; |
|
2190 %}. |
|
2191 nReceived notNil ifTrue:[ |
|
2192 nReceived < 0 ifTrue:[ |
|
2193 'Socket [warning]: ' infoPrint. |
|
2194 (OperatingSystem errorTextForNumber:lastErrorNumber) infoPrintCR. |
|
2195 ]. |
|
2196 ^ nReceived |
|
2197 ]. |
|
2198 " |
|
2199 arrive here if you try to receive into an invalid buffer (i.e. not ByteArray-like) |
|
2200 " |
|
2201 self primitiveFailed |
|
2202 ! |
|
2203 |
|
2204 receiveFrom:anAddressBuffer buffer:aDataBuffer |
|
2205 "receive datagramm data - put address of originating host into |
|
2206 anAddressBuffer, data into aBuffer. |
|
2207 Both must be ByteArray-like. The addressBuffer must |
|
2208 provide space for a valid address for my domain (i.e. for inet, a 4-byte byteArray). |
|
2209 Return the number of bytes received, or a negative number on error. |
|
2210 On error, the unix error code is left in the lastErrorNumber |
|
2211 instance variable." |
|
2212 |
|
2213 ^ self receiveFrom:anAddressBuffer buffer:aDataBuffer start:1 for:(aDataBuffer size) |
|
2214 ! |
|
2215 |
|
2216 receiveFrom:anAddressBuffer buffer:aDataBuffer start:startIndex for:nBytes |
|
2217 "receive datagramm data |
|
2218 - put address of originating host into anAddressBuffer, data into aBuffer. |
|
2219 For backward compatibility, the addressBuffer may be a non-SocketAddress; |
|
2220 then, it must be a byteArray with appropriate size for the addressBytes. |
|
2221 |
|
2222 Return the number of bytes received, or a negative number on error. |
|
2223 On error, the unix error code is left in the lastErrorNumber |
|
2224 instance variable. |
|
2225 The thread blocks until data arrives - you may want to wait before |
|
2226 receiving, using #readWait or #readWaitWithTimeout:." |
|
2227 |
|
2228 |domainClass addr addrLen nReceived| |
|
2229 |
|
2230 domainClass := self class socketAddressClassForDomain:domain. |
|
2231 domainClass isNil ifTrue:[ |
|
2232 ^ self error:'invalid (unsupported) domain'. |
|
2233 ]. |
|
2234 (anAddressBuffer isKindOf:SocketAddress) ifTrue:[ |
|
2235 anAddressBuffer class == domainClass ifFalse:[ |
|
2236 ^ self error:'addressBuffer class mismatch (domain)'. |
|
2237 ]. |
|
2238 addr := anAddressBuffer. |
|
2239 ] ifFalse:[ |
|
2240 anAddressBuffer notNil ifTrue:[ |
|
2241 addr := domainClass new. |
|
2242 ]. |
|
2243 ]. |
|
2244 |
|
2245 %{ |
|
2246 #ifndef NO_SOCKET |
|
2247 OBJ fp = __INST(filePointer); |
|
2248 |
|
2249 if (fp != nil) { |
|
2250 SOCKET sock; |
|
2251 int objSize; |
|
2252 union sockaddr_u sa; |
|
2253 unsigned int alen = 0; |
|
2254 int n, offs; |
|
2255 int flags = 0; |
|
2256 char *extPtr; |
|
2257 unsigned char *allocatedBuffer = NULL; |
|
2258 unsigned char *buffer = NULL; |
|
2259 |
|
2260 sock = SOCKET_FROM_FILE_OBJECT(fp); |
|
2261 |
|
2262 if (! setupBufferParameters(aDataBuffer, startIndex, &extPtr, &offs, &objSize)) goto bad; |
|
2263 if (__isSmallInteger(nBytes)) { |
|
2264 if (__intVal(nBytes) < objSize) { |
|
2265 objSize = __intVal(nBytes); |
|
2266 } |
|
2267 } |
|
2268 # ifdef DO_WRAP_CALLS |
|
2269 if (extPtr) { |
|
2270 buffer = extPtr + offs; |
|
2271 } else { |
|
2272 allocatedBuffer = buffer = (char *)malloc(objSize); |
|
2273 } |
|
2274 |
|
2275 do { |
|
2276 __threadErrno = 0; |
|
2277 alen = sizeof(sa); |
|
2278 n = STX_WSA_CALL6("recvfrom", recvfrom, sock, buffer, objSize, flags, (struct sockaddr *)&sa, &alen); |
|
2279 } while ((n < 0) && (__threadErrno == EINTR)); |
|
2280 |
|
2281 if (allocatedBuffer) { |
|
2282 if (n > 0) { |
|
2283 bcopy(allocatedBuffer, (char *)__InstPtr(aDataBuffer) + offs, n); |
|
2284 } |
|
2285 free(allocatedBuffer); |
|
2286 } |
|
2287 # else |
|
2288 __BEGIN_INTERRUPTABLE__ |
|
2289 do { |
|
2290 alen = sizeof(sa); |
|
2291 if (extPtr) { |
|
2292 n = recvfrom(sock, extPtr + offs, objSize, flags, (struct sockaddr *) &sa, &alen); |
|
2293 } else { |
|
2294 n = recvfrom(sock, (char *)__InstPtr(aDataBuffer) + offs, objSize, flags, (struct sockaddr *) &sa, &alen); |
|
2295 } |
|
2296 } while ((n < 0) && (errno == EINTR)); |
|
2297 __END_INTERRUPTABLE__ |
|
2298 # endif |
|
2299 |
|
2300 if (n >= 0) { |
|
2301 if (__isNonNilObject(addr)) { |
|
2302 char *addrPtr; |
|
2303 OBJ oClass; |
|
2304 int nInstVars, nInstBytes, objSize; |
|
2305 |
|
2306 oClass = __qClass(addr); |
|
2307 if (! __isBytes(addr) ) |
|
2308 goto bad; |
|
2309 nInstVars = __intVal(__ClassInstPtr(oClass)->c_ninstvars); |
|
2310 nInstBytes = OHDR_SIZE + (nInstVars * sizeof(OBJ)); |
|
2311 objSize = __qSize(addr) - nInstBytes; |
|
2312 addrPtr = (char *)__InstPtr(addr) + nInstBytes; |
|
2313 if (objSize < alen) |
|
2314 goto bad; |
|
2315 |
|
2316 /* |
|
2317 * extract the datagrams address |
|
2318 */ |
|
2319 bcopy((char *)&sa, addrPtr, alen); |
|
2320 addrLen = __MKSMALLINT(alen); |
|
2321 } |
|
2322 } |
|
2323 if (n < 0) { |
|
2324 __INST(lastErrorNumber) = __MKSMALLINT(errno); |
|
2325 } |
|
2326 nReceived = __MKSMALLINT(n); |
|
2327 } |
|
2328 #endif |
|
2329 bad: ; |
|
2330 %}. |
|
2331 nReceived notNil ifTrue:[ |
|
2332 nReceived < 0 ifTrue:[ |
|
2333 'Socket [warning]: ' infoPrint. |
|
2334 (OperatingSystem errorTextForNumber:lastErrorNumber) infoPrintCR. |
|
2335 ]. |
|
2336 addrLen notNil ifTrue:[ |
|
2337 (addr == anAddressBuffer) ifFalse:[ |
|
2338 self obsoleteFeatureWarning:'please use a socketAddress argument'. |
|
2339 |
|
2340 " can be a ByteArray for backward compatibility " |
|
2341 anAddressBuffer replaceFrom:1 to:addrLen with:(addr hostAddress). |
|
2342 ]. |
|
2343 ]. |
|
2344 ^ nReceived |
|
2345 ]. |
|
2346 " |
|
2347 arrive here if you try to receive into an invalid buffer |
|
2348 (i.e. not ByteArray-like), |
|
2349 or if the addressBuffer is nonNil AND not a SocketAddress/ByteArray |
|
2350 or if the addressBuffer is nonNil AND too small. |
|
2351 " |
|
2352 self primitiveFailed |
|
2353 ! |
|
2354 |
|
2355 sendBuffer:aDataBuffer start:startIndex for:nBytes flags:flags |
|
2356 "send data. |
|
2357 Both must be ByteArray-like. The bytes in the addressBuffer must |
|
2358 be a valid address for my domain (i.e. for inet, a 4-byte byteArray). |
|
2359 Return the number of bytes transmitted, or a negative number on error. |
|
2360 On error, the unix error code is left in the lastErrorNumber |
|
2361 instance variable." |
|
2362 |
|
2363 |nReceived portNo| |
|
2364 |
|
2365 %{ |
|
2366 #ifndef NO_SOCKET |
|
2367 OBJ fp = __INST(filePointer); |
|
2368 |
|
2369 if ((fp != nil) |
|
2370 && __isSmallInteger(startIndex) |
|
2371 && __isSmallInteger(nBytes)) { |
|
2372 SOCKET sock; |
|
2373 int objSize; |
|
2374 int n; |
|
2375 char *extPtr; |
|
2376 int _flags = 0; |
|
2377 int offs; |
|
2378 unsigned long norder; |
|
2379 unsigned char *buffer; |
|
2380 unsigned char *allocatedBuffer; |
|
2381 |
|
2382 _flags = __longIntVal(flags); |
|
2383 |
|
2384 sock = SOCKET_FROM_FILE_OBJECT(fp); |
|
2385 |
|
2386 if (! setupBufferParameters(aDataBuffer, startIndex, &extPtr, &offs, &objSize)) goto bad; |
|
2387 if (__isSmallInteger(nBytes)) { |
|
2388 if (__intVal(nBytes) < objSize) { |
|
2389 objSize = __intVal(nBytes); |
|
2390 } |
|
2391 } |
|
2392 |
|
2393 # ifdef DGRAM_DEBUG |
|
2394 console_printf("sending %d bytes ...\n", nBytes); |
|
2395 # endif |
|
2396 |
|
2397 #ifdef DO_WRAP_CALLS |
|
2398 if (extPtr) { |
|
2399 buffer = extPtr + offs; |
|
2400 } else { |
|
2401 allocatedBuffer = buffer = (char *)malloc(objSize); |
|
2402 bcopy((char *)__InstPtr(aDataBuffer) + offs, allocatedBuffer, objSize); |
|
2403 } |
|
2404 |
|
2405 do { |
|
2406 __threadErrno = 0; |
|
2407 n = STX_WSA_CALL4("send", send, sock, buffer, objSize, _flags); |
|
2408 } while ((n < 0) && (__threadErrno == EINTR)); |
|
2409 |
|
2410 if (allocatedBuffer) { |
|
2411 free(allocatedBuffer); |
|
2412 } |
|
2413 #else |
|
2414 __BEGIN_INTERRUPTABLE__ |
|
2415 do { |
|
2416 if (extPtr) { |
|
2417 n = send(sock, extPtr + offs, objSize, _flags); |
|
2418 } else { |
|
2419 n = send(sock, (char *)__InstPtr(aDataBuffer) + offs, objSize, _flags); |
|
2420 } |
|
2421 } while ((n < 0) && (errno == EINTR)); |
|
2422 __END_INTERRUPTABLE__ |
|
2423 #endif |
|
2424 |
|
2425 if (n < 0) { |
|
2426 __INST(lastErrorNumber) = __MKSMALLINT(errno); |
|
2427 } |
|
2428 RETURN (__MKSMALLINT(n)); |
|
2429 } |
|
2430 #endif |
|
2431 bad: ; |
|
2432 %}. |
|
2433 " |
|
2434 arrive here if you try to send from an invalid buffer (i.e. not ByteArray-like), |
|
2435 " |
|
2436 self primitiveFailed |
|
2437 ! |
|
2438 |
|
2439 sendTo:anAddressBuffer buffer:buffer |
|
2440 "send datagramm data - fetch address of destination host from |
|
2441 anAddressBuffer, data from aDataBuffer. |
|
2442 Both must be ByteArray-like. The bytes in the addressBuffer must |
|
2443 be a valid address for my domain (i.e. for inet, a 4-byte byteArray). |
|
2444 Return the number of bytes transmitted, or a negative number on error. |
|
2445 On error, the unix error code is left in the lastErrorNumber |
|
2446 instance variable. |
|
2447 Flags is currently ignored; it is there for ST-80 compatibility." |
|
2448 |
|
2449 ^ self sendTo:anAddressBuffer buffer:buffer start:1 for:buffer size flags:0 |
|
2450 ! |
|
2451 |
|
2452 sendTo:anAddressBuffer buffer:buffer start:startIndex for:count |
|
2453 "send datagramm data - fetch address of destination host from |
|
2454 anAddressBuffer, data from aDataBuffer. |
|
2455 Both must be ByteArray-like. The bytes in the addressBuffer must |
|
2456 be a valid address for my domain (i.e. for inet, a 4-byte byteArray). |
|
2457 Return the number of bytes transmitted, or a negative number on error. |
|
2458 On error, the unix error code is left in the lastErrorNumber |
|
2459 instance variable. |
|
2460 Flags is currently ignored; it is there for ST-80 compatibility." |
|
2461 |
|
2462 ^ self sendTo:anAddressBuffer buffer:buffer start:startIndex for:count flags:0 |
|
2463 ! |
|
2464 |
|
2465 sendTo:anAddressBuffer buffer:aDataBuffer start:startIndex for:nBytes flags:flags |
|
2466 "send datagramm data - fetch address of destination host from |
|
2467 anAddressBuffer, data from aDataBuffer starting at startIndex, |
|
2468 sending count bytes. |
|
2469 Both must be ByteArray-like. The bytes in the addressBuffer must |
|
2470 be a valid address for my domain (i.e. for inet, a 4-byte byteArray). |
|
2471 Return the number of bytes transmitted, or a negative number on error. |
|
2472 On error, the unix error code is left in the lastErrorNumber |
|
2473 instance variable." |
|
2474 |
|
2475 |domainClass addr| |
|
2476 |
|
2477 domainClass := self class socketAddressClassForDomain:domain. |
|
2478 domainClass isNil ifTrue:[ |
|
2479 ^ self error:'invalid (unsupported) domain'. |
|
2480 ]. |
|
2481 |
|
2482 (anAddressBuffer isKindOf:SocketAddress) ifTrue:[ |
|
2483 addr := anAddressBuffer. |
|
2484 ] ifFalse:[ |
|
2485 anAddressBuffer isByteArray ifFalse:[ |
|
2486 ^ self error:'bad socketAddress argument' |
|
2487 ]. |
|
2488 addr := domainClass hostAddress:anAddressBuffer. |
|
2489 ]. |
|
2490 %{ |
|
2491 #ifndef NO_SOCKET |
|
2492 OBJ fp = __INST(filePointer); |
|
2493 |
|
2494 if ((fp != nil) |
|
2495 && __isSmallInteger(startIndex) |
|
2496 && __isSmallInteger(nBytes)) { |
|
2497 SOCKET sock; |
|
2498 int objSize; |
|
2499 struct sockaddr *sockaddr_ptr; |
|
2500 union sockaddr_u sa; |
|
2501 int alen = 0; |
|
2502 int sockAddrOffs, sockaddr_size; |
|
2503 int n; |
|
2504 char *extPtr; |
|
2505 int _flags = 0; |
|
2506 int offs; |
|
2507 unsigned long norder; |
|
2508 unsigned char *buffer; |
|
2509 unsigned char *allocatedBuffer; |
|
2510 |
|
2511 _flags = __longIntVal(flags); |
|
2512 sock = SOCKET_FROM_FILE_OBJECT(fp); |
|
2513 |
|
2514 if (! __isBytes(addr)) { |
|
2515 sockaddr_size = 0; |
|
2516 sockaddr_ptr = (struct sockaddr *)0; |
|
2517 } else { |
|
2518 int nIndex; |
|
2519 OBJ cls; |
|
2520 |
|
2521 sockAddrOffs = 0; |
|
2522 if ((cls = __qClass(addr)) != @global(ByteArray)) |
|
2523 sockAddrOffs += __OBJS2BYTES__(__intVal(__ClassInstPtr(cls)->c_ninstvars)); |
|
2524 nIndex = __qSize(addr) - OHDR_SIZE; |
|
2525 sockaddr_size = nIndex - sockAddrOffs; |
|
2526 if (sockaddr_size > sizeof(sa)) { |
|
2527 console_fprintf(stderr, "Socket [warning]: bad socketAddr\n"); |
|
2528 goto bad; |
|
2529 } |
|
2530 bcopy((__byteArrayVal(addr) + sockAddrOffs), &sa, sockaddr_size); |
|
2531 sockaddr_ptr = (struct sockaddr *)(&sa); |
|
2532 } |
|
2533 |
|
2534 if (! setupBufferParameters(aDataBuffer, startIndex, &extPtr, &offs, &objSize)) goto bad; |
|
2535 if (__isSmallInteger(nBytes)) { |
|
2536 if (__intVal(nBytes) < objSize) { |
|
2537 objSize = __intVal(nBytes); |
|
2538 } |
|
2539 } |
|
2540 |
|
2541 #ifdef DO_WRAP_CALLS |
|
2542 if (extPtr) { |
|
2543 buffer = extPtr + offs; |
|
2544 } else { |
|
2545 allocatedBuffer = buffer = (char *)malloc(objSize); |
|
2546 bcopy((char *)__InstPtr(aDataBuffer) + offs, allocatedBuffer, objSize); |
|
2547 } |
|
2548 |
|
2549 do { |
|
2550 __threadErrno = 0; |
|
2551 n = STX_WSA_CALL6("sendto", sendto, sock, buffer, objSize, _flags, sockaddr_ptr, sockaddr_size); |
|
2552 } while ((n < 0) && (__threadErrno == EINTR)); |
|
2553 |
|
2554 if (allocatedBuffer) { |
|
2555 free(allocatedBuffer); |
|
2556 } |
|
2557 #else |
|
2558 __BEGIN_INTERRUPTABLE__ |
|
2559 do { |
|
2560 if (extPtr) { |
|
2561 n = sendto(sock, extPtr + offs, objSize, _flags, sockaddr_ptr, sockaddr_size); |
|
2562 } else { |
|
2563 n = sendto(sock, (char *)__InstPtr(aDataBuffer) + offs, objSize, _flags, sockaddr_ptr, sockaddr_size); |
|
2564 } |
|
2565 } while ((n < 0) && (errno == EINTR)); |
|
2566 __END_INTERRUPTABLE__ |
|
2567 #endif |
|
2568 |
|
2569 if (n < 0) { |
|
2570 __INST(lastErrorNumber) = __MKSMALLINT(errno); |
|
2571 } |
|
2572 RETURN (__MKSMALLINT(n)); |
|
2573 } |
|
2574 #endif |
|
2575 bad: ; |
|
2576 %}. |
|
2577 " |
|
2578 arrive here if you try to send from an invalid buffer |
|
2579 (i.e. not ByteArray-like), |
|
2580 or if the addressBuffer is nonNil AND not a ByteArray/String |
|
2581 or if the addressBuffer is nonNil AND too small. |
|
2582 " |
|
2583 self primitiveFailed |
|
2584 ! ! |
|
2585 |
|
2586 !Socket protectedMethodsFor:'low level'! |
|
2587 |
|
2588 closeFile |
|
2589 "low level close" |
|
2590 |
|
2591 %{ /* NOCONTEXT */ |
|
2592 #ifndef NO_SOCKET |
|
2593 OBJ t; |
|
2594 |
|
2595 t = __INST(filePointer); |
|
2596 if (t != nil) { |
|
2597 FILE *fp; |
|
2598 SOCKET sock; |
|
2599 int fd; |
|
2600 |
|
2601 __INST(filePointer) = nil; |
|
2602 fp = __FILEVal(t); |
|
2603 fd = fileno(fp); |
|
2604 sock = SOCKET_FROM_FD(fd); |
|
2605 |
|
2606 # ifdef xxDO_WRAP_CALLS |
|
2607 { int ret; |
|
2608 |
|
2609 do { |
|
2610 __threadErrno = 0; |
|
2611 ret = STX_C_CALL1("fclose", fclose, fp); |
|
2612 } while ((ret < 0) && (__threadErrno == EINTR)); |
|
2613 |
|
2614 # ifdef WIN32 |
|
2615 do { |
|
2616 __threadErrno = 0; |
|
2617 ret = STX_WSA_CALL1("closesocket", closesocket, sock); |
|
2618 } while ((ret < 0) && (__threadErrno == EINTR)); |
|
2619 closesocket(sock); |
|
2620 # endif |
|
2621 } |
|
2622 # else /* !DO_WRAP_CALLS */ |
|
2623 |
|
2624 DBGFPRINTF((stderr, "SOCKET: fflush %x (%d %d)\n", fp, fileno(fp), sock)); |
|
2625 fflush(fp); |
|
2626 |
|
2627 # if defined(CLOSESOCKET_BEFORE_FCLOSE) |
|
2628 DBGFPRINTF((stderr, "SOCKET: closesocket (%d)\n", sock)); |
|
2629 closesocket(sock); |
|
2630 # endif |
|
2631 if ((@global(FileOpenTrace) == true) || __debugging__) { |
|
2632 console_fprintf(stderr, "SOCKET: fclose %x (%d %d)\n", fp, fileno(fp), sock); |
|
2633 } |
|
2634 fclose(fp); |
|
2635 |
|
2636 # if defined(CLOSESOCKET_AFTER_FCLOSE) |
|
2637 DBGFPRINTF((stderr, "SOCKET: closesocket (%d)\n", sock)); |
|
2638 closesocket(sock); |
|
2639 # endif |
|
2640 # endif /* !DO_WRAP_CALLS */ |
|
2641 } |
|
2642 #endif /* NO_SOCKET */ |
|
2643 %} |
|
2644 ! ! |
|
2645 |
|
2646 !Socket methodsFor:'low level'! |
|
2647 |
|
2648 getSocketAdress |
|
2649 "BAD SPELLING, of #getSocketAddress, kept for compatibility with swazoo" |
|
2650 |
|
2651 <resource: #obsolete> |
|
2652 |
|
2653 ^ self getSocketAddress |
|
2654 ! |
|
2655 |
|
2656 getSocketError |
|
2657 "get the SO_ERROR form the socket, which indicates the |
|
2658 result of an asynchronous operation" |
|
2659 |
|
2660 %{ |
|
2661 #ifndef NO_SOCKET |
|
2662 OBJ fp; |
|
2663 int err; |
|
2664 |
|
2665 fp = __INST(filePointer); |
|
2666 if (fp == nil) { |
|
2667 err = EBADF; |
|
2668 } else { |
|
2669 unsigned int sz; |
|
2670 SOCKET sock; |
|
2671 |
|
2672 sock = SOCKET_FROM_FILE_OBJECT(fp); |
|
2673 sz = sizeof(err); |
|
2674 if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &err, &sz) < 0) { |
|
2675 # ifdef WIN32 |
|
2676 errno = WSAGetLastError(); |
|
2677 # endif |
|
2678 err = errno; |
|
2679 } |
|
2680 } |
|
2681 |
|
2682 RETURN(__MKSMALLINT(err)); |
|
2683 #endif |
|
2684 %} |
|
2685 ! |
|
2686 |
|
2687 listenWithBacklog:aNumber |
|
2688 <resource: #obsolete> |
|
2689 "same as listenFor: - backward compatibility with old ST/X" |
|
2690 |
|
2691 ^ self listenFor:aNumber |
|
2692 ! |
|
2693 |
|
2694 pollingWaitForNewConnectionOrDataOnAny:otherConnections timeout:timeoutSeconds |
|
2695 <resource: #obsolete> |
|
2696 "stupid MSDOS does not support select on sockets (sigh). |
|
2697 Must poll here." |
|
2698 |
|
2699 |millis newConnection| |
|
2700 |
|
2701 millis := timeoutSeconds * 1000. |
|
2702 [millis > 0] whileTrue:[ |
|
2703 otherConnections size > 0 ifTrue:[ |
|
2704 otherConnections do:[:aConnection | |
|
2705 aConnection canReadWithoutBlocking ifTrue:[ |
|
2706 ^ aConnection |
|
2707 ] |
|
2708 ]. |
|
2709 ]. |
|
2710 newConnection := self blockingAccept. |
|
2711 newConnection notNil ifTrue:[^ newConnection]. |
|
2712 Delay waitForMilliseconds:20. |
|
2713 millis := millis - 20. |
|
2714 ]. |
|
2715 ^ nil. |
|
2716 ! |
|
2717 |
|
2718 pollingWaitForNewConnectionWithTimeout:timeoutSeconds |
|
2719 <resource: #obsolete> |
|
2720 "stupid MSDOS does not support select on sockets (sigh). |
|
2721 Must poll here." |
|
2722 |
|
2723 |millis newConnection| |
|
2724 |
|
2725 timeoutSeconds notNil ifTrue:[ |
|
2726 millis := timeoutSeconds * 1000. |
|
2727 ]. |
|
2728 [millis isNil or:[millis > 0]] whileTrue:[ |
|
2729 newConnection := self blockingAccept. |
|
2730 newConnection notNil ifTrue:[^ newConnection]. |
|
2731 Delay waitForMilliseconds:20. |
|
2732 millis notNil ifTrue:[ |
|
2733 millis := millis - 20. |
|
2734 ] |
|
2735 ]. |
|
2736 ^ nil. |
|
2737 ! |
|
2738 |
|
2739 primAcceptOn:aSocket blocking:blocking |
|
2740 "accept a connection on a server port (created with:'Socket>>onIPPort:') |
|
2741 usage is: (Socket basicNew acceptOn:(Socket onIPPort:9999)). |
|
2742 Return the true if ok; false if not. |
|
2743 If blocking is true, the accept() syscall (and the whole smalltalk image) |
|
2744 will block, until a connection is accepted. |
|
2745 If blocking is false, this call will return immediately, if there is no connection pending." |
|
2746 |
|
2747 |serverSocketFd addr addrLen domainClass| |
|
2748 |
|
2749 filePointer notNil ifTrue:[ |
|
2750 ^ self errorAlreadyOpen |
|
2751 ]. |
|
2752 |
|
2753 domain := aSocket domain. |
|
2754 socketType := aSocket type. |
|
2755 serverSocketFd := aSocket fileDescriptor. |
|
2756 serverSocketFd isNil ifTrue:[ |
|
2757 ^ self error:'invalid server socket' |
|
2758 ]. |
|
2759 (serverSocketFd isMemberOf:SmallInteger) ifFalse:[ |
|
2760 ^ self error:'invalid server socket' |
|
2761 ]. |
|
2762 |
|
2763 domainClass := self class socketAddressClassForDomain:domain. |
|
2764 domainClass isNil ifTrue:[ |
|
2765 ^ self error:'invalid (unsupported) domain'. |
|
2766 ]. |
|
2767 addrLen := domainClass socketAddressSize. |
|
2768 addr := domainClass new. |
|
2769 |
|
2770 %{ /* STACK: 100000 */ |
|
2771 #ifndef NO_SOCKET |
|
2772 FILE *fp; |
|
2773 int flags; |
|
2774 SOCKET sock, newSock; |
|
2775 union sockaddr_u sa; |
|
2776 unsigned int alen, alen0; |
|
2777 struct hostent *he ; |
|
2778 char dotted[20] ; |
|
2779 |
|
2780 if (!__isSmallInteger(addrLen)) { |
|
2781 DBGPRINTF(("SOCKET: bad addrLen\n")); |
|
2782 RETURN (false); |
|
2783 } |
|
2784 alen0 = __intVal(addrLen); |
|
2785 sock = SOCKET_FROM_FD(__intVal(serverSocketFd)); |
|
2786 |
|
2787 if (blocking == false) { |
|
2788 # if defined(O_NONBLOCK) && defined(SET_NDELAY) |
|
2789 flags = fcntl(sock, F_GETFL); |
|
2790 fcntl(sock, F_SETFL, flags | O_NONBLOCK); |
|
2791 # endif |
|
2792 } |
|
2793 |
|
2794 # ifdef DO_WRAP_CALLS |
|
2795 do { |
|
2796 __threadErrno = 0; |
|
2797 alen = alen0; |
|
2798 newSock = STX_WSA_CALL3("accept", accept, sock, &sa, &alen); |
|
2799 } while ((newSock < 0) && (__threadErrno == EINTR)); |
|
2800 # else |
|
2801 __BEGIN_INTERRUPTABLE__ |
|
2802 do { |
|
2803 alen = alen0; |
|
2804 newSock = accept(sock, (struct sockaddr *) &sa, &alen); |
|
2805 } while ((newSock < 0) && (errno == EINTR)); |
|
2806 __END_INTERRUPTABLE__ |
|
2807 # endif |
|
2808 DBGFPRINTF((stderr, "SOCKET: accept newSock=%d\n", newSock)); |
|
2809 |
|
2810 if (blocking == false) { |
|
2811 # if defined(O_NDELAY) && defined(SET_NDELAY) |
|
2812 fcntl(sock, F_SETFL, flags); |
|
2813 # endif |
|
2814 } |
|
2815 |
|
2816 if (newSock < 0) { |
|
2817 DBGPRINTF(("SOCKET: accept call failed errno=%d\n", errno)); |
|
2818 __INST(lastErrorNumber) = __MKSMALLINT(errno); |
|
2819 RETURN (false); |
|
2820 } |
|
2821 |
|
2822 if (__isNonNilObject(addr)) { |
|
2823 OBJ oClass; |
|
2824 int nInstVars, nInstBytes, objSize; |
|
2825 char *cp; |
|
2826 |
|
2827 oClass = __qClass(addr); |
|
2828 if (! __isBytes(addr) ) { |
|
2829 DBGPRINTF(("SOCKET: bad addr\n")); |
|
2830 closesocket(newSock); |
|
2831 RETURN (false); |
|
2832 } |
|
2833 |
|
2834 nInstVars = __intVal(__ClassInstPtr(oClass)->c_ninstvars); |
|
2835 nInstBytes = OHDR_SIZE + (nInstVars * sizeof(OBJ)); |
|
2836 objSize = __qSize(addr) - nInstBytes; |
|
2837 cp = (char *)__InstPtr(addr) + nInstBytes; |
|
2838 if (objSize < alen) { |
|
2839 DBGPRINTF(("SOCKET: bad addr\n")); |
|
2840 closesocket(newSock); |
|
2841 RETURN (false); |
|
2842 } |
|
2843 |
|
2844 /* |
|
2845 * extract the partners address |
|
2846 */ |
|
2847 bcopy((char *)&sa, cp, alen); |
|
2848 addrLen = __MKSMALLINT(alen); |
|
2849 } |
|
2850 |
|
2851 /* |
|
2852 * make it a FILE * |
|
2853 */ |
|
2854 # ifdef WIN32 |
|
2855 { |
|
2856 int _fd = _open_osfhandle(newSock, 0); |
|
2857 fp = fdopen(_fd, "r+"); |
|
2858 DBGPRINTF(("SOCKET: sock=%d fd=%d fp=%x\n",newSock,_fd, fp)); |
|
2859 } |
|
2860 # else |
|
2861 fp = fdopen(newSock, "r+"); |
|
2862 # endif |
|
2863 |
|
2864 if (! fp) { |
|
2865 DBGPRINTF(("SOCKET: fdopen call failed\n")); |
|
2866 __INST(lastErrorNumber) = __MKSMALLINT(errno); |
|
2867 # ifdef DO_WRAP_CALLS |
|
2868 { |
|
2869 int ret; |
|
2870 do { |
|
2871 __threadErrno = 0; |
|
2872 ret = STX_WSA_CALL1("closesocket", closesocket, newSock); |
|
2873 } while ((ret < 0) && (__threadErrno == EINTR)); |
|
2874 } |
|
2875 # else |
|
2876 closesocket(newSock); |
|
2877 # endif |
|
2878 DBGFPRINTF((stderr, "SOCKET: close (fdopen failed) (%d)\n", newSock)); |
|
2879 RETURN (false); |
|
2880 } |
|
2881 |
|
2882 if ((@global(FileOpenTrace) == true) || __debugging__) { |
|
2883 # ifdef WIN32 |
|
2884 { |
|
2885 HANDLE h; |
|
2886 int _fd = fileno(fp); |
|
2887 h = (HANDLE)_get_osfhandle(_fd); |
|
2888 console_fprintf(stderr, "fdopen [Socket] -> %x (fd: %d) (H: %x)\n", fp, _fd, h); |
|
2889 } |
|
2890 # else |
|
2891 console_fprintf(stderr, "fdopen [Socket] -> %x (fd: %d)\n", fp, newSock); |
|
2892 # endif |
|
2893 } |
|
2894 |
|
2895 # ifdef BUGGY_STDIO_LIB |
|
2896 setbuf(fp, NULL); |
|
2897 __INST(buffered) = false; |
|
2898 # endif |
|
2899 |
|
2900 # if 0 |
|
2901 // The original code was: |
|
2902 __INST(filePointer) = __MKOBJ((INT)fp); __STORESELF(filePointer); |
|
2903 // but for that, gcc generates wrong code, which loads self (volatile) into |
|
2904 // a register (bp), then calls __MKOBJ, then stores indirect bp. |
|
2905 // That is wrong if a scavenge occurs in MKOBJ, as bp is now still pointing to the old |
|
2906 // object. |
|
2907 # endif |
|
2908 { |
|
2909 OBJ t; |
|
2910 |
|
2911 t = __MKOBJ(fp); |
|
2912 __INST(filePointer) = t; |
|
2913 __STORE(self, t); |
|
2914 } |
|
2915 #endif /* not NO_SOCKET */ |
|
2916 %}. |
|
2917 mode := #readwrite. |
|
2918 Lobby register:self. |
|
2919 binary := false. |
|
2920 port := aSocket port. |
|
2921 |
|
2922 addr notNil ifTrue:[ |
|
2923 peer := addr. |
|
2924 ]. |
|
2925 |
|
2926 ^ true |
|
2927 ! ! |
|
2928 |
|
2929 !Socket protectedMethodsFor:'low level'! |
|
2930 |
|
2931 setSocketOption:option argument:arg1 argument:arg2 |
|
2932 |ok| |
|
2933 |
|
2934 %{ /* STACK: 32000 */ |
|
2935 OBJ fp = __INST(filePointer); |
|
2936 |
|
2937 if (fp != nil) { |
|
2938 SOCKET sock; |
|
2939 int opt = -1; |
|
2940 int level = -1; |
|
2941 int usize = -1; |
|
2942 int ret; |
|
2943 union u { |
|
2944 BOOL u_bool; |
|
2945 int u_int; |
|
2946 struct linger u_linger; |
|
2947 } u; |
|
2948 |
|
2949 sock = SOCKET_FROM_FILE_OBJECT(fp); |
|
2950 |
|
2951 # ifdef SO_BROADCAST |
|
2952 if (option == @symbol(SO_BROADCAST)) { |
|
2953 /* Enables transmission and receipt of broadcast messages on the socket. */ |
|
2954 opt = SO_BROADCAST; |
|
2955 level = SOL_SOCKET; |
|
2956 usize = sizeof(u.u_bool); |
|
2957 if (arg1 == true) u.u_bool = TRUE; |
|
2958 else if (arg1 == false) u.u_bool = FALSE; |
|
2959 else goto argError; |
|
2960 } |
|
2961 # endif /* SO_BROADCAST */ |
|
2962 |
|
2963 # ifdef SO_CONDITIONAL |
|
2964 # if 0 |
|
2965 if (option == @symbol(SO_CONDITIONAL)) { |
|
2966 /* Enables sockets to delay the acknowledgment of a connection until after the WSAAccept condition function is called. */ |
|
2967 opt = SO_CONDITIONAL; |
|
2968 level = SOL_SOCKET; |
|
2969 usize = sizeof(u.u_bool); |
|
2970 if (arg1 == true) u.u_bool = TRUE; |
|
2971 else if (arg1 == false) u.u_bool = FALSE; |
|
2972 else goto argError; |
|
2973 } |
|
2974 # endif |
|
2975 # endif /* SO_CONDITIONAL */ |
|
2976 |
|
2977 # ifdef SO_DEBUG |
|
2978 if (option == @symbol(SO_DEBUG)) { |
|
2979 /* Records debugging information. */ |
|
2980 opt = SO_DEBUG; |
|
2981 level = SOL_SOCKET; |
|
2982 usize = sizeof(u.u_bool); |
|
2983 if (arg1 == true) u.u_bool = TRUE; |
|
2984 else if (arg1 == false) u.u_bool = FALSE; |
|
2985 else goto argError; |
|
2986 } |
|
2987 # endif /* SO_DEBUG */ |
|
2988 |
|
2989 # ifdef SO_DONTLINGER |
|
2990 if (option == @symbol(SO_DONTLINGER)) { |
|
2991 /* Does not block close waiting for unsent data to be sent. |
|
2992 Setting this option is equivalent to setting SO_LINGER with l_onoff set to zero. */ |
|
2993 opt = SO_DONTLINGER; |
|
2994 level = SOL_SOCKET; |
|
2995 usize = sizeof(u.u_bool); |
|
2996 if (arg1 == true) u.u_bool = TRUE; |
|
2997 else if (arg1 == false) u.u_bool = FALSE; |
|
2998 else goto argError; |
|
2999 } |
|
3000 # endif /* SO_DONTLINGER */ |
|
3001 |
|
3002 # ifdef SO_DONTROUTE |
|
3003 if (option == @symbol(SO_DONTROUTE)) { |
|
3004 /* Does not route: sends directly to interface. |
|
3005 Succeeds but is ignored on AF_INET sockets; |
|
3006 fails on AF_INET6 sockets with WSAENOPROTOOPT. |
|
3007 Not supported on ATM sockets (results in an error). */ |
|
3008 opt = SO_DONTROUTE; |
|
3009 level = SOL_SOCKET; |
|
3010 usize = sizeof(u.u_bool); |
|
3011 if (arg1 == true) u.u_bool = TRUE; |
|
3012 else if (arg1 == false) u.u_bool = FALSE; |
|
3013 else goto argError; |
|
3014 } |
|
3015 # endif /* SO_DONTROUTE */ |
|
3016 |
|
3017 # ifdef SO_KEEPALIVE |
|
3018 if (option == @symbol(SO_KEEPALIVE)) { |
|
3019 /* Sends keep-alives. Not supported on ATM sockets (results in an error). */ |
|
3020 opt = SO_KEEPALIVE; |
|
3021 level = SOL_SOCKET; |
|
3022 usize = sizeof(u.u_bool); |
|
3023 if (arg1 == true) u.u_bool = TRUE; |
|
3024 else if (arg1 == false) u.u_bool = FALSE; |
|
3025 else goto argError; |
|
3026 } |
|
3027 # endif /* SO_KEEPALIVE */ |
|
3028 |
|
3029 # ifdef SO_LINGER |
|
3030 if (option == @symbol(SO_LINGER)) { |
|
3031 /* Lingers on close if unsent data is present. */ |
|
3032 opt = SO_LINGER; |
|
3033 level = SOL_SOCKET; |
|
3034 usize = sizeof(u.u_linger); |
|
3035 if (arg1 == true) u.u_linger.l_onoff = TRUE; |
|
3036 else if (arg1 == false) u.u_linger.l_onoff = FALSE; |
|
3037 else goto argError; |
|
3038 if (arg2 == nil) u.u_linger.l_linger = 0; |
|
3039 else if (__isSmallInteger(arg2))u.u_linger.l_linger = __intVal(arg2); |
|
3040 else goto argError; |
|
3041 DBGPRINTF(("SOCKET: SO_LINGER %d %d\n", u.u_linger.l_onoff, u.u_linger.l_linger)); |
|
3042 } |
|
3043 # endif /* SO_LINGER */ |
|
3044 |
|
3045 # ifdef SO_OOBINLINE |
|
3046 if (option == @symbol(SO_OOBINLINE)) { |
|
3047 /* Receives OOB data in the normal data stream. */ |
|
3048 opt = SO_OOBINLINE; |
|
3049 level = SOL_SOCKET; |
|
3050 usize = sizeof(u.u_bool); |
|
3051 if (arg1 == true) u.u_bool = TRUE; |
|
3052 else if (arg1 == false) u.u_bool = FALSE; |
|
3053 else goto argError; |
|
3054 } |
|
3055 # endif /* SO_OOBINLINE */ |
|
3056 |
|
3057 # ifdef SO_RCVBUF |
|
3058 if (option == @symbol(SO_RCVBUF)) { |
|
3059 /* Specifies the total per-socket buffer space reserved for receives. |
|
3060 This is unrelated to SO_MAX_MSG_SIZE or the size of a TCP window. */ |
|
3061 opt = SO_RCVBUF; |
|
3062 level = SOL_SOCKET; |
|
3063 usize = sizeof(u.u_int); |
|
3064 if (__isSmallInteger(arg1))u.u_int = __intVal(arg1); |
|
3065 else goto argError; |
|
3066 } |
|
3067 # endif /* SO_RCVBUF */ |
|
3068 |
|
3069 # ifdef SO_SNDBUF |
|
3070 if (option == @symbol(SO_SNDBUF)) { |
|
3071 /* Specifies the total per-socket buffer space reserved for sends. |
|
3072 This is unrelated to SO_MAX_MSG_SIZE or the size of a TCP window. */ |
|
3073 opt = SO_SNDBUF; |
|
3074 level = SOL_SOCKET; |
|
3075 usize = sizeof(u.u_int); |
|
3076 if (__isSmallInteger(arg1))u.u_int = __intVal(arg1); |
|
3077 else goto argError; |
|
3078 } |
|
3079 # endif /* SO_SNDBUF */ |
|
3080 |
|
3081 # ifdef SO_REUSEADDR |
|
3082 if (option == @symbol(SO_REUSEADDR)) { |
|
3083 /* Allows the socket to be bound to an address that is already in use. */ |
|
3084 opt = SO_REUSEADDR; |
|
3085 level = SOL_SOCKET; |
|
3086 usize = sizeof(u.u_bool); |
|
3087 if (arg1 == true) u.u_bool = TRUE; |
|
3088 else if (arg1 == false) u.u_bool = FALSE; |
|
3089 else goto argError; |
|
3090 } |
|
3091 # endif /* SO_OOBINLINE */ |
|
3092 |
|
3093 # ifdef SO_EXCLUSIVEADDRUSE |
|
3094 if (option == @symbol(SO_EXCLUSIVEADDRUSE)) { |
|
3095 /* Enables a socket to be bound for exclusive access. |
|
3096 Does not require administrative privilege. */ |
|
3097 opt = SO_EXCLUSIVEADDRUSE; |
|
3098 level = SOL_SOCKET; |
|
3099 usize = sizeof(u.u_bool); |
|
3100 if (arg1 == true) u.u_bool = TRUE; |
|
3101 else if (arg1 == false) u.u_bool = FALSE; |
|
3102 else goto argError; |
|
3103 } |
|
3104 # endif /* SO_OOBINLINE */ |
|
3105 |
|
3106 if (usize == -1) goto argError; |
|
3107 |
|
3108 ok = ( setsockopt( sock, level, opt, &u, usize) >= 0) ? true : false; |
|
3109 } |
|
3110 argError: ; |
|
3111 |
|
3112 %}. |
|
3113 ok isNil ifTrue:[ |
|
3114 self primitiveFailed |
|
3115 ]. |
|
3116 ok ifFalse:[ |
|
3117 'setsocketoption failed' infoPrintCR. |
|
3118 ]. |
|
3119 ! ! |
|
3120 |
|
3121 !Socket methodsFor:'low level'! |
|
3122 |
|
3123 shutdown: howNum |
|
3124 "shutDown the socket - inform it that no more I/O will be performed. |
|
3125 0 - read side (no further reads) |
|
3126 1 - write side (no further writes) |
|
3127 2 - both (no further I/O at all) |
|
3128 shutDown:2 |
|
3129 discards any pending data |
|
3130 (as opposed to close, which might wait until data is delivered as set by LINGER)" |
|
3131 |
|
3132 %{ |
|
3133 #ifndef NO_SOCKET |
|
3134 |
|
3135 OBJ fp; |
|
3136 |
|
3137 fp = __INST(filePointer); |
|
3138 if ((fp != nil) && __isSmallInteger(howNum)) { |
|
3139 SOCKET sock; |
|
3140 int ret; |
|
3141 |
|
3142 sock = SOCKET_FROM_FILE_OBJECT(fp); |
|
3143 # ifdef DO_WRAP_CALLS |
|
3144 do { |
|
3145 __threadErrno = 0; |
|
3146 DBGFPRINTF((stderr, "SOCKET: shutDown...\n")); |
|
3147 ret = STX_WSA_CALL2("shutdown", shutdown, sock, __intVal(howNum)); |
|
3148 DBGFPRINTF((stderr, "SOCKET: shutDown -> %d (%d)\n", ret, __threadErrno)); |
|
3149 } while ((ret < 0) && (__threadErrno == EINTR)); |
|
3150 # else |
|
3151 __BEGIN_INTERRUPTABLE__ |
|
3152 shutdown(sock, __intVal(howNum)); |
|
3153 __END_INTERRUPTABLE__ |
|
3154 # endif |
|
3155 } |
|
3156 #endif |
|
3157 %}. |
|
3158 ! ! |
|
3159 |
3240 !Socket methodsFor:'printing & storing'! |
3160 !Socket methodsFor:'printing & storing'! |
3241 |
3161 |
3242 printOn:aStream |
3162 printOn:aStream |
3243 aStream nextPutAll:self className; nextPutAll:'(protocol='. |
3163 aStream nextPutAll:self className; nextPutAll:'(protocol='. |
3244 protocol printOn:aStream. |
3164 protocol printOn:aStream. |
3245 aStream nextPutAll:' port='. |
3165 aStream nextPutAll:' port='. |
3246 port printOn:aStream. |
3166 self port printOn:aStream. |
3247 aStream nextPutAll:' peer='. |
3167 aStream nextPutAll:' peer='. |
3248 peer printOn:aStream. |
3168 peer printOn:aStream. |
3249 aStream nextPut:$). |
3169 aStream nextPut:$). |
3250 ! ! |
3170 ! ! |
3251 |
3171 |