2 * Copyright (c) 1999-2002 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.1 (the "License"). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
14 * The Original Code and all software distributed under the License are
15 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
22 * @APPLE_LICENSE_HEADER_END@
25 * Services file lookup
26 * Copyright (C) 1989 by NeXT, Inc.
29 #include <mach/mach.h>
33 #include <netinet/in.h>
37 #define SERVICE_CACHE_SIZE 10
39 static pthread_mutex_t _service_cache_lock
= PTHREAD_MUTEX_INITIALIZER
;
40 static void *_service_cache
[SERVICE_CACHE_SIZE
] = { NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
};
41 static unsigned int _service_cache_index
= 0;
42 static unsigned int _service_cache_init
= 0;
44 static pthread_mutex_t _service_lock
= PTHREAD_MUTEX_INITIALIZER
;
50 extern struct servent
*_old_getservbyport();
51 extern struct servent
*_old_getservbyname();
52 extern struct servent
*_old_getservent();
53 extern void _old_setservent();
54 extern void _old_endservent();
55 extern void _old_setservfile();
57 #define ENTRY_SIZE sizeof(struct servent)
58 #define ENTRY_KEY _li_data_key_service
60 static struct servent
*
61 copy_service(struct servent
*in
)
63 if (in
== NULL
) return NULL
;
65 return LI_ils_create("s*4s", in
->s_name
, in
->s_aliases
, in
->s_port
, in
->s_proto
);
69 * Extract the next service entry from a kvarray.
72 extract_service(kvarray_t
*in
)
75 uint32_t d
, k
, kcount
;
78 if (in
== NULL
) return NULL
;
83 if (d
>= in
->count
) return NULL
;
86 memset(&tmp
, 0, ENTRY_SIZE
);
88 kcount
= in
->dict
[d
].kcount
;
90 for (k
= 0; k
< kcount
; k
++)
92 if (!strcmp(in
->dict
[d
].key
[k
], "s_name"))
94 if (tmp
.s_name
!= NULL
) continue;
95 if (in
->dict
[d
].vcount
[k
] == 0) continue;
97 tmp
.s_name
= (char *)in
->dict
[d
].val
[k
][0];
99 else if (!strcmp(in
->dict
[d
].key
[k
], "s_aliases"))
101 if (tmp
.s_aliases
!= NULL
) continue;
102 if (in
->dict
[d
].vcount
[k
] == 0) continue;
104 tmp
.s_aliases
= (char **)in
->dict
[d
].val
[k
];
106 else if (!strcmp(in
->dict
[d
].key
[k
], "s_port"))
108 if (in
->dict
[d
].vcount
[k
] == 0) continue;
109 tmp
.s_port
= htons(atoi(in
->dict
[d
].val
[k
][0]));
111 else if (!strcmp(in
->dict
[d
].key
[k
], "s_proto"))
113 if (tmp
.s_proto
!= NULL
) continue;
114 if (in
->dict
[d
].vcount
[k
] == 0) continue;
116 tmp
.s_proto
= (char *)in
->dict
[d
].val
[k
][0];
120 if (tmp
.s_name
== NULL
) tmp
.s_name
= "";
121 if (tmp
.s_proto
== NULL
) tmp
.s_proto
= "";
122 if (tmp
.s_aliases
== NULL
) tmp
.s_aliases
= empty
;
124 return copy_service(&tmp
);
128 cache_service(struct servent
*s
)
130 struct servent
*scache
;
132 if (s
== NULL
) return;
134 pthread_mutex_lock(&_service_cache_lock
);
136 scache
= copy_service(s
);
138 if (_service_cache
[_service_cache_index
] != NULL
) LI_ils_free(_service_cache
[_service_cache_index
], ENTRY_SIZE
);
139 _service_cache
[_service_cache_index
] = scache
;
140 _service_cache_index
= (_service_cache_index
+ 1) % SERVICE_CACHE_SIZE
;
142 _service_cache_init
= 1;
144 pthread_mutex_unlock(&_service_cache_lock
);
148 service_cache_check()
152 /* don't consult cache if it has not been initialized */
153 if (_service_cache_init
== 0) return 1;
155 status
= LI_L1_cache_check(ENTRY_KEY
);
157 /* don't consult cache if it is disabled or if we can't validate */
158 if ((status
== LI_L1_CACHE_DISABLED
) || (status
== LI_L1_CACHE_FAILED
)) return 1;
160 /* return 0 if cache is OK */
161 if (status
== LI_L1_CACHE_OK
) return 0;
164 pthread_mutex_lock(&_service_cache_lock
);
166 for (i
= 0; i
< SERVICE_CACHE_SIZE
; i
++)
168 LI_ils_free(_service_cache
[i
], ENTRY_SIZE
);
169 _service_cache
[i
] = NULL
;
172 _service_cache_index
= 0;
174 pthread_mutex_unlock(&_service_cache_lock
);
176 /* don't consult cache - it's now empty */
181 static struct servent
*
182 cache_getservbyname(const char *name
, const char *proto
)
185 struct servent
*s
, *res
;
188 if (name
== NULL
) return NULL
;
189 if (service_cache_check() != 0) return NULL
;
191 pthread_mutex_lock(&_service_cache_lock
);
193 for (i
= 0; i
< SERVICE_CACHE_SIZE
; i
++)
195 s
= (struct servent
*)_service_cache
[i
];
196 if (s
== NULL
) continue;
198 if (s
->s_name
!= NULL
)
200 if (!strcmp(name
, s
->s_name
))
202 if ((proto
== NULL
) || ((s
->s_proto
!= NULL
) && (!strcmp(proto
, s
->s_proto
))))
204 res
= copy_service(s
);
205 pthread_mutex_unlock(&_service_cache_lock
);
211 aliases
= s
->s_aliases
;
214 pthread_mutex_unlock(&_service_cache_lock
);
218 for (; *aliases
!= NULL
; *aliases
++)
220 if (!strcmp(name
, *aliases
))
222 if ((proto
== NULL
) || ((s
->s_proto
!= NULL
) && (!strcmp(proto
, s
->s_proto
))))
224 res
= copy_service(s
);
225 pthread_mutex_unlock(&_service_cache_lock
);
232 pthread_mutex_unlock(&_service_cache_lock
);
236 static struct servent
*
237 cache_getservbyport(int port
, const char *proto
)
240 struct servent
*s
, *res
;
242 if (service_cache_check() != 0) return NULL
;
244 pthread_mutex_lock(&_service_cache_lock
);
246 for (i
= 0; i
< SERVICE_CACHE_SIZE
; i
++)
248 s
= (struct servent
*)_service_cache
[i
];
249 if (s
== NULL
) continue;
251 if (port
== s
->s_port
)
253 if ((proto
== NULL
) || ((s
->s_proto
!= NULL
) && (!strcmp(proto
, s
->s_proto
))))
255 res
= copy_service(s
);
256 pthread_mutex_unlock(&_service_cache_lock
);
262 pthread_mutex_unlock(&_service_cache_lock
);
266 static struct servent
*
267 ds_getservbyport(int port
, const char *proto
)
269 struct servent
*entry
;
272 kern_return_t status
;
273 static int proc
= -1;
279 status
= LI_DSLookupGetProcedureNumber("getservbyport", &proc
);
280 if (status
!= KERN_SUCCESS
) return NULL
;
284 if (proto
== NULL
) proto
= "";
287 snprintf(val
, sizeof(val
), "%d", ntohs(sport
));
289 request
= kvbuf_query("ksks", "port", val
, "proto", proto
);
290 if (request
== NULL
) return NULL
;
293 status
= LI_DSLookupQuery(proc
, request
, &reply
);
296 if (status
!= KERN_SUCCESS
) return NULL
;
298 entry
= extract_service(reply
);
304 static struct servent
*
305 ds_getservbyname(const char *name
, const char *proto
)
307 struct servent
*entry
;
310 kern_return_t status
;
311 static int proc
= -1;
315 status
= LI_DSLookupGetProcedureNumber("getservbyname", &proc
);
316 if (status
!= KERN_SUCCESS
) return NULL
;
320 if (name
== NULL
) name
= "";
321 if (proto
== NULL
) proto
= "";
323 request
= kvbuf_query("ksks", "name", name
, "proto", proto
);
324 if (request
== NULL
) return NULL
;
327 status
= LI_DSLookupQuery(proc
, request
, &reply
);
330 if (status
!= KERN_SUCCESS
) return NULL
;
332 entry
= extract_service(reply
);
341 LI_data_free_kvarray(LI_data_find_key(ENTRY_KEY
));
350 static struct servent
*
353 static int proc
= -1;
355 return (struct servent
*)LI_getent("getservent", &proc
, extract_service
, ENTRY_KEY
, ENTRY_SIZE
);
358 static struct servent
*
359 getserv(const char *name
, const char *proto
, int port
, int source
)
361 struct servent
*res
= NULL
;
362 struct li_thread_info
*tdata
;
365 tdata
= LI_data_create_key(ENTRY_KEY
, ENTRY_SIZE
);
366 if (tdata
== NULL
) return NULL
;
374 res
= cache_getservbyname(name
, proto
);
377 res
= cache_getservbyport(port
, proto
);
385 else if (_ds_running())
390 res
= ds_getservbyname(name
, proto
);
393 res
= ds_getservbyport(port
, proto
);
396 res
= ds_getservent();
401 if (res
!= NULL
) add_to_cache
= 1;
405 pthread_mutex_lock(&_service_lock
);
409 res
= copy_service(_old_getservbyname(name
, proto
));
412 res
= copy_service(_old_getservbyport(port
, proto
));
415 res
= copy_service(_old_getservent());
419 pthread_mutex_unlock(&_service_lock
);
422 if (add_to_cache
== 1) cache_service(res
);
424 LI_data_recycle(tdata
, res
, ENTRY_SIZE
);
425 return (struct servent
*)tdata
->li_entry
;
429 getservbyport(int port
, const char *proto
)
431 return getserv(NULL
, proto
, port
, S_GET_PORT
);
435 getservbyname(const char *name
, const char *proto
)
437 return getserv(name
, proto
, 0, S_GET_NAME
);
443 return getserv(NULL
, NULL
, 0, S_GET_ENT
);
447 setservent(int stayopen
)
449 if (_ds_running()) ds_setservent();
450 else _old_setservent();
456 if (_ds_running()) ds_endservent();
457 else _old_endservent();