const char * time_string (time_t t, int usec, bool show_usec, struct gc_arena *gc) { struct buffer out = alloc_buf_gc (64, gc); struct timeval tv; if (t) { tv.tv_sec = t; tv.tv_usec = usec; } else { gettimeofday (&tv, NULL); } t = tv.tv_sec; buf_printf (&out, "%s", ctime(&t)); buf_rmtail (&out, '\n'); if (show_usec && tv.tv_usec) buf_printf (&out, " us=%d", (int)tv.tv_usec); return BSTR (&out); }
const char * format_extended_socket_error (int fd, int *mtu, struct gc_arena *gc) { int res; struct probehdr rcvbuf; struct iovec iov; struct msghdr msg; struct cmsghdr *cmsg; struct sock_extended_err *e; struct sockaddr_in addr; struct buffer out = alloc_buf_gc (256, gc); char *cbuf = (char *) gc_malloc (256, false, gc); *mtu = 0; while (true) { memset (&rcvbuf, -1, sizeof (rcvbuf)); iov.iov_base = &rcvbuf; iov.iov_len = sizeof (rcvbuf); msg.msg_name = (uint8_t *) &addr; msg.msg_namelen = sizeof (addr); msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_flags = 0; msg.msg_control = cbuf; msg.msg_controllen = 256; /* size of cbuf */ res = recvmsg (fd, &msg, MSG_ERRQUEUE); if (res < 0) goto exit; e = NULL; for (cmsg = CMSG_FIRSTHDR (&msg); cmsg; cmsg = CMSG_NXTHDR (&msg, cmsg)) { if (cmsg->cmsg_level == SOL_IP) { if (cmsg->cmsg_type == IP_RECVERR) { e = (struct sock_extended_err *) CMSG_DATA (cmsg); } else { buf_printf (&out ,"CMSG=%d|", cmsg->cmsg_type); } } } if (e == NULL) { buf_printf (&out, "NO-INFO|"); goto exit; } switch (e->ee_errno) { case ETIMEDOUT: buf_printf (&out, "ETIMEDOUT|"); break; case EMSGSIZE: buf_printf (&out, "EMSGSIZE Path-MTU=%d|", e->ee_info); *mtu = e->ee_info; break; case ECONNREFUSED: buf_printf (&out, "ECONNREFUSED|"); break; case EPROTO: buf_printf (&out, "EPROTO|"); break; case EHOSTUNREACH: buf_printf (&out, "EHOSTUNREACH|"); break; case ENETUNREACH: buf_printf (&out, "ENETUNREACH|"); break; case EACCES: buf_printf (&out, "EACCES|"); break; default: buf_printf (&out, "UNKNOWN|"); break; } } exit: buf_rmtail (&out, '|'); return BSTR (&out); }