2 * Copyright (c) 2006-2008,2010-2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
25 * ioSock.c - socket-based I/O routines for use with Secure Transport
33 #include <sys/types.h>
34 #include <netinet/in.h>
35 #include <sys/socket.h>
37 #include <arpa/inet.h>
40 #include <Security/SecBase.h>
44 /* debugging for this module */
45 #define SSL_OT_DEBUG 1
47 /* log errors to stdout */
48 #define SSL_OT_ERRLOG 1
50 /* trace all low-level network I/O */
51 #define SSL_OT_IO_TRACE 0
53 /* if SSL_OT_IO_TRACE, only log non-zero length transfers */
54 #define SSL_OT_IO_TRACE_NZ 1
56 /* pause after each I/O (only meaningful if SSL_OT_IO_TRACE == 1) */
57 #define SSL_OT_IO_PAUSE 0
59 /* print a stream of dots while I/O pending */
62 /* dump some bytes of each I/O (only meaningful if SSL_OT_IO_TRACE == 1) */
63 #define SSL_OT_IO_DUMP 0
64 #define SSL_OT_IO_DUMP_SIZE 256
66 /* indicate errSSLWouldBlock with a '.' */
67 #define SSL_DISPL_WOULD_BLOCK 0
69 /* general, not-too-verbose debugging */
71 #define dprintf(s) printf s
76 /* errors --> stdout */
78 #define eprintf(s) printf s
83 /* trace completion of every r/w */
91 #if SSL_OT_IO_TRACE_NZ
96 printf("%s(%u): moved (%u) bytes\n", str
, (unsigned)req
, (unsigned)act
);
101 for(i
=0; i
<act
; i
++) {
102 printf("%02X ", buf
[i
]);
103 if(i
>= (SSL_OT_IO_DUMP_SIZE
- 1)) {
113 printf("CR to continue: ");
120 #define tprintf(str, req, act, buf)
121 #endif /* SSL_OT_IO_TRACE */
124 * If SSL_OT_DOT, output a '.' every so often while waiting for
125 * connection. This gives user a chance to do something else with the
131 static time_t lastTime
= (time_t)0;
132 #define TIME_INTERVAL 3
134 static void outputDot()
136 time_t thisTime
= time(0);
138 if((thisTime
- lastTime
) >= TIME_INTERVAL
) {
139 printf("."); fflush(stdout
);
149 * One-time only init.
159 #define GETHOST_RETRIES 3
161 OSStatus
MakeServerConnection(
162 const char *hostName
,
164 int nonBlocking
, // 0 or 1
165 otSocket
*socketNo
, // RETURNED
166 PeerSpec
*peer
) // RETURNED
168 struct sockaddr_in addr
;
174 if (hostName
[0] >= '0' && hostName
[0] <= '9')
176 host
.s_addr
= inet_addr(hostName
);
180 /* seeing a lot of soft failures here that I really don't want to track down */
181 for(dex
=0; dex
<GETHOST_RETRIES
; dex
++) {
183 printf("\n...retrying gethostbyname(%s)", hostName
);
185 ent
= gethostbyname(hostName
);
191 printf("\n***gethostbyname(%s) returned: %s\n", hostName
, hstrerror(h_errno
));
194 memcpy(&host
, ent
->h_addr
, sizeof(struct in_addr
));
196 sock
= socket(AF_INET
, SOCK_STREAM
, 0);
197 addr
.sin_addr
= host
;
198 addr
.sin_port
= htons((u_short
)port
);
200 addr
.sin_family
= AF_INET
;
201 if (connect(sock
, (struct sockaddr
*) &addr
, sizeof(struct sockaddr_in
)) != 0)
202 { printf("connect returned error\n");
207 /* OK to do this after connect? */
208 int rtn
= fcntl(sock
, F_SETFL
, O_NONBLOCK
);
210 perror("fctnl(O_NONBLOCK)");
215 peer
->ipAddr
= addr
.sin_addr
.s_addr
;
216 peer
->port
= htons((u_short
)port
);
217 *socketNo
= (otSocket
)sock
;
218 return errSecSuccess
;
222 * Set up an otSocket to listen for client connections. Call once, then
223 * use multiple AcceptClientConnection calls.
225 OSStatus
ListenForClients(
227 int nonBlocking
, // 0 or 1
228 otSocket
*socketNo
) // RETURNED
230 struct sockaddr_in addr
;
235 sock
= socket(AF_INET
, SOCK_STREAM
, 0);
242 int err
= setsockopt(sock
, SOL_SOCKET
, SO_REUSEADDR
, &reuse
, sizeof(reuse
));
244 perror("setsockopt");
248 ent
= gethostbyname("localhost");
250 perror("gethostbyname");
253 memcpy(&addr
.sin_addr
, ent
->h_addr
, sizeof(struct in_addr
));
255 addr
.sin_port
= htons((u_short
)port
);
256 addr
.sin_addr
.s_addr
= INADDR_ANY
;
257 addr
.sin_family
= AF_INET
;
258 len
= sizeof(struct sockaddr_in
);
259 if (bind(sock
, (struct sockaddr
*) &addr
, len
)) {
262 if(theErr
== EADDRINUSE
) {
270 int rtn
= fcntl(sock
, F_SETFL
, O_NONBLOCK
);
272 perror("fctnl(O_NONBLOCK)");
278 int rtn
= listen(sock
, 1);
281 *socketNo
= (otSocket
)sock
;
298 * Accept a client connection.
302 * Currently we always get back a different peer port number on successive
303 * connections, no matter what the client is doing. To test for resumable
304 * session support, force peer port = 0.
306 #define FORCE_ACCEPT_PEER_PORT_ZERO 1
308 OSStatus
AcceptClientConnection(
309 otSocket listenSock
, // obtained from ListenForClients
310 otSocket
*acceptSock
, // RETURNED
311 PeerSpec
*peer
) // RETURNED
313 struct sockaddr_in addr
;
317 len
= sizeof(struct sockaddr_in
);
319 sock
= accept((int)listenSock
, (struct sockaddr
*) &addr
, &len
);
321 if(errno
== EAGAIN
) {
322 /* nonblocking, no connection yet */
334 *acceptSock
= (otSocket
)sock
;
335 peer
->ipAddr
= addr
.sin_addr
.s_addr
;
336 #if FORCE_ACCEPT_PEER_PORT_ZERO
339 peer
->port
= ntohs(addr
.sin_port
);
341 return errSecSuccess
;
345 * Shut down a connection.
347 void endpointShutdown(
354 * R/W. Called out from SSL.
357 SSLConnectionRef connection
,
358 void *data
, /* owned by
361 size_t *dataLength
) /* IN/OUT */
363 UInt32 bytesToGo
= *dataLength
;
364 UInt32 initLen
= bytesToGo
;
365 UInt8
*currData
= (UInt8
*)data
;
366 int sock
= (int)((long)connection
);
367 OSStatus rtn
= errSecSuccess
;
375 /* paranoid check, ensure errno is getting written */
377 rrtn
= recv(sock
, currData
, bytesToGo
, 0);
381 rtn
= errSSLClosedGraceful
;
388 * Undocumented but I definitely see this.
389 * Non-blocking sockets only. Definitely retriable
390 * just like an EAGAIN.
392 dprintf(("SocketRead RETRYING on ENOENT, rrtn %d\n",
395 //rtn = errSSLWouldBlock;
396 /* ...for temp testing.... */
400 /* explicit peer abort */
401 rtn
= errSSLClosedAbort
;
404 /* nonblocking, no data */
405 rtn
= errSSLWouldBlock
;
408 dprintf(("SocketRead: read(%u) error %d, rrtn %d\n",
409 (unsigned)bytesToGo
, theErr
, (int)rrtn
));
413 /* in any case, we're done with this call if rrtn <= 0 */
417 bytesToGo
-= bytesRead
;
418 currData
+= bytesRead
;
421 /* filled buffer with incoming data, done */
425 *dataLength
= initLen
- bytesToGo
;
426 tprintf("SocketRead", initLen
, *dataLength
, (UInt8
*)data
);
428 #if SSL_OT_DOT || (SSL_OT_DEBUG && !SSL_OT_IO_TRACE)
429 if((rtn
== 0) && (*dataLength
== 0)) {
434 #if SSL_DISPL_WOULD_BLOCK
435 if(rtn
== errSSLWouldBlock
) {
436 printf("."); fflush(stdout
);
444 OSStatus
SocketWrite(
445 SSLConnectionRef connection
,
447 size_t *dataLength
) /* IN/OUT */
449 size_t bytesSent
= 0;
450 int sock
= (int)((long)connection
);
452 size_t dataLen
= *dataLength
;
453 const UInt8
*dataPtr
= (UInt8
*)data
;
456 if(oneAtATime
&& (*dataLength
> 1)) {
462 for(i
=0; i
<dataLen
; i
++) {
464 ortn
= SocketWrite(connection
, dataPtr
, &thisMove
);
471 return errSecSuccess
;
477 (char*)dataPtr
+ bytesSent
,
478 dataLen
- bytesSent
);
479 } while ((length
> 0) &&
480 ( (bytesSent
+= length
) < dataLen
) );
486 ortn
= errSSLWouldBlock
; break;
488 ortn
= errSSLClosedAbort
; break;
490 dprintf(("SocketWrite: write(%u) error %d\n",
491 (unsigned)(dataLen
- bytesSent
), theErr
));
497 ortn
= errSecSuccess
;
499 tprintf("SocketWrite", dataLen
, bytesSent
, dataPtr
);
500 *dataLength
= bytesSent
;