static int _init_server(OpenSSL * openssl, char const * name) { String * crt; struct sockaddr_in sa; if((crt = string_new_append(SYSCONFDIR, "/AppServer/", name, ".crt")) == NULL) return -1; if((openssl->ssl_ctx = SSL_CTX_new(SSLv3_server_method())) == NULL || SSL_CTX_set_cipher_list(openssl->ssl_ctx, SSL_DEFAULT_CIPHER_LIST) != 1 || SSL_CTX_use_certificate_file(openssl->ssl_ctx, crt, SSL_FILETYPE_PEM) == 0 || SSL_CTX_use_PrivateKey_file(openssl->ssl_ctx, crt, SSL_FILETYPE_PEM) == 0) { string_delete(crt); return -_openssl_error_ssl(1); } string_delete(crt); if((openssl->fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) return -_openssl_error("socket", 1); sa.sin_family = AF_INET; sa.sin_port = htons(4242); /* XXX hard-coded */ sa.sin_addr.s_addr = htonl(INADDR_ANY); if(bind(openssl->fd, (struct sockaddr *)&sa, sizeof(sa)) != 0) return -_openssl_error("bind", 1); if(listen(openssl->fd, 5) != 0) return -_openssl_error("listen", 1); event_register_io_read(openssl->helper->event, openssl->fd, (EventIOFunc)_openssl_callback_accept, openssl); return 0; }
static int _accept_client(SSLTransport * transport, int fd, SSL * ssl, struct sockaddr * sa, socklen_t sa_len) { SSLSocket * sslsocket; #ifdef DEBUG fprintf(stderr, "DEBUG: %s(%d)\n", __func__, fd); #endif if((sslsocket = _ssl_socket_new_fd(transport, fd, ssl, sa, sa_len)) == NULL) return -1; if(_ssl_server_add_client(transport, sslsocket) != 0) { /* XXX workaround for a double-close() */ sslsocket->fd = -1; _ssl_socket_delete(sslsocket); return -1; } SSL_set_accept_state(sslsocket->ssl); event_register_io_read(transport->helper->event, sslsocket->fd, (EventIOFunc)_ssl_socket_callback_read, sslsocket); #ifdef DEBUG fprintf(stderr, "DEBUG: %s(%d) => 0\n", __func__, fd); #endif return 0; }
static int _init_client(SSLTransport * ssl, char const * name) { struct addrinfo * aip; #ifdef DEBUG struct sockaddr_in * sa; #endif ssl->u.client.transport = ssl; ssl->u.client.fd = -1; /* obtain the remote address */ if((ssl->ai = _init_address(name, TCP_FAMILY, 0)) == NULL) return -1; /* connect to the remote host */ for(aip = ssl->ai; aip != NULL; aip = aip->ai_next) { ssl->u.client.fd = -1; /* initialize the client socket */ if(_ssl_socket_init(&ssl->u.client, aip->ai_family, ssl) != 0) continue; #ifdef DEBUG if(aip->ai_family == AF_INET) { sa = (struct sockaddr_in *)aip->ai_addr; fprintf(stderr, "DEBUG: %s() %s (%s:%u)\n", __func__, "connect()", inet_ntoa(sa->sin_addr), ntohs(sa->sin_port)); } else fprintf(stderr, "DEBUG: %s() %s %d\n", __func__, "connect()", aip->ai_family); #endif if(connect(ssl->u.client.fd, aip->ai_addr, aip->ai_addrlen) != 0) { if(errno != EINPROGRESS) { close(ssl->u.client.fd); ssl->u.client.fd = -1; _ssl_error("socket", 1); continue; } event_register_io_write(ssl->helper->event, ssl->u.client.fd, (EventIOFunc)_ssl_callback_connect, ssl); } else /* listen for any incoming message */ event_register_io_read(ssl->helper->event, ssl->u.client.fd, (EventIOFunc)_ssl_socket_callback_read, &ssl->u.client); ssl->ai_addrlen = aip->ai_addrlen; break; } freeaddrinfo(ssl->ai); ssl->ai = NULL; return (aip != NULL) ? 0 : -1; }
static int _init_server(SSLTransport * ssl, char const * name) { struct addrinfo * aip; SSLSocket sslsocket; #ifdef DEBUG struct sockaddr_in * sa; #endif ssl->u.server.fd = -1; /* obtain the local address */ if((ssl->ai = _init_address(name, TCP_FAMILY, AI_PASSIVE)) == NULL) return -1; for(aip = ssl->ai; aip != NULL; aip = aip->ai_next) { /* create the socket */ if(_ssl_socket_init(&sslsocket, aip->ai_family, ssl) != 0) continue; /* XXX ugly */ ssl->u.server.fd = sslsocket.fd; /* accept incoming connections */ #ifdef DEBUG if(aip->ai_family == AF_INET) { sa = (struct sockaddr_in *)aip->ai_addr; fprintf(stderr, "DEBUG: %s() %s (%s:%u)\n", __func__, "bind()", inet_ntoa(sa->sin_addr), ntohs(sa->sin_port)); } else fprintf(stderr, "DEBUG: %s() %s %d\n", __func__, "bind()", aip->ai_family); #endif if(bind(ssl->u.server.fd, aip->ai_addr, aip->ai_addrlen) != 0) { _ssl_error("bind", 1); close(ssl->u.server.fd); ssl->u.server.fd = -1; continue; } #ifdef DEBUG fprintf(stderr, "DEBUG: %s() %s\n", __func__, "listen()"); #endif if(listen(ssl->u.server.fd, SOMAXCONN) != 0) { _ssl_error("listen", 1); close(ssl->u.server.fd); ssl->u.server.fd = -1; continue; } ssl->ai_addrlen = aip->ai_addrlen; event_register_io_read(ssl->helper->event, ssl->u.server.fd, (EventIOFunc)_ssl_callback_accept, ssl); break; } freeaddrinfo(ssl->ai); ssl->ai = NULL; return (aip != NULL) ? 0 : -1; }
/* ssl_callback_connect */ static int _ssl_callback_connect(int fd, SSLTransport * transport) { int res; socklen_t s = sizeof(res); #ifdef DEBUG fprintf(stderr, "DEBUG: %s(%d)\n", __func__, fd); #endif /* check parameters */ if(transport->u.client.fd != fd) return -1; /* obtain the connection status */ if(getsockopt(fd, SOL_SOCKET, SO_ERROR, &res, &s) != 0) { error_set_code(1, "%s: %s", "getsockopt", strerror(errno)); SSL_free(transport->u.client.ssl); transport->u.client.ssl = NULL; close(fd); transport->u.client.fd = -1; /* FIXME report error */ #ifdef DEBUG fprintf(stderr, "DEBUG: %s() %s\n", __func__, strerror(errno)); #endif return -1; } if(res != 0) { /* the connection failed */ error_set_code(1, "%s: %s", "connect", strerror(res)); SSL_free(transport->u.client.ssl); transport->u.client.ssl = NULL; close(fd); transport->u.client.fd = -1; /* FIXME report error */ #ifdef DEBUG fprintf(stderr, "DEBUG: %s() %s\n", __func__, strerror(res)); #endif return -1; } SSL_set_connect_state(transport->u.client.ssl); /* listen for any incoming message */ event_register_io_read(transport->helper->event, fd, (EventIOFunc)_ssl_socket_callback_read, &transport->u.client); /* write pending messages if any */ if(transport->u.client.bufout_cnt > 0) { event_register_io_write(transport->helper->event, fd, (EventIOFunc)_ssl_socket_callback_write, &transport->u.client); return 0; } return 1; }
static int _socket_callback_recv(SSLSocket * sslsocket) { const size_t inc = INC; int ssize; char * p; int err; char buf[128]; if((p = realloc(sslsocket->bufin, sslsocket->bufin_cnt + inc)) == NULL) return -1; sslsocket->bufin = p; if((ssize = SSL_read(sslsocket->ssl, &sslsocket->bufin[sslsocket->bufin_cnt], inc)) <= 0) { /* FIXME not tested */ if((err = SSL_get_error(sslsocket->ssl, ssize)) == SSL_ERROR_WANT_WRITE) { event_unregister_io_write( sslsocket->transport->helper->event, sslsocket->fd); event_register_io_write( sslsocket->transport->helper->event, sslsocket->fd, (EventIOFunc)_ssl_socket_callback_read, sslsocket); return 1; } else if(err == SSL_ERROR_WANT_READ) { event_register_io_read( sslsocket->transport->helper->event, sslsocket->fd, (EventIOFunc)_ssl_socket_callback_read, sslsocket); return 1; } else { /* XXX report error (and reconnect clients) */ ERR_error_string(err, buf); error_set_code(1, "%s", buf); SSL_free(sslsocket->ssl); sslsocket->ssl = NULL; close(sslsocket->fd); sslsocket->fd = -1; return -1; } } sslsocket->bufin_cnt += ssize; return 0; }