/* * SIPB service monitor: TCP connections * * Nickolai Zeldovich * May 2002 */ #include #include #include "sipbmon.h" struct tcpconn_t { bool abort; tcpconn_t () : abort (false) {} }; static void tcpconn_write_cb (int fd, cbi cb, tcpconn_t *tc) { fdcb (fd, selwrite, NULL); if (tc->abort) { close (fd); delete tc; return; } sockaddr_in sin; socklen_t sn = sizeof (sin); if (!getpeername (fd, (sockaddr *) &sin, &sn)) { (*cb) (fd); delete tc; return; } int err = 0; sn = sizeof (err); getsockopt (fd, SOL_SOCKET, SO_ERROR, (char *) &err, &sn); close (fd); errno = err ? err : ECONNREFUSED; (*cb) (-1); delete tc; } static void tcpconn_name_cb (u_int16_t port, cbi cb, tcpconn_t *tc, ptrh, int err) { if (tc->abort) { delete tc; return; } if (!h) { errno = ENOENT; (*cb) (-1); delete tc; return; } sockaddr_in sin; bzero (&sin, sizeof (sin)); sin.sin_family = AF_INET; sin.sin_port = htons (port); sin.sin_addr = *(in_addr *) h->h_addr; int fd = inetsocket (SOCK_STREAM); if (fd < 0) { (*cb) (-1); delete tc; return; } make_async (fd); close_on_exec (fd); if (connect (fd, (sockaddr *) &sin, sizeof (sin)) < 0 && errno != EINPROGRESS) { close (fd); (*cb) (-1); delete tc; return; } fdcb (fd, selwrite, wrap (&tcpconn_write_cb, fd, cb, tc)); } tcpconn_t * tcpconn (str host, u_int16_t port, cbi cb) { tcpconn_t *tc = New tcpconn_t; dns_hostbyname (host, wrap (&tcpconn_name_cb, port, cb, tc), true); return tc; } void tcpconn_abort (tcpconn_t *tc) { tc->abort = true; }