OLD | NEW |
| (Empty) |
1 /* apps/s_socket.c - socket-related functions used by s_client and s_server */ | |
2 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) | |
3 * All rights reserved. | |
4 * | |
5 * This package is an SSL implementation written | |
6 * by Eric Young (eay@cryptsoft.com). | |
7 * The implementation was written so as to conform with Netscapes SSL. | |
8 * | |
9 * This library is free for commercial and non-commercial use as long as | |
10 * the following conditions are aheared to. The following conditions | |
11 * apply to all code found in this distribution, be it the RC4, RSA, | |
12 * lhash, DES, etc., code; not just the SSL code. The SSL documentation | |
13 * included with this distribution is covered by the same copyright terms | |
14 * except that the holder is Tim Hudson (tjh@cryptsoft.com). | |
15 * | |
16 * Copyright remains Eric Young's, and as such any Copyright notices in | |
17 * the code are not to be removed. | |
18 * If this package is used in a product, Eric Young should be given attribution | |
19 * as the author of the parts of the library used. | |
20 * This can be in the form of a textual message at program startup or | |
21 * in documentation (online or textual) provided with the package. | |
22 * | |
23 * Redistribution and use in source and binary forms, with or without | |
24 * modification, are permitted provided that the following conditions | |
25 * are met: | |
26 * 1. Redistributions of source code must retain the copyright | |
27 * notice, this list of conditions and the following disclaimer. | |
28 * 2. Redistributions in binary form must reproduce the above copyright | |
29 * notice, this list of conditions and the following disclaimer in the | |
30 * documentation and/or other materials provided with the distribution. | |
31 * 3. All advertising materials mentioning features or use of this software | |
32 * must display the following acknowledgement: | |
33 * "This product includes cryptographic software written by | |
34 * Eric Young (eay@cryptsoft.com)" | |
35 * The word 'cryptographic' can be left out if the rouines from the library | |
36 * being used are not cryptographic related :-). | |
37 * 4. If you include any Windows specific code (or a derivative thereof) from | |
38 * the apps directory (application code) you must include an acknowledgement: | |
39 * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" | |
40 * | |
41 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND | |
42 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
43 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
44 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | |
45 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
46 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
47 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
49 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
50 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
51 * SUCH DAMAGE. | |
52 * | |
53 * The licence and distribution terms for any publically available version or | |
54 * derivative of this code cannot be changed. i.e. this code cannot simply be | |
55 * copied and put under another distribution licence | |
56 * [including the GNU Public Licence.] | |
57 */ | |
58 | |
59 #include <stdio.h> | |
60 #include <stdlib.h> | |
61 #include <string.h> | |
62 #include <errno.h> | |
63 #include <signal.h> | |
64 | |
65 #ifdef FLAT_INC | |
66 #include "e_os2.h" | |
67 #else | |
68 #include "../e_os2.h" | |
69 #endif | |
70 | |
71 /* With IPv6, it looks like Digital has mixed up the proper order of | |
72 recursive header file inclusion, resulting in the compiler complaining | |
73 that u_int isn't defined, but only if _POSIX_C_SOURCE is defined, which | |
74 is needed to have fileno() declared correctly... So let's define u_int */ | |
75 #if defined(OPENSSL_SYS_VMS_DECC) && !defined(__U_INT) | |
76 #define __U_INT | |
77 typedef unsigned int u_int; | |
78 #endif | |
79 | |
80 #define USE_SOCKETS | |
81 #define NON_MAIN | |
82 #include "apps.h" | |
83 #undef USE_SOCKETS | |
84 #undef NON_MAIN | |
85 #include "s_apps.h" | |
86 #include <openssl/ssl.h> | |
87 | |
88 #ifdef FLAT_INC | |
89 #include "e_os.h" | |
90 #else | |
91 #include "../e_os.h" | |
92 #endif | |
93 | |
94 #ifndef OPENSSL_NO_SOCK | |
95 | |
96 #if defined(OPENSSL_SYS_NETWARE) && defined(NETWARE_BSDSOCK) | |
97 #include "netdb.h" | |
98 #endif | |
99 | |
100 static struct hostent *GetHostByName(char *name); | |
101 #if defined(OPENSSL_SYS_WINDOWS) || (defined(OPENSSL_SYS_NETWARE) && !defined(NE
TWARE_BSDSOCK)) | |
102 static void ssl_sock_cleanup(void); | |
103 #endif | |
104 static int ssl_sock_init(void); | |
105 static int init_client_ip(int *sock,unsigned char ip[4], int port, int type); | |
106 static int init_server(int *sock, int port, int type); | |
107 static int init_server_long(int *sock, int port,char *ip, int type); | |
108 static int do_accept(int acc_sock, int *sock, char **host); | |
109 static int host_ip(char *str, unsigned char ip[4]); | |
110 | |
111 #ifdef OPENSSL_SYS_WIN16 | |
112 #define SOCKET_PROTOCOL 0 /* more microsoft stupidity */ | |
113 #else | |
114 #define SOCKET_PROTOCOL IPPROTO_TCP | |
115 #endif | |
116 | |
117 #if defined(OPENSSL_SYS_NETWARE) && !defined(NETWARE_BSDSOCK) | |
118 static int wsa_init_done=0; | |
119 #endif | |
120 | |
121 #ifdef OPENSSL_SYS_WINDOWS | |
122 static struct WSAData wsa_state; | |
123 static int wsa_init_done=0; | |
124 | |
125 #ifdef OPENSSL_SYS_WIN16 | |
126 static HWND topWnd=0; | |
127 static FARPROC lpTopWndProc=NULL; | |
128 static FARPROC lpTopHookProc=NULL; | |
129 extern HINSTANCE _hInstance; /* nice global CRT provides */ | |
130 | |
131 static LONG FAR PASCAL topHookProc(HWND hwnd, UINT message, WPARAM wParam, | |
132 LPARAM lParam) | |
133 { | |
134 if (hwnd == topWnd) | |
135 { | |
136 switch(message) | |
137 { | |
138 case WM_DESTROY: | |
139 case WM_CLOSE: | |
140 SetWindowLong(topWnd,GWL_WNDPROC,(LONG)lpTopWndProc); | |
141 ssl_sock_cleanup(); | |
142 break; | |
143 } | |
144 } | |
145 return CallWindowProc(lpTopWndProc,hwnd,message,wParam,lParam); | |
146 } | |
147 | |
148 static BOOL CALLBACK enumproc(HWND hwnd,LPARAM lParam) | |
149 { | |
150 topWnd=hwnd; | |
151 return(FALSE); | |
152 } | |
153 | |
154 #endif /* OPENSSL_SYS_WIN32 */ | |
155 #endif /* OPENSSL_SYS_WINDOWS */ | |
156 | |
157 #ifdef OPENSSL_SYS_WINDOWS | |
158 static void ssl_sock_cleanup(void) | |
159 { | |
160 if (wsa_init_done) | |
161 { | |
162 wsa_init_done=0; | |
163 #ifndef OPENSSL_SYS_WINCE | |
164 WSACancelBlockingCall(); | |
165 #endif | |
166 WSACleanup(); | |
167 } | |
168 } | |
169 #elif defined(OPENSSL_SYS_NETWARE) && !defined(NETWARE_BSDSOCK) | |
170 static void sock_cleanup(void) | |
171 { | |
172 if (wsa_init_done) | |
173 { | |
174 wsa_init_done=0; | |
175 WSACleanup(); | |
176 } | |
177 } | |
178 #endif | |
179 | |
180 static int ssl_sock_init(void) | |
181 { | |
182 #ifdef WATT32 | |
183 extern int _watt_do_exit; | |
184 _watt_do_exit = 0; | |
185 if (sock_init()) | |
186 return (0); | |
187 #elif defined(OPENSSL_SYS_WINDOWS) | |
188 if (!wsa_init_done) | |
189 { | |
190 int err; | |
191 | |
192 #ifdef SIGINT | |
193 signal(SIGINT,(void (*)(int))ssl_sock_cleanup); | |
194 #endif | |
195 wsa_init_done=1; | |
196 memset(&wsa_state,0,sizeof(wsa_state)); | |
197 if (WSAStartup(0x0101,&wsa_state)!=0) | |
198 { | |
199 err=WSAGetLastError(); | |
200 BIO_printf(bio_err,"unable to start WINSOCK, error code=
%d\n",err); | |
201 return(0); | |
202 } | |
203 | |
204 #ifdef OPENSSL_SYS_WIN16 | |
205 EnumTaskWindows(GetCurrentTask(),enumproc,0L); | |
206 lpTopWndProc=(FARPROC)GetWindowLong(topWnd,GWL_WNDPROC); | |
207 lpTopHookProc=MakeProcInstance((FARPROC)topHookProc,_hInstance); | |
208 | |
209 SetWindowLong(topWnd,GWL_WNDPROC,(LONG)lpTopHookProc); | |
210 #endif /* OPENSSL_SYS_WIN16 */ | |
211 } | |
212 #elif defined(OPENSSL_SYS_NETWARE) && !defined(NETWARE_BSDSOCK) | |
213 WORD wVerReq; | |
214 WSADATA wsaData; | |
215 int err; | |
216 | |
217 if (!wsa_init_done) | |
218 { | |
219 | |
220 # ifdef SIGINT | |
221 signal(SIGINT,(void (*)(int))sock_cleanup); | |
222 # endif | |
223 | |
224 wsa_init_done=1; | |
225 wVerReq = MAKEWORD( 2, 0 ); | |
226 err = WSAStartup(wVerReq,&wsaData); | |
227 if (err != 0) | |
228 { | |
229 BIO_printf(bio_err,"unable to start WINSOCK2, error code=%d\n",err); | |
230 return(0); | |
231 } | |
232 } | |
233 #endif /* OPENSSL_SYS_WINDOWS */ | |
234 return(1); | |
235 } | |
236 | |
237 int init_client(int *sock, char *host, int port, int type) | |
238 { | |
239 unsigned char ip[4]; | |
240 | |
241 memset(ip, '\0', sizeof ip); | |
242 if (!host_ip(host,&(ip[0]))) | |
243 return 0; | |
244 return init_client_ip(sock,ip,port,type); | |
245 } | |
246 | |
247 static int init_client_ip(int *sock, unsigned char ip[4], int port, int type) | |
248 { | |
249 unsigned long addr; | |
250 struct sockaddr_in them; | |
251 int s,i; | |
252 | |
253 if (!ssl_sock_init()) return(0); | |
254 | |
255 memset((char *)&them,0,sizeof(them)); | |
256 them.sin_family=AF_INET; | |
257 them.sin_port=htons((unsigned short)port); | |
258 addr=(unsigned long) | |
259 ((unsigned long)ip[0]<<24L)| | |
260 ((unsigned long)ip[1]<<16L)| | |
261 ((unsigned long)ip[2]<< 8L)| | |
262 ((unsigned long)ip[3]); | |
263 them.sin_addr.s_addr=htonl(addr); | |
264 | |
265 if (type == SOCK_STREAM) | |
266 s=socket(AF_INET,SOCK_STREAM,SOCKET_PROTOCOL); | |
267 else /* ( type == SOCK_DGRAM) */ | |
268 s=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP); | |
269 | |
270 if (s == INVALID_SOCKET) { perror("socket"); return(0); } | |
271 | |
272 #if defined(SO_KEEPALIVE) && !defined(OPENSSL_SYS_MPE) | |
273 if (type == SOCK_STREAM) | |
274 { | |
275 i=0; | |
276 i=setsockopt(s,SOL_SOCKET,SO_KEEPALIVE,(char *)&i,sizeof(i)); | |
277 if (i < 0) { perror("keepalive"); return(0); } | |
278 } | |
279 #endif | |
280 | |
281 if (connect(s,(struct sockaddr *)&them,sizeof(them)) == -1) | |
282 { closesocket(s); perror("connect"); return(0); } | |
283 *sock=s; | |
284 return(1); | |
285 } | |
286 | |
287 int do_server(int port, int type, int *ret, int (*cb)(char *hostname, int s, uns
igned char *context), unsigned char *context) | |
288 { | |
289 int sock; | |
290 char *name = NULL; | |
291 int accept_socket = 0; | |
292 int i; | |
293 | |
294 if (!init_server(&accept_socket,port,type)) return(0); | |
295 | |
296 if (ret != NULL) | |
297 { | |
298 *ret=accept_socket; | |
299 /* return(1);*/ | |
300 } | |
301 for (;;) | |
302 { | |
303 if (type==SOCK_STREAM) | |
304 { | |
305 if (do_accept(accept_socket,&sock,&name) == 0) | |
306 { | |
307 SHUTDOWN(accept_socket); | |
308 return(0); | |
309 } | |
310 } | |
311 else | |
312 sock = accept_socket; | |
313 i=(*cb)(name,sock, context); | |
314 if (name != NULL) OPENSSL_free(name); | |
315 if (type==SOCK_STREAM) | |
316 SHUTDOWN2(sock); | |
317 if (i < 0) | |
318 { | |
319 SHUTDOWN2(accept_socket); | |
320 return(i); | |
321 } | |
322 } | |
323 } | |
324 | |
325 static int init_server_long(int *sock, int port, char *ip, int type) | |
326 { | |
327 int ret=0; | |
328 struct sockaddr_in server; | |
329 int s= -1; | |
330 | |
331 if (!ssl_sock_init()) return(0); | |
332 | |
333 memset((char *)&server,0,sizeof(server)); | |
334 server.sin_family=AF_INET; | |
335 server.sin_port=htons((unsigned short)port); | |
336 if (ip == NULL) | |
337 server.sin_addr.s_addr=INADDR_ANY; | |
338 else | |
339 /* Added for T3E, address-of fails on bit field (beckman@acl.lanl.gov) */ | |
340 #ifndef BIT_FIELD_LIMITS | |
341 memcpy(&server.sin_addr.s_addr,ip,4); | |
342 #else | |
343 memcpy(&server.sin_addr,ip,4); | |
344 #endif | |
345 | |
346 if (type == SOCK_STREAM) | |
347 s=socket(AF_INET,SOCK_STREAM,SOCKET_PROTOCOL); | |
348 else /* type == SOCK_DGRAM */ | |
349 s=socket(AF_INET, SOCK_DGRAM,IPPROTO_UDP); | |
350 | |
351 if (s == INVALID_SOCKET) goto err; | |
352 #if defined SOL_SOCKET && defined SO_REUSEADDR | |
353 { | |
354 int j = 1; | |
355 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, | |
356 (void *) &j, sizeof j); | |
357 } | |
358 #endif | |
359 if (bind(s,(struct sockaddr *)&server,sizeof(server)) == -1) | |
360 { | |
361 #ifndef OPENSSL_SYS_WINDOWS | |
362 perror("bind"); | |
363 #endif | |
364 goto err; | |
365 } | |
366 /* Make it 128 for linux */ | |
367 if (type==SOCK_STREAM && listen(s,128) == -1) goto err; | |
368 *sock=s; | |
369 ret=1; | |
370 err: | |
371 if ((ret == 0) && (s != -1)) | |
372 { | |
373 SHUTDOWN(s); | |
374 } | |
375 return(ret); | |
376 } | |
377 | |
378 static int init_server(int *sock, int port, int type) | |
379 { | |
380 return(init_server_long(sock, port, NULL, type)); | |
381 } | |
382 | |
383 static int do_accept(int acc_sock, int *sock, char **host) | |
384 { | |
385 int ret; | |
386 struct hostent *h1,*h2; | |
387 static struct sockaddr_in from; | |
388 int len; | |
389 /* struct linger ling; */ | |
390 | |
391 if (!ssl_sock_init()) return(0); | |
392 | |
393 #ifndef OPENSSL_SYS_WINDOWS | |
394 redoit: | |
395 #endif | |
396 | |
397 memset((char *)&from,0,sizeof(from)); | |
398 len=sizeof(from); | |
399 /* Note: under VMS with SOCKETSHR the fourth parameter is currently | |
400 * of type (int *) whereas under other systems it is (void *) if | |
401 * you don't have a cast it will choke the compiler: if you do | |
402 * have a cast then you can either go for (int *) or (void *). | |
403 */ | |
404 ret=accept(acc_sock,(struct sockaddr *)&from,(void *)&len); | |
405 if (ret == INVALID_SOCKET) | |
406 { | |
407 #if defined(OPENSSL_SYS_WINDOWS) || (defined(OPENSSL_SYS_NETWARE) && !defined(NE
TWARE_BSDSOCK)) | |
408 int i; | |
409 i=WSAGetLastError(); | |
410 BIO_printf(bio_err,"accept error %d\n",i); | |
411 #else | |
412 if (errno == EINTR) | |
413 { | |
414 /*check_timeout(); */ | |
415 goto redoit; | |
416 } | |
417 fprintf(stderr,"errno=%d ",errno); | |
418 perror("accept"); | |
419 #endif | |
420 return(0); | |
421 } | |
422 | |
423 /* | |
424 ling.l_onoff=1; | |
425 ling.l_linger=0; | |
426 i=setsockopt(ret,SOL_SOCKET,SO_LINGER,(char *)&ling,sizeof(ling)); | |
427 if (i < 0) { perror("linger"); return(0); } | |
428 i=0; | |
429 i=setsockopt(ret,SOL_SOCKET,SO_KEEPALIVE,(char *)&i,sizeof(i)); | |
430 if (i < 0) { perror("keepalive"); return(0); } | |
431 */ | |
432 | |
433 if (host == NULL) goto end; | |
434 #ifndef BIT_FIELD_LIMITS | |
435 /* I should use WSAAsyncGetHostByName() under windows */ | |
436 h1=gethostbyaddr((char *)&from.sin_addr.s_addr, | |
437 sizeof(from.sin_addr.s_addr),AF_INET); | |
438 #else | |
439 h1=gethostbyaddr((char *)&from.sin_addr, | |
440 sizeof(struct in_addr),AF_INET); | |
441 #endif | |
442 if (h1 == NULL) | |
443 { | |
444 BIO_printf(bio_err,"bad gethostbyaddr\n"); | |
445 *host=NULL; | |
446 /* return(0); */ | |
447 } | |
448 else | |
449 { | |
450 if ((*host=(char *)OPENSSL_malloc(strlen(h1->h_name)+1)) == NULL
) | |
451 { | |
452 perror("OPENSSL_malloc"); | |
453 return(0); | |
454 } | |
455 BUF_strlcpy(*host,h1->h_name,strlen(h1->h_name)+1); | |
456 | |
457 h2=GetHostByName(*host); | |
458 if (h2 == NULL) | |
459 { | |
460 BIO_printf(bio_err,"gethostbyname failure\n"); | |
461 return(0); | |
462 } | |
463 if (h2->h_addrtype != AF_INET) | |
464 { | |
465 BIO_printf(bio_err,"gethostbyname addr is not AF_INET\n"
); | |
466 return(0); | |
467 } | |
468 } | |
469 end: | |
470 *sock=ret; | |
471 return(1); | |
472 } | |
473 | |
474 int extract_host_port(char *str, char **host_ptr, unsigned char *ip, | |
475 short *port_ptr) | |
476 { | |
477 char *h,*p; | |
478 | |
479 h=str; | |
480 p=strchr(str,':'); | |
481 if (p == NULL) | |
482 { | |
483 BIO_printf(bio_err,"no port defined\n"); | |
484 return(0); | |
485 } | |
486 *(p++)='\0'; | |
487 | |
488 if ((ip != NULL) && !host_ip(str,ip)) | |
489 goto err; | |
490 if (host_ptr != NULL) *host_ptr=h; | |
491 | |
492 if (!extract_port(p,port_ptr)) | |
493 goto err; | |
494 return(1); | |
495 err: | |
496 return(0); | |
497 } | |
498 | |
499 static int host_ip(char *str, unsigned char ip[4]) | |
500 { | |
501 unsigned int in[4]; | |
502 int i; | |
503 | |
504 if (sscanf(str,"%u.%u.%u.%u",&(in[0]),&(in[1]),&(in[2]),&(in[3])) == 4) | |
505 { | |
506 for (i=0; i<4; i++) | |
507 if (in[i] > 255) | |
508 { | |
509 BIO_printf(bio_err,"invalid IP address\n"); | |
510 goto err; | |
511 } | |
512 ip[0]=in[0]; | |
513 ip[1]=in[1]; | |
514 ip[2]=in[2]; | |
515 ip[3]=in[3]; | |
516 } | |
517 else | |
518 { /* do a gethostbyname */ | |
519 struct hostent *he; | |
520 | |
521 if (!ssl_sock_init()) return(0); | |
522 | |
523 he=GetHostByName(str); | |
524 if (he == NULL) | |
525 { | |
526 BIO_printf(bio_err,"gethostbyname failure\n"); | |
527 goto err; | |
528 } | |
529 /* cast to short because of win16 winsock definition */ | |
530 if ((short)he->h_addrtype != AF_INET) | |
531 { | |
532 BIO_printf(bio_err,"gethostbyname addr is not AF_INET\n"
); | |
533 return(0); | |
534 } | |
535 ip[0]=he->h_addr_list[0][0]; | |
536 ip[1]=he->h_addr_list[0][1]; | |
537 ip[2]=he->h_addr_list[0][2]; | |
538 ip[3]=he->h_addr_list[0][3]; | |
539 } | |
540 return(1); | |
541 err: | |
542 return(0); | |
543 } | |
544 | |
545 int extract_port(char *str, short *port_ptr) | |
546 { | |
547 int i; | |
548 struct servent *s; | |
549 | |
550 i=atoi(str); | |
551 if (i != 0) | |
552 *port_ptr=(unsigned short)i; | |
553 else | |
554 { | |
555 s=getservbyname(str,"tcp"); | |
556 if (s == NULL) | |
557 { | |
558 BIO_printf(bio_err,"getservbyname failure for %s\n",str)
; | |
559 return(0); | |
560 } | |
561 *port_ptr=ntohs((unsigned short)s->s_port); | |
562 } | |
563 return(1); | |
564 } | |
565 | |
566 #define GHBN_NUM 4 | |
567 static struct ghbn_cache_st | |
568 { | |
569 char name[128]; | |
570 struct hostent ent; | |
571 unsigned long order; | |
572 } ghbn_cache[GHBN_NUM]; | |
573 | |
574 static unsigned long ghbn_hits=0L; | |
575 static unsigned long ghbn_miss=0L; | |
576 | |
577 static struct hostent *GetHostByName(char *name) | |
578 { | |
579 struct hostent *ret; | |
580 int i,lowi=0; | |
581 unsigned long low= (unsigned long)-1; | |
582 | |
583 for (i=0; i<GHBN_NUM; i++) | |
584 { | |
585 if (low > ghbn_cache[i].order) | |
586 { | |
587 low=ghbn_cache[i].order; | |
588 lowi=i; | |
589 } | |
590 if (ghbn_cache[i].order > 0) | |
591 { | |
592 if (strncmp(name,ghbn_cache[i].name,128) == 0) | |
593 break; | |
594 } | |
595 } | |
596 if (i == GHBN_NUM) /* no hit*/ | |
597 { | |
598 ghbn_miss++; | |
599 ret=gethostbyname(name); | |
600 if (ret == NULL) return(NULL); | |
601 /* else add to cache */ | |
602 if(strlen(name) < sizeof ghbn_cache[0].name) | |
603 { | |
604 strcpy(ghbn_cache[lowi].name,name); | |
605 memcpy((char *)&(ghbn_cache[lowi].ent),ret,sizeof(struct
hostent)); | |
606 ghbn_cache[lowi].order=ghbn_miss+ghbn_hits; | |
607 } | |
608 return(ret); | |
609 } | |
610 else | |
611 { | |
612 ghbn_hits++; | |
613 ret= &(ghbn_cache[i].ent); | |
614 ghbn_cache[i].order=ghbn_miss+ghbn_hits; | |
615 return(ret); | |
616 } | |
617 } | |
618 | |
619 #endif | |
OLD | NEW |