1/* 2 * io_sock.c - SecureTransport sample I/O module, X sockets version 3 */ 4 5#include "ioSockThr.h" 6#include <errno.h> 7#include <stdio.h> 8 9#include <unistd.h> 10#include <sys/types.h> 11#include <netinet/in.h> 12#include <sys/socket.h> 13#include <netdb.h> 14#include <arpa/inet.h> 15#include <fcntl.h> 16 17#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h> 18#include <time.h> 19#include <strings.h> 20 21/* debugging for this module */ 22#define SSL_OT_DEBUG 1 23 24/* log errors to stdout */ 25#define SSL_OT_ERRLOG 1 26 27/* trace all low-level network I/O */ 28#define SSL_OT_IO_TRACE 0 29 30/* if SSL_OT_IO_TRACE, only log non-zero length transfers */ 31#define SSL_OT_IO_TRACE_NZ 1 32 33/* pause after each I/O (only meaningful if SSL_OT_IO_TRACE == 1) */ 34#define SSL_OT_IO_PAUSE 0 35 36/* print a stream of dots while I/O pending */ 37#define SSL_OT_DOT 1 38 39/* dump some bytes of each I/O (only meaningful if SSL_OT_IO_TRACE == 1) */ 40#define SSL_OT_IO_DUMP 0 41#define SSL_OT_IO_DUMP_SIZE 64 42 43/* general, not-too-verbose debugging */ 44#if SSL_OT_DEBUG 45#define dprintf(s) printf s 46#else 47#define dprintf(s) 48#endif 49 50/* errors --> stdout */ 51#if SSL_OT_ERRLOG 52#define eprintf(s) printf s 53#else 54#define eprintf(s) 55#endif 56 57/* enable nonblocking I/O - maybe should be an arg to MakeServerConnection() */ 58#define NON_BLOCKING 0 59 60/* trace completion of every r/w */ 61#if SSL_OT_IO_TRACE 62static void tprintf( 63 const char *str, 64 UInt32 req, 65 UInt32 act, 66 const UInt8 *buf) 67{ 68 #if SSL_OT_IO_TRACE_NZ 69 if(act == 0) { 70 return; 71 } 72 #endif 73 printf("%s(%d): moved %d bytes\n", str, req, act); 74 #if SSL_OT_IO_DUMP 75 { 76 int i; 77 78 for(i=0; i<act; i++) { 79 printf("%02X ", buf[i]); 80 if(i >= (SSL_OT_IO_DUMP_SIZE - 1)) { 81 break; 82 } 83 } 84 printf("\n"); 85 } 86 #endif 87 #if SSL_OT_IO_PAUSE 88 { 89 char instr[20]; 90 printf("CR to continue: "); 91 gets(instr); 92 } 93 #endif 94} 95 96#else 97#define tprintf(str, req, act, buf) 98#endif /* SSL_OT_IO_TRACE */ 99 100/* 101 * If SSL_OT_DOT, output a '.' every so often while waiting for 102 * connection. This gives user a chance to do something else with the 103 * UI. 104 */ 105 106#if SSL_OT_DOT 107 108static time_t lastTime = (time_t)0; 109#define TIME_INTERVAL 3 110 111static void outputDot() 112{ 113 time_t thisTime = time(0); 114 115 if((thisTime - lastTime) >= TIME_INTERVAL) { 116 printf("."); fflush(stdout); 117 lastTime = thisTime; 118 } 119} 120#else 121#define outputDot() 122#endif 123 124 125/* 126 * One-time only init. 127 */ 128void initSslOt() 129{ 130 131} 132 133/* 134 * Connect to server. 135 * 136 * Seeing a lot of soft errors...for threadTest (only) let's retry. 137 */ 138#define CONNECT_RETRIES 10 139 140OSStatus MakeServerConnection( 141 const char *hostName, 142 int port, 143 otSocket *socketNo, // RETURNED 144 PeerSpec *peer) // RETURNED 145{ 146 struct sockaddr_in addr; 147 struct hostent *ent; 148 struct in_addr host; 149 int sock = 0; 150 int i; 151 152 *socketNo = NULL; 153 if (hostName[0] >= '0' && hostName[0] <= '9') { 154 host.s_addr = inet_addr(hostName); 155 } 156 else { 157 for(i=0; i<CONNECT_RETRIES; i++) { 158 /* seeing a lot of spurious "No address associated with name" 159 * failures on known good names (www.amazon.com) */ 160 ent = gethostbyname(hostName); 161 if (ent == NULL) { 162 printf("gethostbyname failed\n"); 163 herror("hostName"); 164 165 } 166 else { 167 memcpy(&host, ent->h_addr, sizeof(struct in_addr)); 168 break; 169 } 170 } 171 if(ent == NULL) { 172 return ioErr; 173 } 174 } 175 addr.sin_family = AF_INET; 176 for(i=0; i<CONNECT_RETRIES; i++) { 177 sock = socket(AF_INET, SOCK_STREAM, 0); 178 addr.sin_addr = host; 179 addr.sin_port = htons((u_short)port); 180 181 if (connect(sock, (struct sockaddr *) &addr, 182 sizeof(struct sockaddr_in)) == 0) { 183 break; 184 } 185 /* retry */ 186 close(sock); 187 fprintf(stderr, "%s ", hostName); 188 perror("connect"); 189 } 190 if(i == CONNECT_RETRIES) { 191 return ioErr; 192 } 193 194 #if NON_BLOCKING 195 /* OK to do this after connect? */ 196 { 197 int rtn = fcntl(sock, F_SETFL, O_NONBLOCK); 198 if(rtn == -1) { 199 perror("fctnl(O_NONBLOCK)"); 200 return ioErr; 201 } 202 } 203 #endif /* NON_BLOCKING*/ 204 205 peer->ipAddr = addr.sin_addr.s_addr; 206 peer->port = htons((u_short)port); 207 *socketNo = (otSocket)sock; 208 return noErr; 209} 210 211/* 212 * Accept a client connection. 213 */ 214OSStatus AcceptClientConnection( 215 int port, 216 otSocket *socketNo, // RETURNED 217 PeerSpec *peer) // RETURNED 218{ 219 /* maybe some day */ 220 return unimpErr; 221} 222 223/* 224 * Shut down a connection. 225 */ 226void endpointShutdown( 227 otSocket socket) 228{ 229 close((int)socket); 230} 231 232/* 233 * R/W. Called out from SSL. 234 */ 235OSStatus SocketRead( 236 SSLConnectionRef connection, 237 void *data, /* owned by 238 * caller, data 239 * RETURNED */ 240 size_t *dataLength) /* IN/OUT */ 241{ 242 size_t bytesToGo = *dataLength; 243 size_t initLen = bytesToGo; 244 UInt8 *currData = (UInt8 *)data; 245 int sock = (int)((long)connection); 246 OSStatus rtn = noErr; 247 size_t bytesRead; 248 int rrtn; 249 250 *dataLength = 0; 251 252 for(;;) { 253 bytesRead = 0; 254 rrtn = read(sock, currData, bytesToGo); 255 if (rrtn <= 0) { 256 /* this is guesswork... */ 257 switch(errno) { 258 case ENOENT: 259 /* connection closed */ 260 rtn = errSSLClosedGraceful; 261 break; 262 #if NON_BLOCKING 263 case EAGAIN: 264 #else 265 case 0: /* ??? */ 266 #endif 267 rtn = errSSLWouldBlock; 268 break; 269 default: 270 dprintf(("SocketRead: read(%lu) error %d\n", 271 bytesToGo, errno)); 272 rtn = ioErr; 273 break; 274 } 275 break; 276 } 277 else { 278 bytesRead = rrtn; 279 } 280 bytesToGo -= bytesRead; 281 currData += bytesRead; 282 283 if(bytesToGo == 0) { 284 /* filled buffer with incoming data, done */ 285 break; 286 } 287 } 288 *dataLength = initLen - bytesToGo; 289 tprintf("SocketRead", initLen, *dataLength, (UInt8 *)data); 290 291 #if SSL_OT_DOT || (SSL_OT_DEBUG && !SSL_OT_IO_TRACE) 292 if((rtn == 0) && (*dataLength == 0)) { 293 /* keep UI alive */ 294 outputDot(); 295 } 296 #endif 297 return rtn; 298} 299 300OSStatus SocketWrite( 301 SSLConnectionRef connection, 302 const void *data, 303 size_t *dataLength) /* IN/OUT */ 304{ 305 size_t bytesSent = 0; 306 int sock = (int)((long)connection); 307 int length; 308 UInt32 dataLen = *dataLength; 309 const UInt8 *dataPtr = (UInt8 *)data; 310 OSStatus ortn; 311 312 *dataLength = 0; 313 314 do { 315 length = write(sock, 316 (char*)dataPtr + bytesSent, 317 dataLen - bytesSent); 318 } while ((length > 0) && 319 ( (bytesSent += length) < dataLen) ); 320 321 if(length == 0) { 322 if(errno == EAGAIN) { 323 ortn = errSSLWouldBlock; 324 } 325 else { 326 ortn = ioErr; 327 } 328 } 329 else { 330 ortn = noErr; 331 } 332 tprintf("SocketWrite", dataLen, bytesSent, dataPtr); 333 *dataLength = bytesSent; 334 return ortn; 335} 336