nsock_core.c
来自「Ubuntu packages of security software。 相」· C语言 代码 · 共 1,013 行 · 第 1/3 页
C
1,013 行
ms->mioi.max_sd = MAX(ms->mioi.max_sd, iod->sd); } else if (rc == -1 && sslerr == SSL_ERROR_WANT_WRITE) { nse->sslinfo.ssl_desire = sslerr; FD_SET(iod->sd, &ms->mioi.fds_master_w); ms->mioi.max_sd = MAX(ms->mioi.max_sd, iod->sd); } else { /* Unexpected error */ nse->event_done = 1; nse->status = NSE_STATUS_ERROR; nse->errnum = EIO; } } }#endif return;}void handle_write_result(mspool *ms, msevent *nse, enum nse_status status) { int bytesleft; char *str; int res; int err; msiod *iod = nse->iod; if (status == NSE_STATUS_TIMEOUT || status == NSE_STATUS_CANCELLED) { nse->event_done = 1; nse->status = status; } else if (status == NSE_STATUS_SUCCESS) { str = FILESPACE_STR(&nse->iobuf) + nse->writeinfo.written_so_far; bytesleft = FILESPACE_LENGTH(&nse->iobuf) - nse->writeinfo.written_so_far; assert(bytesleft > 0);#if HAVE_OPENSSL if (iod->ssl) res = SSL_write(iod->ssl, str, bytesleft); else#endif res = send(nse->iod->sd, str, bytesleft, 0); if (res == bytesleft) { nse->event_done = 1; nse->status = NSE_STATUS_SUCCESS; } else if (res >= 0) { nse->writeinfo.written_so_far += res; } else { assert(res == -1); if (iod->ssl) {#if HAVE_OPENSSL 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;} /* 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, 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
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?