char* quic_ssl_keylog_env = "SSLKEYLOGFILE";
pthread_t client_tid;
-uint32_t client_total_sent = 0;
-uint8_t server_total_data[INPUT_BUFF_MAX + 65536 + 65536] = {0};
+uint64_t client_total_sent = 0;
+//uint8_t server_total_data[INPUT_BUFF_MAX + 65536 + 65536] = {0};
uint64_t server_total_recvd = 0;
uint64_t server_this_recvd = 0;
+int server_done = 0;
void server_recv(QUIC_BUFFER* qbuff, uint32_t buff_count, uint64_t buff_tot_len){
server_total_recvd += buff_tot_len;
- printf("buffer count: %lu\n", buff_count);
- printf("server total buffer length: %llu\n", buff_tot_len);
for(int i = 0 ; i < buff_count; i++){
server_this_recvd += qbuff[i].Length;
- printf("server this buffer length: %llu\n", qbuff[i].Length);
+
}
- printf("server total buff count: %llu\n", server_total_recvd);
- printf("server this buff count: %llu\n", server_this_recvd);
+ //printf("server total buff count: %llu\n", server_total_recvd);
+ //printf("server this buff count: %llu\n", server_this_recvd);
return;
}
UNREFERENCED_PARAMETER(Context);
switch (Event->Type) {
case QUIC_STREAM_EVENT_SEND_COMPLETE:
- //
- // A previous StreamSend call has completed, and the context is being
- // returned back to the app.
- //
free(Event->SEND_COMPLETE.ClientContext);
- printf("[strm][%p] Data sent\n", Stream);
break;
case QUIC_STREAM_EVENT_RECEIVE:
- //
- // Data was received from the peer on the stream.
- //
-
server_recv(Event->RECEIVE.Buffers, Event->RECEIVE.BufferCount, Event->RECEIVE.TotalBufferLength);
-
- printf("[strm][%p] Data received\n", Stream);
break;
case QUIC_STREAM_EVENT_PEER_SEND_SHUTDOWN:
- //
- // The peer gracefully shut down its send direction of the stream.
- //
- printf("[strm][%p] Peer shut down\n", Stream);
+ printf("client shut down\n");
break;
case QUIC_STREAM_EVENT_PEER_SEND_ABORTED:
- //
- // The peer aborted its send direction of the stream.
- //
- printf("[strm][%p] Peer aborted\n", Stream);
+ printf("client aborted\n");
quic_api->StreamShutdown(Stream, QUIC_STREAM_SHUTDOWN_FLAG_ABORT, 0);
break;
case QUIC_STREAM_EVENT_SHUTDOWN_COMPLETE:
- //
- // Both directions of the stream have been shut down and quic_api is done
- // with the stream. It can now be safely cleaned up.
- //
-
- printf("[strm][%p] All done\n", Stream);
+ printf("stream done\n");
quic_api->StreamClose(Stream);
break;
default:
return QUIC_STATUS_SUCCESS;
}
-//
-// The server's callback for connection events from quic_api.
-//
QUIC_STATUS server_conn_cb(HQUIC Connection,void* Context, QUIC_CONNECTION_EVENT* Event){
UNREFERENCED_PARAMETER(Context);
switch (Event->Type) {
case QUIC_CONNECTION_EVENT_CONNECTED:
- //
- // The handshake has completed for the connection.
- //
- printf("[conn][%p] Connected\n", Connection);
+
+ printf("client connected\n");
quic_api->ConnectionSendResumptionTicket(Connection, QUIC_SEND_RESUMPTION_FLAG_NONE, 0, NULL);
break;
case QUIC_CONNECTION_EVENT_SHUTDOWN_INITIATED_BY_TRANSPORT:
- //
- // The connection has been shut down by the transport. Generally, this
- // is the expected way for the connection to shut down with this
- // protocol, since we let idle timeout kill the connection.
- //
if (Event->SHUTDOWN_INITIATED_BY_TRANSPORT.Status == QUIC_STATUS_CONNECTION_IDLE) {
- printf("[conn][%p] Successfully shut down on idle.\n", Connection);
+ printf("successfully shut down on idle\n");
} else {
- printf("[conn][%p] Shut down by transport, 0x%x\n", Connection, Event->SHUTDOWN_INITIATED_BY_TRANSPORT.Status);
+ printf("shut down by transport: 0x%x\n", Event->SHUTDOWN_INITIATED_BY_TRANSPORT.Status);
}
break;
case QUIC_CONNECTION_EVENT_SHUTDOWN_INITIATED_BY_PEER:
- //
- // The connection was explicitly shut down by the peer.
- //
- printf("[conn][%p] Shut down by peer, 0x%llu\n", Connection, (unsigned long long)Event->SHUTDOWN_INITIATED_BY_PEER.ErrorCode);
+ printf("shut down by peer: 0x%llu\n",(unsigned long long)Event->SHUTDOWN_INITIATED_BY_PEER.ErrorCode);
break;
case QUIC_CONNECTION_EVENT_SHUTDOWN_COMPLETE:
- //
- // The connection has completed the shutdown process and is ready to be
- // safely cleaned up.
- //
- printf("[conn][%p] All done\n", Connection);
+ printf("connection done\n");
quic_api->ConnectionClose(Connection);
+ server_done = 1;
break;
case QUIC_CONNECTION_EVENT_PEER_STREAM_STARTED:
- //
- // The peer has started/created a new stream. The app MUST set the
- // callback handler before returning.
- //
- printf("[strm][%p] Peer started\n", Event->PEER_STREAM_STARTED.Stream);
+ printf("client stream started\n");
quic_api->SetCallbackHandler(Event->PEER_STREAM_STARTED.Stream, (void*)server_stream_cb, NULL);
break;
case QUIC_CONNECTION_EVENT_RESUMED:
- //
- // The connection succeeded in doing a TLS resumption of a previous
- // connection's session.
- //
- printf("[conn][%p] Connection resumed!\n", Connection);
+ printf("client connection resumed\n");
break;
default:
break;
return QUIC_STATUS_SUCCESS;
}
-//
-// The server's callback for listener events from quic_api.
-//
-
QUIC_STATUS server_listen_cb(HQUIC Listener, void* Context, QUIC_LISTENER_EVENT* Event){
UNREFERENCED_PARAMETER(Listener);
QUIC_STATUS Status = QUIC_STATUS_NOT_SUPPORTED;
switch (Event->Type) {
case QUIC_LISTENER_EVENT_NEW_CONNECTION:
- //
- // A new connection is being attempted by a client. For the handshake to
- // proceed, the server must provide a configuration for QUIC to use. The
- // app MUST set the callback handler before returning.
- //
quic_api->SetCallbackHandler(Event->NEW_CONNECTION.Connection, (void*)server_conn_cb, NULL);
Status = quic_api->ConnectionSetConfiguration(Event->NEW_CONNECTION.Connection, quic_configuration);
break;
}
-//
-// Helper function to load a server configuration. Uses the command line
-// arguments to load the credential part of the configuration.
-//
+
BOOLEAN server_conf() {
QUIC_SETTINGS Settings = {0};
- //
- // Configures the server's idle timeout.
- //
+
Settings.IdleTimeoutMs = quic_idle_timeoutms;
Settings.IsSet.IdleTimeoutMs = TRUE;
- //
- // Configures the server's resumption level to allow for resumption and
- // 0-RTT.
- //
+
Settings.ServerResumptionLevel = QUIC_SERVER_RESUME_AND_ZERORTT;
Settings.IsSet.ServerResumptionLevel = TRUE;
- //
- // Configures the server's settings to allow for the peer to open a single
- // bidirectional stream. By default connections are not configured to allow
- // any streams from the peer.
- //
+
Settings.PeerBidiStreamCount = 1;
Settings.IsSet.PeerBidiStreamCount = TRUE;
-
QUIC_CREDENTIAL_CONFIG_HELPER Config;
memset(&Config, 0, sizeof(Config));
Config.CredConfig.Flags = QUIC_CREDENTIAL_FLAG_NONE;
Config.CredConfig.Flags |= QUIC_CREDENTIAL_FLAG_SET_CA_CERTIFICATE_FILE;
-
const char* Ca = CERT_CA;
const char* Cert = CERT_SERVER;
const char* KeyFile = KEY_SERVER;
-
Config.CertFile.CertificateFile = (char*)Cert;
Config.CertFile.PrivateKeyFile = (char*)KeyFile;
Config.CredConfig.Type = QUIC_CREDENTIAL_TYPE_CERTIFICATE_FILE;
Config.CredConfig.CertificateFile = &Config.CertFile;
Config.CredConfig.CaCertificateFile = Ca;
- //
- // Allocate/initialize the configuration object, with the configured ALPN
- // and settings.
- //
+
QUIC_STATUS Status = QUIC_STATUS_SUCCESS;
if (QUIC_FAILED(Status = quic_api->ConfigurationOpen(quic_registration, &quic_alpn, 1, &Settings, sizeof(Settings), NULL, &quic_configuration))) {
printf("ConfigurationOpen failed, 0x%x!\n", Status);
return FALSE;
}
- //
- // Loads the TLS credential part of the configuration.
- //
if (QUIC_FAILED(Status = quic_api->ConfigurationLoadCredential(quic_configuration, &Config.CredConfig))) {
printf("ConfigurationLoadCredential failed, 0x%x!\n", Status);
return FALSE;
return TRUE;
}
-//
-// Runs the server side of the protocol.
-//
+
void run_server(){
QUIC_STATUS Status;
HQUIC Listener = NULL;
- //
- // Configures the address used for the listener to listen on all IP
- // addresses and the given UDP port.
- //
QUIC_ADDR Address = {0};
QuicAddrSetFamily(&Address, QUIC_ADDRESS_FAMILY_UNSPEC);
QuicAddrSetPort(&Address, quic_udp_port);
- //
- // Load the server configuration based on the command line.
- //
if (!server_conf()) {
return;
}
- //
- // Create/allocate a new listener object.
- //
if (QUIC_FAILED(Status = quic_api->ListenerOpen(quic_registration, server_listen_cb, NULL, &Listener))) {
printf("ListenerOpen failed, 0x%x!\n", Status);
goto Error;
}
- //
- // Starts listening for incoming connections.
- //
+
if (QUIC_FAILED(Status = quic_api->ListenerStart(Listener, &quic_alpn, 1, &Address))) {
printf("ListenerStart failed, 0x%x!\n", Status);
goto Error;
}
- //
- // Continue listening for connections until the Enter key is pressed.
- //
- printf("Press Enter to exit.\n\n");
- getchar();
+ while(!server_done){
+ sleep(1);
+ }
Error:
UNREFERENCED_PARAMETER(Context);
switch (Event->Type) {
case QUIC_STREAM_EVENT_SEND_COMPLETE:
- //
- // A previous StreamSend call has completed, and the context is being
- // returned back to the app.
- //
+
//free(Event->SEND_COMPLETE.ClientContext);
- //printf("[strm][%p] Data sent\n", Stream);
+
break;
case QUIC_STREAM_EVENT_RECEIVE:
- //
- // Data was received from the peer on the stream.
- //
- printf("[strm][%p] Data received\n", Stream);
+
break;
case QUIC_STREAM_EVENT_PEER_SEND_ABORTED:
- //
- // The peer gracefully shut down its send direction of the stream.
- //
- printf("[strm][%p] Peer aborted\n", Stream);
+
+ printf("server aborted\n");
break;
case QUIC_STREAM_EVENT_PEER_SEND_SHUTDOWN:
- //
- // The peer aborted its send direction of the stream.
- //
- printf("[strm][%p] Peer shut down\n", Stream);
+ printf("server shut down\n");
break;
case QUIC_STREAM_EVENT_SHUTDOWN_COMPLETE:
- //
- // Both directions of the stream have been shut down and quic_api is done
- // with the stream. It can now be safely cleaned up.
- //
- printf("[strm][%p] All done\n", Stream);
+ printf("stream done\n");
if (!Event->SHUTDOWN_COMPLETE.AppCloseInProgress) {
quic_api->StreamClose(Stream);
}
HQUIC Connection = (HQUIC)varg;
QUIC_STATUS Status;
HQUIC Stream = NULL;
- uint8_t* SendBufferRaw;
+ uint8_t* SendBufferRaw = NULL;
uint8_t* sb_fill = NULL;
QUIC_BUFFER* SendBuffer;
- //
- // Create/allocate a new bidirectional stream. The stream is just allocated
- // and no QUIC stream identifier is assigned until it's started.
- //
if (QUIC_FAILED(Status = quic_api->StreamOpen(Connection, QUIC_STREAM_OPEN_FLAG_NONE, client_stream_cb, NULL, &Stream))) {
printf("StreamOpen failed, 0x%x!\n", Status);
goto Error;
}
- printf("[strm][%p] Starting...\n", Stream);
-
- //
- // Starts the bidirectional stream. By default, the peer is not notified of
- // the stream being started until data is sent on the stream.
- //
if (QUIC_FAILED(Status = quic_api->StreamStart(Stream, QUIC_STREAM_START_FLAG_NONE))) {
printf("StreamStart failed, 0x%x!\n", Status);
quic_api->StreamClose(Stream);
goto Error;
}
- //
- // Allocates and builds the buffer to send over the stream.
- //
SendBufferRaw = (uint8_t*)malloc(sizeof(QUIC_BUFFER) + quic_send_buffer_len);
if (SendBufferRaw == NULL) {
printf("SendBuffer allocation failed!\n");
}
*/
- printf("[strm][%p] Sending data...\n", Stream);
- //
- // Sends the buffer over the stream. Note the FIN flag is passed along with
- // the buffer. This indicates this is the last buffer on the stream and the
- // the stream is shut down (in the send direction) immediately after.
- //
+ struct timeval t1, t2;
+ gettimeofday(&t1, NULL);
+
+ printf("client sending...\n");
- /*
- if(getrandom(SendBuffer->Buffer, quic_send_buffer_len, 0) < 0){
- printf("getrandom failed\n");
- goto Error;
- }
- if (QUIC_FAILED(Status = quic_api->StreamSend(Stream, SendBuffer, 1, QUIC_SEND_FLAG_FIN, SendBuffer))) {
- printf("StreamSend failed, 0x%x!\n", Status);
- free(SendBufferRaw);
- goto Error;
- }
- */
-
for(;;){
if(getrandom(SendBuffer->Buffer, quic_send_buffer_len, 0) < 0){
printf("getrandom failed\n");
goto Error;
}
client_total_sent += quic_send_buffer_len;
- printf("client sent: %lu\n", client_total_sent);
- if(client_total_sent >= INPUT_BUFF_MAX - 1){
+ //printf("client sent: %lu\n", client_total_sent);
+ if(client_total_sent >= INPUT_BUFF_MAX){
+ SendBuffer->Length = 0;
if (QUIC_FAILED(Status = quic_api->StreamSend(Stream, SendBuffer, 1, QUIC_SEND_FLAG_FIN, SendBuffer))) {
printf("StreamSend failed, 0x%x!\n", Status);
free(SendBufferRaw);
break;
}
}
+ gettimeofday(&t2, NULL);
+
+ uint32_t seconds = t2.tv_sec - t1.tv_sec;
+ uint32_t ms = (t2.tv_usec - t1.tv_usec) / 1000;
+
+ printf("sec: %lu ms: %lu\n", seconds, ms);
Error:
quic_api->ConnectionShutdown(Connection, QUIC_CONNECTION_SHUTDOWN_FLAG_NONE, 0);
}
+ if(SendBufferRaw != NULL){
+ free(SendBufferRaw);
+ }
+
pthread_exit(NULL);
}
-//
-// The clients's callback for connection events from quic_api.
-//
-
QUIC_STATUS client_conn_cb(HQUIC Connection, void* Context, QUIC_CONNECTION_EVENT* Event){
UNREFERENCED_PARAMETER(Context);
switch (Event->Type) {
case QUIC_CONNECTION_EVENT_CONNECTED:
- //
- // The handshake has completed for the connection.
- //
- printf("[conn][%p] Connected\n", Connection);
+ printf("connected\n");
break;
case QUIC_CONNECTION_EVENT_SHUTDOWN_INITIATED_BY_TRANSPORT:
- //
- // The connection has been shut down by the transport. Generally, this
- // is the expected way for the connection to shut down with this
- // protocol, since we let idle timeout kill the connection.
- //
if (Event->SHUTDOWN_INITIATED_BY_TRANSPORT.Status == QUIC_STATUS_CONNECTION_IDLE) {
- printf("[conn][%p] Successfully shut down on idle.\n", Connection);
+ printf("successfully shut down on idle\n");
} else {
- printf("[conn][%p] Shut down by transport, 0x%x\n", Connection, Event->SHUTDOWN_INITIATED_BY_TRANSPORT.Status);
+ printf("shut down by transport: 0x%x\n", Event->SHUTDOWN_INITIATED_BY_TRANSPORT.Status);
}
break;
case QUIC_CONNECTION_EVENT_SHUTDOWN_INITIATED_BY_PEER:
- //
- // The connection was explicitly shut down by the peer.
- //
- printf("[conn][%p] Shut down by peer, 0x%llu\n", Connection, (unsigned long long)Event->SHUTDOWN_INITIATED_BY_PEER.ErrorCode);
+
+ printf("shut down by server: 0x%llu\n",(unsigned long long)Event->SHUTDOWN_INITIATED_BY_PEER.ErrorCode);
break;
case QUIC_CONNECTION_EVENT_SHUTDOWN_COMPLETE:
- //
- // The connection has completed the shutdown process and is ready to be
- // safely cleaned up.
- //
- printf("[conn][%p] All done\n", Connection);
+
+ printf("connection done\n");
if (!Event->SHUTDOWN_COMPLETE.AppCloseInProgress) {
quic_api->ConnectionClose(Connection);
}
break;
case QUIC_CONNECTION_EVENT_RESUMPTION_TICKET_RECEIVED:
- //
- // A resumption ticket (also called New Session Ticket or NST) was
- // received from the server.
- //
- printf("[conn][%p] Resumption ticket received (%u bytes)\n", Connection, Event->RESUMPTION_TICKET_RECEIVED.ResumptionTicketLength);
+ printf("resumption ticket received: %u bytes\n", Event->RESUMPTION_TICKET_RECEIVED.ResumptionTicketLength);
pthread_create(&client_tid, NULL, client_send, (void*)Connection);
break;
default:
return QUIC_STATUS_SUCCESS;
}
-//
-// Helper function to load a client configuration.
-//
+
BOOLEAN client_conf()
{
QUIC_SETTINGS Settings = {0};
- //
- // Configures the client's idle timeout.
- //
+
Settings.IdleTimeoutMs = quic_idle_timeoutms;
Settings.IsSet.IdleTimeoutMs = TRUE;
- //
- // Configures a default client configuration, optionally disabling
- // server certificate validation.
- //
QUIC_CREDENTIAL_CONFIG Config;
memset(&Config, 0, sizeof(Config));
Config.Type = QUIC_CREDENTIAL_TYPE_CERTIFICATE_FILE;
Config.CertificateFile = &CertFile;
Config.CaCertificateFile = Ca;
- //
- // Allocate/initialize the configuration object, with the configured ALPN
- // and settings.
- //
+
QUIC_STATUS Status = QUIC_STATUS_SUCCESS;
if (QUIC_FAILED(Status = quic_api->ConfigurationOpen(quic_registration, &quic_alpn, 1, &Settings, sizeof(Settings), NULL, &quic_configuration))) {
printf("ConfigurationOpen failed, 0x%x!\n", Status);
return FALSE;
}
- //
- // Loads the TLS credential part of the configuration. This is required even
- // on client side, to indicate if a certificate is required or not.
- //
if (QUIC_FAILED(Status = quic_api->ConfigurationLoadCredential(quic_configuration, &Config))) {
printf("ConfigurationLoadCredential failed, 0x%x!\n", Status);
return FALSE;
return TRUE;
}
-//
-// Runs the client side of the protocol.
-//
void run_client() {
- //
- // Load the client configuration based on the "unsecure" command line option.
- //
+
if (!client_conf()) {
return;
}
const char* SslKeyLogFile = getenv(quic_ssl_keylog_env);
HQUIC Connection = NULL;
- //
- // Allocate a new connection object.
- //
if (QUIC_FAILED(Status = quic_api->ConnectionOpen(quic_registration, client_conn_cb, NULL, &Connection))) {
printf("ConnectionOpen failed, 0x%x!\n", Status);
goto Error;
}
- //
- // Get the target / server name or IP from the command line.
- //
const char* Target = SERVER_ADDR;
- printf("[conn][%p] Connecting...\n", Connection);
-
- //
- // Start the connection to the server.
- //
if (QUIC_FAILED(Status = quic_api->ConnectionStart(Connection, quic_configuration, QUIC_ADDRESS_FAMILY_UNSPEC, Target, quic_udp_port))) {
printf("ConnectionStart failed, 0x%x!\n", Status);
goto Error;
quic_api->ConfigurationClose(quic_configuration);
}
if (quic_registration != NULL) {
- //
- // This will block until all outstanding child objects have been
- // closed.
- //
quic_api->RegistrationClose(quic_registration);
}
MsQuicClose(quic_api);
+++ /dev/null
-#include "tcp.h"
-
-
-static int client(){
-
- int result = 0;
- int sockfd = -1;
- struct sockaddr_in servaddr;
- in_addr_t s_addr = inet_addr(SERVER_ADDR);
- int addr_port = SERVER_PORT;
- int keepalive = 1;
- int chunk = 0;
- int content_len = 0;
- int message_len = 0;
- float percent = 0;
- struct timeval t1, t2;
-
- uint64_t total_sent = 0;
- uint8_t data[INPUT_BUFF_CHUNK] = {0};
-
- sockfd = socket(AF_INET, SOCK_STREAM, 0);
- if (sockfd == -1) {
- fprintf(stderr, "socket creation failed\n");
- return -1;
- }
-
- servaddr.sin_family = AF_INET;
- servaddr.sin_addr.s_addr = s_addr;
- servaddr.sin_port = htons(addr_port);
-
- if (connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr))!= 0) {
- fprintf(stderr, "connection failed\n");
- return -2;
- }
-
- printf("connected, sending...\n");
-
- gettimeofday(&t1, NULL);
-
- while(keepalive){
-
- if(getrandom(data, INPUT_BUFF_CHUNK, 0) < 0){
- printf("getrandom failed\n");
- return -3;
- }
-
- int wb = write(sockfd, data, INPUT_BUFF_CHUNK);
-
- if(wb <= 0){
- keepalive = 0;
- continue;
- }
-
- total_sent += (uint64_t)wb;
-
- percent = ((float)total_sent / (float)INPUT_BUFF_MAX) * 100;
-
- printf("progress: %.2f\n", percent);
-
- if(total_sent > INPUT_BUFF_MAX){
- keepalive = 0;
- continue;
- }
-
- }
-
- if(total_sent <= INPUT_BUFF_MAX){
- printf("connection closed before sending completed\n");
- return -4;
- }
-
- gettimeofday(&t2, NULL);
-
- uint32_t seconds = t2.tv_sec - t1.tv_sec;
- uint32_t ms = (t2.tv_usec - t1.tv_usec) / 1000;
-
- printf("sec: %lu ms: %lu\n", seconds, ms);
- printf("total sent: " "%" PRIu64 "\n", total_sent);
-
- return 0;
-}
-
-
-
-static int server(){
-
- int sockfd, connfd = -1;
- struct sockaddr_in servaddr, cli;
- int keepalive = 1;
-
-
- in_addr_t s_addr = INADDR_ANY;
-
- int addr_port = SERVER_PORT;
- int enable = 1;
- int clilen = sizeof(cli);
-
- uint8_t data[INPUT_BUFF_CHUNK] = {0};
-
- sockfd = socket(AF_INET, SOCK_STREAM, 0);
- if (sockfd == -1) {
- fprintf(stderr,"socket creation failed...\n");
- return -1;
- }
-
- servaddr.sin_family = AF_INET;
- servaddr.sin_addr.s_addr = s_addr;
- servaddr.sin_port = htons(addr_port);
-
- if ((bind(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr))) != 0) {
- fprintf(stderr, "socket bind failed\n");
- return -2;
- }
-
- if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0){
- fprintf(stderr, "socket opt failed\n");
- return -3;
- }
-
- if ((listen(sockfd, 1)) != 0) {
- fprintf(stderr,"socket listen failed\n");
- return -4;
- }
-
- while(keepalive){
-
- connfd = accept(sockfd, (struct sockaddr*)&cli, (socklen_t*)&clilen);
- if (connfd < 0) {
- fprintf(stderr, "server accept failed\n");
- continue;
- }
-
- printf("client connected\n");
- printf("receiving...\n");
-
- while(keepalive){
-
- int valread = 0;
-
- while(valread < INPUT_BUFF_CHUNK){
-
- int rb = read(connfd, data + valread, INPUT_BUFF_CHUNK - valread);
- if (rb <= 0){
- keepalive = 0;
- break;
- }
- valread += rb;
-
- }
-
- if(keepalive == 0){
- continue;
- }
- }
-
- close(connfd);
-
- }
- return 0;
-}
-
-
-
-static void help(){
-
- printf("option: [c|s]\n");
- printf("c: client mode\n");
- printf("s: server mode\n");
-}
-
-
-int main(int argc, char** argv){
-
- int result = 0;
-
- if(argc != 2){
-
- help();
-
- return -1;
- }
-
- if(strcmp(argv[1], "c") == 0){
-
- result = client();
-
- } else if(strcmp(argv[1], "s") == 0){
-
- result = server();
-
- } else {
-
- help();
-
- return -1;
- }
-
- return result;
-}
\ No newline at end of file
--- /dev/null
+#include "tls.h"
+
+char* PREFERRED_CIPHERS = "HIGH:!aNULL:!kRSA:!SRP:!PSK:!CAMELLIA:!RC4:!MD5:!DSS";
+
+void init_openssl_library(void){
+
+ (void)SSL_library_init();
+ SSL_load_error_strings();
+ CONF_modules_load(NULL, NULL, CONF_MFLAGS_IGNORE_MISSING_FILE);
+#if defined (OPENSSL_THREADS)
+ /* https://www.openssl.org/docs/crypto/threads.html */
+ fprintf(stdout, "Warning: thread locking is not implemented\n");
+#endif
+}
+
+void print_cn_name(const char* label, X509_NAME* const name)
+{
+ int idx = -1, success = 0;
+ unsigned char *utf8 = NULL;
+ do{
+ if(!name) break; /* failed */
+ idx = X509_NAME_get_index_by_NID(name, NID_commonName, -1);
+ if(!(idx > -1)) break; /* failed */
+ X509_NAME_ENTRY* entry = X509_NAME_get_entry(name, idx);
+ if(!entry) break; /* failed */
+ ASN1_STRING* data = X509_NAME_ENTRY_get_data(entry);
+ if(!data) break; /* failed */
+ int length = ASN1_STRING_to_UTF8(&utf8, data);
+ if(!utf8 || !(length > 0)) break; /* failed */
+ fprintf(stdout, " %s: %s\n", label, utf8);
+ success = 1;
+ } while (0);
+
+ if(utf8){
+ OPENSSL_free(utf8);
+ }
+ if(!success){
+ fprintf(stdout, " %s: <not available>\n", label);
+ }
+}
+
+void print_san_name(const char* label, X509* const cert){
+ int success = 0;
+ GENERAL_NAMES* names = NULL;
+ unsigned char* utf8 = NULL;
+ do{
+ if(!cert) break; /* failed */
+ names = X509_get_ext_d2i(cert, NID_subject_alt_name, 0, 0 );
+ if(!names) break;
+ int i = 0, count = sk_GENERAL_NAME_num(names);
+ if(!count) break; /* failed */
+ for( i = 0; i < count; ++i ){
+ GENERAL_NAME* entry = sk_GENERAL_NAME_value(names, i);
+ if(!entry) continue;
+ if(GEN_DNS == entry->type){
+ int len1 = 0, len2 = -1;
+ len1 = ASN1_STRING_to_UTF8(&utf8, entry->d.dNSName);
+ if(utf8) {
+ len2 = (int)strlen((const char*)utf8);
+ }
+ if(len1 != len2) {
+ fprintf(stderr, " Strlen and ASN1_STRING size do not match (embedded null?): %d vs %d\n", len2, len1);
+ }
+ if(utf8 && len1 && len2 && (len1 == len2)) {
+ fprintf(stdout, " %s: %s\n", label, utf8);
+ success = 1;
+ }
+ if(utf8) {
+ OPENSSL_free(utf8), utf8 = NULL;
+ }
+ }
+ else{
+ fprintf(stderr, " Unknown GENERAL_NAME type: %d\n", entry->type);
+ }
+ }
+ } while (0);
+
+ if(names){
+ GENERAL_NAMES_free(names);
+ }
+ if(utf8){
+ OPENSSL_free(utf8);
+ }
+ if(!success){
+ fprintf(stdout, " %s: <not available>\n", label);
+ }
+}
+
+int verify_callback(int preverify, X509_STORE_CTX* x509_ctx){
+
+ int depth = X509_STORE_CTX_get_error_depth(x509_ctx);
+ int err = X509_STORE_CTX_get_error(x509_ctx);
+ X509* cert = X509_STORE_CTX_get_current_cert(x509_ctx);
+ X509_NAME* iname = cert ? X509_get_issuer_name(cert) : NULL;
+ X509_NAME* sname = cert ? X509_get_subject_name(cert) : NULL;
+ fprintf(stdout, "verify_callback (depth=%d)(preverify=%d)\n", depth, preverify);
+ print_cn_name("Issuer (cn)", iname);
+ print_cn_name("Subject (cn)", sname);
+ if(depth == 0) {
+ print_san_name("Subject (san)", cert);
+ }
+ if(preverify == 0){
+ if(err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY)
+ fprintf(stdout, " Error = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY\n");
+ else if(err == X509_V_ERR_CERT_UNTRUSTED)
+ fprintf(stdout, " Error = X509_V_ERR_CERT_UNTRUSTED\n");
+ else if(err == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN)
+ fprintf(stdout, " Error = X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN\n");
+ else if(err == X509_V_ERR_CERT_NOT_YET_VALID)
+ fprintf(stdout, " Error = X509_V_ERR_CERT_NOT_YET_VALID\n");
+ else if(err == X509_V_ERR_CERT_HAS_EXPIRED)
+ fprintf(stdout, " Error = X509_V_ERR_CERT_HAS_EXPIRED\n");
+ else if(err == X509_V_OK)
+ fprintf(stdout, " Error = X509_V_OK\n");
+ else
+ fprintf(stdout, " Error = %d\n", err);
+ }
+ return preverify;
+}
+
+
+static int client(){
+
+ SSL_CTX* ctx = NULL;
+ SSL *ssl = NULL;
+ SSL_METHOD *method = NULL;
+
+ int result = 0;
+ int sockfd = -1;
+
+ struct addrinfo hints;
+ struct addrinfo* rp;
+
+ struct sockaddr_in servaddr;
+ in_addr_t s_addr = inet_addr(SERVER_ADDR);
+ int addr_port = SERVER_PORT;
+ int keepalive = 1;
+ int chunk = 0;
+ int content_len = 0;
+ int message_len = 0;
+ float percent = 0;
+ struct timeval t1, t2;
+
+ uint64_t total_sent = 0;
+ uint8_t data[INPUT_BUFF_CHUNK] = {0};
+
+
+ method = SSLv23_method();
+ if(method == NULL){
+ printf("ssl null method\n");
+ return -1;
+ }
+ ctx = SSL_CTX_new(method);
+ if(ctx == NULL){
+ printf("ctx null\n");
+ return -2;
+ }
+ SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_callback);
+ SSL_CTX_set_verify_depth(ctx, 5);
+
+ const long flags = SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION;
+
+ SSL_CTX_set_options(ctx, flags);
+ result = SSL_CTX_load_verify_locations(ctx, CERT_CA, NULL);
+
+ if (result != 1){
+ printf("load verification cert\n");
+ return -3;
+ }
+
+ ssl = SSL_new(ctx);
+
+ if(ssl == NULL){
+ printf("ssl new failed\n");
+ return -4;
+ }
+
+ sockfd = socket(AF_INET, SOCK_STREAM, 0);
+ if (sockfd == -1) {
+ fprintf(stderr, "socket creation failed\n");
+ return -1;
+ }
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_INET; // IPv4
+ hints.ai_socktype = SOCK_STREAM;
+ result = getaddrinfo(SERVER_ADDR, NULL, &hints, &rp);
+ if(result != 0){
+ printf("failed to get addr info\n");
+ return -11;
+ }
+ struct sockaddr_in* ipv4 = (struct sockaddr_in*)rp->ai_addr;
+
+ servaddr.sin_family = AF_INET;
+ servaddr.sin_addr = ipv4->sin_addr;
+ servaddr.sin_port = htons(addr_port);
+
+ if (connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr))!= 0) {
+ fprintf(stderr, "connection failed\n");
+ return -2;
+ }
+
+ SSL_set_fd(ssl, sockfd);
+
+ result = SSL_connect(ssl);
+ if(result != 1){
+ printf("failed to handshake: %d\n", result);
+ return -3;
+ }
+
+ X509* cert = SSL_get_peer_certificate(ssl);
+ if(cert == NULL){
+ printf("failed to get peer cert\n");
+ return -4;
+ }
+
+ result = SSL_get_verify_result(ssl);
+ if (result != X509_V_OK){
+ printf("ssl peer verification failed\n");
+ return -5;
+ }
+
+ printf("connected, sending...\n");
+
+ gettimeofday(&t1, NULL);
+
+ while(keepalive){
+
+ if(getrandom(data, INPUT_BUFF_CHUNK, 0) < 0){
+ printf("getrandom failed\n");
+ return -3;
+ }
+
+ int wb = SSL_write(ssl, data, INPUT_BUFF_CHUNK);
+
+ if(wb <= 0){
+ keepalive = 0;
+ continue;
+ }
+
+ total_sent += (uint64_t)wb;
+
+ percent = ((float)total_sent / (float)INPUT_BUFF_MAX) * 100;
+
+ //printf("progress: %.2f\n", percent);
+
+ if(total_sent > INPUT_BUFF_MAX){
+ keepalive = 0;
+ continue;
+ }
+
+ }
+
+ if(total_sent <= INPUT_BUFF_MAX){
+ printf("connection closed before sending completed\n");
+ return -4;
+ }
+
+ gettimeofday(&t2, NULL);
+
+ uint32_t seconds = t2.tv_sec - t1.tv_sec;
+ uint32_t ms = (t2.tv_usec - t1.tv_usec) / 1000;
+
+ printf("sec: %lu ms: %lu\n", seconds, ms);
+ printf("total sent: " "%" PRIu64 "\n", total_sent);
+
+ return 0;
+}
+
+
+
+static int server(){
+
+ SSL *ssl;
+ SSL_CTX *ctx;
+ SSL_METHOD *method;
+
+ int sockfd, connfd = -1;
+ struct sockaddr_in servaddr, cli;
+ int keepalive = 1;
+
+
+ in_addr_t s_addr = INADDR_ANY;
+
+ int addr_port = SERVER_PORT;
+ int enable = 1;
+ int clilen = sizeof(cli);
+
+ uint8_t data[INPUT_BUFF_CHUNK] = {0};
+
+
+ SSL_library_init();
+
+
+ method = TLS_server_method();
+
+ ctx = SSL_CTX_new(method);
+ if (!ctx) {
+ printf("unable to create SSL context");
+ return -1;
+ }
+
+ if (SSL_CTX_use_certificate_file(ctx, CERT_SERVER, SSL_FILETYPE_PEM) <= 0) {
+ printf("failed to use server cert\n");
+ return -2;
+ }
+
+ if (SSL_CTX_use_PrivateKey_file(ctx, KEY_SERVER, SSL_FILETYPE_PEM) <= 0 ) {
+ printf("failed to use server key\n");
+ return -3;
+ }
+
+ ssl = SSL_new(ctx);
+
+ sockfd = socket(AF_INET, SOCK_STREAM, 0);
+ if (sockfd == -1) {
+ printf("socket creation failed...\n");
+ return -1;
+ }
+ servaddr.sin_family = AF_INET;
+ servaddr.sin_addr.s_addr = s_addr;
+ servaddr.sin_port = htons(addr_port);
+
+ if ((bind(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr))) != 0) {
+ fprintf(stderr, "socket bind failed\n");
+ return -2;
+ }
+
+ if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0){
+ fprintf(stderr, "socket opt failed\n");
+ return -3;
+ }
+
+ if ((listen(sockfd, 1)) != 0) {
+ fprintf(stderr,"socket listen failed\n");
+ return -4;
+ }
+
+ while(keepalive){
+
+ connfd = accept(sockfd, (struct sockaddr*)&cli, (socklen_t*)&clilen);
+ if (connfd < 0) {
+ fprintf(stderr, "server accept failed\n");
+ continue;
+ }
+
+ SSL_set_fd(ssl, connfd);
+
+ if(SSL_accept(ssl) != 1){
+ fprintf(stderr, "server ssl accept failed\n");
+ continue;
+ };
+
+ printf("client connected\n");
+ printf("receiving...\n");
+
+ while(keepalive){
+
+ int valread = 0;
+
+ while(valread < INPUT_BUFF_CHUNK){
+
+ int rb = SSL_read(ssl, data + valread, INPUT_BUFF_CHUNK - valread);
+ if (rb <= 0){
+ keepalive = 0;
+ break;
+ }
+ valread += rb;
+
+ }
+
+ if(keepalive == 0){
+ continue;
+ }
+ }
+
+ close(connfd);
+
+ }
+ return 0;
+}
+
+
+
+static void help(){
+
+ printf("option: [c|s]\n");
+ printf("c: client mode\n");
+ printf("s: server mode\n");
+}
+
+
+int main(int argc, char** argv){
+
+ int result = 0;
+
+ if(argc != 2){
+
+ help();
+
+ return -1;
+ }
+
+ if(strcmp(argv[1], "c") == 0){
+
+ result = client();
+
+ } else if(strcmp(argv[1], "s") == 0){
+
+ result = server();
+
+ } else {
+
+ help();
+
+ return -1;
+ }
+
+ return result;
+}
\ No newline at end of file