3 * Hidetoshi Shimokawa. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
16 * This product includes software developed by Hidetoshi Shimokawa.
18 * 4. Neither the name of the author nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * $Id: dconschat.c,v 1.76 2003/10/23 06:21:13 simokawa Exp $
35 * $FreeBSD: src/usr.sbin/dconschat/dconschat.c,v 1.6 2004/05/26 22:59:54 brooks Exp $
36 * $DragonFly: src/usr.sbin/dconschat/dconschat.c,v 1.1 2004/09/23 06:38:29 simokawa Exp $
39 #include <sys/param.h>
40 #include <sys/types.h>
48 #include <sys/socket.h>
49 #include <netinet/in.h>
53 #include <sys/eui64.h>
54 #include <sys/event.h>
56 #include <arpa/telnet.h>
59 #include <dev/misc/dcons/dcons.h>
60 #include <bus/firewire/firewire.h>
61 #include <bus/firewire/iec13213.h>
63 #include <dev/dcons/dcons.h>
64 #include <dev/firewire/firewire.h>
65 #include <dev/firewire/iec13213.h>
71 #include <sys/errno.h>
73 #define DCONS_POLL_HZ 100
74 #define DCONS_POLL_OFFLINE 2 /* sec */
78 #ifdef CSRVAL_VENDOR_PRIVATE
86 int poll_hz
= DCONS_POLL_HZ
;
88 #define IS_CONSOLE(p) ((p)->port == 0)
89 #define IS_GDB(p) ((p)->port == 1)
91 static struct dcons_state
{
96 #define F_READY (1 << 1)
97 #define F_RD_ONLY (1 << 2)
98 #define F_ALT_BREAK (1 << 3)
99 #define F_TELNET (1 << 4)
100 #define F_USE_CROM (1 << 5)
101 #define F_ONE_SHOT (1 << 6)
102 #define F_REPLAY (1 << 7)
118 struct addrinfo
*res
;
122 struct timespec zero
;
123 struct termios tsave
;
127 dread(struct dcons_state
*dc
, void *buf
, size_t n
, off_t offset
)
131 return (pread(dc
->fd
, buf
, n
, offset
));
133 return (kvm_read(dc
->kd
, offset
, buf
, n
));
139 dwrite(struct dcons_state
*dc
, void *buf
, size_t n
, off_t offset
)
141 if ((dc
->flags
& F_RD_ONLY
) != 0)
146 return (pwrite(dc
->fd
, buf
, n
, offset
));
148 return (kvm_write(dc
->kd
, offset
, buf
, n
));
154 dconschat_cleanup(int sig
)
156 struct dcons_state
*dc
;
160 tcsetattr(STDIN_FILENO
, TCSADRAIN
, &dc
->tsave
);
163 printf("\n[dconschat exiting with signal %d ...]\n", sig
);
165 printf("\n[dconschat exiting...]\n");
171 dconschat_get_crom(struct dcons_state
*dc
)
175 u_int32_t buf
, hi
= 0, lo
= 0;
178 reg
= (struct csrreg
*)&buf
;
180 addr
= (addr
<< 32) | 0xf0000400;
181 for (i
= 20; i
< 0x400; i
+= 4) {
182 if (dread(dc
, &buf
, 4, addr
+ i
) < 0) {
184 warn("crom read faild");
189 printf("%d %02x %06x\n", state
, reg
->key
, reg
->val
);
192 if (reg
->key
== CSRKEY_SPEC
&&
193 reg
->val
== CSRVAL_VENDOR_PRIVATE
)
197 if (reg
->key
== CSRKEY_VER
&&
198 reg
->val
== DCONS_CSR_VAL_VER
)
202 if (reg
->key
== DCONS_CSR_KEY_HI
)
204 else if (reg
->key
== DCONS_CSR_KEY_LO
) {
215 printf("addr: %06x %06x\n", hi
, lo
);
216 dc
->paddr
= ((off_t
)hi
<< 24) | lo
;
222 dconschat_ready(struct dcons_state
*dc
, int ready
, char *reason
)
224 static char oldreason
[64] = "";
227 old
= (dc
->flags
& F_READY
) ? 1 : 0;
230 dc
->flags
|= F_READY
;
232 printf("[dcons connected]\r\n");
235 dc
->flags
&= ~F_READY
;
236 if (strncmp(oldreason
, reason
, sizeof(oldreason
)) != 0) {
237 printf("[dcons disconnected (%s)]\r\n", reason
);
238 strlcpy(oldreason
, reason
, sizeof(oldreason
));
244 dconschat_fetch_header(struct dcons_state
*dc
)
247 struct dcons_buf dbuf
;
251 if (dc
->paddr
== 0 && (dc
->flags
& F_USE_CROM
) != 0) {
252 if (dconschat_get_crom(dc
)) {
253 dconschat_ready(dc
, 0, "get crom failed");
259 if (dread(dc
, &dbuf
, DCONS_HEADER_SIZE
, dc
->paddr
) < 0) {
260 dconschat_ready(dc
, 0, "read header failed");
263 if (dbuf
.magic
!= htonl(DCONS_MAGIC
)) {
264 if ((dc
->flags
& F_USE_CROM
) !=0)
266 snprintf(ebuf
, sizeof(ebuf
), "wrong magic 0x%08x", dbuf
.magic
);
267 dconschat_ready(dc
, 0, ebuf
);
270 if (ntohl(dbuf
.version
) != DCONS_VERSION
) {
271 snprintf(ebuf
, sizeof(ebuf
),
272 #if __FreeBSD_version < 500000
273 "wrong version %ld,%d",
275 "wrong version %d,%d",
277 ntohl(dbuf
.version
), DCONS_VERSION
);
279 dconschat_ready(dc
, 0, ebuf
);
283 for (j
= 0; j
< DCONS_NPORT
; j
++) {
284 struct dcons_ch
*o
, *i
;
289 newbuf
= dc
->paddr
+ ntohl(dbuf
.ooffset
[j
]);
290 o
->size
= ntohl(dbuf
.osize
[j
]);
292 if (newbuf
!= o
->buf
) {
293 /* buffer address has changes */
295 o
->gen
= ntohl(dbuf
.optr
[j
]) >> DCONS_GEN_SHIFT
;
296 o
->pos
= ntohl(dbuf
.optr
[j
]) & DCONS_POS_MASK
;
301 i
->size
= ntohl(dbuf
.isize
[j
]);
302 i
->gen
= ntohl(dbuf
.iptr
[j
]) >> DCONS_GEN_SHIFT
;
303 i
->pos
= ntohl(dbuf
.iptr
[j
]) & DCONS_POS_MASK
;
304 i
->buf
= dc
->paddr
+ ntohl(dbuf
.ioffset
[j
]);
307 printf("port %d size offset gen pos\n", j
);
308 #if __FreeBSD_version < 500000
309 printf("output: %5d %6ld %5d %5d\n"
310 "input : %5d %6ld %5d %5d\n",
312 printf("output: %5d %6d %5d %5d\n"
313 "input : %5d %6d %5d %5d\n",
315 o
->size
, ntohl(dbuf
.ooffset
[j
]), o
->gen
, o
->pos
,
316 i
->size
, ntohl(dbuf
.ioffset
[j
]), i
->gen
, i
->pos
);
319 if (IS_CONSOLE(&dc
->port
[j
]) && new &&
320 (dc
->flags
& F_REPLAY
) !=0) {
327 dconschat_ready(dc
, 1, NULL
);
332 dconschat_get_ptr (struct dcons_state
*dc
) {
334 u_int32_t ptr
[DCONS_NPORT
*2+1];
335 static int retry
= RETRY
;
338 dlen
= dread(dc
, &ptr
, sizeof(ptr
),
339 dc
->paddr
+ __offsetof(struct dcons_buf
, magic
));
342 if (errno
== ETIMEDOUT
)
345 dconschat_ready(dc
, 0, "get ptr failed");
348 if (ptr
[0] != htonl(DCONS_MAGIC
)) {
349 dconschat_ready(dc
, 0, "wrong magic");
353 for (i
= 0; i
< DCONS_NPORT
; i
++) {
354 dc
->port
[i
].optr
= ntohl(ptr
[i
+ 1]);
355 dc
->port
[i
].iptr
= ntohl(ptr
[DCONS_NPORT
+ i
+ 1]);
360 #define MAX_XFER 2048
362 dconschat_read_dcons(struct dcons_state
*dc
, int port
, char *buf
, int len
)
365 u_int32_t ptr
, pos
, gen
, next_gen
;
366 int rlen
, dlen
, lost
;
369 ch
= &dc
->port
[port
].o
;
370 ptr
= dc
->port
[port
].optr
;
371 gen
= ptr
>> DCONS_GEN_SHIFT
;
372 pos
= ptr
& DCONS_POS_MASK
;
373 if (gen
== ch
->gen
&& pos
== ch
->pos
)
376 next_gen
= DCONS_NEXT_GEN(ch
->gen
);
377 /* XXX sanity check */
378 if (gen
== ch
->gen
) {
381 lost
= ch
->size
* DCONS_GEN_MASK
- ch
->pos
;
383 } else if (gen
== next_gen
) {
386 lost
= pos
- ch
->pos
;
389 lost
= gen
- ch
->gen
;
391 lost
+= DCONS_GEN_MASK
;
393 printf("[genskip %d]", lost
);
394 lost
= lost
* ch
->size
- ch
->pos
;
398 /* generation skipped !! */
401 printf("[lost %d]", lost
);
404 rlen
= pos
- ch
->pos
;
406 rlen
= ch
->size
- ch
->pos
;
415 printf("[%d]", rlen
); fflush(stdout
);
419 dlen
= dread(dc
, buf
, rlen
, ch
->buf
+ ch
->pos
);
421 if (errno
== ETIMEDOUT
)
424 dconschat_ready(dc
, 0, "read buffer failed");
428 warnx("dlen(%d) != rlen(%d)\n", dlen
, rlen
);
430 if (ch
->pos
>= ch
->size
) {
434 printf("read_dcons: gen=%d", ch
->gen
);
440 dconschat_write_dcons(struct dcons_state
*dc
, int port
, char *buf
, int blen
)
447 ch
= &dc
->port
[port
].i
;
448 ptr
= dc
->port
[port
].iptr
;
450 /* the others may advance the pointer sync with it */
451 ch
->gen
= ptr
>> DCONS_GEN_SHIFT
;
452 ch
->pos
= ptr
& DCONS_POS_MASK
;
455 wlen
= MIN(blen
, ch
->size
- ch
->pos
);
456 wlen
= MIN(wlen
, MAX_XFER
);
457 len
= dwrite(dc
, buf
, wlen
, ch
->buf
+ ch
->pos
);
459 if (errno
== ETIMEDOUT
)
461 continue; /* try again */
462 dconschat_ready(dc
, 0, "write buffer failed");
468 if (ch
->pos
>= ch
->size
) {
469 ch
->gen
= DCONS_NEXT_GEN(ch
->gen
);
472 printf("write_dcons: gen=%d", ch
->gen
);
477 ptr
= DCONS_MAKE_PTR(ch
);
478 dc
->port
[port
].iptr
= ptr
;
481 printf("(iptr: 0x%x)", ptr
);
483 len
= dwrite(dc
, &ptr
, sizeof(u_int32_t
),
484 dc
->paddr
+ __offsetof(struct dcons_buf
, iptr
[port
]));
486 if (errno
== ETIMEDOUT
)
489 dconschat_ready(dc
, 0, "write ptr failed");
496 dconschat_write_socket(int fd
, char *buf
, int len
)
507 dconschat_init_socket(struct dcons_state
*dc
, int port
, char *host
, int sport
)
509 struct addrinfo hints
, *res
;
513 struct dcons_port
*p
;
517 p
->infd
= p
->outfd
= -1;
524 /* Use stdin and stdout */
525 p
->infd
= STDIN_FILENO
;
526 p
->outfd
= STDOUT_FILENO
;
529 tcgetattr(STDIN_FILENO
, &dc
->tsave
) == 0) {
534 tcsetattr(STDIN_FILENO
, TCSADRAIN
, &traw
);
537 EV_SET(&kev
, p
->infd
, EVFILT_READ
, EV_ADD
, NOTE_LOWAT
, 1,
539 kevent(dc
->kq
, &kev
, 1, NULL
, 0, &dc
->zero
);
543 memset(&hints
, 0, sizeof(hints
));
544 hints
.ai_flags
= AI_PASSIVE
;
545 #if 1 /* gdb can talk v4 only */
546 hints
.ai_family
= PF_INET
;
548 hints
.ai_family
= PF_UNSPEC
;
550 hints
.ai_socktype
= SOCK_STREAM
;
551 hints
.ai_protocol
= 0;
554 printf("%s:%d for port %d\n",
555 host
== NULL
? "*" : host
, sport
, port
);
556 snprintf(service
, sizeof(service
), "%d", sport
);
557 error
= getaddrinfo(host
, service
, &hints
, &res
);
559 errx(1, "tcp/%s: %s\n", service
, gai_strerror(error
));
561 p
->s
= socket(res
->ai_family
, res
->ai_socktype
, res
->ai_protocol
);
564 setsockopt(p
->s
, SOL_SOCKET
, SO_REUSEADDR
, &on
, sizeof(on
));
566 if (bind(p
->s
, p
->res
->ai_addr
, p
->res
->ai_addrlen
) < 0) {
569 if (listen(p
->s
, 1) < 0)
571 EV_SET(&kev
, p
->s
, EVFILT_READ
, EV_ADD
| EV_ONESHOT
, 0, 0, (void *)p
);
572 error
= kevent(dc
->kq
, &kev
, 1, NULL
, 0, &dc
->to
);
579 dconschat_accept_socket(struct dcons_state
*dc
, struct dcons_port
*p
)
584 /* accept connection */
585 foo
= p
->res
->ai_addrlen
;
586 ns
= accept(p
->s
, p
->res
->ai_addr
, &foo
);
590 printf("port%d accepted\n", p
->port
);
592 flags
= fcntl(ns
, F_GETFL
, 0);
594 fcntl(ns
, F_SETFL
, flags
);
596 if (IS_CONSOLE(p
) && (dc
->flags
& F_TELNET
) != 0) {
597 char sga
[] = {IAC
, WILL
, TELOPT_SGA
};
598 char linemode
[] = {IAC
, DONT
, TELOPT_LINEMODE
};
599 char echo
[] = {IAC
, WILL
, TELOPT_ECHO
};
600 char bin
[] = {IAC
, DO
, TELOPT_BINARY
};
602 write(ns
, sga
, sizeof(sga
));
603 write(ns
, linemode
, sizeof(linemode
));
604 write(ns
, echo
, sizeof(echo
));
605 write(ns
, bin
, sizeof(bin
));
610 p
->infd
= p
->outfd
= ns
;
611 EV_SET(&kev
, ns
, EVFILT_READ
, EV_ADD
, NOTE_LOWAT
, 1, (void *)p
);
612 kevent(dc
->kq
, &kev
, 1, NULL
, 0, &dc
->zero
);
617 dconschat_read_filter(struct dcons_state
*dc
, struct dcons_port
*p
,
618 u_char
*sp
, int slen
, u_char
*dp
, int *dlen
)
620 static u_char abreak
[3] = {13 /* CR */, 126 /* ~ */, 2 /* ^B */};
624 if ((dc
->flags
& F_TELNET
) != 0) {
625 /* XXX Telent workarounds */
626 if (p
->skip_read
-- > 0) {
641 printf("(0 stripped)");
647 switch (dc
->escape_state
) {
649 if (*sp
== KEY_TILDE
)
650 dc
->escape_state
= STATE2
;
652 dc
->escape_state
= STATE0
;
655 dc
->escape_state
= STATE0
;
657 dconschat_cleanup(0);
660 dc
->escape_state
= STATE1
;
661 } else if (IS_GDB(p
)) {
662 /* GDB: ^C -> CR+~+^B */
663 if (*sp
== 0x3 && (dc
->flags
& F_ALT_BREAK
) != 0) {
664 bcopy(abreak
, dp
, 3);
668 /* discard rest of the packet */
682 dconschat_read_socket(struct dcons_state
*dc
, struct dcons_port
*p
)
686 char rbuf
[MAX_XFER
], wbuf
[MAX_XFER
+2];
688 if ((len
= read(p
->infd
, rbuf
, sizeof(rbuf
))) > 0) {
690 dconschat_read_filter(dc
, p
, rbuf
, len
, wbuf
, &wlen
);
691 /* XXX discard if not ready*/
692 if (wlen
> 0 && (dc
->flags
& F_READY
) != 0) {
693 dconschat_write_dcons(dc
, p
->port
, wbuf
, wlen
);
696 printf("(%s)\n", wbuf
);
699 printf("(%d)", wlen
);
706 warnx("port%d: closed", p
->port
);
708 warn("port%d: read", p
->port
);
710 EV_SET(&kev
, p
->infd
, EVFILT_READ
,
711 EV_DELETE
, 0, 0, NULL
);
712 kevent(dc
->kq
, &kev
, 1, NULL
, 0, &dc
->zero
);
715 /* XXX exit for pipe case XXX */
716 EV_SET(&kev
, p
->s
, EVFILT_READ
,
717 EV_ADD
| EV_ONESHOT
, 0, 0, (void *) p
);
718 kevent(dc
->kq
, &kev
, 1, NULL
, 0, &dc
->zero
);
719 p
->infd
= p
->outfd
= -1;
725 dconschat_proc_socket(struct dcons_state
*dc
)
727 struct kevent elist
[NEVENT
], *e
;
729 struct dcons_port
*p
;
731 n
= kevent(dc
->kq
, NULL
, 0, elist
, NEVENT
, &dc
->to
);
732 for (i
= 0; i
< n
; i
++) {
734 p
= (struct dcons_port
*)e
->udata
;
735 if (e
->ident
== p
->s
) {
736 dconschat_accept_socket(dc
, p
);
738 dconschat_read_socket(dc
, p
);
745 dconschat_proc_dcons(struct dcons_state
*dc
)
749 struct dcons_port
*p
;
751 err
= dconschat_get_ptr(dc
);
753 /* XXX we should stop write operation too. */
756 for (port
= 0; port
< DCONS_NPORT
; port
++) {
760 while ((len
= dconschat_read_dcons(dc
, port
, buf
,
762 dconschat_write_socket(p
->outfd
, buf
, len
);
763 dconschat_get_ptr(dc
);
765 if ((dc
->flags
& F_ONE_SHOT
) != 0 && len
<= 0)
766 dconschat_cleanup(0);
772 dconschat_start_session(struct dcons_state
*dc
)
777 if ((dc
->flags
& F_READY
) == 0 &&
778 (++counter
% (poll_hz
* DCONS_POLL_OFFLINE
)) == 0)
779 dconschat_fetch_header(dc
);
780 if ((dc
->flags
& F_READY
) != 0)
781 dconschat_proc_dcons(dc
);
782 dconschat_proc_socket(dc
);
791 "usage: dconschat [-brvwRT1] [-h hz] [-C port] [-G port]\n"
792 "\t\t\t[-M core] [-N system]\n"
793 "\t\t\t[-u unit] [-a address] [-t target_eui64]\n"
794 "\t-b translate ctrl-C to CR+~+ctrl-B on gdb port\n"
796 "\t-w listen on wildcard address rather than localhost\n"
797 "\t-r replay old buffer on connection\n"
799 "\t-T enable Telnet protocol workaround on console port\n"
800 "\t-1 one shot: read buffer and exit\n"
801 "\t-h polling rate\n"
802 "\t-C port number for console port\n"
803 "\t-G port number for gdb port\n"
808 "\t-u specify unit number of the bus\n"
809 "\t-t EUI64 of target host (must be specified)\n"
810 "\t-a physical address of dcons buffer on target host\n"
815 main(int argc
, char **argv
)
817 struct dcons_state
*dc
;
820 char devname
[256], *core
= NULL
, *system
= NULL
;
822 int unit
=0, wildcard
=0;
823 int port
[DCONS_NPORT
];
825 bzero(&sc
, sizeof(sc
));
827 dc
->flags
|= USE_CROM
? F_USE_CROM
: 0;
830 port
[0] = 0; /* stdin/out for console */
831 port
[1] = -1; /* disable gdb port */
833 while ((ch
= getopt(argc
, argv
, "a:bh:rt:u:vwC:G:M:N:RT1")) != -1) {
836 dc
->paddr
= strtoull(optarg
, NULL
, 0);
837 dc
->flags
&= ~F_USE_CROM
;
840 dc
->flags
|= F_ALT_BREAK
;
843 poll_hz
= strtoul(optarg
, NULL
, 0);
845 poll_hz
= DCONS_POLL_HZ
;
848 dc
->flags
|= F_REPLAY
;
851 if (eui64_hostton(optarg
, &target
) != 0 &&
852 eui64_aton(optarg
, &target
) != 0)
853 errx(1, "invalid target: %s", optarg
);
854 eui
.hi
= ntohl(*(u_int32_t
*)&(target
.octet
[0]));
855 eui
.lo
= ntohl(*(u_int32_t
*)&(target
.octet
[4]));
859 unit
= strtol(optarg
, NULL
, 0);
868 port
[0] = strtol(optarg
, NULL
, 0);
871 port
[1] = strtol(optarg
, NULL
, 0);
880 dc
->flags
|= F_RD_ONLY
;
883 dc
->flags
|= F_TELNET
;
886 dc
->flags
|= F_ONE_SHOT
| F_REPLAY
;
892 if (dc
->paddr
== 0 && (dc
->flags
& F_USE_CROM
) == 0) {
893 warnx("no address specified");
897 if (port
[0] < 0 && port
[1] < 0) {
898 warnx("no port specified");
902 /* set signal handler */
903 signal(SIGHUP
, dconschat_cleanup
);
904 signal(SIGINT
, dconschat_cleanup
);
905 signal(SIGPIPE
, dconschat_cleanup
);
906 signal(SIGTERM
, dconschat_cleanup
);
912 for (i
= 0; i
< MAXDEV
; i
++) {
913 snprintf(devname
, sizeof(devname
),
914 "/dev/fwmem%d.%d", unit
, i
);
915 dc
->fd
= open(devname
, O_RDWR
);
921 error
= ioctl(dc
->fd
, FW_SDEUI64
, &eui
);
927 struct nlist nl
[] = {{"dcons_buf"}, {""}};
930 dc
->kd
= kvm_open(system
, core
, NULL
,
931 (dc
->flags
& F_RD_ONLY
) ? O_RDONLY
: O_RDWR
, "dconschat");
935 if (kvm_nlist(dc
->kd
, nl
) < 0)
936 errx(1, "kvm_nlist: %s", kvm_geterr(dc
->kd
));
938 if (kvm_read(dc
->kd
, nl
[0].n_value
, &dcons_buf
,
940 errx(1, "kvm_read: %s", kvm_geterr(dc
->kd
));
941 dc
->paddr
= (uintptr_t)dcons_buf
;
943 printf("dcons_buf: 0x%x\n", (uint
)dc
->paddr
);
947 dconschat_fetch_header(dc
);
956 dc
->to
.tv_nsec
= 1000 * 1000 * 1000 / poll_hz
;
959 dc
->zero
.tv_nsec
= 0;
960 for (i
= 0; i
< DCONS_NPORT
; i
++)
961 dconschat_init_socket(dc
, i
,
962 wildcard
? NULL
: "localhost", port
[i
]);
964 dconschat_start_session(dc
);
966 for (i
= 0; i
< DCONS_NPORT
; i
++) {
967 freeaddrinfo(dc
->port
[i
].res
);