nsock_core.c
来自「Ubuntu packages of security software。 相」· C语言 代码 · 共 1,208 行 · 第 1/3 页
C
1,208 行
err = SSL_get_error(iod->ssl, res); if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE ) { nse->sslinfo.ssl_desire = err; } else { /* Unexpected error */ nse->event_done = 1; nse->status = NSE_STATUS_ERROR; nse->errnum = EIO; }#endif } else { err = socket_errno(); if (err != EINTR && err != EAGAIN #ifndef WIN32 && err != EBUSY#endif ) { nse->event_done = 1; nse->status = NSE_STATUS_ERROR; nse->errnum = err; } } } } if (nse->event_done && nse->iod->sd != -1) { if (!iod->ssl) { FD_CLR(nse->iod->sd, &ms->mioi.fds_master_w); FD_CLR(nse->iod->sd, &ms->mioi.fds_results_w); } else if (iod->events_pending <= 1) { FD_CLR(iod->sd, &ms->mioi.fds_master_r); FD_CLR(iod->sd, &ms->mioi.fds_results_r); FD_CLR(iod->sd, &ms->mioi.fds_master_w); FD_CLR(iod->sd, &ms->mioi.fds_results_w); } /* Note -- I only want to decrement IOD if there are no other events hinging on it. For example, there could be a READ and WRITE outstanding at once */ if (nse->iod->events_pending <= 1 && ms->mioi.max_sd == nse->iod->sd) ms->mioi.max_sd--; } return;}void handle_timer_result(mspool *ms, msevent *nse, enum nse_status status) { /* Ooh this is a hard job :) */ nse->event_done = 1; nse->status = status; return;}/* Returns -1 if an error, otherwise the number of newly written bytes */static int do_actual_read(mspool *ms, msevent *nse) { char buf[8192]; int buflen = 0; msiod *iod = nse->iod; int err = 0; int max_chunk = NSOCK_READ_CHUNK_SIZE; int startlen = FILESPACE_LENGTH(&nse->iobuf); if (nse->readinfo.read_type == NSOCK_READBYTES && nse->readinfo.num > max_chunk) max_chunk = nse->readinfo.num; if (!iod->ssl) { /* Traditional read() - no SSL - using recv() because that works better on Windows */ do { buflen = recv(iod->sd, buf, sizeof(buf), 0); if (buflen == -1) err = socket_errno(); if (buflen > 0) { if (fscat(&nse->iobuf, buf, buflen) == -1) { nse->event_done = 1; nse->status = NSE_STATUS_ERROR; nse->errnum = ENOMEM; return -1; } /* Sometimes a service just spews and spews data. So we return * after a somewhat large amount to avoid monopolizing resources * and avoid DOS attacks. */ if (FILESPACE_LENGTH(&nse->iobuf) > max_chunk) return FILESPACE_LENGTH(&nse->iobuf) - startlen; /* No good reason to read again if we we were successful in the read but * didn't fill up the buffer. I'll insist on it being TCP too, because I * think UDP might only give me one packet worth at a time (I dunno ...). */ if (buflen > 0 && buflen < sizeof(buf) && iod->lastproto == IPPROTO_TCP) return FILESPACE_LENGTH(&nse->iobuf) - startlen; } } while (buflen > 0 || (buflen == -1 && err == EINTR)); if (buflen == -1) { if (err != EINTR && err != EAGAIN) { nse->event_done = 1; nse->status = NSE_STATUS_ERROR; nse->errnum = err; return -1; } } } else {#if HAVE_OPENSSL /* OpenSSL read */ while ((buflen = SSL_read(iod->ssl, buf, sizeof(buf))) > 0) { if (fscat(&nse->iobuf, buf, buflen) == -1) { nse->event_done = 1; nse->status = NSE_STATUS_ERROR; nse->errnum = ENOMEM; return -1; } /* Sometimes a service just spews and spews data. So we return * after a somewhat large amount to avoid monopolizing resources * and avoid DOS attacks. */ if (FILESPACE_LENGTH(&nse->iobuf) > NSOCK_READ_CHUNK_SIZE) return FILESPACE_LENGTH(&nse->iobuf) - startlen; } if (buflen == -1) { err = SSL_get_error(iod->ssl, buflen); if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE ) { nse->sslinfo.ssl_desire = err; } else { /* Unexpected error */ nse->event_done = 1; nse->status = NSE_STATUS_ERROR; nse->errnum = EIO; if (ms->tracelevel > 2) nsock_trace(ms, "SSL_read() failed for reason %s on NSI %li", ERR_reason_error_string(err), iod->id); return -1; } }#endif /* HAVE_OPENSSL */ } if (buflen == 0) { nse->event_done = 1; nse->eof = 1; if (FILESPACE_LENGTH(&nse->iobuf) > 0) { nse->status = NSE_STATUS_SUCCESS; return FILESPACE_LENGTH(&nse->iobuf) - startlen; } else { nse->status = NSE_STATUS_EOF; return 0; } } return FILESPACE_LENGTH(&nse->iobuf) - startlen;}void handle_read_result(mspool *ms, msevent *nse, enum nse_status status) { unsigned int count; char *str; int rc, len; msiod *iod = nse->iod; if (status == NSE_STATUS_TIMEOUT) { nse->event_done = 1; if (FILESPACE_LENGTH(&nse->iobuf) > 0) { nse->status = NSE_STATUS_SUCCESS; } else { nse->status = NSE_STATUS_TIMEOUT; } } else if (status == NSE_STATUS_CANCELLED) { nse->status = status; nse->event_done = 1; } else if (status == NSE_STATUS_SUCCESS) { rc = do_actual_read(ms, nse); /* printf("DBG: Just read %d new bytes%s.\n", rc, iod->ssl? "( SSL!)" : ""); */ if (rc > 0) { /* We decide whether we have read enough to return */ switch(nse->readinfo.read_type) { case NSOCK_READ: nse->status = NSE_STATUS_SUCCESS; nse->event_done = 1; break; case NSOCK_READBYTES: if (FILESPACE_LENGTH(&nse->iobuf) >= nse->readinfo.num) { nse->status = NSE_STATUS_SUCCESS; nse->event_done = 1; } /* else we are not done */ break; case NSOCK_READLINES: /* Lets count the number of lines we have ... */ count = 0; len = FILESPACE_LENGTH(&nse->iobuf) -1; str = FILESPACE_STR(&nse->iobuf); for(count=0; len >= 0; len--) { if (str[len] == '\n') { count++; if ((int) count >= nse->readinfo.num) break; } } if ((int) count >= nse->readinfo.num) { nse->event_done = 1; nse->status = NSE_STATUS_SUCCESS; } /* Else we are not done */ break; default: assert(0); break; /* unreached */ } } } else { assert(0); /* Currently we only know about TIMEOUT, CANCELLED, and SUCCESS callbacks */ } /* If we asked for an event dispatch, we are done reading on the socket so we can take it off the descriptor list ... */ if (nse->event_done && iod->sd >= 0) { /* Exception: If this is an SSL socket and there is another pending event (such as a write), it might actually be waiting on a read so we can't clear in that case */ if (!iod->ssl) { FD_CLR(iod->sd, &ms->mioi.fds_master_r); FD_CLR(iod->sd, &ms->mioi.fds_results_r); } else if (iod->events_pending <= 1) { FD_CLR(iod->sd, &ms->mioi.fds_master_r); FD_CLR(iod->sd, &ms->mioi.fds_results_r); FD_CLR(iod->sd, &ms->mioi.fds_master_w); FD_CLR(iod->sd, &ms->mioi.fds_results_w); } /* Note -- I only want to decrement IOD if there are no other events hinging on it. * For example, there could be a READ and WRITE outstanding at once */ if (iod->events_pending <= 1 && ms->mioi.max_sd == iod->sd) ms->mioi.max_sd--; }#if HAVE_OPENSSL /* For SSL the type of listening we have to do varies. I can't clear the other type due to the possibility of a pending event needing it */ if (iod->ssl && nse->event_done == 0) { if (nse->sslinfo.ssl_desire == SSL_ERROR_WANT_READ) { FD_SET(iod->sd, &ms->mioi.fds_master_r); ms->mioi.max_sd = MAX(ms->mioi.max_sd, iod->sd); } else if (nse->sslinfo.ssl_desire == SSL_ERROR_WANT_WRITE) { FD_SET(iod->sd, &ms->mioi.fds_master_w); ms->mioi.max_sd = MAX(ms->mioi.max_sd, iod->sd); } }#endif /* HAVE_OPENSSL */ return;}#if HAVE_PCAPvoid handle_pcap_read_result(mspool *ms, msevent *nse, enum nse_status status) { msiod *iod = nse->iod; mspcap *mp = (mspcap *) iod->pcap; if (status == NSE_STATUS_TIMEOUT) { nse->status = NSE_STATUS_TIMEOUT; nse->event_done = 1; } else if (status == NSE_STATUS_CANCELLED) { nse->status = NSE_STATUS_CANCELLED; nse->event_done = 1; } else if (status == NSE_STATUS_SUCCESS) { /* check if we already have something read */ if(FILESPACE_LENGTH(&(nse->iobuf)) == 0){ nse->status = NSE_STATUS_TIMEOUT; nse->event_done = 0; }else{ nse->status = NSE_STATUS_SUCCESS;/* we have full buffer */ nse->event_done = 1; } } else { assert(0); /* Currently we only know about TIMEOUT, CANCELLED, and SUCCESS callbacks */ } /* If we asked for an event dispatch, we are done reading on the socket so we can take it off the descriptor list ... */ if (nse->event_done && mp->pcap_desc >= 0) { FD_CLR(mp->pcap_desc, &ms->mioi.fds_master_r); FD_CLR(mp->pcap_desc, &ms->mioi.fds_results_r); } return;}/* * returns number of descriptors on which data was read * */static int pcap_read_on_nonselect(mspool *nsp){ gh_list *event_list = &nsp->evl.pcap_read_events; gh_list_elem *current, *next; msevent *nse; int rc; int ret = 0; for(current = GH_LIST_FIRST_ELEM(event_list); current != NULL; current = next) { nse = (msevent *) GH_LIST_ELEM_DATA(current); rc = do_actual_pcap_read(nse); if(rc==1){ /* something received */ ret++; break; } next = GH_LIST_ELEM_NEXT(current); } return(ret);}#endif // HAVE_PCAP /* Iterate through all the event lists (such as connect_events, read_events, timer_events, etc) and take action for those that have completed (due to timeout, i/o, etc) */static void iterate_through_event_lists(mspool *nsp) { gh_list_elem *current, *next; msevent *nse; int match_r = 0, match_w = 0;#if HAVE_OPENSSL int desire_r = 0, desire_w = 0;#endif gh_list *event_lists[] = { &nsp->evl.connect_events, &nsp->evl.read_events, &nsp->evl.write_events, &nsp->evl.timer_events, #if HAVE_PCAP &nsp->evl.pcap_read_events, #endif 0 }; int current_list_idx; nsp->evl.next_ev.tv_sec = 0; /* Clear it -- We will find the next event as we go through the list */ /* We keep the events seperate because we want to handle them in the order: connect => read => write => timer for several reasons: 1) Makes sure we have gone through all the net i/o events before a timer expires (would be a shame to timeout after the data was available but before we delivered the events 2) The connect() results often lead to a read or write that can be processed in the same cycle. In the same way, read() often leads to write(). */ /* foreach list */ if (nsp->tracelevel > 7){ for(current_list_idx = 0; event_lists[current_list_idx] != NULL; current_list_idx++) { nsock_trace(nsp, "before iterating, list %i", current_list_idx); for(current = GH_LIST_FIRST_ELEM(event_lists[current_list_idx]); current != NULL; current = GH_LIST_ELEM_NEXT(current)) { nse = (msevent *) GH_LIST_ELEM_DATA(current); nsock_trace(nsp, "before iterating %lu",nse->id); } } } /* foreach list */ for(current_list_idx = 0; event_lists[current_list_idx] != NULL; current_list_idx++) { /* foreach element in the list */ for(current = GH_LIST_FIRST_ELEM(event_lists[current_list_idx]); current != NULL; current = next) { nse = (msevent *) GH_LIST_ELEM_DATA(current); if (nsp->tracelevel > 7) nsock_trace(nsp, "list %i, iterating %lu",current_list_idx, nse->id); if ( ! nse->event_done) { switch(nse->type) { case NSE_TYPE_CONNECT: case NSE_TYPE_CONNECT_SSL: if (FD_ISSET(nse->iod->sd, &nsp->mioi.fds_results_r) || FD_ISSET(nse->iod->sd, &nsp->mioi.fds_results_w) || FD_ISSET(nse->iod->sd, &nsp->mioi.fds_results_x)) { handle_connect_result(nsp, nse, NSE_STATUS_SUCCESS); } if (!nse->event_done && nse->timeout.tv_sec && TIMEVAL_MSEC_SUBTRACT(nse->timeout, nsock_tod) <= 0) { handle_connect_result(nsp, nse, NSE_STATUS_TIMEOUT); } break;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?