]>
Commit | Line | Data |
---|---|---|
d8f41ccd A |
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 | |
62 | static 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 | ||
108 | static time_t lastTime = (time_t)0; | |
109 | #define TIME_INTERVAL 3 | |
110 | ||
111 | static 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 | */ | |
128 | void 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 | ||
140 | OSStatus 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 | */ | |
214 | OSStatus 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 | */ | |
226 | void endpointShutdown( | |
227 | otSocket socket) | |
228 | { | |
229 | close((int)socket); | |
230 | } | |
231 | ||
232 | /* | |
233 | * R/W. Called out from SSL. | |
234 | */ | |
235 | OSStatus 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 | ||
300 | OSStatus 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 | } |