2 * Copyright (c) 2004-2011 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 <sys/types.h>
26 #include <sys/socket.h>
27 #include <netinet/in.h>
28 #include <netinet/tcp.h>
29 #include <arpa/inet.h>
43 #define forever for(;;)
45 #define MY_ID "remote"
47 #define LOCKDOWN_PATH "/var/run/lockdown"
48 #define SYSLOG_SOCK_PATH "/var/run/lockdown/syslog.sock"
49 #define ASL_REMOTE_PORT 203
55 #define WATCH_LOCKDOWN_START 1
58 #define SESSION_FLAGS_LOCKDOWN 0x00000001
66 static dispatch_source_t in_src_local
;
67 static dispatch_source_t in_src_tcp
;
68 static dispatch_queue_t in_queue
;
71 typedef uint32_t notify_state_t
;
72 extern int notify_set_state(int, notify_state_t
);
74 typedef uint64_t notify_state_t
;
77 extern char *asl_list_to_string(asl_search_result_t
*list
, uint32_t *outlen
);
78 extern size_t asl_memory_size(asl_memory_t
*s
);
79 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
);
81 #define SESSION_WRITE(f,x) if (write(f, x, strlen(x)) < 0) goto exit_session
90 remote_db_size(uint32_t sel
)
92 if (sel
== DB_TYPE_FILE
) return global
.db_file_max
;
93 if (sel
== DB_TYPE_MEMORY
) return global
.db_memory_max
;
94 if (sel
== DB_TYPE_MINI
) return global
.db_mini_max
;
99 remote_db_set_size(uint32_t sel
, uint32_t size
)
101 if (sel
== DB_TYPE_FILE
) global
.db_file_max
= size
;
102 if (sel
== DB_TYPE_MEMORY
) global
.db_memory_max
= size
;
103 if (sel
== DB_TYPE_MINI
) global
.db_mini_max
= size
;
108 remote_db_stats(uint32_t sel
)
113 if (sel
== DB_TYPE_FILE
) asl_store_statistics(global
.file_db
, &m
);
114 if (sel
== DB_TYPE_MEMORY
) asl_memory_statistics(global
.memory_db
, &m
);
115 if (sel
== DB_TYPE_MINI
) asl_mini_memory_statistics(global
.mini_db
, &m
);
122 int i
, s
, wfd
, status
, pfmt
, watch
, wtoken
, nfd
, do_prompt
;
124 asl_search_result_t ql
;
129 char str
[1024], *p
, *qs
, *out
;
131 fd_set readfds
, errfds
;
132 uint64_t low_id
, high_id
;
133 uint32_t dbselect
, flags
;
136 if (x
== NULL
) pthread_exit(NULL
);
138 sp
= (session_args_t
*)x
;
143 asldebug("%s %d: starting interactive session for %ssocket %d\n", MY_ID
, s
, (flags
& SESSION_FLAGS_LOCKDOWN
) ? "lockdown " : "", s
);
151 if (global
.dbtype
& DB_TYPE_MEMORY
) dbselect
= DB_TYPE_MEMORY
;
152 else if (global
.dbtype
& DB_TYPE_MINI
) dbselect
= DB_TYPE_MINI
;
153 else if (global
.dbtype
& DB_TYPE_FILE
) dbselect
= DB_TYPE_FILE
;
160 memset(&ql
, 0, sizeof(asl_search_result_t
));
162 snprintf(str
, sizeof(str
), "\n========================\nASL is here to serve you\n");
163 if (write(s
, str
, strlen(str
)) < 0)
172 if (((flags
& SESSION_FLAGS_LOCKDOWN
) == 0) && (do_prompt
> 0))
174 snprintf(str
, sizeof(str
), "> ");
175 SESSION_WRITE(s
, str
);
180 memset(str
, 0, sizeof(str
));
190 FD_SET(wfd
, &readfds
);
191 if (wfd
> nfd
) nfd
= wfd
;
194 status
= select(nfd
+ 1, &readfds
, NULL
, &errfds
, NULL
);
195 if (status
== 0) continue;
198 asldebug("%s %d: select %d %s\n", MY_ID
, s
, errno
, strerror(errno
));
202 if (FD_ISSET(s
, &errfds
))
204 asldebug("%s %d: error on socket %d\n", MY_ID
, s
, s
);
208 if ((wfd
!= -1) && (FD_ISSET(wfd
, &readfds
)))
210 (void)read(wfd
, &i
, sizeof(int));
213 if (FD_ISSET(s
, &readfds
))
215 len
= read(s
, str
, sizeof(str
) - 1);
218 asldebug("%s %d: read error on socket %d: %d %s\n", MY_ID
, s
, s
, errno
, strerror(errno
));
222 while ((len
> 1) && ((str
[len
- 1] == '\n') || (str
[len
- 1] == '\r')))
228 if ((!strcmp(str
, "q")) || (!strcmp(str
, "quit")) || (!strcmp(str
, "exit")))
230 snprintf(str
, sizeof(str
), "Goodbye\n");
231 write(s
, str
, strlen(str
));
237 if ((!strcmp(str
, "?")) || (!strcmp(str
, "help")))
239 snprintf(str
, sizeof(str
), "Commands\n");
240 SESSION_WRITE(s
, str
);
241 snprintf(str
, sizeof(str
), " quit exit session\n");
242 SESSION_WRITE(s
, str
);
243 snprintf(str
, sizeof(str
), " select [val] get [set] current database\n");
244 SESSION_WRITE(s
, str
);
245 snprintf(str
, sizeof(str
), " val must be \"file\", \"mem\", or \"mini\"\n");
246 SESSION_WRITE(s
, str
);
247 snprintf(str
, sizeof(str
), " file [on/off] enable / disable file store\n");
248 SESSION_WRITE(s
, str
);
249 snprintf(str
, sizeof(str
), " memory [on/off] enable / disable memory store\n");
250 SESSION_WRITE(s
, str
);
251 snprintf(str
, sizeof(str
), " mini [on/off] enable / disable mini memory store\n");
252 SESSION_WRITE(s
, str
);
253 snprintf(str
, sizeof(str
), " stats database statistics\n");
254 SESSION_WRITE(s
, str
);
255 snprintf(str
, sizeof(str
), " flush flush database\n");
256 SESSION_WRITE(s
, str
);
257 snprintf(str
, sizeof(str
), " dbsize [val] get [set] database size (# of records)\n");
258 SESSION_WRITE(s
, str
);
259 snprintf(str
, sizeof(str
), " watch print new messages as they arrive\n");
260 SESSION_WRITE(s
, str
);
261 snprintf(str
, sizeof(str
), " stop stop watching for new messages\n");
262 SESSION_WRITE(s
, str
);
263 snprintf(str
, sizeof(str
), " raw use raw format for printing messages\n");
264 SESSION_WRITE(s
, str
);
265 snprintf(str
, sizeof(str
), " std use standard format for printing messages\n");
266 SESSION_WRITE(s
, str
);
267 snprintf(str
, sizeof(str
), " * show all log messages\n");
268 SESSION_WRITE(s
, str
);
269 snprintf(str
, sizeof(str
), " * key val equality search for messages (single key/value pair)\n");
270 SESSION_WRITE(s
, str
);
271 snprintf(str
, sizeof(str
), " * op key val search for matching messages (single key/value pair)\n");
272 SESSION_WRITE(s
, str
);
273 snprintf(str
, sizeof(str
), " * [op key val] ... search for matching messages (multiple key/value pairs)\n");
274 SESSION_WRITE(s
, str
);
275 snprintf(str
, sizeof(str
), " operators: = < > ! (not equal) T (key exists) R (regex)\n");
276 SESSION_WRITE(s
, str
);
277 snprintf(str
, sizeof(str
), " modifiers (must follow operator):\n");
278 SESSION_WRITE(s
, str
);
279 snprintf(str
, sizeof(str
), " C=casefold N=numeric S=substring A=prefix Z=suffix\n");
280 SESSION_WRITE(s
, str
);
281 snprintf(str
, sizeof(str
), "\n");
282 SESSION_WRITE(s
, str
);
285 else if (!strcmp(str
, "stats"))
287 stats
= remote_db_stats(dbselect
);
288 out
= asl_format_message((asl_msg_t
*)stats
, ASL_MSG_FMT_RAW
, ASL_TIME_FMT_SEC
, ASL_ENCODE_NONE
, &outlen
);
289 write(s
, out
, outlen
);
294 else if (!strcmp(str
, "flush"))
296 else if (!strncmp(str
, "select", 6))
299 while ((*p
== ' ') || (*p
== '\t')) p
++;
302 if (dbselect
== 0) snprintf(str
, sizeof(str
), "no store\n");
303 else if (dbselect
== DB_TYPE_FILE
) snprintf(str
, sizeof(str
), "file store\n");
304 else if (dbselect
== DB_TYPE_MEMORY
) snprintf(str
, sizeof(str
), "memory store\n");
305 else if (dbselect
== DB_TYPE_MINI
) snprintf(str
, sizeof(str
), "mini memory store\n");
306 SESSION_WRITE(s
, str
);
310 if (!strncmp(p
, "file", 4))
312 if ((global
.dbtype
& DB_TYPE_FILE
) == 0)
314 snprintf(str
, sizeof(str
), "file database is not enabled\n");
315 SESSION_WRITE(s
, str
);
319 dbselect
= DB_TYPE_FILE
;
321 else if (!strncmp(p
, "mem", 3))
323 if ((global
.dbtype
& DB_TYPE_MEMORY
) == 0)
325 snprintf(str
, sizeof(str
), "memory database is not enabled\n");
326 SESSION_WRITE(s
, str
);
330 dbselect
= DB_TYPE_MEMORY
;
332 else if (!strncmp(p
, "mini", 4))
334 if ((global
.dbtype
& DB_TYPE_MINI
) == 0)
336 if (global
.mini_db
!= NULL
)
338 snprintf(str
, sizeof(str
), "mini memory database is enabled for disaster messages\n");
339 SESSION_WRITE(s
, str
);
343 snprintf(str
, sizeof(str
), "mini memory database is not enabled\n");
344 SESSION_WRITE(s
, str
);
349 dbselect
= DB_TYPE_MINI
;
353 snprintf(str
, sizeof(str
), "unknown database type\n");
354 SESSION_WRITE(s
, str
);
358 snprintf(str
, sizeof(str
), "OK\n");
359 SESSION_WRITE(s
, str
);
362 else if (!strncmp(str
, "file", 4))
365 while ((*p
== ' ') || (*p
== '\t')) p
++;
368 snprintf(str
, sizeof(str
), "file database is %senabled\n", (global
.dbtype
& DB_TYPE_FILE
) ? "" : "not ");
369 SESSION_WRITE(s
, str
);
370 if ((global
.dbtype
& DB_TYPE_FILE
) != 0) dbselect
= DB_TYPE_FILE
;
374 if (!strcmp(p
, "on")) global
.dbtype
|= DB_TYPE_FILE
;
375 else if (!strcmp(p
, "off")) global
.dbtype
&= ~ DB_TYPE_FILE
;
377 snprintf(str
, sizeof(str
), "OK\n");
378 SESSION_WRITE(s
, str
);
381 else if (!strncmp(str
, "memory", 6))
384 while ((*p
== ' ') || (*p
== '\t')) p
++;
387 snprintf(str
, sizeof(str
), "memory database is %senabled\n", (global
.dbtype
& DB_TYPE_MEMORY
) ? "" : "not ");
388 SESSION_WRITE(s
, str
);
389 if ((global
.dbtype
& DB_TYPE_MEMORY
) != 0) dbselect
= DB_TYPE_MEMORY
;
393 if (!strcmp(p
, "on")) global
.dbtype
|= DB_TYPE_MEMORY
;
394 else if (!strcmp(p
, "off")) global
.dbtype
&= ~ DB_TYPE_MEMORY
;
396 snprintf(str
, sizeof(str
), "OK\n");
397 SESSION_WRITE(s
, str
);
400 else if (!strncmp(str
, "mini", 4))
403 while ((*p
== ' ') || (*p
== '\t')) p
++;
406 snprintf(str
, sizeof(str
), "mini database is %senabled\n", (global
.dbtype
& DB_TYPE_MINI
) ? "" : "not ");
407 SESSION_WRITE(s
, str
);
408 if ((global
.dbtype
& DB_TYPE_MINI
) != 0) dbselect
= DB_TYPE_MINI
;
412 if (!strcmp(p
, "on")) global
.dbtype
|= DB_TYPE_MINI
;
413 else if (!strcmp(p
, "off")) global
.dbtype
&= ~ DB_TYPE_MINI
;
415 snprintf(str
, sizeof(str
), "OK\n");
416 SESSION_WRITE(s
, str
);
419 else if (!strncmp(str
, "dbsize", 6))
423 snprintf(str
, sizeof(str
), "no store\n");
424 SESSION_WRITE(s
, str
);
429 while ((*p
== ' ') || (*p
== '\t')) p
++;
432 snprintf(str
, sizeof(str
), "DB size %u\n", remote_db_size(dbselect
));
433 SESSION_WRITE(s
, str
);
438 remote_db_set_size(dbselect
, i
);
440 snprintf(str
, sizeof(str
), "OK\n");
441 SESSION_WRITE(s
, str
);
444 else if (!strcmp(str
, "stop"))
446 if (watch
!= WATCH_OFF
)
449 notify_cancel(wtoken
);
456 if (query
!= NULL
) free(query
);
459 snprintf(str
, sizeof(str
), "OK\n");
460 SESSION_WRITE(s
, str
);
464 snprintf(str
, sizeof(str
), "not watching!\n");
465 SESSION_WRITE(s
, str
);
468 else if (!strcmp(str
, "raw"))
473 else if (!strcmp(str
, "std"))
478 else if (!strcmp(str
, "watch"))
480 if (((flags
& SESSION_FLAGS_LOCKDOWN
) == 0) && (watch
!= WATCH_OFF
))
482 snprintf(str
, sizeof(str
), "already watching!\n");
483 SESSION_WRITE(s
, str
);
487 if (flags
& SESSION_FLAGS_LOCKDOWN
)
489 watch
= WATCH_LOCKDOWN_START
;
493 status
= notify_register_file_descriptor(kNotifyASLDBUpdate
, &wfd
, 0, &wtoken
);
496 snprintf(str
, sizeof(str
), "notify_register_file_descriptor failed: %d\n", status
);
497 SESSION_WRITE(s
, str
);
504 snprintf(str
, sizeof(str
), "OK\n");
505 SESSION_WRITE(s
, str
);
508 else if ((str
[0] == '*') || (str
[0] == 'T') || (str
[0] == '=') || (str
[0] == '!') || (str
[0] == '<') || (str
[0] == '>'))
510 memset(&ql
, 0, sizeof(asl_search_result_t
));
511 if (query
!= NULL
) free(query
);
516 while ((*p
== ' ') || (*p
== '\t')) p
++;
525 asprintf(&qs
, "Q %s", p
);
526 query
= asl_msg_from_string(qs
);
529 else if ((*p
== 'T') || (*p
== '=') || (*p
== '!') || (*p
== '<') || (*p
== '>') || (*p
== 'R'))
532 asprintf(&qs
, "Q [%s]", p
);
533 query
= asl_msg_from_string(qs
);
539 asprintf(&qs
, "Q [= %s]", p
);
540 query
= asl_msg_from_string(qs
);
546 snprintf(str
, sizeof(str
), "unrecognized command\n");
547 SESSION_WRITE(s
, str
);
548 snprintf(str
, sizeof(str
), "enter \"help\" for help\n");
549 SESSION_WRITE(s
, str
);
555 * If this session is PurpleConsole watching for log messages,
556 * we pass through this part of the loop once initially to pick up
557 * existing messages already in memory. After that, dbserver will
558 * send new messages in send_to_direct_watchers(). We wait until
559 * the initial messages are sent to PurpleConsole before setting
560 * global.lockdown_session_fd to allow this query to complete before
561 * dbserver starts sending. To prevent a race between this query and
562 * when messages are sent by send_to_direct_watchers, we suspend the
563 * work queue here and resume it when lockdown_session_fd is set.
565 if ((flags
& SESSION_FLAGS_LOCKDOWN
) && (watch
== WATCH_RUN
)) continue;
567 if (watch
== WATCH_LOCKDOWN_START
) dispatch_suspend(global
.work_queue
);
576 if (watch
== WATCH_OFF
) low_id
= 0;
578 memset(&res
, 0, sizeof(aslresponse
));
580 (void)db_query(&ql
, (aslresponse
*)&res
, low_id
, 0, 0, &high_id
, 0, 0);
582 if ((watch
== WATCH_RUN
) && (high_id
>= low_id
)) low_id
= high_id
+ 1;
586 if (watch
== WATCH_OFF
)
588 snprintf(str
, sizeof(str
), "-nil-\n");
589 SESSION_WRITE(s
, str
);
593 if (do_prompt
!= 2) do_prompt
= 0;
596 else if (pfmt
== PRINT_RAW
)
598 if (watch
== WATCH_RUN
)
600 snprintf(str
, sizeof(str
), "\n");
601 SESSION_WRITE(s
, str
);
605 out
= asl_list_to_string((asl_search_result_t
*)res
, &outlen
);
606 write(s
, out
, outlen
);
609 snprintf(str
, sizeof(str
), "\n");
610 SESSION_WRITE(s
, str
);
614 if (watch
== WATCH_RUN
)
616 snprintf(str
, sizeof(str
), "\n");
617 SESSION_WRITE(s
, str
);
620 snprintf(str
, sizeof(str
), "\n");
621 for (i
= 0; i
< res
->count
; i
++)
625 out
= asl_format_message(res
->msg
[i
], ASL_MSG_FMT_STD
, ASL_TIME_FMT_LCL
, ASL_ENCODE_SAFE
, &outlen
);
632 wstatus
= write(s
, out
, outlen
);
635 asldebug("%s %d: %d/%d write data failed: %d %s\n", MY_ID
, s
, i
, res
->count
, errno
, strerror(errno
));
647 } while (errno
== EAGAIN
);
650 if (global
.remote_delay_time
> 0) usleep(global
.remote_delay_time
);
654 aslresponse_free(res
);
656 if (watch
== WATCH_LOCKDOWN_START
)
658 global
.lockdown_session_fd
= s
;
659 global
.watchers_active
++;
662 dispatch_resume(global
.work_queue
);
668 asldebug("%s %d: terminating session for %ssocket %d\n", MY_ID
, s
, (flags
& SESSION_FLAGS_LOCKDOWN
) ? "lockdown " : "", s
);
672 if (s
== global
.lockdown_session_fd
) global
.lockdown_session_fd
= -1;
673 if (global
.watchers_active
> 0) global
.watchers_active
--;
677 if (watch
== WATCH_LOCKDOWN_START
) dispatch_resume(global
.work_queue
);
678 if (wtoken
>= 0) notify_cancel(wtoken
);
679 if (query
!= NULL
) asl_msg_release(query
);
684 remote_acceptmsg(int fd
, int tcp
)
687 int s
, flags
, status
, v
;
690 struct sockaddr_storage from
;
693 fromlen
= sizeof(struct sockaddr_un
);
694 if (tcp
== 1) fromlen
= sizeof(struct sockaddr_storage
);
696 memset(&from
, 0, sizeof(from
));
698 s
= accept(fd
, (struct sockaddr
*)&from
, &fromlen
);
701 asldebug("%s: accept: %s\n", MY_ID
, strerror(errno
));
705 flags
= fcntl(s
, F_GETFL
, 0);
706 flags
&= ~ O_NONBLOCK
;
707 status
= fcntl(s
, F_SETFL
, flags
);
710 asldebug("%s: fcntl: %s\n", MY_ID
, strerror(errno
));
716 setsockopt(s
, SOL_SOCKET
, SO_NOSIGPIPE
, &v
, sizeof(v
));
721 setsockopt(s
, IPPROTO_TCP
, TCP_NODELAY
, &flags
, sizeof(int));
724 sp
= (session_args_t
*)calloc(1, sizeof(session_args_t
));
727 asldebug("%s: malloc: %s\n", MY_ID
, strerror(errno
));
733 if ((tcp
== 0) && (global
.lockdown_session_fd
< 0))
735 sp
->flags
|= SESSION_FLAGS_LOCKDOWN
;
738 pthread_attr_init(&attr
);
739 pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
740 pthread_create(&t
, &attr
, (void *(*)(void *))session
, (void *)sp
);
741 pthread_attr_destroy(&attr
);
747 remote_acceptmsg_local(int fd
)
749 return remote_acceptmsg(fd
, 0);
753 remote_acceptmsg_tcp(int fd
)
755 return remote_acceptmsg(fd
, 1);
759 remote_init_lockdown(void)
761 int status
, reuse
, fd
;
762 struct sockaddr_un local
;
764 fd
= socket(AF_UNIX
, SOCK_STREAM
, 0);
767 asldebug("%s: socket: %s\n", MY_ID
, strerror(errno
));
772 status
= setsockopt(fd
, SOL_SOCKET
, SO_REUSEPORT
, &reuse
, sizeof(int));
775 asldebug("%s: setsockopt: %s\n", MY_ID
, strerror(errno
));
780 /* make sure the lockdown directory exists */
781 mkdir(LOCKDOWN_PATH
, 0777);
783 memset(&local
, 0, sizeof(local
));
784 local
.sun_family
= AF_UNIX
;
785 strlcpy(local
.sun_path
, SYSLOG_SOCK_PATH
, sizeof(local
.sun_path
));
786 unlink(local
.sun_path
);
788 status
= bind(fd
, (struct sockaddr
*)&local
, sizeof(local
.sun_family
) + sizeof(local
.sun_path
));
792 asldebug("%s: bind: %s\n", MY_ID
, strerror(errno
));
797 status
= fcntl(fd
, F_SETFL
, O_NONBLOCK
);
800 asldebug("%s: fcntl: %s\n", MY_ID
, strerror(errno
));
805 status
= listen(fd
, 5);
808 asldebug("%s: listen: %s\n", MY_ID
, strerror(errno
));
813 chmod(SYSLOG_SOCK_PATH
, 0666);
815 in_src_local
= dispatch_source_create(DISPATCH_SOURCE_TYPE_READ
, (uintptr_t)fd
, 0, in_queue
);
816 dispatch_source_set_event_handler(in_src_local
, ^{ remote_acceptmsg_local(fd
); });
817 dispatch_resume(in_src_local
);
823 remote_init_tcp(int family
)
825 int status
, reuse
, fd
;
826 struct sockaddr_in a4
;
827 struct sockaddr_in6 a6
;
831 fd
= socket(family
, SOCK_STREAM
, 0);
834 asldebug("%s: socket: %s\n", MY_ID
, strerror(errno
));
839 status
= setsockopt(fd
, SOL_SOCKET
, SO_REUSEPORT
, &reuse
, sizeof(int));
842 asldebug("%s: setsockopt: %s\n", MY_ID
, strerror(errno
));
847 memset(&(a4
.sin_addr
), 0, sizeof(struct in_addr
));
848 a4
.sin_family
= AF_INET
;
849 a4
.sin_port
= htons(ASL_REMOTE_PORT
);
851 memset(&(a6
.sin6_addr
), 0, sizeof(struct in6_addr
));
852 a6
.sin6_family
= AF_INET6
;
853 a6
.sin6_port
= htons(ASL_REMOTE_PORT
);
855 s
= (struct sockaddr
*)&a4
;
856 len
= sizeof(struct sockaddr_in
);
858 if (family
== AF_INET6
)
860 s
= (struct sockaddr
*)&a6
;
861 len
= sizeof(struct sockaddr_in6
);
864 status
= bind(fd
, s
, len
);
867 asldebug("%s: bind: %s\n", MY_ID
, strerror(errno
));
872 status
= fcntl(fd
, F_SETFL
, O_NONBLOCK
);
875 asldebug("%s: fcntl: %s\n", MY_ID
, strerror(errno
));
880 status
= listen(fd
, 5);
883 asldebug("%s: listen: %s\n", MY_ID
, strerror(errno
));
888 in_src_tcp
= dispatch_source_create(DISPATCH_SOURCE_TYPE_READ
, (uintptr_t)fd
, 0, in_queue
);
889 dispatch_source_set_event_handler(in_src_tcp
, ^{ remote_acceptmsg_tcp(fd
); });
890 dispatch_resume(in_src_tcp
);
898 static dispatch_once_t once
;
900 dispatch_once(&once
, ^{
901 in_queue
= dispatch_queue_create(MY_ID
, NULL
);
904 asldebug("%s: init\n", MY_ID
);
907 rfdl
= remote_init_lockdown();
911 rfd4
= remote_init_tcp(AF_INET
);
915 rfd6
= remote_init_tcp(AF_INET6
);
954 return remote_init();