/* An event has been completed and the handler is about to be called. This * function writes out tracing data about the event if necessary */ void nsock_trace_handler_callback(struct npool *ms, struct nevent *nse) { struct niod *nsi; char *str; int strlength = 0; char displaystr[256]; char errstr[256]; if (NsockLogLevel > NSOCK_LOG_INFO) return; nsi = nse->iod; if (nse->status == NSE_STATUS_ERROR) Snprintf(errstr, sizeof(errstr), "[%s (%d)] ", socket_strerror(nse->errnum), nse->errnum); else errstr[0] = '\0'; /* Some types have special tracing treatment */ switch (nse->type) { case NSE_TYPE_CONNECT: case NSE_TYPE_CONNECT_SSL: nsock_log_info("Callback: %s %s %sfor EID %li [%s]", nse_type2str(nse->type), nse_status2str(nse->status), errstr, nse->id, get_peeraddr_string(nsi)); break; case NSE_TYPE_READ: if (nse->status != NSE_STATUS_SUCCESS) { nsock_log_info("Callback: %s %s %sfor EID %li [%s]", nse_type2str(nse->type), nse_status2str(nse->status), errstr, nse->id, get_peeraddr_string(nsi)); } else { str = nse_readbuf(nse, &strlength); if (strlength < 80) { memcpy(displaystr, ": ", 2); memcpy(displaystr + 2, str, strlength); displaystr[2 + strlength] = '\0'; replacenonprintable(displaystr + 2, strlength, '.'); } else { displaystr[0] = '\0'; } nsock_log_info("Callback: %s %s for EID %li [%s] %s(%d bytes)%s", nse_type2str(nse->type), nse_status2str(nse->status), nse->id, get_peeraddr_string(nsi), nse_eof(nse) ? "[EOF]" : "", strlength, displaystr); } break; case NSE_TYPE_WRITE: nsock_log_info("Callback: %s %s %sfor EID %li [%s]", nse_type2str(nse->type), nse_status2str(nse->status), errstr, nse->id, get_peeraddr_string(nsi)); break; case NSE_TYPE_TIMER: nsock_log_info("Callback: %s %s %sfor EID %li", nse_type2str(nse->type), nse_status2str(nse->status), errstr, nse->id); break; #if HAVE_PCAP case NSE_TYPE_PCAP_READ: nsock_log_info("Callback: %s %s %sfor EID %li ", nse_type2str(nse->type), nse_status2str(nse->status), errstr, nse->id); break; #endif default: fatal("Invalid nsock event type (%d)", nse->type); } }
void telnet_event_handler(nsock_pool nsp, nsock_event nse, void *mydata) { nsock_iod nsi = nse_iod(nse); enum nse_status status = nse_status(nse); enum nse_type type = nse_type(nse); struct sockaddr_in peer; struct telnet_state *ts; int nbytes; char *str; int read_timeout = -1; int write_timeout = 2000; ts = (struct telnet_state *)mydata; printf("telnet_event_handler: Received callback of type %s with status %s\n", nse_type2str(type), nse_status2str(status)); if (status == NSE_STATUS_SUCCESS) { switch (type) { case NSE_TYPE_CONNECT: case NSE_TYPE_CONNECT_SSL: nsi_getlastcommunicationinfo(nsi, NULL, NULL, NULL, (struct sockaddr *)&peer, sizeof peer); printf("Successfully connected %sto %s:%hu -- start typing lines\n", (type == NSE_TYPE_CONNECT_SSL) ? "(SSL!) " : "", inet_ntoa(peer.sin_addr), peer.sin_port); /* First of all, lets add STDIN to our list of watched filehandles */ if ((ts->stdin_nsi = nsi_new2(nsp, STDIN_FILENO, NULL)) == NULL) { fprintf(stderr, "Failed to create stdin msi\n"); exit(1); } /* Now lets read from stdin and the network, line buffered (by nsock) */ ts->latest_readtcpev = nsock_readlines(nsp, ts->tcp_nsi, telnet_event_handler, read_timeout, ts, 1); ts->latest_readstdinev = nsock_readlines(nsp, ts->stdin_nsi, telnet_event_handler, read_timeout, ts, 1); break; case NSE_TYPE_READ: str = nse_readbuf(nse, &nbytes); if (nsi == ts->tcp_nsi) { printf("%s", str); /* printf("Read from tcp socket (%d bytes):\n%s", nbytes, str); */ ts->latest_readtcpev = nsock_readlines(nsp, ts->tcp_nsi, telnet_event_handler, read_timeout, ts, 1); } else { /* printf("Read from stdin (%d bytes):\n%s", nbytes, str); */ nsock_write(nsp, ts->tcp_nsi, telnet_event_handler, write_timeout, ts, str, nbytes); ts->latest_readstdinev = nsock_readlines(nsp, ts->stdin_nsi, telnet_event_handler, read_timeout, ts, 1); } break; case NSE_TYPE_WRITE: /* Nothing to do, really */ break; case NSE_TYPE_TIMER: break; default: fprintf(stderr, "telnet_event_handler: Got bogus type -- quitting\n"); exit(1); break; } } else if (status == NSE_STATUS_EOF) { printf("Got EOF from %s\nCancelling outstanding readevents.\n", (nsi == ts->tcp_nsi) ? "tcp socket" : "stdin"); /* One of these is the event I am currently handling! But I wanted to be evil when testing this out... */ if (nsock_event_cancel(nsp, ts->latest_readtcpev, 1) != 0) { printf("Cancelled tcp event: %li\n", ts->latest_readtcpev); } if (nsock_event_cancel(nsp, ts->latest_readstdinev, 1) != 0) { printf("Cancelled stdin event: %li\n", ts->latest_readstdinev); } } else if (status == NSE_STATUS_ERROR) { if (nsi_checkssl(nsi)) { printf("SSL %s failed: %s\n", nse_type2str(type), ERR_error_string(ERR_get_error(), NULL)); } else { int err; err = nse_errorcode(nse); printf("%s failed: (%d) %s\n", nse_type2str(type), err, strerror(err)); } } return; }
/* An event has been completed and the handler is about to be called. This * function writes out tracing data about the event if necessary */ void nsock_trace_handler_callback(mspool *ms, msevent *nse) { msiod *nsi; char *str; int strlength = 0; char displaystr[256]; char errstr[256]; if (ms->tracelevel == 0) return; nsi = nse->iod; if (nse->status == NSE_STATUS_ERROR) Snprintf(errstr, sizeof(errstr), "[%s (%d)] ", socket_strerror(nse->errnum), nse->errnum); else errstr[0] = '\0'; /* Some types have special tracing treatment */ switch(nse->type) { case NSE_TYPE_CONNECT: case NSE_TYPE_CONNECT_SSL: nsock_trace(ms, "Callback: %s %s %sfor EID %li [%s]", nse_type2str(nse->type), nse_status2str(nse->status), errstr, nse->id, get_peeraddr_string(nsi)); break; case NSE_TYPE_READ: if (nse->status != NSE_STATUS_SUCCESS) { if (nsi->peerlen > 0) { nsock_trace(ms, "Callback: %s %s %sfor EID %li [%s]", nse_type2str(nse->type), nse_status2str(nse->status), errstr, nse->id, get_peeraddr_string(nsi)); } else { nsock_trace(ms, "Callback: %s %s %sfor EID %li (peer unspecified)", nse_type2str(nse->type), nse_status2str(nse->status), errstr, nse->id); } } else { str = nse_readbuf(nse, &strlength); if (ms->tracelevel > 1 && strlength < 80) { memcpy(displaystr, ": ", 2); memcpy(displaystr + 2, str, strlength); displaystr[2 + strlength] = '\0'; replacenonprintable(displaystr + 2, strlength, '.'); } else { displaystr[0] = '\0'; } if (nsi->peerlen > 0) { nsock_trace(ms, "Callback: %s %s for EID %li [%s] %s(%d bytes)%s", nse_type2str(nse->type), nse_status2str(nse->status), nse->id, get_peeraddr_string(nsi), nse_eof(nse)? "[EOF]" : "", strlength, displaystr); } else { nsock_trace(ms, "Callback %s %s for EID %li (peer unspecified) %s(%d bytes)%s", nse_type2str(nse->type), nse_status2str(nse->status), nse->id, nse_eof(nse)? "[EOF]" : "", strlength, displaystr); } } break; case NSE_TYPE_WRITE: nsock_trace(ms, "Callback: %s %s %sfor EID %li [%s]", nse_type2str(nse->type), nse_status2str(nse->status), errstr, nse->id, get_peeraddr_string(nsi)); break; case NSE_TYPE_TIMER: nsock_trace(ms, "Callback: %s %s %sfor EID %li", nse_type2str(nse->type), nse_status2str(nse->status), errstr, nse->id); break; #if HAVE_PCAP case NSE_TYPE_PCAP_READ: nsock_trace(ms, "Callback: %s %s %sfor EID %li ", nse_type2str(nse->type), nse_status2str(nse->status), errstr, nse->id); break; #endif default: assert(0); break; } }
void timer_handler(nsock_pool nsp, nsock_event nse, void *mydata) { enum nse_status status = nse_status(nse); enum nse_type type = nse_type(nse); int rnd, rnd2; printf("%ld:timer_handler: Received callback of type %s; status %s; id %li\n", time(NULL), nse_type2str(type), nse_status2str(status), nse_id(nse)); rnd = rand() % num_ids; rnd2 = rand() % 3; if (num_ids > (sizeof(ev_ids) / sizeof(nsock_event_id)) - 3) { printf("\n\nSUCCEEDED DUE TO CREATING ENOUGH EVENTS THAT IT WAS GOING TO OVERFLOW MY BUFFER :)\n\n"); exit(0); } if (status == NSE_STATUS_SUCCESS) { switch (rnd2) { case 0: /* do nothing */ /* Actually I think I'll create two timers :) */ ev_ids[num_ids++] = request_timer(nsp, timer_handler, rand() % 3000, NULL); ev_ids[num_ids++] = request_timer(nsp, timer_handler, rand() % 3000, NULL); break; case 1: /* Kill another id (which may or may not be active */ try_cancel_timer(nsp, rnd, rand() % 2); break; case 2: /* Create a new timer */ ev_ids[num_ids++] = request_timer(nsp, timer_handler, rand() % 3000, NULL); break; default: assert(0); } } }
/* An internal function for cancelling an event when you already have a pointer * to the msevent (use nsock_event_cancel if you just have an ID). The * event_list passed in should correspond to the type of the event. For example, * with NSE_TYPE_READ, you would pass in &nsp->read_events;. elem is the list * element in event_list which holds the event. Pass a nonzero for notify if * you want the program owning the event to be notified that it has been * cancelled */ int msevent_cancel(mspool *nsp, msevent *nse, gh_list_t *event_list, gh_lnode_t *elem, int notify) { if (nse->event_done) { /* This event has already been marked for death somewhere else -- it will be * gone soon (and if we try to kill it now all hell will break loose due to * reentrancy. */ return 0; } nsock_log_info(nsp, "msevent_cancel on event #%li (type %s)", nse->id, nse_type2str(nse->type)); /* Now that we found the event... we go through the motions of cleanly * cancelling it */ switch (nse->type) { case NSE_TYPE_CONNECT: case NSE_TYPE_CONNECT_SSL: handle_connect_result(nsp, nse, NSE_STATUS_CANCELLED); break; case NSE_TYPE_READ: handle_read_result(nsp, nse, NSE_STATUS_CANCELLED); break; case NSE_TYPE_WRITE: handle_write_result(nsp, nse, NSE_STATUS_CANCELLED); break; case NSE_TYPE_TIMER: handle_timer_result(nsp, nse, NSE_STATUS_CANCELLED); break; #if HAVE_PCAP case NSE_TYPE_PCAP_READ: handle_pcap_read_result(nsp, nse, NSE_STATUS_CANCELLED); break; #endif default: fatal("Invalid nsock event type (%d)", nse->type); } assert(nse->event_done); if (nse->timeout.tv_sec) gh_heap_remove(&nsp->expirables, &nse->expire); if (event_list) { update_first_events(nse); gh_list_remove(event_list, elem); } gh_list_append(&nsp->free_events, &nse->nodeq_io); nsock_log_debug_all(nsp, "NSE #%lu: Removing event from list", nse->id); #if HAVE_PCAP #if PCAP_BSD_SELECT_HACK if (nse->type == NSE_TYPE_PCAP_READ) { nsock_log_debug_all(nsp, "PCAP NSE #%lu: CANCEL TEST pcap=%p read=%p curr=%p sd=%i", nse->id, &nsp->pcap_read_events, &nsp->read_events, event_list,((mspcap *)nse->iod->pcap)->pcap_desc); /* If event occurred, and we're in BSD_HACK mode, then this event was added to * two queues. read_event and pcap_read_event Of course we should * destroy it only once. I assume we're now in read_event, so just unlink * this event from pcap_read_event */ if (((mspcap *)nse->iod->pcap)->pcap_desc >= 0 && event_list == &nsp->read_events) { /* event is done, list is read_events and we're in BSD_HACK mode. So unlink * event from pcap_read_events */ gh_list_remove(&nsp->pcap_read_events, &nse->nodeq_pcap); nsock_log_debug_all(nsp, "PCAP NSE #%lu: Removing event from PCAP_READ_EVENTS", nse->id); } if (((mspcap *)nse->iod->pcap)->pcap_desc >= 0 && event_list == &nsp->pcap_read_events) { /* event is done, list is read_events and we're in BSD_HACK mode. * So unlink event from read_events */ gh_list_remove(&nsp->read_events, &nse->nodeq_io); nsock_log_debug_all(nsp, "PCAP NSE #%lu: Removing event from READ_EVENTS", nse->id); } } #endif #endif msevent_dispatch_and_delete(nsp, nse, notify); return 1; }
/* Cancel an event (such as a timer or read request). If notify is nonzero, the * requester will be sent an event CANCELLED status back to the given handler. * But in some cases there is no need to do this (like if the function deleting * it is the one which created it), in which case 0 can be passed to skip the * step. This function returns zero if the event is not found, nonzero * otherwise. */ int nsock_event_cancel(nsock_pool ms_pool, nsock_event_id id, int notify) { mspool *nsp = (mspool *)ms_pool; enum nse_type type; unsigned int i; gh_list_t *event_list = NULL, *event_list2 = NULL; gh_lnode_t *current, *next; msevent *nse = NULL; assert(nsp); type = get_event_id_type(id); nsock_log_info(nsp, "Event #%li (type %s) cancelled", id, nse_type2str(type)); /* First we figure out what list it is in */ switch (type) { case NSE_TYPE_CONNECT: case NSE_TYPE_CONNECT_SSL: event_list = &nsp->connect_events; break; case NSE_TYPE_READ: event_list = &nsp->read_events; break; case NSE_TYPE_WRITE: event_list = &nsp->write_events; break; case NSE_TYPE_TIMER: for (i = 0; i < gh_heap_count(&nsp->expirables); i++) { gh_hnode_t *hnode; hnode = gh_heap_find(&nsp->expirables, i); nse = container_of(hnode, msevent, expire); if (nse->id == id) return msevent_cancel(nsp, nse, NULL, NULL, notify); } return 0; #if HAVE_PCAP case NSE_TYPE_PCAP_READ: event_list = &nsp->read_events; event_list2 = &nsp->pcap_read_events; break; #endif default: fatal("Bogus event type in nsock_event_cancel"); break; } /* Now we try to find the event in the list */ for (current = gh_list_first_elem(event_list); current != NULL; current = next) { next = gh_lnode_next(current); nse = lnode_msevent(current); if (nse->id == id) break; } if (current == NULL && event_list2) { event_list = event_list2; for (current = gh_list_first_elem(event_list); current != NULL; current = next) { next = gh_lnode_next(current); nse = lnode_msevent2(current); if (nse->id == id) break; } } if (current == NULL) return 0; return msevent_cancel(nsp, nse, event_list, current, notify); }
/* Cancel an event (such as a timer or read request). If notify is nonzero, the * requester will be sent an event CANCELLED status back to the given handler. * But in some cases there is no need to do this (like if the function deleting * it is the one which created it), in which case 0 can be passed to skip the * step. This function returns zero if the event is not found, nonzero * otherwise. */ int nsock_event_cancel(nsock_pool ms_pool, nsock_event_id id, int notify) { mspool *nsp = (mspool *)ms_pool; enum nse_type type; gh_list *event_list = NULL, *event_list2 = NULL; gh_list_elem *current, *next; msevent *nse = NULL; assert(nsp); type = get_event_id_type(id); nsock_log_info(nsp, "Event #%li (type %s) cancelled", id, nse_type2str(type)); /* First we figure out what list it is in */ switch(type) { case NSE_TYPE_CONNECT: event_list = &nsp->connect_events; break; case NSE_TYPE_READ: event_list = &nsp->read_events; break; case NSE_TYPE_WRITE: event_list = &nsp->write_events; break; case NSE_TYPE_TIMER: event_list = &nsp->timer_events; break; #if HAVE_PCAP case NSE_TYPE_PCAP_READ: event_list = &nsp->read_events; event_list2 = &nsp->pcap_read_events; break; #endif default: fatal("Bogus event type in nsock_event_cancel"); break; } /* Now we try to find the event in the list */ for (current = GH_LIST_FIRST_ELEM(event_list); current != NULL; current = next) { next = GH_LIST_ELEM_NEXT(current); nse = (msevent *)GH_LIST_ELEM_DATA(current); if (nse->id == id) break; } if (current == NULL && event_list2){ event_list = event_list2; for (current = GH_LIST_FIRST_ELEM(event_list); current != NULL; current = next) { next = GH_LIST_ELEM_NEXT(current); nse = (msevent *)GH_LIST_ELEM_DATA(current); if (nse->id == id) break; } } if (current == NULL) return 0; return msevent_cancel(nsp, nse, event_list, current, notify); }