Sockets SSL_accept()失败,返回值为-1

Sockets SSL_accept()失败,返回值为-1,sockets,tcp,openssl,Sockets,Tcp,Openssl,为了理解SSL/TLS,我在Windows-7上下载了OpenSSL-1.0.2k,并使用Cygwingcc64位编译器进行编译。我从gcc中获取了服务器/客户端的示例,并使用cygwin-gcc进行编译。编译一开始就成功了。我使用以下命令从cmd执行服务器和客户端 (Server) D:\>ssl-server.exe 5000 (Client) D:\>ssl-client.exe 127.0.0.1 5000 客户端退出时没有任何响应,但另一方面,服务器显示它已建立连

为了理解
SSL/TLS
,我在
Windows-7
上下载了
OpenSSL-1.0.2k
,并使用
Cygwin
gcc
64位
编译器进行编译。我从gcc中获取了服务器/客户端的
示例,并使用
cygwin-gcc
进行编译。编译一开始就成功了。我使用以下命令从
cmd
执行服务器和客户端

(Server)   D:\>ssl-server.exe 5000
(Client)   D:\>ssl-client.exe 127.0.0.1 5000
客户端退出时没有任何响应,但另一方面,服务器显示它已建立连接,例如

Connection: 127.0.0.1:50475
无限期地等待下一行

然后我开始调试服务器端,发现过程
void Servlet(SSL*SSL)
中的
SSL\u accept()
返回一个值
-1
,这是不期望的。我查阅了
OpenSSL
的文档

TLS/SSL握手未成功,因为在协议级别发生致命错误或发生连接故障。关闭不干净。如果需要继续非阻塞BIOs的操作,也可能会发生这种情况。使用返回值ret调用SSL_get_error()以查找原因

SSL\u get\u error()
返回
SSL\u error\u SYSCALL
。在这次调用之后,我检查了
errno
的值,发现
no error
。下面是
Servlet
方法的完整代码。代码的其余部分和链接中的相同

void Servlet(SSL* ssl) /* Serve the connection -- threadable */
{   char buf[1024];
    char reply[1024];
    int sd, bytes;
    const char* HTMLecho="<html><body><pre>%s</pre></body></html>\n\n";
    int ret;
    ret = SSL_accept(ssl);  /* do SSL-protocol accept */ 
    if ( ret == -1 )    
    {
        // printf(" SSL_accept() returned -1\n");
        switch(SSL_get_error(ssl, ret) )
        {
            case SSL_ERROR_SYSCALL:
                perror("errno");
                break;
            default:
                printf( "default" );
                break;
        }
        exit(-1);
    }
    else if ( ret == 0)
    {
        printf(" SSL_accept() returned 0\n");
        exit(-1);
    }
    else if ( ret == 1) // The TLS/SSL connection has been established. 
    {
        ShowCerts(ssl);        /* get any certificates */
        bytes = SSL_read(ssl, buf, sizeof(buf)); /* get request */
        if ( bytes > 0 )
        {
            buf[bytes] = 0;
            printf("Client msg: \"%s\"\n", buf);
            sprintf(reply, HTMLecho, buf);   /* construct reply */
            SSL_write(ssl, reply, strlen(reply)); /* send reply */
        }
        else
            ERR_print_errors_fp(stderr);
    }
    sd = SSL_get_fd(ssl);       /* get socket connection */
    SSL_free(ssl);         /* release SSL state */
    close(sd);          /* close connection */
}
void Servlet(SSL*SSL)/*为连接提供服务--可线程化*/
{char buf[1024];
字符回复[1024];
int-sd,字节;
常量char*HTMLecho=“%s\n\n”;
int ret;
ret=SSL_接受(SSL);/*SSL协议接受吗*/
如果(ret==-1)
{
//printf(“SSL_accept()返回-1\n”);
交换机(SSL_获取_错误(SSL,ret))
{
案例SSL\u错误\u系统调用:
佩罗尔(“埃尔诺”);
打破
违约:
printf(“违约”);
打破
}
出口(-1);
}
else if(ret==0)
{
printf(“SSL_accept()返回0\n”);
出口(-1);
}
else if(ret==1)//已建立TLS/SSL连接。
{
ShowCerts(ssl);/*获取任何证书*/
bytes=SSL_read(SSL,buf,sizeof(buf));/*get请求*/
如果(字节>0)
{
buf[字节]=0;
printf(“客户端消息:\%s\”\n),buf);
sprintf(reply,HTMLecho,buf);/*构造reply*/
SSL_write(SSL,reply,strlen(reply));/*发送回复*/
}
其他的
错误打印错误fp(stderr);
}
sd=SSL_get_fd(SSL);/*获取套接字连接*/
无SSL(SSL);/*释放SSL状态*/
关闭(sd);/*关闭连接*/
}
  • 当您没有遇到您列举的SSL\u错误情况时,您应该跟踪
    SSL\u get\u ERROR()
    的值,以便开始调试。而不仅仅是举手
  • 在本例中,值为
    SSL\u ERROR\u SYSCALL
    。你没有在你认为应该的地方抓住它,因为
    case(SSL_ERROR|u SYSCALL | SSL_ERROR_SSL | SSL_ERROR_WANT_CONNECT | SSL_ERROR_WANT_ACCEPT):
    没有按照你的想法去做。由于
    |
    的语义,它将变成
    情况1
    。每个值都应该有单独的
    case
    语句
  • SSL\u ERROR\u SYSCALL
    表示根据您自己引用的文档,基本错误在
    errno
    中,这意味着您应该跟踪该错误。而不仅仅是举手。请注意,您必须在调用任何其他系统调用(例如通过
    printf()
    调用
    write()
    )之前执行此操作,以便立即保存
    errno
  • 您可以使用
    printf(“errno=%d\n”,errno)
    直接打印
    errno
    ,但打印错误消息更有用,您可以使用
    peror()
    printf(“error=%s\n”,strerror(errno))
  • SSL\u get\u error()
    的值不是
    errno
    值,也不是您开始使用的原始-1。
    errno
    值来自
    errno
    变量
  • 但是,除非
    SSL\u accept()
    返回了-1,否则不应该执行这些操作,这里没有实际的证据
  • 所以这里完全可能没有错误

  • 当您没有遇到您列举的SSL\u错误情况时,您应该跟踪
    SSL\u get\u ERROR()
    的值,以便开始调试。而不仅仅是举手
  • 在本例中,值为
    SSL\u ERROR\u SYSCALL
    。你没有在你认为应该的地方抓住它,因为
    case(SSL_ERROR|u SYSCALL | SSL_ERROR_SSL | SSL_ERROR_WANT_CONNECT | SSL_ERROR_WANT_ACCEPT):
    没有按照你的想法去做。由于
    |
    的语义,它将变成
    情况1
    。每个值都应该有单独的
    case
    语句
  • SSL\u ERROR\u SYSCALL
    表示根据您自己引用的文档,基本错误在
    errno
    中,这意味着您应该跟踪该错误。而不仅仅是举手。请注意,您必须在调用任何其他系统调用(例如通过
    printf()
    调用
    write()
    )之前执行此操作,以便立即保存
    errno
  • 您可以使用
    printf(“errno=%d\n”,errno)
    直接打印
    errno
    ,但打印错误消息更有用,您可以使用
    peror()
    printf(“error=%s\n”,strerror(errno))
  • SSL\u get\u error()
    的值不是
    errno
    值,也不是您开始使用的原始-1。一个
    错误