2  * Copyright (c) 2006-2008,2010,2012-2013 Apple Inc. All Rights Reserved. 
   4  * io_sock.c - SecureTransport sample I/O module, X sockets version 
  10 #include <Security/SecBase.h> 
  12 #include <sys/types.h> 
  13 #include <netinet/in.h> 
  14 #include <sys/socket.h> 
  16 #include <arpa/inet.h> 
  19 #include <Security/SecBase.h> 
  24 /* debugging for this module */ 
  25 #define SSL_OT_DEBUG            1 
  27 /* log errors to stdout */ 
  28 #define SSL_OT_ERRLOG           1 
  30 /* trace all low-level network I/O */ 
  31 #define SSL_OT_IO_TRACE         0 
  33 /* if SSL_OT_IO_TRACE, only log non-zero length transfers */ 
  34 #define SSL_OT_IO_TRACE_NZ      1 
  36 /* pause after each I/O (only meaningful if SSL_OT_IO_TRACE == 1) */ 
  37 #define SSL_OT_IO_PAUSE         0 
  39 /* print a stream of dots while I/O pending */ 
  42 /* dump some bytes of each I/O (only meaningful if SSL_OT_IO_TRACE == 1) */ 
  43 #define SSL_OT_IO_DUMP          0 
  44 #define SSL_OT_IO_DUMP_SIZE     256 
  46 /* indicate errSSLWouldBlock with a '.' */ 
  47 #define SSL_DISPL_WOULD_BLOCK   0 
  49 /* general, not-too-verbose debugging */ 
  51 #define dprintf(s)      printf s 
  56 /* errors --> stdout */ 
  58 #define eprintf(s)      printf s 
  63 /* trace completion of every r/w */ 
  71         #if     SSL_OT_IO_TRACE_NZ 
  76         printf("%s(%u): moved (%u) bytes\n", str
, (unsigned)req
, (unsigned)act
); 
  81                 for(i
=0; i
<act
; i
++) { 
  82                         printf("%02X ", buf
[i
]); 
  83                         if(i 
>= (SSL_OT_IO_DUMP_SIZE 
- 1)) { 
  93                 printf("CR to continue: "); 
 100 #define tprintf(str, req, act, buf) 
 101 #endif  /* SSL_OT_IO_TRACE */ 
 104  * If SSL_OT_DOT, output a '.' every so often while waiting for 
 105  * connection. This gives user a chance to do something else with the 
 111 static time_t lastTime 
= (time_t)0; 
 112 #define TIME_INTERVAL           3 
 114 static void outputDot() 
 116         time_t thisTime 
= time(0); 
 118         if((thisTime 
- lastTime
) >= TIME_INTERVAL
) { 
 119                 printf("."); fflush(stdout
); 
 129  * One-time only init. 
 139 #define GETHOST_RETRIES         3 
 141 OSStatus 
MakeServerConnection( 
 142         const char *hostName
,  
 144         int nonBlocking
,                // 0 or 1 
 145         otSocket 
*socketNo
,     // RETURNED 
 146         PeerSpec 
*peer
)                 // RETURNED 
 148     struct sockaddr_in  addr
; 
 154     if (hostName
[0] >= '0' && hostName
[0] <= '9') 
 156         host
.s_addr 
= inet_addr(hostName
); 
 160                 /* seeing a lot of soft failures here that I really don't want to track down */ 
 161                 for(dex
=0; dex
<GETHOST_RETRIES
; dex
++) { 
 163                                 printf("\n...retrying gethostbyname(%s)", hostName
); 
 165                         ent 
= gethostbyname(hostName
); 
 171                         printf("\n***gethostbyname(%s) returned: %s\n", hostName
, hstrerror(h_errno
)); 
 174         memcpy(&host
, ent
->h_addr
, sizeof(struct in_addr
)); 
 176     sock 
= socket(AF_INET
, SOCK_STREAM
, 0); 
 177     addr
.sin_addr 
= host
; 
 178     addr
.sin_port 
= htons((u_short
)port
); 
 180     addr
.sin_family 
= AF_INET
; 
 181     if (connect(sock
, (struct sockaddr 
*) &addr
, sizeof(struct sockaddr_in
)) != 0) 
 182     {   printf("connect returned error\n"); 
 187                 /* OK to do this after connect? */ 
 188                 int rtn 
= fcntl(sock
, F_SETFL
, O_NONBLOCK
); 
 190                         perror("fctnl(O_NONBLOCK)"); 
 195     peer
->ipAddr 
= addr
.sin_addr
.s_addr
; 
 196     peer
->port 
= htons((u_short
)port
); 
 197         *socketNo 
= (otSocket
)sock
; 
 198     return errSecSuccess
; 
 202  * Set up an otSocket to listen for client connections. Call once, then 
 203  * use multiple AcceptClientConnection calls.  
 205 OSStatus 
ListenForClients( 
 207         int nonBlocking
,                // 0 or 1 
 208         otSocket 
*socketNo
)     // RETURNED 
 210         struct sockaddr_in  addr
; 
 215     sock 
= socket(AF_INET
, SOCK_STREAM
, 0); 
 222     int err 
= setsockopt(sock
, SOL_SOCKET
, SO_REUSEADDR
, &reuse
, sizeof(reuse
)); 
 224         perror("setsockopt"); 
 228     ent 
= gethostbyname("localhost"); 
 230                 perror("gethostbyname"); 
 233     memcpy(&addr
.sin_addr
, ent
->h_addr
, sizeof(struct in_addr
)); 
 235     addr
.sin_port 
= htons((u_short
)port
); 
 236     addr
.sin_addr
.s_addr 
= INADDR_ANY
; 
 237     addr
.sin_family 
= AF_INET
; 
 238     len 
= sizeof(struct sockaddr_in
); 
 239     if (bind(sock
, (struct sockaddr 
*) &addr
, len
)) { 
 242                 if(theErr 
== EADDRINUSE
) { 
 250                 int rtn 
= fcntl(sock
, F_SETFL
, O_NONBLOCK
); 
 252                         perror("fctnl(O_NONBLOCK)"); 
 258                 int rtn 
= listen(sock
, 1); 
 261                                 *socketNo 
= (otSocket
)sock
; 
 278  * Accept a client connection. 
 282  * Currently we always get back a different peer port number on successive 
 283  * connections, no matter what the client is doing. To test for resumable  
 284  * session support, force peer port = 0. 
 286 #define FORCE_ACCEPT_PEER_PORT_ZERO             1 
 288 OSStatus 
AcceptClientConnection( 
 289         otSocket listenSock
,            // obtained from ListenForClients 
 290         otSocket 
*acceptSock
,           // RETURNED 
 291         PeerSpec 
*peer
)                         // RETURNED 
 293         struct sockaddr_in  addr
; 
 297     len 
= sizeof(struct sockaddr_in
); 
 299                 sock 
= accept((int)listenSock
, (struct sockaddr 
*) &addr
, &len
); 
 301                         if(errno 
== EAGAIN
) { 
 302                                 /* nonblocking, no connection yet */ 
 314         *acceptSock 
= (otSocket
)sock
; 
 315     peer
->ipAddr 
= addr
.sin_addr
.s_addr
; 
 316         #if     FORCE_ACCEPT_PEER_PORT_ZERO 
 319     peer
->port 
= ntohs(addr
.sin_port
); 
 321     return errSecSuccess
; 
 325  * Shut down a connection. 
 327 void endpointShutdown( 
 334  * R/W. Called out from SSL. 
 337         SSLConnectionRef        connection
, 
 338         void                            *data
,                  /* owned by  
 341         size_t                          *dataLength
)    /* IN/OUT */  
 343         size_t                  bytesToGo 
= *dataLength
; 
 344         size_t                  initLen 
= bytesToGo
; 
 345         UInt8                   
*currData 
= (UInt8 
*)data
; 
 346         int                             sock 
= (int)((long)connection
); 
 347         OSStatus                rtn 
= errSecSuccess
; 
 348         size_t                  bytesRead 
= 0; 
 354                 /* paranoid check, ensure errno is getting written */ 
 356                 rrtn 
= recv(sock
, currData
, bytesToGo
, 0); 
 360                                 rtn 
= errSSLClosedGraceful
; 
 367                                          * Undocumented but I definitely see this. 
 368                                          * Non-blocking sockets only. Definitely retriable 
 369                                          * just like an EAGAIN. 
 371                                         dprintf(("SocketRead RETRYING on ENOENT, rrtn %d\n", 
 374                                         //rtn = errSSLWouldBlock; 
 375                                         /* ...for temp testing.... */ 
 379                                         /* explicit peer abort */ 
 380                                         rtn 
= errSSLClosedAbort
; 
 383                                         /* nonblocking, no data */ 
 384                                         rtn 
= errSSLWouldBlock
; 
 387                                         dprintf(("SocketRead: read(%u) error %d, rrtn %d\n",  
 388                                                 (unsigned)bytesToGo
, theErr
, (int)rrtn
)); 
 392                         /* in any case, we're done with this call if rrtn <= 0 */ 
 396                 bytesToGo 
-= bytesRead
; 
 397                 currData  
+= bytesRead
; 
 400                         /* filled buffer with incoming data, done */ 
 404         *dataLength 
= initLen 
- bytesToGo
; 
 405         tprintf("SocketRead", initLen
, *dataLength
, (UInt8 
*)data
); 
 407         #if SSL_OT_DOT || (SSL_OT_DEBUG && !SSL_OT_IO_TRACE) 
 408         if((rtn 
== 0) && (*dataLength 
== 0)) { 
 413         #if SSL_DISPL_WOULD_BLOCK 
 414         if(rtn 
== errSSLWouldBlock
) { 
 415                 printf("."); fflush(stdout
); 
 423 OSStatus 
SocketWrite( 
 424         SSLConnectionRef        connection
, 
 426         size_t                          *dataLength
)    /* IN/OUT */  
 428         size_t          bytesSent 
= 0; 
 429         int                     sock 
= (int)((long)connection
); 
 431         size_t          dataLen 
= *dataLength
; 
 432         const UInt8 
*dataPtr 
= (UInt8 
*)data
; 
 435         if(oneAtATime 
&& (*dataLength 
> 1)) { 
 441                 for(i
=0; i
<dataLen
; i
++) { 
 443                         ortn 
= SocketWrite(connection
, dataPtr
, &thisMove
); 
 450                 return errSecSuccess
; 
 456                                 (char*)dataPtr 
+ bytesSent
,  
 457                                 dataLen 
- bytesSent
); 
 458     } while ((length 
> 0) &&  
 459                          ( (bytesSent 
+= length
) < dataLen
) ); 
 465                                 ortn 
= errSSLWouldBlock
; break; 
 467                                 ortn 
= errSSLClosedAbort
; break; 
 469                                 dprintf(("SocketWrite: write(%u) error %d\n",  
 470                                           (unsigned)(dataLen 
- bytesSent
), theErr
)); 
 476                 ortn 
= errSecSuccess
; 
 478         tprintf("SocketWrite", dataLen
, bytesSent
, dataPtr
); 
 479         *dataLength 
= bytesSent
;