/* * Handle socket events, such as connection failure or success. * - BEV_EVENT_ERROR - network is unreachable * - BEV_EVENT_ERROR+READING - connection refused or connection timed out * - BEV_EVENT_TIMEOUT+READING - write timeout, if activated by * bufferevent_set_timeouts */ static void session_eventcb(struct bufferevent *bev, short what, void *thunk) { struct session *session = thunk; switch (what & ~(BEV_EVENT_READING|BEV_EVENT_WRITING)) { case BEV_EVENT_CONNECTED: session_send(session); return; case BEV_EVENT_EOF: bufferevent_disable(bev, EV_READ|EV_WRITE); if (session->completed) target_mark(session->t, session->seq, '.'); else target_mark(session->t, session->seq, '%'); break; case BEV_EVENT_ERROR: bufferevent_disable(bev, EV_READ|EV_WRITE); target_mark(session->t, session->seq, '#'); break; case BEV_EVENT_TIMEOUT: target_mark(session->t, session->seq, '?'); break; } session_free(session); }
/* * Read response status. Attempt to read the status line, but if CRLF * can not be found in the first 2048 bytes, consider it an error and * disconnect. Once status line is read switch to draining the rest of * the data. The server should close the connection due to * "Connection: close" header otherwise it will be caught by timeout. * * Even though status line says 200, the actual success is registered * on socket close. */ static void session_readcb_status(struct bufferevent *bev, void *thunk) { struct session *session = thunk; struct evbuffer *evbuf = bufferevent_get_input(bev); size_t len; char *line; char *protocol; char *number; line = evbuffer_readln(evbuf, &len, EVBUFFER_EOL_CRLF); if (line == NULL) { if (evbuffer_get_length(evbuf) > 2048) { session_free(session); return; } else return; /* wait for more data */ } /* Parse response line */ protocol = strsep(&line, " "); if (line == NULL) return session_free(session); number = strsep(&line, " "); if (line == NULL) return session_free(session); (void)protocol; (void)number; switch (atoi(number)) { case 200: session->completed = 1; break; default: target_mark(session->t, session->seq, '%'); break; } /* Drain the response on future callbacks */ bufferevent_setcb(session->bev, session_readcb_drain, NULL, session_eventcb, session); }
/* * Register status for send and "timed out" requests and send a probe. */ static void target_probe(int fd, short what, void *thunk) { struct target *t = thunk; /* Missed request */ if (t->npkts > 0 && GETRES(t, -1) != '.') { if (GETRES(t, -1) == ' ') target_mark(t, t->npkts - 1, '?'); if (A_flag == 1) (void)write(STDOUT_FILENO, "\a", 1); else if (A_flag >= 2 && GETRES(t, -4) == '.' && GETRES(t, -3) == '.' && GETRES(t, -2) != '.' && GETRES(t, -1) != '.') (void)write(STDOUT_FILENO, "\a", 1); } /* Check packet count limit */ if (c_count && t->npkts >= c_count) { numcomplete++; event_del(t->ev_write); if (numcomplete >= numtargets) { event_base_loopexit(ev_base, NULL); } return; } /* Transmit request */ t->res[t->npkts % NUM] = ' '; probe_send(t->prb, t->npkts); t->npkts++; ui_update(t); }