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