2 * Copyright (c) 2004-2012 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
24 #include <TargetConditionals.h>
26 #if TARGET_IPHONE_SIMULATOR
30 #include <sys/types.h>
32 #include <sys/socket.h>
33 #include <netinet/in.h>
34 #include <netinet/tcp.h>
35 #include <arpa/inet.h>
49 #define forever for(;;)
51 #define MY_ID "remote"
53 #define LOCKDOWN_PATH "/var/run/lockdown"
54 #define SYSLOG_SOCK_PATH "/var/run/lockdown/syslog.sock"
55 #define ASL_REMOTE_PORT 203
61 #define WATCH_LOCKDOWN_START 1
64 #define SESSION_FLAGS_LOCKDOWN 0x00000001
72 static dispatch_source_t in_src_local
;
73 static dispatch_source_t in_src_tcp
;
74 static dispatch_queue_t in_queue
;
77 typedef uint32_t notify_state_t
;
78 extern int notify_set_state(int, notify_state_t
);
80 typedef uint64_t notify_state_t
;
83 extern char *asl_list_to_string(asl_search_result_t
*list
, uint32_t *outlen
);
84 extern size_t asl_memory_size(asl_memory_t
*s
);
85 extern uint32_t db_query(aslresponse query
, aslresponse
*res
, uint64_t startid
, int count
, int flags
, uint64_t *lastid
, int32_t ruid
, int32_t rgid
, int raccess
);
87 extern void add_lockdown_session(int fd
);
88 extern void remove_lockdown_session(int fd
);
90 #define SESSION_WRITE(f,x) if (write(f, x, strlen(x)) < 0) goto exit_session
99 remote_db_size(uint32_t sel
)
101 if (sel
== DB_TYPE_FILE
) return global
.db_file_max
;
102 if (sel
== DB_TYPE_MEMORY
) return global
.db_memory_max
;
103 if (sel
== DB_TYPE_MINI
) return global
.db_mini_max
;
108 remote_db_set_size(uint32_t sel
, uint32_t size
)
110 if (sel
== DB_TYPE_FILE
) global
.db_file_max
= size
;
111 if (sel
== DB_TYPE_MEMORY
) global
.db_memory_max
= size
;
112 if (sel
== DB_TYPE_MINI
) global
.db_mini_max
= size
;
117 remote_db_stats(uint32_t sel
)
122 if (sel
== DB_TYPE_FILE
) asl_store_statistics(global
.file_db
, &m
);
123 if (sel
== DB_TYPE_MEMORY
) asl_memory_statistics(global
.memory_db
, &m
);
124 if (sel
== DB_TYPE_MINI
) asl_mini_memory_statistics(global
.mini_db
, &m
);
131 int i
, s
, wfd
, status
, pfmt
, watch
, wtoken
, nfd
, do_prompt
;
133 asl_search_result_t ql
;
138 char str
[1024], *p
, *qs
, *out
;
140 fd_set readfds
, errfds
;
141 uint64_t low_id
, high_id
;
142 uint32_t dbselect
, flags
;
145 if (x
== NULL
) pthread_exit(NULL
);
147 sp
= (session_args_t
*)x
;
152 asldebug("%s %d: starting interactive session for %ssocket %d\n", MY_ID
, s
, (flags
& SESSION_FLAGS_LOCKDOWN
) ? "lockdown " : "", s
);
160 if (global
.dbtype
& DB_TYPE_MEMORY
) dbselect
= DB_TYPE_MEMORY
;
161 else if (global
.dbtype
& DB_TYPE_MINI
) dbselect
= DB_TYPE_MINI
;
162 else if (global
.dbtype
& DB_TYPE_FILE
) dbselect
= DB_TYPE_FILE
;
169 memset(&ql
, 0, sizeof(asl_search_result_t
));
171 if (flags
& SESSION_FLAGS_LOCKDOWN
) sleep(1);
173 snprintf(str
, sizeof(str
), "\n========================\nASL is here to serve you\n");
174 if (write(s
, str
, strlen(str
)) < 0)
181 if (flags
& SESSION_FLAGS_LOCKDOWN
)
183 snprintf(str
, sizeof(str
), "> ");
184 SESSION_WRITE(s
, str
);
189 if (((flags
& SESSION_FLAGS_LOCKDOWN
) == 0) && (do_prompt
> 0))
191 snprintf(str
, sizeof(str
), "> ");
192 SESSION_WRITE(s
, str
);
197 memset(str
, 0, sizeof(str
));
207 FD_SET(wfd
, &readfds
);
208 if (wfd
> nfd
) nfd
= wfd
;
211 status
= select(nfd
+ 1, &readfds
, NULL
, &errfds
, NULL
);
212 if (status
== 0) continue;
215 asldebug("%s %d: select %d %s\n", MY_ID
, s
, errno
, strerror(errno
));
219 if (FD_ISSET(s
, &errfds
))
221 asldebug("%s %d: error on socket %d\n", MY_ID
, s
, s
);
225 if ((wfd
!= -1) && (FD_ISSET(wfd
, &readfds
)))
227 (void)read(wfd
, &i
, sizeof(int));
230 if (FD_ISSET(s
, &errfds
))
232 asldebug("%s %d: socket %d reported error\n", MY_ID
, s
, s
);
236 if (FD_ISSET(s
, &readfds
))
238 len
= read(s
, str
, sizeof(str
) - 1);
241 asldebug("%s %d: read error on socket %d: %d %s\n", MY_ID
, s
, s
, errno
, strerror(errno
));
245 while ((len
> 1) && ((str
[len
- 1] == '\n') || (str
[len
- 1] == '\r')))
251 if ((!strcmp(str
, "q")) || (!strcmp(str
, "quit")) || (!strcmp(str
, "exit")))
253 snprintf(str
, sizeof(str
), "Goodbye\n");
254 write(s
, str
, strlen(str
));
260 if ((!strcmp(str
, "?")) || (!strcmp(str
, "help")))
262 snprintf(str
, sizeof(str
), "Commands\n");
263 SESSION_WRITE(s
, str
);
264 snprintf(str
, sizeof(str
), " quit exit session\n");
265 SESSION_WRITE(s
, str
);
266 snprintf(str
, sizeof(str
), " select [val] get [set] current database\n");
267 SESSION_WRITE(s
, str
);
268 snprintf(str
, sizeof(str
), " val must be \"file\", \"mem\", or \"mini\"\n");
269 SESSION_WRITE(s
, str
);
270 snprintf(str
, sizeof(str
), " file [on/off] enable / disable file store\n");
271 SESSION_WRITE(s
, str
);
272 snprintf(str
, sizeof(str
), " memory [on/off] enable / disable memory store\n");
273 SESSION_WRITE(s
, str
);
274 snprintf(str
, sizeof(str
), " mini [on/off] enable / disable mini memory store\n");
275 SESSION_WRITE(s
, str
);
276 snprintf(str
, sizeof(str
), " stats database statistics\n");
277 SESSION_WRITE(s
, str
);
278 snprintf(str
, sizeof(str
), " flush flush database\n");
279 SESSION_WRITE(s
, str
);
280 snprintf(str
, sizeof(str
), " dbsize [val] get [set] database size (# of records)\n");
281 SESSION_WRITE(s
, str
);
282 snprintf(str
, sizeof(str
), " watch print new messages as they arrive\n");
283 SESSION_WRITE(s
, str
);
284 snprintf(str
, sizeof(str
), " stop stop watching for new messages\n");
285 SESSION_WRITE(s
, str
);
286 snprintf(str
, sizeof(str
), " raw use raw format for printing messages\n");
287 SESSION_WRITE(s
, str
);
288 snprintf(str
, sizeof(str
), " std use standard format for printing messages\n");
289 SESSION_WRITE(s
, str
);
290 snprintf(str
, sizeof(str
), " * show all log messages\n");
291 SESSION_WRITE(s
, str
);
292 snprintf(str
, sizeof(str
), " * key val equality search for messages (single key/value pair)\n");
293 SESSION_WRITE(s
, str
);
294 snprintf(str
, sizeof(str
), " * op key val search for matching messages (single key/value pair)\n");
295 SESSION_WRITE(s
, str
);
296 snprintf(str
, sizeof(str
), " * [op key val] ... search for matching messages (multiple key/value pairs)\n");
297 SESSION_WRITE(s
, str
);
298 snprintf(str
, sizeof(str
), " operators: = < > ! (not equal) T (key exists) R (regex)\n");
299 SESSION_WRITE(s
, str
);
300 snprintf(str
, sizeof(str
), " modifiers (must follow operator):\n");
301 SESSION_WRITE(s
, str
);
302 snprintf(str
, sizeof(str
), " C=casefold N=numeric S=substring A=prefix Z=suffix\n");
303 SESSION_WRITE(s
, str
);
304 snprintf(str
, sizeof(str
), "\n");
305 SESSION_WRITE(s
, str
);
308 else if (!strcmp(str
, "stats"))
310 stats
= remote_db_stats(dbselect
);
311 out
= asl_format_message((asl_msg_t
*)stats
, ASL_MSG_FMT_RAW
, ASL_TIME_FMT_SEC
, ASL_ENCODE_NONE
, &outlen
);
312 write(s
, out
, outlen
);
317 else if (!strcmp(str
, "flush"))
319 else if (!strncmp(str
, "select", 6))
322 while ((*p
== ' ') || (*p
== '\t')) p
++;
325 if (dbselect
== 0) snprintf(str
, sizeof(str
), "no store\n");
326 else if (dbselect
== DB_TYPE_FILE
) snprintf(str
, sizeof(str
), "file store\n");
327 else if (dbselect
== DB_TYPE_MEMORY
) snprintf(str
, sizeof(str
), "memory store\n");
328 else if (dbselect
== DB_TYPE_MINI
) snprintf(str
, sizeof(str
), "mini memory store\n");
329 SESSION_WRITE(s
, str
);
333 if (!strncmp(p
, "file", 4))
335 if ((global
.dbtype
& DB_TYPE_FILE
) == 0)
337 snprintf(str
, sizeof(str
), "file database is not enabled\n");
338 SESSION_WRITE(s
, str
);
342 dbselect
= DB_TYPE_FILE
;
344 else if (!strncmp(p
, "mem", 3))
346 if ((global
.dbtype
& DB_TYPE_MEMORY
) == 0)
348 snprintf(str
, sizeof(str
), "memory database is not enabled\n");
349 SESSION_WRITE(s
, str
);
353 dbselect
= DB_TYPE_MEMORY
;
355 else if (!strncmp(p
, "mini", 4))
357 if ((global
.dbtype
& DB_TYPE_MINI
) == 0)
359 if (global
.mini_db
!= NULL
)
361 snprintf(str
, sizeof(str
), "mini memory database is enabled for disaster messages\n");
362 SESSION_WRITE(s
, str
);
366 snprintf(str
, sizeof(str
), "mini memory database is not enabled\n");
367 SESSION_WRITE(s
, str
);
372 dbselect
= DB_TYPE_MINI
;
376 snprintf(str
, sizeof(str
), "unknown database type\n");
377 SESSION_WRITE(s
, str
);
381 snprintf(str
, sizeof(str
), "OK\n");
382 SESSION_WRITE(s
, str
);
385 else if (!strncmp(str
, "file", 4))
388 while ((*p
== ' ') || (*p
== '\t')) p
++;
391 snprintf(str
, sizeof(str
), "file database is %senabled\n", (global
.dbtype
& DB_TYPE_FILE
) ? "" : "not ");
392 SESSION_WRITE(s
, str
);
393 if ((global
.dbtype
& DB_TYPE_FILE
) != 0) dbselect
= DB_TYPE_FILE
;
397 if (!strcmp(p
, "on")) global
.dbtype
|= DB_TYPE_FILE
;
398 else if (!strcmp(p
, "off")) global
.dbtype
&= ~ DB_TYPE_FILE
;
400 snprintf(str
, sizeof(str
), "OK\n");
401 SESSION_WRITE(s
, str
);
404 else if (!strncmp(str
, "memory", 6))
407 while ((*p
== ' ') || (*p
== '\t')) p
++;
410 snprintf(str
, sizeof(str
), "memory database is %senabled\n", (global
.dbtype
& DB_TYPE_MEMORY
) ? "" : "not ");
411 SESSION_WRITE(s
, str
);
412 if ((global
.dbtype
& DB_TYPE_MEMORY
) != 0) dbselect
= DB_TYPE_MEMORY
;
416 if (!strcmp(p
, "on")) global
.dbtype
|= DB_TYPE_MEMORY
;
417 else if (!strcmp(p
, "off")) global
.dbtype
&= ~ DB_TYPE_MEMORY
;
419 snprintf(str
, sizeof(str
), "OK\n");
420 SESSION_WRITE(s
, str
);
423 else if (!strncmp(str
, "mini", 4))
426 while ((*p
== ' ') || (*p
== '\t')) p
++;
429 snprintf(str
, sizeof(str
), "mini database is %senabled\n", (global
.dbtype
& DB_TYPE_MINI
) ? "" : "not ");
430 SESSION_WRITE(s
, str
);
431 if ((global
.dbtype
& DB_TYPE_MINI
) != 0) dbselect
= DB_TYPE_MINI
;
435 if (!strcmp(p
, "on")) global
.dbtype
|= DB_TYPE_MINI
;
436 else if (!strcmp(p
, "off")) global
.dbtype
&= ~ DB_TYPE_MINI
;
438 snprintf(str
, sizeof(str
), "OK\n");
439 SESSION_WRITE(s
, str
);
442 else if (!strncmp(str
, "dbsize", 6))
446 snprintf(str
, sizeof(str
), "no store\n");
447 SESSION_WRITE(s
, str
);
452 while ((*p
== ' ') || (*p
== '\t')) p
++;
455 snprintf(str
, sizeof(str
), "DB size %u\n", remote_db_size(dbselect
));
456 SESSION_WRITE(s
, str
);
461 remote_db_set_size(dbselect
, i
);
463 snprintf(str
, sizeof(str
), "OK\n");
464 SESSION_WRITE(s
, str
);
467 else if (!strcmp(str
, "stop"))
469 if (watch
!= WATCH_OFF
)
472 notify_cancel(wtoken
);
479 if (query
!= NULL
) free(query
);
482 snprintf(str
, sizeof(str
), "OK\n");
483 SESSION_WRITE(s
, str
);
487 snprintf(str
, sizeof(str
), "not watching!\n");
488 SESSION_WRITE(s
, str
);
491 else if (!strcmp(str
, "raw"))
496 else if (!strcmp(str
, "std"))
501 else if (!strcmp(str
, "watch"))
503 if (((flags
& SESSION_FLAGS_LOCKDOWN
) == 0) && (watch
!= WATCH_OFF
))
505 snprintf(str
, sizeof(str
), "already watching!\n");
506 SESSION_WRITE(s
, str
);
510 if (flags
& SESSION_FLAGS_LOCKDOWN
)
513 * If this session is PurpleConsole or Xcode watching for log messages,
514 * we pass through the bottom of the loop (below) once to pick up
515 * existing messages already in memory. After that, dbserver will
516 * send new messages in send_to_direct_watchers(). We wait until
517 * the initial messages are sent before adding the connection to
518 * global.lockdown_session_fds to allow this query to complete before
519 * dbserver starts sending. To prevent a race between this query and
520 * when messages are sent by send_to_direct_watchers, we suspend the
521 * work queue and resume it when lockdown_session_fds has been updated.
523 watch
= WATCH_LOCKDOWN_START
;
524 dispatch_suspend(global
.work_queue
);
528 status
= notify_register_file_descriptor(kNotifyASLDBUpdate
, &wfd
, 0, &wtoken
);
531 snprintf(str
, sizeof(str
), "notify_register_file_descriptor failed: %d\n", status
);
532 SESSION_WRITE(s
, str
);
539 snprintf(str
, sizeof(str
), "OK\n");
540 SESSION_WRITE(s
, str
);
543 else if ((str
[0] == '*') || (str
[0] == 'T') || (str
[0] == '=') || (str
[0] == '!') || (str
[0] == '<') || (str
[0] == '>'))
545 memset(&ql
, 0, sizeof(asl_search_result_t
));
546 if (query
!= NULL
) free(query
);
551 while ((*p
== ' ') || (*p
== '\t')) p
++;
560 asprintf(&qs
, "Q %s", p
);
561 query
= asl_msg_from_string(qs
);
564 else if ((*p
== 'T') || (*p
== '=') || (*p
== '!') || (*p
== '<') || (*p
== '>') || (*p
== 'R'))
567 asprintf(&qs
, "Q [%s]", p
);
568 query
= asl_msg_from_string(qs
);
574 asprintf(&qs
, "Q [= %s]", p
);
575 query
= asl_msg_from_string(qs
);
581 snprintf(str
, sizeof(str
), "unrecognized command\n");
582 SESSION_WRITE(s
, str
);
583 snprintf(str
, sizeof(str
), "enter \"help\" for help\n");
584 SESSION_WRITE(s
, str
);
589 if ((flags
& SESSION_FLAGS_LOCKDOWN
) && (watch
== WATCH_RUN
)) continue;
591 /* Bottom of the loop: do a database query and print the results */
600 if (watch
== WATCH_OFF
) low_id
= 0;
602 memset(&res
, 0, sizeof(aslresponse
));
604 (void)db_query(&ql
, (aslresponse
*)&res
, low_id
, 0, 0, &high_id
, 0, 0, 0);
606 if ((watch
== WATCH_RUN
) && (high_id
>= low_id
)) low_id
= high_id
+ 1;
610 if (watch
== WATCH_OFF
)
612 snprintf(str
, sizeof(str
), "-nil-\n");
613 SESSION_WRITE(s
, str
);
617 if (do_prompt
!= 2) do_prompt
= 0;
620 else if (pfmt
== PRINT_RAW
)
622 if (watch
== WATCH_RUN
)
624 snprintf(str
, sizeof(str
), "\n");
625 SESSION_WRITE(s
, str
);
629 out
= asl_list_to_string((asl_search_result_t
*)res
, &outlen
);
630 write(s
, out
, outlen
);
633 snprintf(str
, sizeof(str
), "\n");
634 SESSION_WRITE(s
, str
);
638 if ((watch
== WATCH_RUN
) || (watch
== WATCH_LOCKDOWN_START
))
640 snprintf(str
, sizeof(str
), "\n");
641 SESSION_WRITE(s
, str
);
644 snprintf(str
, sizeof(str
), "\n");
645 for (i
= 0; i
< res
->count
; i
++)
649 out
= asl_format_message(res
->msg
[i
], ASL_MSG_FMT_STD
, ASL_TIME_FMT_LCL
, ASL_ENCODE_SAFE
, &outlen
);
656 wstatus
= write(s
, out
, outlen
);
659 asldebug("%s %d: %d/%d write data failed: %d %s\n", MY_ID
, s
, i
, res
->count
, errno
, strerror(errno
));
671 } while (errno
== EAGAIN
);
674 if (global
.remote_delay_time
> 0) usleep(global
.remote_delay_time
);
678 aslresponse_free(res
);
680 if (watch
== WATCH_LOCKDOWN_START
)
682 add_lockdown_session(s
);
684 dispatch_resume(global
.work_queue
);
690 asldebug("%s %d: terminating session for %ssocket %d\n", MY_ID
, s
, (flags
& SESSION_FLAGS_LOCKDOWN
) ? "lockdown " : "", s
);
694 if (flags
& SESSION_FLAGS_LOCKDOWN
) remove_lockdown_session(s
);
698 if (watch
== WATCH_LOCKDOWN_START
) dispatch_resume(global
.work_queue
);
699 if (wtoken
>= 0) notify_cancel(wtoken
);
700 if (query
!= NULL
) asl_msg_release(query
);
705 remote_acceptmsg(int fd
, int tcp
)
708 int s
, flags
, status
, v
;
711 struct sockaddr_storage from
;
714 fromlen
= sizeof(struct sockaddr_un
);
715 if (tcp
== 1) fromlen
= sizeof(struct sockaddr_storage
);
717 memset(&from
, 0, sizeof(from
));
719 s
= accept(fd
, (struct sockaddr
*)&from
, &fromlen
);
722 asldebug("%s: accept: %s\n", MY_ID
, strerror(errno
));
726 flags
= fcntl(s
, F_GETFL
, 0);
727 flags
&= ~ O_NONBLOCK
;
728 status
= fcntl(s
, F_SETFL
, flags
);
731 asldebug("%s: fcntl: %s\n", MY_ID
, strerror(errno
));
737 setsockopt(s
, SOL_SOCKET
, SO_NOSIGPIPE
, &v
, sizeof(v
));
742 setsockopt(s
, IPPROTO_TCP
, TCP_NODELAY
, &flags
, sizeof(int));
745 sp
= (session_args_t
*)calloc(1, sizeof(session_args_t
));
748 asldebug("%s: malloc: %s\n", MY_ID
, strerror(errno
));
754 if (tcp
== 0) sp
->flags
|= SESSION_FLAGS_LOCKDOWN
;
756 pthread_attr_init(&attr
);
757 pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
758 pthread_create(&t
, &attr
, (void *(*)(void *))session
, (void *)sp
);
759 pthread_attr_destroy(&attr
);
765 remote_acceptmsg_local(int fd
)
767 return remote_acceptmsg(fd
, 0);
771 remote_acceptmsg_tcp(int fd
)
773 return remote_acceptmsg(fd
, 1);
777 remote_init_lockdown(void)
779 int status
, reuse
, fd
;
780 struct sockaddr_un local
;
782 fd
= socket(AF_UNIX
, SOCK_STREAM
, 0);
785 asldebug("%s: socket: %s\n", MY_ID
, strerror(errno
));
790 status
= setsockopt(fd
, SOL_SOCKET
, SO_REUSEPORT
, &reuse
, sizeof(int));
793 asldebug("%s: setsockopt: %s\n", MY_ID
, strerror(errno
));
798 /* make sure the lockdown directory exists */
799 mkdir(LOCKDOWN_PATH
, 0777);
801 memset(&local
, 0, sizeof(local
));
802 local
.sun_family
= AF_UNIX
;
803 strlcpy(local
.sun_path
, SYSLOG_SOCK_PATH
, sizeof(local
.sun_path
));
804 unlink(local
.sun_path
);
806 status
= bind(fd
, (struct sockaddr
*)&local
, sizeof(local
.sun_family
) + sizeof(local
.sun_path
));
810 asldebug("%s: bind: %s\n", MY_ID
, strerror(errno
));
815 status
= fcntl(fd
, F_SETFL
, O_NONBLOCK
);
818 asldebug("%s: fcntl: %s\n", MY_ID
, strerror(errno
));
823 status
= listen(fd
, 5);
826 asldebug("%s: listen: %s\n", MY_ID
, strerror(errno
));
831 chmod(SYSLOG_SOCK_PATH
, 0666);
833 in_src_local
= dispatch_source_create(DISPATCH_SOURCE_TYPE_READ
, (uintptr_t)fd
, 0, in_queue
);
834 dispatch_source_set_event_handler(in_src_local
, ^{ remote_acceptmsg_local(fd
); });
835 dispatch_resume(in_src_local
);
841 remote_init_tcp(int family
)
843 int status
, reuse
, fd
;
844 struct sockaddr_in a4
;
845 struct sockaddr_in6 a6
;
849 fd
= socket(family
, SOCK_STREAM
, 0);
852 asldebug("%s: socket: %s\n", MY_ID
, strerror(errno
));
857 status
= setsockopt(fd
, SOL_SOCKET
, SO_REUSEPORT
, &reuse
, sizeof(int));
860 asldebug("%s: setsockopt: %s\n", MY_ID
, strerror(errno
));
865 memset(&(a4
.sin_addr
), 0, sizeof(struct in_addr
));
866 a4
.sin_family
= AF_INET
;
867 a4
.sin_port
= htons(ASL_REMOTE_PORT
);
869 memset(&(a6
.sin6_addr
), 0, sizeof(struct in6_addr
));
870 a6
.sin6_family
= AF_INET6
;
871 a6
.sin6_port
= htons(ASL_REMOTE_PORT
);
873 s
= (struct sockaddr
*)&a4
;
874 len
= sizeof(struct sockaddr_in
);
876 if (family
== AF_INET6
)
878 s
= (struct sockaddr
*)&a6
;
879 len
= sizeof(struct sockaddr_in6
);
882 status
= bind(fd
, s
, len
);
885 asldebug("%s: bind: %s\n", MY_ID
, strerror(errno
));
890 status
= fcntl(fd
, F_SETFL
, O_NONBLOCK
);
893 asldebug("%s: fcntl: %s\n", MY_ID
, strerror(errno
));
898 status
= listen(fd
, 5);
901 asldebug("%s: listen: %s\n", MY_ID
, strerror(errno
));
906 in_src_tcp
= dispatch_source_create(DISPATCH_SOURCE_TYPE_READ
, (uintptr_t)fd
, 0, in_queue
);
907 dispatch_source_set_event_handler(in_src_tcp
, ^{ remote_acceptmsg_tcp(fd
); });
908 dispatch_resume(in_src_tcp
);
916 static dispatch_once_t once
;
918 dispatch_once(&once
, ^{
919 in_queue
= dispatch_queue_create(MY_ID
, NULL
);
922 asldebug("%s: init\n", MY_ID
);
925 rfdl
= remote_init_lockdown();
929 rfd4
= remote_init_tcp(AF_INET
);
933 rfd6
= remote_init_tcp(AF_INET6
);
972 return remote_init();
975 #endif /* !TARGET_IPHONE_SIMULATOR */