client.c
来自「SSL加密库源码」· C语言 代码 · 共 971 行 · 第 1/3 页
C
971 行
if(c->sock_wfd->fd>fdno) fdno=c->sock_wfd->fd;
if(c->ssl_rfd->fd>fdno) fdno=c->ssl_rfd->fd;
if(c->ssl_wfd->fd>fdno) fdno=c->ssl_wfd->fd;
fdno+=1;
c->sock_ptr=c->ssl_ptr=0;
sock_rd=sock_wr=ssl_rd=ssl_wr=1;
c->sock_bytes=c->ssl_bytes=0;
ssl_closing=0;
while(((sock_rd||c->sock_ptr)&&ssl_wr)||((ssl_rd||c->ssl_ptr)&&sock_wr)) {
FD_ZERO(&rd_set); /* Setup rd_set */
if(sock_rd && c->sock_ptr<BUFFSIZE) /* socket input buffer not full*/
FD_SET(c->sock_rfd->fd, &rd_set);
if(ssl_rd && (
c->ssl_ptr<BUFFSIZE || /* SSL input buffer not full */
((c->sock_ptr||ssl_closing) && SSL_want_read(c->ssl))
/* I want to SSL_write or SSL_shutdown but read from the
* underlying socket needed for the SSL protocol */
)) {
FD_SET(c->ssl_rfd->fd, &rd_set);
}
FD_ZERO(&wr_set); /* Setup wr_set */
if(sock_wr && c->ssl_ptr) /* SSL input buffer not empty */
FD_SET(c->sock_wfd->fd, &wr_set);
if (ssl_wr && (
c->sock_ptr || /* socket input buffer not empty */
ssl_closing==1 || /* initiate SSL_shutdown */
((c->ssl_ptr<BUFFSIZE || ssl_closing==2) &&
SSL_want_write(c->ssl))
/* I want to SSL_read or SSL_shutdown but write to the
* underlying socket needed for the SSL protocol */
)) {
FD_SET(c->ssl_wfd->fd, &wr_set);
}
tv.tv_sec=sock_rd ||
(ssl_wr&&c->sock_ptr) || (sock_wr&&c->ssl_ptr) ?
c->opt->timeout_idle : c->opt->timeout_close;
tv.tv_usec=0;
ready=sselect(fdno, &rd_set, &wr_set, NULL, &tv);
if(ready<0) { /* Break the connection for others */
sockerror("select");
return -1;
}
if(!ready) { /* Timeout */
if(sock_rd) { /* No traffic for a long time */
log(LOG_DEBUG, "select timeout: connection reset");
return -1;
} else { /* Timeout waiting for SSL close_notify */
log(LOG_DEBUG, "select timeout waiting for SSL close_notify");
break; /* Leave the while() loop */
}
}
if(ssl_closing==1 /* initiate SSL_shutdown */ || (ssl_closing==2 && (
(SSL_want_read(c->ssl) && FD_ISSET(c->ssl_rfd->fd, &rd_set)) ||
(SSL_want_write(c->ssl) && FD_ISSET(c->ssl_wfd->fd, &wr_set))
))) {
switch(SSL_shutdown(c->ssl)) { /* Send close_notify */
case 1: /* the shutdown was successfully completed */
log(LOG_INFO, "SSL_shutdown successfully sent close_notify");
ssl_wr=0; /* SSL write closed */
/* TODO: It's not really closed. We need to distinguish
* closed SSL and closed underlying file descriptor */
ssl_closing=3; /* done! */
break;
case 0: /* the shutdown is not yet finished */
log(LOG_DEBUG, "SSL_shutdown retrying");
ssl_closing=2; /* next time just retry SSL_shutdown */
break;
case -1: /* a fatal error occurred */
sslerror("SSL_shutdown");
return -1;
}
}
/* Set flag to try and read any buffered SSL data if we made */
/* room in the buffer by writing to the socket */
check_SSL_pending = 0;
if(sock_wr && FD_ISSET(c->sock_wfd->fd, &wr_set)) {
switch(num=writesocket(c->sock_wfd->fd, c->ssl_buff, c->ssl_ptr)) {
case -1: /* error */
switch(get_last_socket_error()) {
case EINTR:
log(LOG_DEBUG,
"writesocket interrupted by a signal: retrying");
break;
case EWOULDBLOCK:
log(LOG_NOTICE, "writesocket would block: retrying");
break;
default:
sockerror("writesocket");
return -1;
}
break;
case 0:
log(LOG_DEBUG, "No data written to the socket: retrying");
break;
default:
memmove(c->ssl_buff, c->ssl_buff+num, c->ssl_ptr-num);
if(c->ssl_ptr==BUFFSIZE)
check_SSL_pending=1;
c->ssl_ptr-=num;
c->sock_bytes+=num;
if(!ssl_rd && !c->ssl_ptr) {
shutdown(c->sock_wfd->fd, SHUT_WR);
log(LOG_DEBUG,
"Socket write shutdown (no more data to send)");
sock_wr=0;
}
}
}
if(ssl_wr && ( /* SSL sockets are still open */
(c->sock_ptr && FD_ISSET(c->ssl_wfd->fd, &wr_set)) ||
/* See if application data can be written */
(SSL_want_read(c->ssl) && FD_ISSET(c->ssl_rfd->fd, &rd_set))
/* I want to SSL_write but read from the underlying */
/* socket needed for the SSL protocol */
)) {
num=SSL_write(c->ssl, c->sock_buff, c->sock_ptr);
err=SSL_get_error(c->ssl, num);
switch(err) {
case SSL_ERROR_NONE:
memmove(c->sock_buff, c->sock_buff+num, c->sock_ptr-num);
c->sock_ptr-=num;
c->ssl_bytes+=num;
if(!ssl_closing && !sock_rd && !c->sock_ptr && ssl_wr) {
log(LOG_DEBUG,
"SSL write shutdown (no more data to send)");
ssl_closing=1;
}
break;
case SSL_ERROR_WANT_WRITE:
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_X509_LOOKUP:
log(LOG_DEBUG, "SSL_write returned WANT_: retrying");
break;
case SSL_ERROR_SYSCALL:
if(num<0) { /* really an error */
switch(get_last_socket_error()) {
case EINTR:
log(LOG_DEBUG,
"SSL_write interrupted by a signal: retrying");
break;
case EAGAIN:
log(LOG_DEBUG,
"SSL_write returned EAGAIN: retrying");
break;
default:
sockerror("SSL_write (ERROR_SYSCALL)");
return -1;
}
}
break;
case SSL_ERROR_ZERO_RETURN: /* close_notify received */
log(LOG_DEBUG, "SSL closed on SSL_write");
ssl_rd=ssl_wr=0;
break;
case SSL_ERROR_SSL:
sslerror("SSL_write");
return -1;
default:
log(LOG_ERR, "SSL_write/SSL_get_error returned %d", err);
return -1;
}
}
if(sock_rd && FD_ISSET(c->sock_rfd->fd, &rd_set)) {
switch(num=readsocket(c->sock_rfd->fd,
c->sock_buff+c->sock_ptr, BUFFSIZE-c->sock_ptr)) {
case -1:
switch(get_last_socket_error()) {
case EINTR:
log(LOG_DEBUG,
"readsocket interrupted by a signal: retrying");
break;
case EWOULDBLOCK:
log(LOG_NOTICE, "readsocket would block: retrying");
break;
default:
sockerror("readsocket");
return -1;
}
break;
case 0: /* close */
log(LOG_DEBUG, "Socket closed on read");
sock_rd=0;
if(!ssl_closing && !c->sock_ptr && ssl_wr) {
log(LOG_DEBUG,
"SSL write shutdown (output buffer empty)");
ssl_closing=1;
}
break;
default:
c->sock_ptr+=num;
}
}
if(ssl_rd && ( /* SSL sockets are still open */
(c->ssl_ptr<BUFFSIZE && FD_ISSET(c->ssl_rfd->fd, &rd_set)) ||
/* See if there's any application data coming in */
(SSL_want_write(c->ssl) && FD_ISSET(c->ssl_wfd->fd, &wr_set)) ||
/* I want to SSL_read but write to the underlying */
/* socket needed for the SSL protocol */
(check_SSL_pending && SSL_pending(c->ssl))
/* Write made space from full buffer */
)) {
num=SSL_read(c->ssl, c->ssl_buff+c->ssl_ptr, BUFFSIZE-c->ssl_ptr);
err=SSL_get_error(c->ssl, num);
switch(err) {
case SSL_ERROR_NONE:
c->ssl_ptr+=num;
break;
case SSL_ERROR_WANT_WRITE:
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_X509_LOOKUP:
log(LOG_DEBUG, "SSL_read returned WANT_: retrying");
break;
case SSL_ERROR_SYSCALL:
if(num<0) { /* not EOF */
switch(get_last_socket_error()) {
case EINTR:
log(LOG_DEBUG,
"SSL_read interrupted by a signal: retrying");
break;
case EAGAIN:
log(LOG_DEBUG,
"SSL_read returned EAGAIN: retrying");
break;
default:
sockerror("SSL_read (ERROR_SYSCALL)");
return -1;
}
} else { /* EOF */
log(LOG_DEBUG, "SSL socket closed on SSL_read");
ssl_rd=ssl_wr=0;
}
break;
case SSL_ERROR_ZERO_RETURN: /* close_notify received */
log(LOG_DEBUG, "SSL closed on SSL_read");
ssl_rd=0;
if(!ssl_closing && !c->sock_ptr && ssl_wr) {
log(LOG_DEBUG,
"SSL write shutdown (output buffer empty)");
ssl_closing=1;
}
if(!c->ssl_ptr && sock_wr) {
shutdown(c->sock_wfd->fd, SHUT_WR);
log(LOG_DEBUG,
"Socket write shutdown (output buffer empty)");
sock_wr=0;
}
break;
case SSL_ERROR_SSL:
sslerror("SSL_read");
return -1;
default:
log(LOG_ERR, "SSL_read/SSL_get_error returned %d", err);
return -1;
}
}
}
return 0; /* OK */
}
static void cleanup(CLI *c, int error) {
/* Cleanup SSL */
if(c->ssl) { /* SSL initialized */
SSL_set_shutdown(c->ssl, SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN);
SSL_free(c->ssl);
ERR_remove_state(0);
}
/* Cleanup remote socket */
if(c->remote_fd.fd>=0) { /* Remote socket initialized */
if(error && c->remote_fd.is_socket)
reset(c->remote_fd.fd, "linger (remote)");
closesocket(c->remote_fd.fd);
}
/* Cleanup local socket */
if(c->local_rfd.fd>=0) { /* Local socket initialized */
if(c->local_rfd.fd==c->local_wfd.fd) {
if(error && c->local_rfd.is_socket)
reset(c->local_rfd.fd, "linger (local)");
closesocket(c->local_rfd.fd);
} else { /* STDIO */
if(error && c->local_rfd.is_socket)
reset(c->local_rfd.fd, "linger (local_rfd)");
if(error && c->local_wfd.is_socket)
reset(c->local_wfd.fd, "linger (local_wfd)");
}
}
}
static void print_cipher(CLI *c) { /* print negotiated cipher */
#if SSLEAY_VERSION_NUMBER <= 0x0800
log(LOG_INFO, "%s opened with SSLv%d, cipher %s",
c->opt->servname, ssl->session->ssl_version, SSL_get_cipher(c->ssl));
#else
SSL_CIPHER *cipher;
char buf[STRLEN];
int len;
cipher=SSL_get_current_cipher(c->ssl);
SSL_CIPHER_description(cipher, buf, STRLEN);
len=strlen(buf);
if(len>0)
buf[len-1]='\0';
log(LOG_INFO, "Negotiated ciphers: %s", buf);
#endif
}
static int auth_libwrap(CLI *c) {
#ifdef USE_LIBWRAP
struct request_info request;
int result;
enter_critical_section(CRIT_NTOA); /* libwrap is not mt-safe */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?