2012-08-27 46 views
2

我正在尝试编写一个简单的使用OpenSSL的Web服务器。我不断收到“Broken Pipe”错误。即使在我处理错误时,套接字似乎永远不会写入。SIGPIPE,简单的OpenSSL Web服务器中的破管

我在做什么错?

这里是我的代码:

/* 
* I created tempory certificates like this: 
* 
* openssl req -newkey rsa:1024 -x509 -keyout key.pem -out root.pem 
* 
* I compile like this: 
* 
* gcc -g -o webssl webssl.c -lssl -lcrypto 
* 
* I get this error: 
* 
* Program received signal SIGPIPE, Broken pipe. 
*/ 

#include <stdlib.h> 
#include <stdio.h> 
#include <string.h> 
#include <arpa/inet.h> 
#include <netdb.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <sys/stat.h> 
#include <fcntl.h> 

#include "openssl/bio.h" 
#include "openssl/ssl.h" 
#include "openssl/err.h" 

const char *password = "jake"; 
const char *KEY_FILE = "key.pem"; 
const char *CA_LIST = "root.pem"; 

const char *response = "HTTP/1.0 200 OK\r\nServer : webssl\r\n\r\n<html><head><title>Hello World!</title></head><body><h1>Hello world!</h1></body></html>"; 

void sigpipe_handle(int x) 
{ 
    printf("broken pipe\n"); 
} 


int password_cb(char *buf, int num, int rwflag, void *userdata) 
{ 
    if(num<strlen(password)+1) 
     return 0; 
    strcpy(buf, password); 
    return strlen(password); 
} 

int main(int argc, char *argv[]) 
{ 
    SSL *ssl = NULL; 
    SSL_CTX *ctx = NULL; 

    int listenfd, clientfd; 
    struct sockaddr_in clientaddr; 
    socklen_t addrlen; 
    char *port = "8080"; 

    struct addrinfo hints, *res; 

    char buffer[5000]; 

    SSL_library_init(); 

    /* Set up a SIGPIPE handler */ 
    signal(SIGPIPE,sigpipe_handle); 

    ctx = SSL_CTX_new(SSLv23_server_method()); 
    SSL_CTX_use_certificate_chain_file(ctx, KEY_FILE); 
    SSL_CTX_set_default_passwd_cb(ctx, password_cb); 
    SSL_CTX_use_PrivateKey_file(ctx, KEY_FILE, SSL_FILETYPE_PEM); 
    SSL_CTX_load_verify_locations(ctx, CA_LIST, 0); 

    memset(&hints, 0, sizeof(hints)); 
    hints.ai_family = AF_INET; 
    hints.ai_socktype = SOCK_STREAM; 
    hints.ai_flags = AI_PASSIVE; 

    getaddrinfo(NULL, port, &hints, &res); 
    listenfd = socket(res->ai_family, res->ai_socktype, 0); 
    bind(listenfd, res->ai_addr, res->ai_addrlen); 
    freeaddrinfo(res); 

    listen(listenfd, 15); 

    while (1) { 
     addrlen = sizeof(clientaddr); 
     clientfd = accept(listenfd, (struct sockaddr *)&clientaddr, &addrlen); 

     ssl = SSL_new(ctx); 
     SSL_set_fd(ssl, clientfd); 
     SSL_accept(ssl); 

     SSL_read(ssl, buffer, 5000); 

     SSL_write(ssl, response, strlen(response)); 

     SSL_free(ssl); 
     close(clientfd); 
    } 

    return 0; 
} 
+4

SIGPIPE升高,当你'发(2)'在另一端关闭的插座中。通过'MSG_NOSIGNAL'标志来抑制信号。 –

回答

1

SIGPIPE, Broken Pipe in a simple OpenSSL web server

我想我是生成证书错误。我需要用一个server.pem我做这样的:

openssl req -newkey rsa:1024 -x509 -keyout key.pem -out root.pem 
cat key.pem root.pem > server.pem 

我还是不太清楚的问题是什么,但此代码的工作:

/* 
* Created my new server.pem like this: 
* 
* openssl req -newkey rsa:1024 -x509 -keyout key.pem -out root.pem 
* cat key.pem root.pem > server.pem 
* 
* Compiled like this: 
* gcc -o webssl webssl.c -lssl -lcrypto 
* 
*/ 
#include <stdio.h> 
#include <stdlib.h> 
#include <errno.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <netinet/tcp.h> 
#include <netdb.h> 
#include <fcntl.h> 
#include <signal.h> 
#include <unistd.h> 
#include <string.h> 
#include <openssl/ssl.h> 

const int PORT = 3000; 
const char *CA_LIST = "root.pem"; 
const char *KEY_FILE = "server.pem"; 
const char *PASSWORD = "jake"; 

const char *message = "HTTP/1.0 200 OK\r\nServer: webssl\r\n\r\n<html><head><title>Hi</title></head><body><h1>Hello World!</h1></body></html>"; 

static int password_cb(char *buf, int num, int rwflag, void *userdata) 
{ 
    if(num<strlen(PASSWORD)+1) 
    return(0); 

    strcpy(buf,PASSWORD); 
    return(strlen(PASSWORD)); 
} 

static void sigpipe_handle(int x) {} 

int main(int argc, char *argv[]) 
{ 
    struct sockaddr_in sin; 
    int sock, s; 
    SSL_CTX *ctx = NULL; 
    SSL *ssl = NULL; 
    char buffer[5000]; 

    BIO *sbio = NULL; 
    BIO *io = NULL; 
    BIO *ssl_bio = NULL; 

    SSL_library_init(); 

    signal(SIGPIPE, sigpipe_handle); 

    ctx = SSL_CTX_new(SSLv23_method()); 
    SSL_CTX_use_certificate_chain_file(ctx, KEY_FILE); 
    SSL_CTX_set_default_passwd_cb(ctx, password_cb); 
    SSL_CTX_use_PrivateKey_file(ctx, KEY_FILE, SSL_FILETYPE_PEM); 
    SSL_CTX_load_verify_locations(ctx, CA_LIST, 0); 

    sock = socket(AF_INET, SOCK_STREAM, 0); 
    memset(&sin, 0, sizeof(sin)); 
    sin.sin_addr.s_addr = INADDR_ANY; 
    sin.sin_family = AF_INET; 
    sin.sin_port = htons(PORT); 

    bind(sock, (struct sockaddr *)&sin, sizeof(sin)); 
    listen(sock, 5); 

    while (1) { 
     memset(buffer, 0, 5000); 

     s = accept(sock, 0, 0); 

     sbio=BIO_new_socket(s,BIO_NOCLOSE); 
     ssl = SSL_new(ctx); 
     SSL_set_bio(ssl,sbio,sbio); 


     SSL_accept(ssl); 

     io=BIO_new(BIO_f_buffer()); 
     ssl_bio=BIO_new(BIO_f_ssl()); 
     BIO_set_ssl(ssl_bio,ssl,BIO_CLOSE); 
     BIO_push(io,ssl_bio); 


     BIO_gets(io, buffer, 5000); 

     BIO_puts(io, message); 
     BIO_flush(io); 

     SSL_shutdown(ssl); 
     SSL_free(ssl); 
     close(s); 
    } 

    return 0; 
} 
1

你可以试试signal(SIGPIPE, SIG_IGN)。这应该使发送返回EPIPE错误。否则,您可以在向发送呼叫发送MSG_NOSIGNAL标志的注释中遵循Kerrek SB的建议。