2012-08-27 2 views
2

J'essaye d'écrire un serveur web simple qui utilise OpenSSL. Je reçois toujours une erreur "Broken Pipe". Même lorsque je gère l'erreur, il semble que le socket n'est jamais ouvert à écrire.SIGPIPE, Broken Pipe dans un simple serveur web OpenSSL

Qu'est-ce que je fais mal?

Voici mon code:

/* 
* 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 est élevé lorsque vous envoyez ' (2) 'dans une prise qui a été fermée à l'autre extrémité. Passez l'indicateur 'MSG_NOSIGNAL' pour supprimer le signal. –

Répondre

1

SIGPIPE, Broken Pipe in a simple OpenSSL web server

Je pense que je générait les certificats faux. Je avais besoin d'utiliser un server.pem que je fais comme ceci:

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

Je ne suis toujours pas tout à fait sûr de ce que le problème, mais ce code fonctionne:

/* 
* 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

Vous pouvez signal(SIGPIPE, SIG_IGN). Cela devrait faire renvoyer l'erreur EPIPE. Sinon, vous pouvez suivre la suggestion de Kerrek SB dans le commentaire d'envoi d'un indicateur MSG_NOSIGNAL à l'appel.

Questions connexes