use SocketAddress in #connect
authorClaus Gittinger <cg@exept.de>
Tue, 20 May 2003 18:27:08 +0200
changeset 1224 530a6f9723a1
parent 1223 24b2821edf3f
child 1225 8839f52dde96
use SocketAddress in #connect
Socket.st
--- a/Socket.st	Tue May 20 17:47:09 2003 +0200
+++ b/Socket.st	Tue May 20 18:27:08 2003 +0200
@@ -3566,7 +3566,7 @@
 !
 
 shutDown 
-    "shutDown without flushing "
+    "shutDown and close without flushing "
 
     filePointer isNil ifTrue:[^ self].
     Lobby unregister:self.
@@ -3578,21 +3578,21 @@
 
     fp = __INST(filePointer);
     if (fp != nil) {
-	FILE *f;
-	int fd;
-
-	__INST(filePointer) = nil;
-	f = __FILEVal(fp);
-	fd = fileno(f);
-	__BEGIN_INTERRUPTABLE__
-	shutdown(fd, 2);
-	DBGFPRINTF((stderr, "socket fclose %x (%d)\n", fp, fd));
-	if (@global(FileOpenTrace) == true) {
-	    fprintf(stderr, "fclose [Socket] %x\n", f);
-	}
-	fclose(f);
-	/* close(fd); */
-	__END_INTERRUPTABLE__
+        FILE *f;
+        int fd;
+
+        __INST(filePointer) = nil;
+        f = __FILEVal(fp);
+        fd = fileno(f);
+        __BEGIN_INTERRUPTABLE__
+        shutdown(fd, 2);
+        DBGFPRINTF((stderr, "socket fclose %x (%d)\n", fp, fd));
+        if (@global(FileOpenTrace) == true) {
+            fprintf(stderr, "fclose [Socket] %x\n", f);
+        }
+        fclose(f);
+        /* close(fd); */
+        __END_INTERRUPTABLE__
     }
 #endif
 %}
@@ -4052,413 +4052,168 @@
 !Socket methodsFor:'low level-connecting'!
 
 connectTo:hostOrPathName port:portNrOrName
-    "low level connect; connect to port, portNrOrName on host, hostName.
-     For unix-domain sockets, the port argument is ignored and pathName is taken.
-     Other sockets are not yet implemented.
+    "low level connect; connect to port, portNrOrNameOrNil on host, hostName.
+     For backward compatibility, host may be also a string or a byteArray,
+     but it is recommended to pass socketAddress instances.
+
      Return true if ok, false otherwise.
-     Hostname must be a string, portNrOrName an integer port number (in inet domain).
-     The current process will block (but not the whole Smalltalk) until the connection
-     is established. 
+     The current process will block (but not the whole Smalltalk) until the connection is established.
      See also: #connectTo:port:withTimeout: for a somewhat nicer interface."
 
     ^ self connectTo:hostOrPathName port:portNrOrName withTimeout:nil
 !
 
-connectTo:hostOrPathName port:portNrOrName withTimeout:timeout
-    "low level connect; connect to port, portNrOrName on host, hostName.
-     For unix-domain sockets, the port argument is ignored and pathName is taken.
-     Other sockets are not yet implemented.
+connectTo:hostOrPathNameOrSocketAddr port:portNrOrNameOrNil withTimeout:timeout
+    "low level connect; connect to port, portNrOrNameOrNil on host, hostName.
+     For backward compatibility, host may be also a string or a byteArray,
+     but it is recommended to pass socketAddress instances.
+
      Return true if ok, false otherwise.
-     Hostname must be a string, portNrOrName an integer port number (in inet domain).
-     The current process will block (but not the whole Smalltalk) until the connection
-     is established. 
-     See also: #connectTo:port:withTimeout: for a somewhat nicer interface."
-
-    |isAsync err|
+     The current process will block (but not the whole Smalltalk) until the connection is established,
+     or timeout millliseconds have passed."
+
+    |isAsync err domainClass addr addrName|
 
     filePointer isNil ifTrue:[
-	^ self errorNotOpen
+        ^ self errorNotOpen
+    ].
+
+    domainClass := self class socketAddressClassForDomain:domain.
+    domainClass isNil ifTrue:[
+        ^ self error:'invalid (unsupported) domain'.
     ].
+
+    "/ backward compatibility: support for byteArray and string arg
+
+    hostOrPathNameOrSocketAddr isString ifTrue:[
+        addr := domainClass hostName:hostOrPathNameOrSocketAddr port:portNrOrNameOrNil.
+        addrName := hostOrPathNameOrSocketAddr.
+    ] ifFalse:[
+        hostOrPathNameOrSocketAddr isBytes ifFalse:[
+            ^ self error:'bad host (socketAddress) argument'
+        ].
+        (hostOrPathNameOrSocketAddr isKindOf:SocketAddress) ifTrue:[
+            addr := hostOrPathNameOrSocketAddr.
+            portNrOrNameOrNil notNil ifTrue:[
+                addr port:portNrOrNameOrNil.
+            ].
+        ] ifFalse:[
+            addr := domainClass hostAddress:hostOrPathNameOrSocketAddr port:portNrOrNameOrNil.
+        ].
+    ].
+
 %{  /* STACK: 100000 */
 
 #ifndef NO_SOCKET
     OBJ t = __INST(filePointer);
-    OBJ myDomain;
-    union sockaddr_u sa;
-    struct hostent *hp ;
-    int a, sock ;
-    long addr;
+    struct sockaddr *sockaddr_ptr;
+    int a, sock;
     FILE *fp;
     int ret, oldFlags;
     int on = 1;
-    int ok;
     int sockaddr_size;
 
-    if (!__isString(__INST(domain)) && !__isSymbol(__INST(domain))) {
-	DBGPRINTF(("SOCKET: invalid domain arg\n"));
-	RETURN (false);
-    }
-
-    ok = 0;
-    myDomain = __INST(domain);
-    bzero((char *) &sa, sizeof(sa)) ;
-
-    if (0) {
-	/* for ese below */
-    }
-#ifdef AF_INET
-    else if (myDomain == @symbol(inet)) {
-	/*
-	 * INET addressing: port must be a smallInteger;
-	 * hostOrPathName the name of the host (dot notation allowed)
-	 * or a byteArray containing the 4 address bytes.
-	 */
-	if (! __isSmallInteger(portNrOrName)) {
-	    DBGPRINTF(("SOCKET: invalid port arg\n"));
-	    RETURN (false);
-	}
-
-	sa.in.sin_family = AF_INET;
-	sa.in.sin_port = htons((u_short) __intVal(portNrOrName)) ;
-
-	if (__isByteArray(hostOrPathName)) {
-	    unsigned char *cp;
-	    int n;
-	    unsigned intAddr;
-
-	    cp = __ByteArrayInstPtr(hostOrPathName)->ba_element;
-	    n = __byteArraySize(hostOrPathName);
-	    if (n < 4) {
-		DBGPRINTF(("SOCKET: invalid ipAddr arg\n"));
-		RETURN (false);
-	    }
-	    intAddr = cp[0];
-	    intAddr = (intAddr << 8) | cp[1];
-	    intAddr = (intAddr << 8) | cp[2];
-	    intAddr = (intAddr << 8) | cp[3];
-	    sa.in.sin_addr.s_addr = htonl(intAddr);
-	    /* bcopy(cp, &sa.in.sin_addr.s_addr, n); */
-	} else {
-	    if (! __isString(hostOrPathName)) {
-		DBGPRINTF(("SOCKET: invalid hostname arg\n"));
-		RETURN (false);
-	    }
-
-	    if ((addr = inet_addr(__stringVal(hostOrPathName))) != -1) {
-		/* 
-		 * is Internet addr in octet notation 
-		 */
-		bcopy(&addr, (char *) &sa.in.sin_addr, sizeof(addr)) ; /* set address */
-	    } else {
-		/* 
-		 * do we know the host's address? 
-		 */
-		GETHOSTBYNAME(hp, __stringVal(hostOrPathName))
-		if (hp == NULL) {
-		    DBGPRINTF(("SOCKET: unknown host:%s\n", __stringVal(hostOrPathName)));
-		    RETURN (false);
-		}
-		bcopy(hp->h_addr, (char *) &sa.in.sin_addr, hp->h_length) ;
-		sa.in.sin_family = hp->h_addrtype;
-	    }
-	}
-
-	DBGPRINTF(("SOCKET: connect addr:%d.%d.%d.%d port: %d\n", 
-			((unsigned char *)(&sa.in.sin_addr.s_addr))[0], 
-			((unsigned char *)(&sa.in.sin_addr.s_addr))[1], 
-			((unsigned char *)(&sa.in.sin_addr.s_addr))[2], 
-			((unsigned char *)(&sa.in.sin_addr.s_addr))[3], 
-			ntohs(sa.in.sin_port)));
-
-	sockaddr_size = sizeof(struct sockaddr_in);
-	ok = 1;
-    }
-#endif /* AF_INET */
-
-#ifdef AF_INET6
-    else if (myDomain == @symbol(inet6)) {
-	/*
-	 * INET6 addressing: port must be a smallInteger;
-	 * hostOrPathName the name of the host
-	 * or a byteArray containing the address bytes.
-	 */
-	if (! __isSmallInteger(portNrOrName)) {
-	    DBGPRINTF(("SOCKET: invalid port arg\n"));
-	    RETURN (false);
-	}
-
-	sa.in6.sin6_family = AF_INET6;
-	sa.in6.sin6_port = htons((u_short) __intVal(portNrOrName)) ;
-
-	if (__isByteArray(hostOrPathName)) {
-	    unsigned char *cp;
-	    int n;
-
-	    cp = __ByteArrayInstPtr(hostOrPathName)->ba_element;
-	    n = __byteArraySize(hostOrPathName);
-	    if (n > sizeof(sa.in6.sin6_addr.s6_addr)) n = sizeof(sa.in6.sin6_addr.s6_addr);
-	    bcopy(cp, sa.in6.sin6_addr.s6_addr, n);
-	} else {
-	    if (! __isString(hostOrPathName)) {
-		DBGPRINTF(("SOCKET: invalid hostname arg\n"));
-		RETURN (false);
-	    }
-
-	    /* 
-	     * do we know the host's address? 
-	     */
-	    GETHOSTBYNAME(hp, __stringVal(hostOrPathName))
-	    if (hp == NULL) {
-		DBGPRINTF(("SOCKET: unknown host:%s\n", __stringVal(hostOrPathName)));
-		RETURN (false);
-	    }
-	    bcopy(hp->h_addr, (char *) &sa.in.sin_addr, hp->h_length) ;
-	    sa.in.sin_family = hp->h_addrtype;
-	}
-
-	DBGPRINTF(("SOCKET: connect addr: %x.%x.%x.%x.%x.%x... port: %d\n", 
-		sa.in6.sin6_addr.s6_addr[0],
-		sa.in6.sin6_addr.s6_addr[1],
-		sa.in6.sin6_addr.s6_addr[2],
-		sa.in6.sin6_addr.s6_addr[3],
-		sa.in6.sin6_addr.s6_addr[4],
-		sa.in6.sin6_addr.s6_addr[5],
-		sa.in6.sin6_port));
-
-	sockaddr_size = sizeof(struct sockaddr_in6);
-	ok = 1;
+    if (!__isNonNilObject(addr) || !__isBytes(addr)) {
+        DBGPRINTF(("SOCKET: invalid addrBytes\n"));
+        RETURN (false);
     }
-#endif /* AF_INET6 */
-
-#ifdef AF_UNIX
-    else if (myDomain == @symbol(unix)) {
-	char *pathName;
-	int l;
-
-	/*
-	 * UNIX domain: port is ignored;
-	 * hostOrPathName is a pathName
-	 */
-	if (! __isString(hostOrPathName)) {
-	    DBGPRINTF(("SOCKET: invalid port (pathname) arg\n"));
-	    RETURN (false);
-	}
-	pathName = (char *) __stringVal(hostOrPathName);
-	l = strlen(pathName);
-	if ((l + sizeof ( sa.un.sun_family )) > sizeof(struct sockaddr_un)) {
-	    DBGPRINTF(("SOCKET: pathname too long\n"));
-	    RETURN (false);
-	}
-
-	strcpy(sa.un.sun_path, pathName);
-	sa.un.sun_family = AF_UNIX;
-	sockaddr_size = l + sizeof ( sa.un.sun_family );
-	ok = 1;
-    }
-#endif /* AF_UNIX */
-
-#ifdef AF_APPLETALK
-    else if (myDomain == @symbol(appletalk)) {
-	/*
-	 * APPLETALK addressing: port must be a smallInteger;
-	 * hostOrPathName the name of the host
-	 * or a byteArray containing the 3 address bytes.
-	 */
-	if (! __isSmallInteger(portNrOrName)) {
-	    DBGPRINTF(("SOCKET: invalid port arg\n"));
-	    RETURN (false);
-	}
-
-	sa.at.sat_family = AF_APPLETALK;
-	sa.at.sat_port = __intVal(portNrOrName);
-
-	if (__isByteArray(hostOrPathName)) {
-	    unsigned char *cp;
-	    int n;
-
-	    cp = __ByteArrayInstPtr(hostOrPathName)->ba_element;
-	    n = __byteArraySize(hostOrPathName);
-	    if (n > 3) n = 3;
-	    bcopy(cp, &sa.at.sat_addr, n);
-	} else {
-	    if (! __isString(hostOrPathName)) {
-		DBGPRINTF(("SOCKET: invalid hostname arg\n"));
-		RETURN (false);
-	    }
-
-	    /* 
-	     * do we know the host's address? 
-	     */
-	    GETHOSTBYNAME(hp, __stringVal(hostOrPathName))
-	    if (hp == NULL) {
-		DBGPRINTF(("SOCKET: unknown host:%s\n", __stringVal(hostOrPathName)));
-		RETURN (false);
-	    }
-	    if (hp->h_addrtype != AF_APPLETALK) {
-		DBGPRINTF(("SOCKET: host:%s is not an appletalk host\n", __stringVal(hostOrPathName)));
-		RETURN (false);
-	    }
-
-	    bcopy(hp->h_addr, (char *) &sa.at.sat_addr, hp->h_length) ;
-	    sa.at.sat_family = hp->h_addrtype;
-	}
-
-	DBGPRINTF(("SOCKET: connect addr: %x port: %d\n", sa.in.sin_addr, sa.in.sin_port));
-
-	sockaddr_size = sizeof(struct sockaddr_at);
-	ok = 1;
-    }
-#endif /* APPLETALK */
-
-    /*
-     * XXXX add addressing stuff for other domains here ...
-     */
-#ifdef AF_X25
-    else if (myDomain == @symbol(x25)) {
-    }
-#endif
-#ifdef AF_AX25
-    else if (myDomain == @symbol(ax25)) {
-    }
-#endif
-#ifdef AF_NS
-    else if ((myDomain == @symbol(ns)) 
-     || (myDomain == @symbol(xns))) {
-    }
-#endif
-# ifdef AF_DECnet
-    else if (myDomain == @symbol(decnet)) {
-    }
-# endif
-#ifdef AF_SNA
-    else if (myDomain == @symbol(sna)) {
-    }
-#endif
-#ifdef AF_RAW 
-    else if (myDomain == @symbol(raw)) {
-    }
-#endif
-# ifdef AF_ISO
-    else if (myDomain == @symbol(iso)) {
-    }
-# endif
-# ifdef AF_NETBIOS
-    else if (myDomain == @symbol(netbios)) {
-    }
-# endif
-# ifdef AF_IPX
-    else if (myDomain == @symbol(ipx)) {
-    }
-# endif
-# ifdef AF_BRIDGE
-    else if (myDomain == @symbol(bridge)) {
-    }
-# endif
-# ifdef AF_BSC
-    else if (myDomain == @symbol(bsc)) {
-    }
-# endif
-# ifdef AF_ROSE
-    else if (myDomain == @symbol(rose)) {
-    }
-# endif
-# ifdef AF_IRDA
-    else if (__INST(domain) == @symbol(irda)) {
-    }
-# endif
-# if defined(AF_CCITT) && (AF_CCITT != AF_X25)
-    else if (myDomain == @symbol(ccitt)) {
-    }
-# endif
-
-    if (! ok) {
-	DBGPRINTF(("SOCKET: unsupported domain\n"));
-	RETURN (false);
+
+    {
+        int indx, nIndex;
+        OBJ cls;
+
+        indx = 0;
+        if ((cls = __qClass(addr)) != @global(ByteArray))
+            indx += __OBJS2BYTES__(__intVal(__ClassInstPtr(cls)->c_ninstvars));
+        nIndex = __qSize(addr) - OHDR_SIZE;
+        sockaddr_size = nIndex - indx;
+        sockaddr_ptr = (struct sockaddr *)(__byteArrayVal(addr) + indx);
     }
 
     sock = fileno(__FILEVal(t));
 
-#if defined(O_NONBLOCK)
+# if defined(O_NONBLOCK)
     /*
      * set to non-blocking and wait later
      */
     oldFlags = fcntl(sock, F_GETFL, 0);
     /* on SUNOS4.x, would use fcntl(osfd, F_SETFL, flags | FNDELAY); */
     fcntl(sock, F_SETFL, oldFlags | O_NONBLOCK);
-#endif
+# endif
 
     /* 
      * connect 
      */
     __BEGIN_INTERRUPTABLE__
     do {
-	ret = connect(sock, (struct sockaddr *)&sa, sockaddr_size);
+        ret = connect(sock, sockaddr_ptr, sockaddr_size);
     } while ((ret < 0) 
-	     && ((errno == EINTR)
-#ifdef EAGAIN
-		 || (errno == EAGAIN)
-#endif
-		));
+             && ((errno == EINTR)
+# ifdef EAGAIN
+                 || (errno == EAGAIN)
+# endif
+                ));
     __END_INTERRUPTABLE__
 
     if (ret < 0) { 
-#if defined(EINPROGRESS) || defined(EALREADY)
-	if (0
-# ifdef EINPROGRESS
-	    || (errno == EINPROGRESS) 
-# endif
-# ifdef EALREADY
-	    || (errno == EALREADY)
+# if defined(EINPROGRESS) || defined(EALREADY)
+        if (0
+#  ifdef EINPROGRESS
+            || (errno == EINPROGRESS) 
+#  endif
+#  ifdef EALREADY
+            || (errno == EALREADY)
+#  endif
+        ) {
+            /*
+             * This was a nonblocking operation that will take some time.
+             * Do a select on read to get informed when the operation is ready.
+             */
+
+            isAsync = true;
+        } else
+# endif /* EINPROGRESS or EALREADY */
+        {
+            DBGPRINTF(("SOCKET: connect failed errno=%d\n", errno));
+# ifdef DUMP_ADDRESS
+            {
+                char *cp = (char *)(&sa);
+                int i;
+
+                printf("address data:\n");
+                for (i=0; i<sockaddr_size; i++) {
+                    printf(" %02x\n", *cp++);
+                }
+            }
 # endif
-	) {
-	    /*
-	     * This was a nonblocking operation that will take some time.
-	     * Do a select on read to get informed when the operation is ready.
-	     */
-
-	    isAsync = true;
-	} else
-#endif /* EINPROGRESS or EALREADY */
-	{
-	    DBGPRINTF(("SOCKET: connect failed errno=%d\n", errno));
-#ifdef DUMP_ADDRESS
-	    {
-		char *cp = (char *)(&sa);
-		int i;
-
-		printf("address data:\n");
-		for (i=0; i<sockaddr_size; i++) {
-		    printf(" %02x\n", *cp++);
-		}
-	    }
-#endif
-	    __INST(lastErrorNumber) = __MKSMALLINT(errno);
-	    RETURN (false);
-	}
+            __INST(lastErrorNumber) = __MKSMALLINT(errno);
+            RETURN (false);
+        }
     }
 
-#if defined(O_NONBLOCK)
+# if defined(O_NONBLOCK)
     fcntl(sock, F_SETFL, oldFlags);
-#endif
-
-#else /* NO_SOCKET */
+# endif
+
+# else /* NO_SOCKET */
     RETURN (false);
-#endif /* NO_SOCKET */
+# endif /* NO_SOCKET */
 %}.
     isAsync == true ifTrue:[
-	(self writeWaitWithTimeoutMs:timeout) ifTrue:[
-	    "/ a timeout occured
-	    "/ should cancel the connect?
-	    ^ false.
-	].
-	err := self getSocketError.
-	err ~~ 0 ifTrue:[
-	    lastErrorNumber := err.
-	    ^ false.
-	].
+        (self writeWaitWithTimeoutMs:timeout) ifTrue:[
+            "/ a timeout occured
+            "/ should cancel the connect?
+            ^ false.
+        ].
+        err := self getSocketError.
+        err ~~ 0 ifTrue:[
+            lastErrorNumber := err.
+            ^ false.
+        ].
     ].
-    port := portNrOrName.
-    peerName := hostOrPathName.
+    port := portNrOrNameOrNil.
+    peer := addr.
+    peerName := addrName.
     ^ true
 
     "
@@ -4574,7 +4329,7 @@
 
     ^ self isActive
       and:[port notNil
-      and:[peerName notNil]]
+      and:[peerName notNil or:[peer notNil]]]
 !
 
 port
@@ -5194,5 +4949,5 @@
 !Socket class methodsFor:'documentation'!
 
 version
-    ^ '$Header: /cvs/stx/stx/libbasic2/Socket.st,v 1.175 2003-05-19 11:12:19 cg Exp $'
+    ^ '$Header: /cvs/stx/stx/libbasic2/Socket.st,v 1.176 2003-05-20 16:27:08 cg Exp $'
 ! !