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
;