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>
32 #include <rpc/types.h>
35 #include <netinet/in.h>
38 #include "_lu_types.h"
42 static pthread_mutex_t _service_lock
= PTHREAD_MUTEX_INITIALIZER
;
48 extern struct servent
*_old_getservbyport();
49 extern struct servent
*_old_getservbyname();
50 extern struct servent
*_old_getservent();
51 extern void _old_setservent();
52 extern void _old_endservent();
53 extern void _old_setservfile();
56 free_service_data(struct servent
*s
)
60 if (s
== NULL
) return;
62 if (s
->s_name
!= NULL
) free(s
->s_name
);
63 if (s
->s_proto
!= NULL
) free(s
->s_proto
);
65 aliases
= s
->s_aliases
;
68 while (*aliases
!= NULL
) free(*aliases
++);
74 free_service(struct servent
*s
)
76 if (s
== NULL
) return;
82 free_lu_thread_info_service(void *x
)
84 struct lu_thread_info
*tdata
;
86 if (x
== NULL
) return;
88 tdata
= (struct lu_thread_info
*)x
;
90 if (tdata
->lu_entry
!= NULL
)
92 free_service((struct servent
*)tdata
->lu_entry
);
93 tdata
->lu_entry
= NULL
;
96 _lu_data_free_vm_xdr(tdata
);
101 static struct servent
*
102 extract_service(XDR
*xdr
, const char *proto
)
105 int i
, j
, nvals
, nkeys
, status
;
108 if (xdr
== NULL
) return NULL
;
110 if (!xdr_int(xdr
, &nkeys
)) return NULL
;
112 s
= (struct servent
*)calloc(1, sizeof(struct servent
));
114 for (i
= 0; i
< nkeys
; i
++)
120 status
= _lu_xdr_attribute(xdr
, &key
, &vals
, &nvals
);
135 if ((s
->s_name
== NULL
) && (!strcmp("name", key
)))
140 s
->s_aliases
= (char **)calloc(nvals
, sizeof(char *));
141 for (j
= 1; j
< nvals
; j
++) s
->s_aliases
[j
-1] = vals
[j
];
145 else if ((s
->s_proto
== NULL
) && (!strcmp("protocol", key
)))
147 if ((proto
== NULL
) || (proto
[0] == '\0'))
149 s
->s_proto
= vals
[0];
154 s
->s_proto
= strdup(proto
);
157 else if ((s
->s_port
== 0) && (!strcmp("port", key
)))
159 s
->s_port
= htons(atoi(vals
[0]));
165 for (; j
< nvals
; j
++) free(vals
[j
]);
170 if (s
->s_name
== NULL
) s
->s_name
= strdup("");
171 if (s
->s_proto
== NULL
) s
->s_proto
= strdup("");
172 if (s
->s_aliases
== NULL
) s
->s_aliases
= (char **)calloc(1, sizeof(char *));
177 static struct servent
*
178 copy_service(struct servent
*in
)
183 if (in
== NULL
) return NULL
;
185 s
= (struct servent
*)calloc(1, sizeof(struct servent
));
187 s
->s_name
= LU_COPY_STRING(in
->s_name
);
190 if (in
->s_aliases
!= NULL
)
192 for (len
= 0; in
->s_aliases
[len
] != NULL
; len
++);
195 s
->s_aliases
= (char **)calloc(len
+ 1, sizeof(char *));
196 for (i
= 0; i
< len
; i
++)
198 s
->s_aliases
[i
] = strdup(in
->s_aliases
[i
]);
201 s
->s_proto
= LU_COPY_STRING(in
->s_proto
);
202 s
->s_port
= in
->s_port
;
208 recycle_service(struct lu_thread_info
*tdata
, struct servent
*in
)
212 if (tdata
== NULL
) return;
213 s
= (struct servent
*)tdata
->lu_entry
;
218 tdata
->lu_entry
= NULL
;
221 if (tdata
->lu_entry
== NULL
)
223 tdata
->lu_entry
= in
;
227 free_service_data(s
);
229 s
->s_name
= in
->s_name
;
230 s
->s_aliases
= in
->s_aliases
;
231 s
->s_proto
= in
->s_proto
;
232 s
->s_port
= in
->s_port
;
237 static struct servent
*
238 lu_getservbyport(int port
, const char *proto
)
241 unsigned int datalen
;
243 static int proc
= -1;
244 char output_buf
[_LU_MAXLUSTRLEN
+ 3 * BYTES_PER_XDR_UNIT
];
250 if (_lookup_link(_lu_port
, "getservbyport", &proc
) != KERN_SUCCESS
)
256 /* Encode NULL for xmission to lookupd. */
257 if (proto
== NULL
) proto
= "";
259 xdrmem_create(&outxdr
, output_buf
, sizeof(output_buf
), XDR_ENCODE
);
260 if (!xdr_int(&outxdr
, &port
) || !xdr__lu_string(&outxdr
, (_lu_string
*)&proto
))
262 xdr_destroy(&outxdr
);
269 if (_lookup_all(_lu_port
, proc
, (unit
*)output_buf
,
270 xdr_getpos(&outxdr
) / BYTES_PER_XDR_UNIT
, &lookup_buf
, &datalen
)
273 xdr_destroy(&outxdr
);
277 xdr_destroy(&outxdr
);
279 datalen
*= BYTES_PER_XDR_UNIT
;
280 if ((lookup_buf
== NULL
) || (datalen
== 0)) return NULL
;
282 xdrmem_create(&inxdr
, lookup_buf
, datalen
, XDR_DECODE
);
285 if (!xdr_int(&inxdr
, &count
))
288 vm_deallocate(mach_task_self(), (vm_address_t
)lookup_buf
, datalen
);
295 vm_deallocate(mach_task_self(), (vm_address_t
)lookup_buf
, datalen
);
300 * lookupd will only send back a reply for a service with the protocol specified
301 * if it finds a match. We pass the protocol name to extract_service, which
302 * copies the requested protocol name into the returned servent. This is a
303 * bit of a kludge, but since NetInfo / lookupd treat services as single entities
304 * with multiple protocols, we are forced to do some special-case handling.
306 s
= extract_service(&inxdr
, proto
);
308 vm_deallocate(mach_task_self(), (vm_address_t
)lookup_buf
, datalen
);
313 static struct servent
*
314 lu_getservbyname(const char *name
, const char *proto
)
317 unsigned int datalen
;
319 char output_buf
[2 * (_LU_MAXLUSTRLEN
+ BYTES_PER_XDR_UNIT
)];
321 static int proc
= -1;
326 if (_lookup_link(_lu_port
, "getservbyname", &proc
) != KERN_SUCCESS
)
332 /* Encode NULL for xmission to lookupd. */
333 if (proto
== NULL
) proto
= "";
335 xdrmem_create(&outxdr
, output_buf
, sizeof(output_buf
), XDR_ENCODE
);
336 if (!xdr__lu_string(&outxdr
, (_lu_string
*)&name
) ||
337 !xdr__lu_string(&outxdr
, (_lu_string
*)&proto
))
339 xdr_destroy(&outxdr
);
346 if (_lookup_all(_lu_port
, proc
, (unit
*)output_buf
,
347 xdr_getpos(&outxdr
) / BYTES_PER_XDR_UNIT
, &lookup_buf
, &datalen
)
350 xdr_destroy(&outxdr
);
354 xdr_destroy(&outxdr
);
356 datalen
*= BYTES_PER_XDR_UNIT
;
357 if ((lookup_buf
== NULL
) || (datalen
== 0)) return NULL
;
359 xdrmem_create(&inxdr
, lookup_buf
, datalen
, XDR_DECODE
);
362 if (!xdr_int(&inxdr
, &count
))
365 vm_deallocate(mach_task_self(), (vm_address_t
)lookup_buf
, datalen
);
372 vm_deallocate(mach_task_self(), (vm_address_t
)lookup_buf
, datalen
);
377 * lookupd will only send back a reply for a service with the protocol specified
378 * if it finds a match. We pass the protocol name to extract_service, which
379 * copies the requested protocol name into the returned servent. This is a
380 * bit of a kludge, but since NetInfo / lookupd treat services as single entities
381 * with multiple protocols, we are forced to do some special-case handling.
383 s
= extract_service(&inxdr
, proto
);
385 vm_deallocate(mach_task_self(), (vm_address_t
)lookup_buf
, datalen
);
393 struct lu_thread_info
*tdata
;
395 tdata
= _lu_data_create_key(_lu_data_key_service
, free_lu_thread_info_service
);
396 _lu_data_free_vm_xdr(tdata
);
405 static struct servent
*
409 static int proc
= -1;
410 struct lu_thread_info
*tdata
;
412 tdata
= _lu_data_create_key(_lu_data_key_service
, free_lu_thread_info_service
);
415 tdata
= (struct lu_thread_info
*)calloc(1, sizeof(struct lu_thread_info
));
416 _lu_data_set_key(_lu_data_key_service
, tdata
);
419 if (tdata
->lu_vm
== NULL
)
423 if (_lookup_link(_lu_port
, "getservent", &proc
) != KERN_SUCCESS
)
430 if (_lookup_all(_lu_port
, proc
, NULL
, 0, &(tdata
->lu_vm
), &(tdata
->lu_vm_length
)) != KERN_SUCCESS
)
436 /* mig stubs measure size in words (4 bytes) */
437 tdata
->lu_vm_length
*= 4;
439 if (tdata
->lu_xdr
!= NULL
)
441 xdr_destroy(tdata
->lu_xdr
);
444 tdata
->lu_xdr
= (XDR
*)calloc(1, sizeof(XDR
));
446 xdrmem_create(tdata
->lu_xdr
, tdata
->lu_vm
, tdata
->lu_vm_length
, XDR_DECODE
);
447 if (!xdr_int(tdata
->lu_xdr
, &tdata
->lu_vm_cursor
))
454 if (tdata
->lu_vm_cursor
== 0)
460 s
= extract_service(tdata
->lu_xdr
, NULL
);
467 tdata
->lu_vm_cursor
--;
472 static struct servent
*
473 getserv(const char *name
, const char *proto
, int port
, int source
)
475 struct servent
*res
= NULL
;
476 struct lu_thread_info
*tdata
;
478 tdata
= _lu_data_create_key(_lu_data_key_service
, free_lu_thread_info_service
);
481 tdata
= (struct lu_thread_info
*)calloc(1, sizeof(struct lu_thread_info
));
482 _lu_data_set_key(_lu_data_key_service
, tdata
);
490 res
= lu_getservbyname(name
, proto
);
493 res
= lu_getservbyport(port
, proto
);
496 res
= lu_getservent();
503 pthread_mutex_lock(&_service_lock
);
507 res
= copy_service(_old_getservbyname(name
, proto
));
510 res
= copy_service(_old_getservbyport(port
, proto
));
513 res
= copy_service(_old_getservent());
517 pthread_mutex_unlock(&_service_lock
);
520 recycle_service(tdata
, res
);
521 return (struct servent
*)tdata
->lu_entry
;
525 getservbyport(int port
, const char *proto
)
527 return getserv(NULL
, proto
, port
, S_GET_PORT
);
531 getservbyname(const char *name
, const char *proto
)
533 return getserv(name
, proto
, 0, S_GET_NAME
);
539 return getserv(NULL
, NULL
, 0, S_GET_ENT
);
543 setservent(int stayopen
)
545 if (_lu_running()) lu_setservent();
546 else _old_setservent();
552 if (_lu_running()) lu_endservent();
553 else _old_endservent();