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>
58 #include <sys/ioccom.h>
60 #include <dev/misc/dcons/dcons.h>
61 #include <bus/firewire/firewire.h>
62 #include <bus/firewire/iec13213.h>
64 #include <dev/dcons/dcons.h>
65 #include <dev/firewire/firewire.h>
66 #include <dev/firewire/iec13213.h>
72 #include <sys/errno.h>
74 #define DCONS_POLL_HZ 100
75 #define DCONS_POLL_OFFLINE 2 /* sec */
79 #ifdef CSRVAL_VENDOR_PRIVATE
87 int poll_hz
= DCONS_POLL_HZ
;
89 #define IS_CONSOLE(p) ((p)->port == 0)
90 #define IS_GDB(p) ((p)->port == 1)
92 static struct dcons_state
{
97 #define F_READY (1 << 1)
98 #define F_RD_ONLY (1 << 2)
99 #define F_ALT_BREAK (1 << 3)
100 #define F_TELNET (1 << 4)
101 #define F_USE_CROM (1 << 5)
102 #define F_ONE_SHOT (1 << 6)
103 #define F_REPLAY (1 << 7)
119 struct addrinfo
*res
;
123 struct timespec zero
;
124 struct termios tsave
;
128 dread(struct dcons_state
*dc
, void *buf
, size_t n
, off_t offset
)
132 return (pread(dc
->fd
, buf
, n
, offset
));
134 return (kvm_read(dc
->kd
, offset
, buf
, n
));
140 dwrite(struct dcons_state
*dc
, void *buf
, size_t n
, off_t offset
)
142 if ((dc
->flags
& F_RD_ONLY
) != 0)
147 return (pwrite(dc
->fd
, buf
, n
, offset
));
149 return (kvm_write(dc
->kd
, offset
, buf
, n
));
155 dconschat_cleanup(int sig
)
157 struct dcons_state
*dc
;
161 tcsetattr(STDIN_FILENO
, TCSADRAIN
, &dc
->tsave
);
164 printf("\n[dconschat exiting with signal %d ...]\n", sig
);
166 printf("\n[dconschat exiting...]\n");
172 dconschat_get_crom(struct dcons_state
*dc
)
176 u_int32_t buf
, hi
= 0, lo
= 0;
179 reg
= (struct csrreg
*)&buf
;
181 addr
= (addr
<< 32) | 0xf0000400;
182 for (i
= 20; i
< 0x400; i
+= 4) {
183 if (dread(dc
, &buf
, 4, addr
+ i
) < 0) {
185 warn("crom read faild");
190 printf("%d %02x %06x\n", state
, reg
->key
, reg
->val
);
193 if (reg
->key
== CSRKEY_SPEC
&&
194 reg
->val
== CSRVAL_VENDOR_PRIVATE
)
198 if (reg
->key
== CSRKEY_VER
&&
199 reg
->val
== DCONS_CSR_VAL_VER
)
203 if (reg
->key
== DCONS_CSR_KEY_HI
)
205 else if (reg
->key
== DCONS_CSR_KEY_LO
) {
216 printf("addr: %06x %06x\n", hi
, lo
);
217 dc
->paddr
= ((off_t
)hi
<< 24) | lo
;
223 dconschat_ready(struct dcons_state
*dc
, int ready
, char *reason
)
225 static char oldreason
[64] = "";
228 old
= (dc
->flags
& F_READY
) ? 1 : 0;
231 dc
->flags
|= F_READY
;
233 printf("[dcons connected]\r\n");
236 dc
->flags
&= ~F_READY
;
237 if (strncmp(oldreason
, reason
, sizeof(oldreason
)) != 0) {
238 printf("[dcons disconnected (%s)]\r\n", reason
);
239 strlcpy(oldreason
, reason
, sizeof(oldreason
));
245 dconschat_fetch_header(struct dcons_state
*dc
)
248 struct dcons_buf dbuf
;
252 if (dc
->paddr
== 0 && (dc
->flags
& F_USE_CROM
) != 0) {
253 if (dconschat_get_crom(dc
)) {
254 dconschat_ready(dc
, 0, "get crom failed");
260 if (dread(dc
, &dbuf
, DCONS_HEADER_SIZE
, dc
->paddr
) < 0) {
261 dconschat_ready(dc
, 0, "read header failed");
264 if (dbuf
.magic
!= htonl(DCONS_MAGIC
)) {
265 if ((dc
->flags
& F_USE_CROM
) !=0)
267 snprintf(ebuf
, sizeof(ebuf
), "wrong magic 0x%08x", dbuf
.magic
);
268 dconschat_ready(dc
, 0, ebuf
);
271 if (ntohl(dbuf
.version
) != DCONS_VERSION
) {
272 snprintf(ebuf
, sizeof(ebuf
),
273 #if __FreeBSD_version < 500000
274 "wrong version %ld,%d",
276 "wrong version %d,%d",
278 ntohl(dbuf
.version
), DCONS_VERSION
);
280 dconschat_ready(dc
, 0, ebuf
);
284 for (j
= 0; j
< DCONS_NPORT
; j
++) {
285 struct dcons_ch
*o
, *i
;
290 newbuf
= dc
->paddr
+ ntohl(dbuf
.ooffset
[j
]);
291 o
->size
= ntohl(dbuf
.osize
[j
]);
293 if (newbuf
!= o
->buf
) {
294 /* buffer address has changes */
296 o
->gen
= ntohl(dbuf
.optr
[j
]) >> DCONS_GEN_SHIFT
;
297 o
->pos
= ntohl(dbuf
.optr
[j
]) & DCONS_POS_MASK
;
302 i
->size
= ntohl(dbuf
.isize
[j
]);
303 i
->gen
= ntohl(dbuf
.iptr
[j
]) >> DCONS_GEN_SHIFT
;
304 i
->pos
= ntohl(dbuf
.iptr
[j
]) & DCONS_POS_MASK
;
305 i
->buf
= dc
->paddr
+ ntohl(dbuf
.ioffset
[j
]);
308 printf("port %d size offset gen pos\n", j
);
309 #if __FreeBSD_version < 500000
310 printf("output: %5d %6ld %5d %5d\n"
311 "input : %5d %6ld %5d %5d\n",
313 printf("output: %5d %6d %5d %5d\n"
314 "input : %5d %6d %5d %5d\n",
316 o
->size
, ntohl(dbuf
.ooffset
[j
]), o
->gen
, o
->pos
,
317 i
->size
, ntohl(dbuf
.ioffset
[j
]), i
->gen
, i
->pos
);
320 if (IS_CONSOLE(&dc
->port
[j
]) && new &&
321 (dc
->flags
& F_REPLAY
) !=0) {
328 dconschat_ready(dc
, 1, NULL
);
333 dconschat_get_ptr (struct dcons_state
*dc
) {
335 u_int32_t ptr
[DCONS_NPORT
*2+1];
336 static int retry
= RETRY
;
339 dlen
= dread(dc
, &ptr
, sizeof(ptr
),
340 dc
->paddr
+ __offsetof(struct dcons_buf
, magic
));
343 if (errno
== ETIMEDOUT
)
346 dconschat_ready(dc
, 0, "get ptr failed");
349 if (ptr
[0] != htonl(DCONS_MAGIC
)) {
350 dconschat_ready(dc
, 0, "wrong magic");
354 for (i
= 0; i
< DCONS_NPORT
; i
++) {
355 dc
->port
[i
].optr
= ntohl(ptr
[i
+ 1]);
356 dc
->port
[i
].iptr
= ntohl(ptr
[DCONS_NPORT
+ i
+ 1]);
361 #define MAX_XFER 2048
363 dconschat_read_dcons(struct dcons_state
*dc
, int port
, char *buf
, int len
)
366 u_int32_t ptr
, pos
, gen
, next_gen
;
367 int rlen
, dlen
, lost
;
370 ch
= &dc
->port
[port
].o
;
371 ptr
= dc
->port
[port
].optr
;
372 gen
= ptr
>> DCONS_GEN_SHIFT
;
373 pos
= ptr
& DCONS_POS_MASK
;
374 if (gen
== ch
->gen
&& pos
== ch
->pos
)
377 next_gen
= DCONS_NEXT_GEN(ch
->gen
);
378 /* XXX sanity check */
379 if (gen
== ch
->gen
) {
382 lost
= ch
->size
* DCONS_GEN_MASK
- ch
->pos
;
384 } else if (gen
== next_gen
) {
387 lost
= pos
- ch
->pos
;
390 lost
= gen
- ch
->gen
;
392 lost
+= DCONS_GEN_MASK
;
394 printf("[genskip %d]", lost
);
395 lost
= lost
* ch
->size
- ch
->pos
;
399 /* generation skipped !! */
402 printf("[lost %d]", lost
);
405 rlen
= pos
- ch
->pos
;
407 rlen
= ch
->size
- ch
->pos
;
416 printf("[%d]", rlen
); fflush(stdout
);
420 dlen
= dread(dc
, buf
, rlen
, ch
->buf
+ ch
->pos
);
422 if (errno
== ETIMEDOUT
)
425 dconschat_ready(dc
, 0, "read buffer failed");
429 warnx("dlen(%d) != rlen(%d)\n", dlen
, rlen
);
431 if (ch
->pos
>= ch
->size
) {
435 printf("read_dcons: gen=%d", ch
->gen
);
441 dconschat_write_dcons(struct dcons_state
*dc
, int port
, char *buf
, int blen
)
448 ch
= &dc
->port
[port
].i
;
449 ptr
= dc
->port
[port
].iptr
;
451 /* the others may advance the pointer sync with it */
452 ch
->gen
= ptr
>> DCONS_GEN_SHIFT
;
453 ch
->pos
= ptr
& DCONS_POS_MASK
;
456 wlen
= MIN(blen
, ch
->size
- ch
->pos
);
457 wlen
= MIN(wlen
, MAX_XFER
);
458 len
= dwrite(dc
, buf
, wlen
, ch
->buf
+ ch
->pos
);
460 if (errno
== ETIMEDOUT
)
462 continue; /* try again */
463 dconschat_ready(dc
, 0, "write buffer failed");
469 if (ch
->pos
>= ch
->size
) {
470 ch
->gen
= DCONS_NEXT_GEN(ch
->gen
);
473 printf("write_dcons: gen=%d", ch
->gen
);
478 ptr
= DCONS_MAKE_PTR(ch
);
479 dc
->port
[port
].iptr
= ptr
;
482 printf("(iptr: 0x%x)", ptr
);
484 len
= dwrite(dc
, &ptr
, sizeof(u_int32_t
),
485 dc
->paddr
+ __offsetof(struct dcons_buf
, iptr
[port
]));
487 if (errno
== ETIMEDOUT
)
490 dconschat_ready(dc
, 0, "write ptr failed");
497 dconschat_write_socket(int fd
, char *buf
, int len
)
508 dconschat_init_socket(struct dcons_state
*dc
, int port
, char *host
, int sport
)
510 struct addrinfo hints
, *res
;
514 struct dcons_port
*p
;
518 p
->infd
= p
->outfd
= -1;
525 /* Use stdin and stdout */
526 p
->infd
= STDIN_FILENO
;
527 p
->outfd
= STDOUT_FILENO
;
530 tcgetattr(STDIN_FILENO
, &dc
->tsave
) == 0) {
535 tcsetattr(STDIN_FILENO
, TCSADRAIN
, &traw
);
538 EV_SET(&kev
, p
->infd
, EVFILT_READ
, EV_ADD
, NOTE_LOWAT
, 1,
540 kevent(dc
->kq
, &kev
, 1, NULL
, 0, &dc
->zero
);
544 memset(&hints
, 0, sizeof(hints
));
545 hints
.ai_flags
= AI_PASSIVE
;
546 #if 1 /* gdb can talk v4 only */
547 hints
.ai_family
= PF_INET
;
549 hints
.ai_family
= PF_UNSPEC
;
551 hints
.ai_socktype
= SOCK_STREAM
;
552 hints
.ai_protocol
= 0;
555 printf("%s:%d for port %d\n",
556 host
== NULL
? "*" : host
, sport
, port
);
557 snprintf(service
, sizeof(service
), "%d", sport
);
558 error
= getaddrinfo(host
, service
, &hints
, &res
);
560 errx(1, "tcp/%s: %s\n", service
, gai_strerror(error
));
562 p
->s
= socket(res
->ai_family
, res
->ai_socktype
, res
->ai_protocol
);
565 setsockopt(p
->s
, SOL_SOCKET
, SO_REUSEADDR
, &on
, sizeof(on
));
567 if (bind(p
->s
, p
->res
->ai_addr
, p
->res
->ai_addrlen
) < 0) {
570 if (listen(p
->s
, 1) < 0)
572 EV_SET(&kev
, p
->s
, EVFILT_READ
, EV_ADD
| EV_ONESHOT
, 0, 0, (void *)p
);
573 error
= kevent(dc
->kq
, &kev
, 1, NULL
, 0, &dc
->to
);
580 dconschat_accept_socket(struct dcons_state
*dc
, struct dcons_port
*p
)
585 /* accept connection */
586 foo
= p
->res
->ai_addrlen
;
587 ns
= accept(p
->s
, p
->res
->ai_addr
, &foo
);
591 printf("port%d accepted\n", p
->port
);
593 flags
= fcntl(ns
, F_GETFL
, 0);
595 fcntl(ns
, F_SETFL
, flags
);
597 if (IS_CONSOLE(p
) && (dc
->flags
& F_TELNET
) != 0) {
598 char sga
[] = {IAC
, WILL
, TELOPT_SGA
};
599 char linemode
[] = {IAC
, DONT
, TELOPT_LINEMODE
};
600 char echo
[] = {IAC
, WILL
, TELOPT_ECHO
};
601 char bin
[] = {IAC
, DO
, TELOPT_BINARY
};
603 write(ns
, sga
, sizeof(sga
));
604 write(ns
, linemode
, sizeof(linemode
));
605 write(ns
, echo
, sizeof(echo
));
606 write(ns
, bin
, sizeof(bin
));
611 p
->infd
= p
->outfd
= ns
;
612 EV_SET(&kev
, ns
, EVFILT_READ
, EV_ADD
, NOTE_LOWAT
, 1, (void *)p
);
613 kevent(dc
->kq
, &kev
, 1, NULL
, 0, &dc
->zero
);
618 dconschat_read_filter(struct dcons_state
*dc
, struct dcons_port
*p
,
619 u_char
*sp
, int slen
, u_char
*dp
, int *dlen
)
621 static u_char abreak
[3] = {13 /* CR */, 126 /* ~ */, 2 /* ^B */};
625 if ((dc
->flags
& F_TELNET
) != 0) {
626 /* XXX Telent workarounds */
627 if (p
->skip_read
-- > 0) {
642 printf("(0 stripped)");
648 switch (dc
->escape_state
) {
650 if (*sp
== KEY_TILDE
)
651 dc
->escape_state
= STATE2
;
653 dc
->escape_state
= STATE0
;
656 dc
->escape_state
= STATE0
;
658 dconschat_cleanup(0);
661 dc
->escape_state
= STATE1
;
662 } else if (IS_GDB(p
)) {
663 /* GDB: ^C -> CR+~+^B */
664 if (*sp
== 0x3 && (dc
->flags
& F_ALT_BREAK
) != 0) {
665 bcopy(abreak
, dp
, 3);
669 /* discard rest of the packet */
683 dconschat_read_socket(struct dcons_state
*dc
, struct dcons_port
*p
)
687 char rbuf
[MAX_XFER
], wbuf
[MAX_XFER
+2];
689 if ((len
= read(p
->infd
, rbuf
, sizeof(rbuf
))) > 0) {
691 dconschat_read_filter(dc
, p
, rbuf
, len
, wbuf
, &wlen
);
692 /* XXX discard if not ready*/
693 if (wlen
> 0 && (dc
->flags
& F_READY
) != 0) {
694 dconschat_write_dcons(dc
, p
->port
, wbuf
, wlen
);
697 printf("(%s)\n", wbuf
);
700 printf("(%d)", wlen
);
707 warnx("port%d: closed", p
->port
);
709 warn("port%d: read", p
->port
);
711 EV_SET(&kev
, p
->infd
, EVFILT_READ
,
712 EV_DELETE
, 0, 0, NULL
);
713 kevent(dc
->kq
, &kev
, 1, NULL
, 0, &dc
->zero
);
716 /* XXX exit for pipe case XXX */
717 EV_SET(&kev
, p
->s
, EVFILT_READ
,
718 EV_ADD
| EV_ONESHOT
, 0, 0, (void *) p
);
719 kevent(dc
->kq
, &kev
, 1, NULL
, 0, &dc
->zero
);
720 p
->infd
= p
->outfd
= -1;
726 dconschat_proc_socket(struct dcons_state
*dc
)
728 struct kevent elist
[NEVENT
], *e
;
730 struct dcons_port
*p
;
732 n
= kevent(dc
->kq
, NULL
, 0, elist
, NEVENT
, &dc
->to
);
733 for (i
= 0; i
< n
; i
++) {
735 p
= (struct dcons_port
*)e
->udata
;
736 if (e
->ident
== p
->s
) {
737 dconschat_accept_socket(dc
, p
);
739 dconschat_read_socket(dc
, p
);
746 dconschat_proc_dcons(struct dcons_state
*dc
)
750 struct dcons_port
*p
;
752 err
= dconschat_get_ptr(dc
);
754 /* XXX we should stop write operation too. */
757 for (port
= 0; port
< DCONS_NPORT
; port
++) {
761 while ((len
= dconschat_read_dcons(dc
, port
, buf
,
763 dconschat_write_socket(p
->outfd
, buf
, len
);
764 dconschat_get_ptr(dc
);
766 if ((dc
->flags
& F_ONE_SHOT
) != 0 && len
<= 0)
767 dconschat_cleanup(0);
773 dconschat_start_session(struct dcons_state
*dc
)
778 if ((dc
->flags
& F_READY
) == 0 &&
779 (++counter
% (poll_hz
* DCONS_POLL_OFFLINE
)) == 0)
780 dconschat_fetch_header(dc
);
781 if ((dc
->flags
& F_READY
) != 0)
782 dconschat_proc_dcons(dc
);
783 dconschat_proc_socket(dc
);
792 "usage: dconschat [-brvwRT1] [-h hz] [-C port] [-G port]\n"
793 "\t\t\t[-M core] [-N system]\n"
794 "\t\t\t[-u unit] [-a address] [-t target_eui64]\n"
795 "\t-b translate ctrl-C to CR+~+ctrl-B on gdb port\n"
797 "\t-w listen on wildcard address rather than localhost\n"
798 "\t-r replay old buffer on connection\n"
800 "\t-T enable Telnet protocol workaround on console port\n"
801 "\t-1 one shot: read buffer and exit\n"
802 "\t-h polling rate\n"
803 "\t-C port number for console port\n"
804 "\t-G port number for gdb port\n"
809 "\t-u specify unit number of the bus\n"
810 "\t-t EUI64 of target host (must be specified)\n"
811 "\t-a physical address of dcons buffer on target host\n"
816 main(int argc
, char **argv
)
818 struct dcons_state
*dc
;
821 char devname
[256], *core
= NULL
, *system
= NULL
;
823 int unit
=0, wildcard
=0;
824 int port
[DCONS_NPORT
];
826 bzero(&sc
, sizeof(sc
));
828 dc
->flags
|= USE_CROM
? F_USE_CROM
: 0;
831 port
[0] = 0; /* stdin/out for console */
832 port
[1] = -1; /* disable gdb port */
834 while ((ch
= getopt(argc
, argv
, "a:bh:rt:u:vwC:G:M:N:RT1")) != -1) {
837 dc
->paddr
= strtoull(optarg
, NULL
, 0);
838 dc
->flags
&= ~F_USE_CROM
;
841 dc
->flags
|= F_ALT_BREAK
;
844 poll_hz
= strtoul(optarg
, NULL
, 0);
846 poll_hz
= DCONS_POLL_HZ
;
849 dc
->flags
|= F_REPLAY
;
852 if (eui64_hostton(optarg
, &target
) != 0 &&
853 eui64_aton(optarg
, &target
) != 0)
854 errx(1, "invalid target: %s", optarg
);
855 eui
.hi
= ntohl(*(u_int32_t
*)&(target
.octet
[0]));
856 eui
.lo
= ntohl(*(u_int32_t
*)&(target
.octet
[4]));
860 unit
= strtol(optarg
, NULL
, 0);
869 port
[0] = strtol(optarg
, NULL
, 0);
872 port
[1] = strtol(optarg
, NULL
, 0);
881 dc
->flags
|= F_RD_ONLY
;
884 dc
->flags
|= F_TELNET
;
887 dc
->flags
|= F_ONE_SHOT
| F_REPLAY
;
893 if (dc
->paddr
== 0 && (dc
->flags
& F_USE_CROM
) == 0) {
894 warnx("no address specified");
898 if (port
[0] < 0 && port
[1] < 0) {
899 warnx("no port specified");
903 /* set signal handler */
904 signal(SIGHUP
, dconschat_cleanup
);
905 signal(SIGINT
, dconschat_cleanup
);
906 signal(SIGPIPE
, dconschat_cleanup
);
907 signal(SIGTERM
, dconschat_cleanup
);
913 for (i
= 0; i
< MAXDEV
; i
++) {
914 snprintf(devname
, sizeof(devname
),
915 "/dev/fwmem%d.%d", unit
, i
);
916 dc
->fd
= open(devname
, O_RDWR
);
922 error
= ioctl(dc
->fd
, FW_SDEUI64
, &eui
);
928 struct nlist nl
[] = {{"dcons_buf"}, {""}};
931 dc
->kd
= kvm_open(system
, core
, NULL
,
932 (dc
->flags
& F_RD_ONLY
) ? O_RDONLY
: O_RDWR
, "dconschat");
936 if (kvm_nlist(dc
->kd
, nl
) < 0)
937 errx(1, "kvm_nlist: %s", kvm_geterr(dc
->kd
));
939 if (kvm_read(dc
->kd
, nl
[0].n_value
, &dcons_buf
,
941 errx(1, "kvm_read: %s", kvm_geterr(dc
->kd
));
942 dc
->paddr
= (uintptr_t)dcons_buf
;
944 printf("dcons_buf: 0x%x\n", (uint
)dc
->paddr
);
948 dconschat_fetch_header(dc
);
957 dc
->to
.tv_nsec
= 1000 * 1000 * 1000 / poll_hz
;
960 dc
->zero
.tv_nsec
= 0;
961 for (i
= 0; i
< DCONS_NPORT
; i
++)
962 dconschat_init_socket(dc
, i
,
963 wildcard
? NULL
: "localhost", port
[i
]);
965 dconschat_start_session(dc
);
967 for (i
= 0; i
< DCONS_NPORT
; i
++) {
968 freeaddrinfo(dc
->port
[i
].res
);