Socket.st
changeset 3513 8105bf370769
parent 3485 2afd6854bff9
child 3514 2d81c5ffa475
--- a/Socket.st	Sat Feb 28 00:11:09 2015 +0100
+++ b/Socket.st	Mon Mar 02 00:59:30 2015 +0100
@@ -1,3 +1,5 @@
+"{ Encoding: utf8 }"
+
 "
  COPYRIGHT (c) 1992 by Claus Gittinger
 	      All Rights Reserved
@@ -1807,13 +1809,17 @@
     |ok error socketAddress|
 
     handle isNil ifTrue:[
-	^ self errorNotOpen
+        ^ self errorNotOpen
     ].
     socketAddress := aSocketAddress.
     socketAddress isNil ifTrue:[
-	"ok, get a all zero socket address, so it is for anyHost
-	 and the port will be assigned"
-	socketAddress := self socketAddressClass new.
+        "ok, get a all zero socket address, so it is for anyHost
+         and the port will be assigned"
+        socketAddress := self socketAddressClass new.
+    ].
+    domain == #'AF_INET6' ifTrue:[
+        "accept also IPv4 connections on IPv6 sockets (this is off by default fow windows"
+        self setSocketOption:#'IPV6_V6ONLY' argument:false argument:nil.
     ].
     ok := false.
 
@@ -1827,52 +1833,52 @@
     int sockAddrOffs;
 
     if (fp == nil) {
-	goto getOutOfHere;
+        goto getOutOfHere;
     }
 
     if (! __isBytes(socketAddress)) {
-	error = __mkSmallInteger(-1);
-	goto getOutOfHere;
+        error = __mkSmallInteger(-1);
+        goto getOutOfHere;
     }
     /* get the socket-address */
     if (__isNonNilObject(socketAddress)){
-	int nIndex;
-	OBJ cls = __qClass(socketAddress);
-
-	sockAddrOffs = __OBJS2BYTES__(__intVal(__ClassInstPtr(cls)->c_ninstvars));
-	nIndex = __qSize(socketAddress) - OHDR_SIZE;
-	sockaddr_size = nIndex - sockAddrOffs;
-	if (sockaddr_size > sizeof(sa)) {
-	    error=__mkSmallInteger(-2);
-	    goto getOutOfHere;
-	}
-	memcpy(&sa, __byteArrayVal(socketAddress) + sockAddrOffs, sockaddr_size);
+        int nIndex;
+        OBJ cls = __qClass(socketAddress);
+
+        sockAddrOffs = __OBJS2BYTES__(__intVal(__ClassInstPtr(cls)->c_ninstvars));
+        nIndex = __qSize(socketAddress) - OHDR_SIZE;
+        sockaddr_size = nIndex - sockAddrOffs;
+        if (sockaddr_size > sizeof(sa)) {
+            error=__mkSmallInteger(-2);
+            goto getOutOfHere;
+        }
+        memcpy(&sa, __byteArrayVal(socketAddress) + sockAddrOffs, sockaddr_size);
     }
 
     sock = SOCKET_FROM_FILE_OBJECT(fp);
 
 # ifdef SO_REUSEADDR
     if (reuse == true) {
-	int on = 1;
-	if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof (on)) < 0) {
-	    DBGPRINTF(("SOCKET: setsockopt - SO_REUSEADDR failed\n"));
-	}
+        int on = 1;
+        if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof (on)) < 0) {
+            DBGPRINTF(("SOCKET: setsockopt - SO_REUSEADDR failed\n"));
+        }
     }
 # endif /* SO_REUSEADDR */
 
 # ifdef BIND_BLOCKS
 #  ifdef DO_WRAP_CALLS
     do {
-	__threadErrno = 0;
-	ret = STX_WSA_NOINT_CALL3("bind", bind, sock, &sa, sockaddr_size);
+        __threadErrno = 0;
+        ret = STX_WSA_NOINT_CALL3("bind", bind, sock, &sa, sockaddr_size);
     } while ((ret < 0) && (__threadErrno == EINTR));
     if (ret < 0) {
-	errno = __threadErrno;
+        errno = __threadErrno;
     }
 #  else
     __BEGIN_INTERRUPTABLE__
     do {
-	ret = bind(sock, (struct sockaddr *)&sa, sockaddr_size);
+        ret = bind(sock, (struct sockaddr *)&sa, sockaddr_size);
     } while ((ret < 0) && (errno == EINTR));
     __END_INTERRUPTABLE__
 #  endif
@@ -1882,68 +1888,68 @@
 # endif
     if (ret < 0) {
 # ifdef WIN32
-	if (errno == 0) {
-	    errno = WSAGetLastError();
-	}
+        if (errno == 0) {
+            errno = WSAGetLastError();
+        }
 # endif
-	DBGPRINTF(("SOCKET: bind failed errno=%d\n", errno));
-	error = __INST(lastErrorNumber) = __MKSMALLINT(errno);
-	goto getOutOfHere;
+        DBGPRINTF(("SOCKET: bind failed errno=%d\n", errno));
+        error = __INST(lastErrorNumber) = __MKSMALLINT(errno);
+        goto getOutOfHere;
     } else {
-	ok = true;
+        ok = true;
     }
 #endif /* NO_SOCKET */
 
 getOutOfHere: ;
 %}.
     ok ~~ true ifTrue:[
-	|errorHolder errorString|
-
-	error isInteger ifTrue:[
-	    errorHolder := OperatingSystem errorHolderForNumber:error.
-	    errorString := errorHolder errorString.
-	] ifFalse:[
-	    errorString := error.
-	].
-	OpenError newException
-	    errorString:('cannot bind socket to address: %1 (%2)'
-			    bindWith:socketAddress
-			    with:errorString);
-	    errorCode:error;
-	    osErrorHolder:errorHolder;
-	    parameter:self;
-	    raiseRequest.
-	"maybe someone catches the error and binds to some other port..."
-	^ true.
+        |errorHolder errorString|
+
+        error isInteger ifTrue:[
+            errorHolder := OperatingSystem errorHolderForNumber:error.
+            errorString := errorHolder errorString.
+        ] ifFalse:[
+            errorString := error.
+        ].
+        OpenError newException
+            errorString:('cannot bind socket to address: %1 (%2)'
+                            bindWith:socketAddress
+                            with:errorString);
+            errorCode:error;
+            osErrorHolder:errorHolder;
+            parameter:self;
+            raiseRequest.
+        "maybe someone catches the error and binds to some other port..."
+        ^ true.
     ].
 
     port := socketAddress port.
     port == 0 ifTrue:[
-	"this is a bind to a random port, now we can get the real port"
-	port := self getFullSocketAddress port.
+        "this is a bind to a random port, now we can get the real port"
+        port := self getFullSocketAddress port.
     ].
     ^ true
 
     "
      (Socket domain:#'AF_INET' type:#stream)
-	bindTo:(IPSocketAddress anyHost port:445) reuseAddress:false;
-	yourself.
+        bindTo:(IPSocketAddress anyHost port:445) reuseAddress:false;
+        yourself.
 
      (Socket domain:#'AF_INET' type:#stream)
-	bindTo:139 reuseAddress:false;
-	yourself.
+        bindTo:139 reuseAddress:false;
+        yourself.
 
      (Socket domain:#'AF_INET6' type:#stream)
-	bindTo:nil reuseAddress:false;
-	yourself.
+        bindTo:nil reuseAddress:false;
+        yourself.
 
      (Socket domain:#'AF_INET' type:#stream)
-	bindTo:(IPSocketAddress localHost port:2122) reuseAddress:false;
-	yourself.
+        bindTo:(IPSocketAddress localHost port:2122) reuseAddress:false;
+        yourself.
 
      (Socket domain:#'AF_UNIX' type:#stream)
-	bindTo:nil reuseAddress:false;
-	yourself.
+        bindTo:nil reuseAddress:false;
+        yourself.
     "
 !
 
@@ -3065,10 +3071,10 @@
 !
 
 setSocketOption:option argument:arg1 argument:arg2
-    |ok|
+    |ok error|
 
     handle isNil ifTrue:[
-	^ self errorNotOpen
+        ^ self errorNotOpen
     ].
 
 %{  /* STACK: 32000 */
@@ -3076,248 +3082,275 @@
     OBJ fp = __INST(handle);
 
     if (fp != nil) {
-	SOCKET sock = SOCKET_FROM_FILE_OBJECT(fp);
-	int opt = -1;
-	int level = -1;
-	int usize = -1;
-	int ret;
-	union u {
-	    BOOL        u_bool;
-	    int         u_int;
-	    struct linger  u_linger;
+        SOCKET sock = SOCKET_FROM_FILE_OBJECT(fp);
+        int opt = -1;
+        int level = -1;
+        int usize = -1;
+        int ret;
+        union u {
+            BOOL        u_bool;
+            int         u_int;
+            struct linger  u_linger;
 # ifdef IP_ADD_MEMBERSHIP
-	    struct ip_mreq u_ip_mreq;
+            struct ip_mreq u_ip_mreq;
 # endif
 # if defined(SO_RCVTIMEO) || defined(SO_SNDTIMEO)
-	    struct timeval u_tv;
+            struct timeval u_tv;
 # endif
 
 
-	} u;
+        } u;
 
 # ifdef IP_ADD_MEMBERSHIP
-	if (option == @symbol(IP_DROP_MEMBERSHIP)) {
-	    opt = IP_DROP_MEMBERSHIP;
-	    goto dropOrAdd;
-	}
-	if (option == @symbol(IP_ADD_MEMBERSHIP)) {
-	    /* add membership to a multicast group */
-	    opt = IP_ADD_MEMBERSHIP;
+        if (option == @symbol(IP_DROP_MEMBERSHIP)) {
+            opt = IP_DROP_MEMBERSHIP;
+            goto dropOrAdd;
+        }
+        if (option == @symbol(IP_ADD_MEMBERSHIP)) {
+            /* add membership to a multicast group */
+            opt = IP_ADD_MEMBERSHIP;
 dropOrAdd:
-	    level = IPPROTO_IP;
-	    usize = sizeof(u.u_ip_mreq);
-	    if (__isByteArrayLike(arg1) && __isByteArrayLike(arg2)) {
-		memcpy(&u.u_ip_mreq.imr_multiaddr, __byteArrayVal(arg1), sizeof(u.u_ip_mreq.imr_multiaddr));
-		memcpy(&u.u_ip_mreq.imr_interface, __byteArrayVal(arg2), sizeof(u.u_ip_mreq.imr_interface));
-	    }
-	    else
-		goto argError;
-	}
+            level = IPPROTO_IP;
+            usize = sizeof(u.u_ip_mreq);
+            if (__isByteArrayLike(arg1) && __isByteArrayLike(arg2)) {
+                memcpy(&u.u_ip_mreq.imr_multiaddr, __byteArrayVal(arg1), sizeof(u.u_ip_mreq.imr_multiaddr));
+                memcpy(&u.u_ip_mreq.imr_interface, __byteArrayVal(arg2), sizeof(u.u_ip_mreq.imr_interface));
+            }
+            else
+                goto argError;
+        }
 # endif /* IP_ADD_MEMBERSHIP */
 
 # ifdef SO_BROADCAST
-	if (option == @symbol(SO_BROADCAST)) {
-	    /* Enables transmission and receipt of broadcast messages on the socket. */
-	    opt = SO_BROADCAST;
-	    level = SOL_SOCKET;
-	    usize = sizeof(u.u_bool);
-	    if (arg1 == true) u.u_bool = TRUE;
-	    else if (arg1 == false) u.u_bool = FALSE;
-	    else goto argError;
-	}
+        if (option == @symbol(SO_BROADCAST)) {
+            /* Enables transmission and receipt of broadcast messages on the socket. */
+            opt = SO_BROADCAST;
+            level = SOL_SOCKET;
+            usize = sizeof(u.u_bool);
+            if (arg1 == true) u.u_bool = TRUE;
+            else if (arg1 == false) u.u_bool = FALSE;
+            else goto argError;
+        }
 # endif /* SO_BROADCAST */
 
 # ifdef SO_CONDITIONAL
 #  if 0
-	if (option == @symbol(SO_CONDITIONAL)) {
-	    /* Enables sockets to delay the acknowledgment of a connection until after the WSAAccept condition function is called. */
-	    opt = SO_CONDITIONAL;
-	    level = SOL_SOCKET;
-	    usize = sizeof(u.u_bool);
-	    if (arg1 == true) u.u_bool = TRUE;
-	    else if (arg1 == false) u.u_bool = FALSE;
-	    else goto argError;
-	}
+        if (option == @symbol(SO_CONDITIONAL)) {
+            /* Enables sockets to delay the acknowledgment of a connection until after the WSAAccept condition function is called. */
+            opt = SO_CONDITIONAL;
+            level = SOL_SOCKET;
+            usize = sizeof(u.u_bool);
+            if (arg1 == true) u.u_bool = TRUE;
+            else if (arg1 == false) u.u_bool = FALSE;
+            else goto argError;
+        }
 #  endif
 # endif /* SO_CONDITIONAL */
 
 # ifdef SO_DEBUG
-	if (option == @symbol(SO_DEBUG)) {
-	    /* Records debugging information. */
-	    opt = SO_DEBUG;
-	    level = SOL_SOCKET;
-	    usize = sizeof(u.u_bool);
-	    if (arg1 == true) u.u_bool = TRUE;
-	    else if (arg1 == false) u.u_bool = FALSE;
-	    else goto argError;
-	}
+        if (option == @symbol(SO_DEBUG)) {
+            /* Records debugging information. */
+            opt = SO_DEBUG;
+            level = SOL_SOCKET;
+            usize = sizeof(u.u_bool);
+            if (arg1 == true) u.u_bool = TRUE;
+            else if (arg1 == false) u.u_bool = FALSE;
+            else goto argError;
+        }
 # endif /* SO_DEBUG */
 
 # ifdef SO_DONTLINGER
-	if (option == @symbol(SO_DONTLINGER)) {
-	    /* Does not block close waiting for unsent data to be sent.
-	       Setting this option is equivalent to setting SO_LINGER with l_onoff set to zero. */
-	    opt = SO_DONTLINGER;
-	    level = SOL_SOCKET;
-	    usize = sizeof(u.u_bool);
-	    if (arg1 == true) u.u_bool = TRUE;
-	    else if (arg1 == false) u.u_bool = FALSE;
-	    else goto argError;
-	}
+        if (option == @symbol(SO_DONTLINGER)) {
+            /* Does not block close waiting for unsent data to be sent.
+               Setting this option is equivalent to setting SO_LINGER with l_onoff set to zero. */
+            opt = SO_DONTLINGER;
+            level = SOL_SOCKET;
+            usize = sizeof(u.u_bool);
+            if (arg1 == true) u.u_bool = TRUE;
+            else if (arg1 == false) u.u_bool = FALSE;
+            else goto argError;
+        }
 # endif /* SO_DONTLINGER */
 
 # ifdef SO_DONTROUTE
-	if (option == @symbol(SO_DONTROUTE)) {
-	    /* Does not route: sends directly to interface.
-	       Succeeds but is ignored on AF_INET sockets;
-	       fails on AF_INET6 sockets with WSAENOPROTOOPT.
-	       Not supported on ATM sockets (results in an error). */
-	    opt = SO_DONTROUTE;
-	    level = SOL_SOCKET;
-	    usize = sizeof(u.u_bool);
-	    if (arg1 == true) u.u_bool = TRUE;
-	    else if (arg1 == false) u.u_bool = FALSE;
-	    else goto argError;
-	}
+        if (option == @symbol(SO_DONTROUTE)) {
+            /* Does not route: sends directly to interface.
+               Succeeds but is ignored on AF_INET sockets;
+               fails on AF_INET6 sockets with WSAENOPROTOOPT.
+               Not supported on ATM sockets (results in an error). */
+            opt = SO_DONTROUTE;
+            level = SOL_SOCKET;
+            usize = sizeof(u.u_bool);
+            if (arg1 == true) u.u_bool = TRUE;
+            else if (arg1 == false) u.u_bool = FALSE;
+            else goto argError;
+        }
 # endif /* SO_DONTROUTE */
 
 #if defined(IPPROTO_TCP) && defined(TCP_NODELAY)
-	if (option == @symbol(TCP_NODELAY)) {
-	    /* enable/disable TCP_NODELAY (i.e. disable/enable the Nagle algorithm) */
-	    opt = TCP_NODELAY;
-	    level = IPPROTO_TCP;
-	    usize = sizeof(u.u_bool);
-	    if (arg1 == true) u.u_bool = TRUE;
-	    else if (arg1 == false) u.u_bool = FALSE;
-	    else goto argError;
-	}
+        if (option == @symbol(TCP_NODELAY)) {
+            /* enable/disable TCP_NODELAY (i.e. disable/enable the Nagle algorithm) */
+            opt = TCP_NODELAY;
+            level = IPPROTO_TCP;
+            usize = sizeof(u.u_bool);
+            if (arg1 == true) u.u_bool = TRUE;
+            else if (arg1 == false) u.u_bool = FALSE;
+            else goto argError;
+        }
 # endif /* TCP_NODELAY */
 
 # ifdef SO_KEEPALIVE
-	if (option == @symbol(SO_KEEPALIVE)) {
-	    /* Sends keep-alives. Not supported on ATM sockets (results in an error). */
-	    opt = SO_KEEPALIVE;
-	    level = SOL_SOCKET;
-	    usize = sizeof(u.u_bool);
-	    if (arg1 == true) u.u_bool = TRUE;
-	    else if (arg1 == false) u.u_bool = FALSE;
-	    else goto argError;
-	}
+        if (option == @symbol(SO_KEEPALIVE)) {
+            /* Sends keep-alives. Not supported on ATM sockets (results in an error). */
+            opt = SO_KEEPALIVE;
+            level = SOL_SOCKET;
+            usize = sizeof(u.u_bool);
+            if (arg1 == true) u.u_bool = TRUE;
+            else if (arg1 == false) u.u_bool = FALSE;
+            else goto argError;
+        }
 # endif /* SO_KEEPALIVE */
 
 # ifdef SO_LINGER
-	if (option == @symbol(SO_LINGER)) {
-	    /* Lingers on close if unsent data is present. */
-	    opt = SO_LINGER;
-	    level = SOL_SOCKET;
-	    usize = sizeof(u.u_linger);
-	    if (arg1 == true) u.u_linger.l_onoff = TRUE;
-	    else if (arg1 == false) u.u_linger.l_onoff = FALSE;
-	    else goto argError;
-	    if (arg2 == nil) u.u_linger.l_linger = 0;
-	    else if (__isSmallInteger(arg2))u.u_linger.l_linger = __intVal(arg2);
-	    else goto argError;
-	    DBGPRINTF(("SOCKET: SO_LINGER %d %d\n", u.u_linger.l_onoff, u.u_linger.l_linger));
-	}
+        if (option == @symbol(SO_LINGER)) {
+            /* Lingers on close if unsent data is present. */
+            opt = SO_LINGER;
+            level = SOL_SOCKET;
+            usize = sizeof(u.u_linger);
+            if (arg1 == true) u.u_linger.l_onoff = TRUE;
+            else if (arg1 == false) u.u_linger.l_onoff = FALSE;
+            else goto argError;
+            if (arg2 == nil) u.u_linger.l_linger = 0;
+            else if (__isSmallInteger(arg2))u.u_linger.l_linger = __intVal(arg2);
+            else goto argError;
+            DBGPRINTF(("SOCKET: SO_LINGER %d %d\n", u.u_linger.l_onoff, u.u_linger.l_linger));
+        }
 # endif /* SO_LINGER */
 
 # ifdef SO_OOBINLINE
-	if (option == @symbol(SO_OOBINLINE)) {
-	    /* Receives OOB data in the normal data stream. */
-	    opt = SO_OOBINLINE;
-	    level = SOL_SOCKET;
-	    usize = sizeof(u.u_bool);
-	    if (arg1 == true) u.u_bool = TRUE;
-	    else if (arg1 == false) u.u_bool = FALSE;
-	    else goto argError;
-	}
+        if (option == @symbol(SO_OOBINLINE)) {
+            /* Receives OOB data in the normal data stream. */
+            opt = SO_OOBINLINE;
+            level = SOL_SOCKET;
+            usize = sizeof(u.u_bool);
+            if (arg1 == true) u.u_bool = TRUE;
+            else if (arg1 == false) u.u_bool = FALSE;
+            else goto argError;
+        }
 # endif /* SO_OOBINLINE */
 
 # ifdef SO_RCVBUF
-	if (option == @symbol(SO_RCVBUF)) {
-	    /* Specifies the total per-socket buffer space reserved for receives.
-	       This is unrelated to SO_MAX_MSG_SIZE or the size of a TCP window. */
-	    opt = SO_RCVBUF;
-	    level = SOL_SOCKET;
-	    usize = sizeof(u.u_int);
-	    if (__isSmallInteger(arg1))u.u_int = __intVal(arg1);
-	    else goto argError;
-	}
+        if (option == @symbol(SO_RCVBUF)) {
+            /* Specifies the total per-socket buffer space reserved for receives.
+               This is unrelated to SO_MAX_MSG_SIZE or the size of a TCP window. */
+            opt = SO_RCVBUF;
+            level = SOL_SOCKET;
+            usize = sizeof(u.u_int);
+            if (__isSmallInteger(arg1))u.u_int = __intVal(arg1);
+            else goto argError;
+        }
 # endif /* SO_RCVBUF */
 
 # ifdef SO_SNDBUF
-	if (option == @symbol(SO_SNDBUF)) {
-	    /* Specifies the total per-socket buffer space reserved for sends.
-	       This is unrelated to SO_MAX_MSG_SIZE or the size of a TCP window. */
-	    opt = SO_SNDBUF;
-	    level = SOL_SOCKET;
-	    usize = sizeof(u.u_int);
-	    if (__isSmallInteger(arg1))u.u_int = __intVal(arg1);
-	    else goto argError;
-	}
+        if (option == @symbol(SO_SNDBUF)) {
+            /* Specifies the total per-socket buffer space reserved for sends.
+               This is unrelated to SO_MAX_MSG_SIZE or the size of a TCP window. */
+            opt = SO_SNDBUF;
+            level = SOL_SOCKET;
+            usize = sizeof(u.u_int);
+            if (__isSmallInteger(arg1))u.u_int = __intVal(arg1);
+            else goto argError;
+        }
 # endif /* SO_SNDBUF */
 
 # ifdef SO_REUSEADDR
-	if (option == @symbol(SO_REUSEADDR)) {
-	    /* Allows the socket to be bound to an address that is already in use.  */
-	    opt = SO_REUSEADDR;
-	    level = SOL_SOCKET;
-	    usize = sizeof(u.u_bool);
-	    if (arg1 == true) u.u_bool = TRUE;
-	    else if (arg1 == false) u.u_bool = FALSE;
-	    else goto argError;
-	}
+        if (option == @symbol(SO_REUSEADDR)) {
+            /* Allows the socket to be bound to an address that is already in use.  */
+            opt = SO_REUSEADDR;
+            level = SOL_SOCKET;
+            usize = sizeof(u.u_bool);
+            if (arg1 == true) u.u_bool = TRUE;
+            else if (arg1 == false) u.u_bool = FALSE;
+            else goto argError;
+        }
 # endif /* SO_OOBINLINE */
 
 # ifdef SO_EXCLUSIVEADDRUSE
-	if (option == @symbol(SO_EXCLUSIVEADDRUSE)) {
-	    /* Enables a socket to be bound for exclusive access.
-	       Does not require administrative privilege.  */
-	    opt = SO_EXCLUSIVEADDRUSE;
-	    level = SOL_SOCKET;
-	    usize = sizeof(u.u_bool);
-	    if (arg1 == true) u.u_bool = TRUE;
-	    else if (arg1 == false) u.u_bool = FALSE;
-	    else goto argError;
-	}
+        if (option == @symbol(SO_EXCLUSIVEADDRUSE)) {
+            /* Enables a socket to be bound for exclusive access.
+               Does not require administrative privilege.  */
+            opt = SO_EXCLUSIVEADDRUSE;
+            level = SOL_SOCKET;
+            usize = sizeof(u.u_bool);
+            if (arg1 == true) u.u_bool = TRUE;
+            else if (arg1 == false) u.u_bool = FALSE;
+            else goto argError;
+        }
 # endif /* SO_OOBINLINE */
 
 # ifdef SO_RCVTIMEO
-	if ((option == @symbol(SO_RCVTIMEO))
-	 && __isSmallInteger(arg1)
-	 && __isSmallInteger(arg2)) {
-	    opt = SO_RCVTIMEO;
-	    level = SOL_SOCKET;
-	    u.u_tv.tv_sec = __intVal(arg1);
-	    u.u_tv.tv_usec = __intVal(arg2);
-	    usize = sizeof(u.u_tv);
-	}
+        if ((option == @symbol(SO_RCVTIMEO))
+         && __isSmallInteger(arg1)
+         && __isSmallInteger(arg2)) {
+            opt = SO_RCVTIMEO;
+            level = SOL_SOCKET;
+            u.u_tv.tv_sec = __intVal(arg1);
+            u.u_tv.tv_usec = __intVal(arg2);
+            usize = sizeof(u.u_tv);
+        }
 # endif /* SO_RCVTIMEO */
 
 # ifdef SO_SNDTIMEO
-	if ((option == @symbol(SO_SNDTIMEO))
-	 && __isSmallInteger(arg1)
-	 && __isSmallInteger(arg2)) {
-	    opt = SO_SNDTIMEO;
-	    level = SOL_SOCKET;
-	    u.u_tv.tv_sec = __intVal(arg1);
-	    u.u_tv.tv_usec = __intVal(arg2);
-	    usize = sizeof(u.u_tv);
-	}
+        if ((option == @symbol(SO_SNDTIMEO))
+         && __isSmallInteger(arg1)
+         && __isSmallInteger(arg2)) {
+            opt = SO_SNDTIMEO;
+            level = SOL_SOCKET;
+            u.u_tv.tv_sec = __intVal(arg1);
+            u.u_tv.tv_usec = __intVal(arg2);
+            usize = sizeof(u.u_tv);
+        }
 # endif /* SO_SNDTIMEO */
 
-	if (usize == -1) goto argError;
-
-	ok = ( setsockopt( sock, level, opt, (char *)(&u), usize) >= 0) ? true : false;
+# if !defined(IPV6_V6ONLY) && defined(WIN32)
+#  define IPPROTO_IPV6 41
+#  define IPV6_V6ONLY 27
+# endif
+
+# if defined(IPV6_V6ONLY)
+        if (option == @symbol(IPV6_V6ONLY)) {
+            opt = IPV6_V6ONLY;
+            level = IPPROTO_IPV6;
+            usize = sizeof(u.u_bool);
+            if (arg1 == true) u.u_bool = TRUE;
+            else if (arg1 == false) u.u_bool = FALSE;
+            else goto argError;
+            _win32_printf("%d %d %d %d\n", level, opt, usize, u.u_int);
+        }
+# endif /* IPV6_V6ONLY */
+
+        if (usize == -1) goto argError;
+
+        ok = (setsockopt(sock, level, opt, (char *)&u, usize) >= 0) ? true : false;
+        # ifdef WIN32
+        if (ok == false) {
+#  ifdef WIN32
+            error = __mkSmallInteger(WSAGetLastError());
+#  else
+            error = __mkSmallInteger(errno);
+#  endif
+        }
+# endif
+
     }
 argError: ;
 #endif /* NO_SOCKET */
 %}.
     ok isNil ifTrue:[
-	self primitiveFailed
+        self primitiveFailed
     ].
     ok ifFalse:[
-	'setsocketoption failed' infoPrintCR.
+        '++++ Info: Socket>>#setSocketOption:... failed. error: ' infoPrint. error infoPrintCR.
     ].
 !
 
@@ -4124,10 +4157,10 @@
 !Socket class methodsFor:'documentation'!
 
 version
-    ^ '$Header: /cvs/stx/stx/libbasic2/Socket.st,v 1.310 2015-02-13 13:12:25 cg Exp $'
+    ^ '$Header: /cvs/stx/stx/libbasic2/Socket.st,v 1.311 2015-03-01 23:59:30 stefan Exp $'
 !
 
 version_CVS
-    ^ '$Header: /cvs/stx/stx/libbasic2/Socket.st,v 1.310 2015-02-13 13:12:25 cg Exp $'
+    ^ '$Header: /cvs/stx/stx/libbasic2/Socket.st,v 1.311 2015-03-01 23:59:30 stefan Exp $'
 ! !