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