The gsk_secure_soc_startInit() API allows you to create secure server applications that can handle request asynchronously.
The following code sample provides an example of how this API can be used. It is similar to the GSKit secure server with asynchronous data receive example, but uses this new API to start a secure session.
The following graphic shows the function calls used to negotiate an asynchronous handshake on a secure server:
To view the client portion of this graphic, see GSKit client .
This flow describes the socket calls in the following sample application.
/* GSK Asynchronous Server Program using Application Id*/ /* and gsk_secure_soc_startInit() */ /* Assummes that application id is already registered */ /* and a certificate has been associated with the */ /* application id. */ /* No parameters, some comments and many hardcoded */ /* values to keep it short and simple */ /* use following command to create bound program: */ /* CRTBNDC PGM(MYLIB/GSKSERVSI) */ /* SRCFILE(MYLIB/CSRC) */ /* SRCMBR(GSKSERVSI) */ #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <gskssl.h> #include <netinet/in.h> #include <arpa/inet.h> #include <errno.h> #define _MULTI_THREADED #include "pthread.h" #include "qsoasync.h" #define Failure 0 #define Success 1 #define TRUE 1 #define FALSE 0 void *workerThread(void *arg); /********************************************************************/ /* Descriptive Name: Master thread will establish a client */ /* connection and hand processing responsibility */ /* to a worker thread. */ /* Note: Due to the thread attribute of this program, spawn() must */ /* be used to invoke. */ /********************************************************************/ int main(void) { gsk_handle my_env_handle=NULL; /* secure environment handle */ gsk_handle my_session_handle=NULL; /* secure session handle */ struct sockaddr_in address; int buf_len, on = 1, rc = 0; int sd = -1, lsd = -1, al, ioCompPort = -1; int successFlag = FALSE; pthread_t thr; void *status; Qso_OverlappedIO_t ioStruct; /*********************************************/ /* Issue all of the command in a do/while */ /* loop so that clean up can happen at end */ /*********************************************/ do { /*********************************************/ /* Create an I/O completion port for this */ /* process. */ /*********************************************/ if ((ioCompPort = QsoCreateIOCompletionPort()) < 0) { perror("QsoCreateIOCompletionPort() failed"); break; } /*********************************************/ /* Create a worker thread */ /* to process all client requests. The */ /* worker thread will wait for client */ /* requests to arrive on the I/O completion */ /* port just created. */ /*********************************************/ rc = pthread_create(&thr, NULL, workerThread, &ioCompPort); if (rc < 0) { perror("pthread_create() failed"); break; } /* open a gsk environment */ rc = errno = 0; printf("gsk_environment_open()\n"); rc = gsk_environment_open(&my_env_handle); if (rc != GSK_OK) { printf("gsk_environment_open() failed with rc = %d and errno = %d.\n", rc,errno); printf("rc of %d means %s\n", rc, gsk_strerror(rc)); break; } /* set the Application ID to use */ rc = errno = 0; rc = gsk_attribute_set_buffer(my_env_handle, GSK_OS400_APPLICATION_ID, "MY_SERVER_APP", 13); if (rc != GSK_OK) { printf("gsk_attribute_set_buffer() failed with rc = %d and errno = %d.\n" ,rc,errno); printf("rc of %d means %s\n", rc, gsk_strerror(rc)); break; } /* set this side as the server */ rc = errno = 0; rc = gsk_attribute_set_enum(my_env_handle, GSK_SESSION_TYPE, GSK_SERVER_SESSION); if (rc != GSK_OK) { printf("gsk_attribute_set_enum() failed with rc = %d and errno = %d.\n", rc,errno); printf("rc of %d means %s\n", rc, gsk_strerror(rc)); break; } /* by default SSL_V2, SSL_V3, and TLS_V1 are enabled */ /* We will disable SSL_V2 for this example. */ rc = errno = 0; rc = gsk_attribute_set_enum(my_env_handle, GSK_PROTOCOL_SSLV2, GSK_PROTOCOL_SSLV2_OFF); if (rc != GSK_OK) { printf("gsk_attribute_set_enum() failed with rc = %d and errno = %d.\n", rc,errno); printf("rc of %d means %s\n", rc, gsk_strerror(rc)); break; } /* set the cipher suite to use. By default our default list */ /* of ciphers is enabled. For this example we will just use one */ rc = errno = 0; rc = gsk_attribute_set_buffer(my_env_handle, GSK_V3_CIPHER_SPECS, "05", /* SSL_RSA_WITH_RC4_128_SHA */ 2); if (rc != GSK_OK) { printf("gsk_attribute_set_buffer() failed with rc = %d and errno = %d.\n" ,rc,errno); printf("rc of %d means %s\n", rc, gsk_strerror(rc)); break; } /* Initialize the secure environment */ rc = errno = 0; printf("gsk_environment_init()\n"); rc = gsk_environment_init(my_env_handle); if (rc != GSK_OK) { printf("gsk_environment_init() failed with rc = %d and errno = %d.\n", rc,errno); printf("rc of %d means %s\n", rc, gsk_strerror(rc)); break; } /* initialize a socket to be used for listening */ printf("socket()\n"); lsd = socket(AF_INET, SOCK_STREAM, 0); if (lsd < 0) { perror("socket() failed"); break; } /* set socket so can be reused immediately */ rc = setsockopt(lsd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)); if (rc < 0) { perror("setsockopt() failed"); break; } /* bind to the local server address */ memset((char *) &address, 0, sizeof(address)); address.sin_family = AF_INET; address.sin_port = 13333; address.sin_addr.s_addr = 0; printf("bind()\n"); rc = bind(lsd, (struct sockaddr *) &address, sizeof(address)); if (rc < 0) { perror("bind() failed"); break; } /* enable the socket for incoming client connections */ printf("listen()\n"); listen(lsd, 5); if (rc < 0) { perror("listen() failed"); break; } /* accept an incoming client connection */ al = sizeof(address); printf("accept()\n"); sd = accept(lsd, (struct sockaddr *) &address, &al); if (sd < 0) { perror("accept() failed"); break; } /* open a secure session */ rc = errno = 0; printf("gsk_secure_soc_open()\n"); rc = gsk_secure_soc_open(my_env_handle, &my_session_handle); if (rc != GSK_OK) { printf("gsk_secure_soc_open() failed with rc = %d and errno = %d.\n", rc,errno); printf("rc of %d means %s\n", rc, gsk_strerror(rc)); break; } /* associate our socket with the secure session */ rc=errno=0; rc = gsk_attribute_set_numeric_value(my_session_handle, GSK_FD, sd); if (rc != GSK_OK) { printf("gsk_attribute_set_numeric_value() failed with rc = %d ", rc); printf("and errno = %d.\n", errno); printf("rc of %d means %s\n", rc, gsk_strerror(rc)); break; } /*********************************************/ /* Issue gsk_secure_soc_startInit() to */ /* process SSL Handshake flow asynchronously */ /*********************************************/ /*********************************************/ /* initialize Qso_OverlappedIO_t structure - */ /* reserved fields must be hex 00's. */ /*********************************************/ memset(&ioStruct, '\0', sizeof(ioStruct)); /*********************************************/ /* Store the session handle in the */ /* Qso_OverlappedIO_t descriptorHandle field.*/ /* This area is used to house information */ /* defining the state of the client */ /* connection. Field descriptorHandle is */ /* defined as a (void *) to allow the server */ /* to address more extensive client */ /* connection state if needed. */ /*********************************************/ ioStruct.descriptorHandle = my_session_handle; /* initiate the SSL handshake */ rc = errno = 0; printf("gsk_secure_soc_startInit()\n"); rc = gsk_secure_soc_startInit(my_session_handle, ioCompPort, &ioStruct); if (rc != GSK_OS400_ASYNCHRONOUS_SOC_INIT) { printf("gsk_secure_soc_startInit() rc = %d and errno = %d.\n",rc,errno); printf("rc of %d means %s\n", rc, gsk_strerror(rc)); break; } else printf("gsk_secure_soc_startInit got GSK_OS400_ASYNCHRONOUS_SOC_INIT\n"); /*********************************************/ /* This is where the server can loop back */ /* to accept a new connection. */ /*********************************************/ /*********************************************/ /* Wait for worker thread to finish */ /* processing client connection. */ /*********************************************/ rc = pthread_join(thr, &status); /* check status of the worker */ if ( rc == 0 && (rc = __INT(status)) == Success) { printf("Success.\n"); printf("Success.\n"); successFlag = TRUE; } else { perror("pthread_join() reported failure"); } } while(FALSE); /* disable the SSL session */ if (my_session_handle != NULL) gsk_secure_soc_close(&my_session_handle); /* disable the SSL environment */ if (my_env_handle != NULL) gsk_environment_close(&my_env_handle); /* close the listening socket */ if (lsd > -1) close(lsd); /* close the accepted socket */ if (sd > -1) close(sd); /* destroy the completion port */ if (ioCompPort > -1) QsoDestroyIOCompletionPort(ioCompPort); if (successFlag) exit(0); exit(-1); } /********************************************************************/ /* Function Name: workerThread */ /* */ /* Descriptive Name: Process client connection. */ /* */ /* Note: To make the sample more straight forward the main routine */ /* handles all of the clean up although this function can */ /* be made responsible for the clientfd and session_handle. */ /********************************************************************/ void *workerThread(void *arg) { struct timeval waitTime; int ioCompPort, clientfd; Qso_OverlappedIO_t ioStruct; int rc, tID; int amtWritten, amtRead; char buff[1024]; gsk_handle client_session_handle; pthread_t thr; pthread_id_np_t t_id; t_id = pthread_getthreadid_np(); tID = t_id.intId.lo; /*********************************************/ /* I/O completion port is passed to this */ /* routine. */ /*********************************************/ ioCompPort = *(int *)arg; /*********************************************/ /* Wait on the supplied I/O completion port */ /* for the SSL handshake to complete. */ /*********************************************/ waitTime.tv_sec = 500; waitTime.tv_usec = 0; sleep(4); printf("QsoWaitForIOCompletion()\n"); rc = QsoWaitForIOCompletion(ioCompPort, &ioStruct, &waitTime); if ((rc == 1) && (ioStruct.returnValue == GSK_OK) && (ioStruct.operationCompleted == GSKSECURESOCSTARTINIT)) /*********************************************/ /* SSL Handshake has completed. */ /*********************************************/ ; else { printf("QsoWaitForIOCompletion()/gsk_secure_soc_startInit() failed.\n"); printf("rc == %d, returnValue - %d, operationCompleted = %d\n", rc, ioStruct.returnValue, ioStruct.operationCompleted); perror("QsoWaitForIOCompletion()/gsk_secure_soc_startInit() failed"); return __VOID(Failure); } /*********************************************/ /* Obtain the session handle associated */ /* with the client connection. */ /*********************************************/ client_session_handle = ioStruct.descriptorHandle; /* get the socket associated with the secure session */ rc=errno=0; printf("gsk_attribute_get_numeric_value()\n"); rc = gsk_attribute_get_numeric_value(client_session_handle, GSK_FD, &clientfd); if (rc != GSK_OK) { printf("gsk_attribute_get_numeric_value() rc = %d and errno = %d.\n", rc,errno); printf("rc of %d means %s\n", rc, gsk_strerror(rc)); return __VOID(Failure); } /* memset buffer to hex zeros */ memset((char *) buff, 0, sizeof(buff)); amtRead = 0; /* receive a message from the client using the secure session */ printf("gsk_secure_soc_read()\n"); rc = gsk_secure_soc_read(client_session_handle, buff, sizeof(buff), &amtRead); if (rc != GSK_OK) { printf("gsk_secure_soc_read() rc = %d and errno = %d.\n",rc,errno); printf("rc of %d means %s\n", rc, gsk_strerror(rc)); return; } /* write results to screen */ printf("gsk_secure_soc_read() received %d bytes, here they are ...\n", amtRead); printf("%s\n",buff); /* send the message to the client using the secure session */ amtWritten = 0; printf("gsk_secure_soc_write()\n"); rc = gsk_secure_soc_write(client_session_handle, buff, amtRead, &amtWritten); if (amtWritten != amtRead) { if (rc != GSK_OK) { printf("gsk_secure_soc_write() rc = %d and errno = %d.\n",rc,errno); printf("rc of %d means %s\n", rc, gsk_strerror(rc)); return __VOID(Failure); } else { printf("gsk_secure_soc_write() did not write all data.\n"); return __VOID(Failure); } } /* write results to screen */ printf("gsk_secure_soc_write() wrote %d bytes...\n", amtWritten); printf("%s\n",buff); return __VOID(Success); } /* end workerThread */