Novell Home

Basic WinSock SSL server

From Developer Community

Shows how to set up a listening socket for a SSL connection using WinSock and LibC on NetWare.

Sample Code

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <nks/thread.h>

#include <novsock2.h>

#include <screen.h>

#define BUFFER_SIZE 256
#define WS_VER MAKEWORD(2,2)

SOCKET SSL_Bind(char *pczPort);
int SendHTTPResponse(SOCKET);

SOCKET gServerSocketHnd;
SOCKET gClientHnd;

void sigHnd(int signal)
{
    closesocket(gServerSocketHnd);
    gServerSocketHnd = INVALID_SOCKET;
    if(INVALID_SOCKET != gClientHnd)
    {
       closesocket(gClientHnd);
       gClientHnd = INVALID_SOCKET;
    }
    WSACleanup();
}

int main(void)
{
    int rcode;
    WORD wVersionRequested = WS_VER;
    WSADATA wsaData;
    char czBuffer[BUFFER_SIZE];
    struct sockaddr_in saClient;
    int iClientSize = sizeof(saClient);

    gClientHnd = INVALID_SOCKET;
    gServerSocketHnd = INVALID_SOCKET;
    signal(SIGTERM, sigHnd);
    memset((char *)&saClient, 0, iClientSize);
    memset(czBuffer, 0, sizeof(czBuffer));

    rcode = WSAStartup(wVersionRequested, &wsaData);
    if(rcode){
        printf("Error: %d with WSAStartup\r\n", WSAGetLastError());
        goto ERR;
    }
    
    if(wsaData.wVersion != wVersionRequested){
        printf("Error: invalid winsock version loaded\r\n");
        goto ERR;
    }

    gServerSocketHnd = SSL_Bind("9000");
    if(INVALID_SOCKET == gServerSocketHnd){
        printf("Error: %d with SSL_Bind\r\n", WSAGetLastError());
        goto ERR;
    }
    while(1){
        gClientHnd = accept(gServerSocketHnd, 
                          (struct sockaddr *)&saClient, 
                          &iClientSize);
        if(INVALID_SOCKET == gClientHnd){
            printf("Error: %d with accept\r\n", WSAGetLastError());
            goto ERR;
        }
        
        printf("Accepted client: %s:%d\r\n", 
                inet_ntoa(saClient.sin_addr),
                ntohs(saClient.sin_port));
                
        
        memset(czBuffer, 0, sizeof(czBuffer));

        rcode = recv(gClientHnd, czBuffer, sizeof(czBuffer), 0);
        if(SOCKET_ERROR == rcode){
            printf("Error: %d with recv\r\n", WSAGetLastError());
            goto ERR;
        }
        
        printf("recv returned %d\r\n", rcode);
        printf("RCV: %s\r\n", czBuffer);
        
        if(0 == strncmp("GET", czBuffer, 3))
        {
            rcode = SendHTTPResponse(gClientHnd);
        }
        else
        {
            rcode = send(gClientHnd, czBuffer, strlen(czBuffer), 0);
        }

        if(SOCKET_ERROR == rcode)
        {
            printf("Error: %d with send\r\n", WSAGetLastError());
//            goto ERR;
        }
        else
        {
            printf("SND: %d Bytes\r\n", rcode);
        }
        
        //NXThreadYield();
        printf("Closing connection\r\n\r\n");
        shutdown(gClientHnd, SD_BOTH);
        closesocket(gClientHnd);
        gClientHnd = INVALID_SOCKET;
    }
  
ERR:
    if(INVALID_SOCKET != gClientHnd)
        closesocket(gClientHnd);
    if(INVALID_SOCKET != gServerSocketHnd)
        closesocket(gServerSocketHnd);
    WSACleanup();
    pressanykey();
    return 0;
}


/*
** function: SSL_Bind
** usage:    binds to a port using ssl information.
*/
SOCKET SSL_Bind(char *pczPort)
{
    SOCKET socketHnd = INVALID_SOCKET;
    int rcode;
    struct sockaddr_in saListenAddr;
    WSAPROTOCOL_INFO sProtocolInfo;
    struct tlsserveropts sWS2Opts;
    struct nwtlsopts    sNWTLSOpts;
    unicode *SASKey = L"SSL CertificateDNS";  //nds name for server key

//zero out structures
    memset((char *)&saListenAddr, 0, sizeof(struct sockaddr_in));
    memset((char *)&sProtocolInfo, 0, sizeof(WSAPROTOCOL_INFO));
    memset((char *)&sWS2Opts, 0, sizeof(struct tlsserveropts));
    memset((char *)&sNWTLSOpts, 0, sizeof(struct nwtlsopts));


    
    
//setup the WSAPROTOCOL_INFO structure
    sProtocolInfo.iAddressFamily = AF_INET;
    sProtocolInfo.iSocketType = SOCK_STREAM;
    sProtocolInfo.iProtocol = IPPROTO_TCP;
    sProtocolInfo.iSecurityScheme = SECURITY_PROTOCOL_SSL;


//create a socket
    socketHnd = WSASocket(AF_INET, 
                          SOCK_STREAM, 
                          IPPROTO_TCP, 
                          &sProtocolInfo, 
                          NULL, 
                          NULL);
    if(INVALID_SOCKET == socketHnd){
        goto ERR;
    }

//setup the tlsserveropts struct
    sWS2Opts.wallet = SASKey;
    sWS2Opts.walletlen = unilen(SASKey);
    sWS2Opts.sidtimeout = 0;
    sWS2Opts.sidentries = 0;
    sWS2Opts.siddir = NULL;
    sWS2Opts.options = &sNWTLSOpts;

//setup the nwtlsopts structure

    sNWTLSOpts.walletProvider               = WAL_PROV_KMO;
    sNWTLSOpts.keysList                     = NULL;
    sNWTLSOpts.numElementsInKeyList         = 0;
    sNWTLSOpts.reservedforfutureuse         = NULL;
    sNWTLSOpts.reservedforfutureCRL         = NULL;
    sNWTLSOpts.reservedforfutureCRLLen      = NULL;
    sNWTLSOpts.reserved1                    = NULL;
    sNWTLSOpts.reserved2                    = NULL;
    sNWTLSOpts.reserved3                    = NULL;


    rcode = WSAIoctl(socketHnd, 
                    SO_TLS_SET_SERVER, 
                    &sWS2Opts, 
                    sizeof(struct tlsserveropts), 
                    NULL, 
                    0, 
                    NULL, 
                    NULL, 
                    NULL);
    if(SOCKET_ERROR == rcode){
        printf("Error: %d with WSAIoctl(SO_TLS_SET_SERVER)\r\n", WSAGetLastError());
        goto ERR;
    }

    saListenAddr.sin_family = AF_INET;
    saListenAddr.sin_port = htons(atoi(pczPort));
    saListenAddr.sin_addr.s_addr = INADDR_ANY;

    rcode = bind(socketHnd, 
                (struct sockaddr *)&saListenAddr, 
                sizeof(struct sockaddr_in));
    
    if(SOCKET_ERROR == rcode){
        printf("Error: %d with bind\r\n", WSAGetLastError());
        goto ERR;
    }
    
    rcode = listen(socketHnd, 0);
    if(SOCKET_ERROR == rcode){
        printf("Error: %d with listen\r\n", WSAGetLastError());
        goto ERR;
    }    

ERR:
    if(rcode){
        closesocket(socketHnd);
        socketHnd = INVALID_SOCKET;
    }
    return socketHnd;

} 

int SendHTTPResponse(SOCKET socketHnd)
{
    char czBuffer[1024];
    
    memset(czBuffer, 0, sizeof(czBuffer));
    
    strcpy(czBuffer, "HTTP/1.0 200 OK\r\n");
    strcat(czBuffer, "Connection: close\r\n");
    strcat(czBuffer, "Content-Type: text/html\r\n\r\n");
    strcat(czBuffer, "<HTML>\r\n");
    strcat(czBuffer, "\t<HEAD>\r\n");
    strcat(czBuffer, "\t\t<TITLE>SSL/TLS Basic Server Example</TITLE>\r\n");
    strcat(czBuffer, "\t</HEAD>\r\n");
    strcat(czBuffer, "\t<BODY>\r\n");
    strcat(czBuffer, "\t\t<H1>Look Basic Worked!!</H1>\r\n");
    strcat(czBuffer, "\t</BODY>\r\n");
    strcat(czBuffer, "</HTML>\r\n\r\n");
    
    return send(socketHnd, czBuffer, strlen(czBuffer) + 1, 0);
}

int __init_environment
(
    void    *reserved
)
{
#pragma unused(reserved)

/*
** The caller isn't a C++ application which would have had to link mwcrtl.lib
** in order to get real C++ initilization. This is just a do-nothing dummy to
** satisfy a missing symbol in the case where the calling C-only application
** failed to link Metrowerks' library which it can do (as long as it isn't
** C++).
*/
    return 0;
}

int __deinit_environment
(
    void    *reserved
)
{
#pragma unused(reserved)

/*
** Similarly, this function satisfies a symbol missing because the calling
** application didn't link mwcrtl.lib.
*/
    return 0;
}

--Benjamin Fjeldsted

Novell® Making IT Work As One

© 2008 Novell, Inc. All Rights Reserved.