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 + -
显示快捷键?