TPS handler

1 post / 0 new

tsctp.c

// tsctp.c  TPS SCTP handler
  
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/sctp.h>
#include <uuid/uuid.h>
#include <openssl/md5.h>
  
#include "tsctp.h"
  
#define MAX_MESSAGE_SIZE 2048
#define SUCCESS 0
#define FAILURE -1
  
// the following are expected to come from the client user settings
#define SERVER_IP "192.168.6.25"
#define SERVER_PORT "8000"
#define FIRSTNAME "Test1"
#define LASTNAME "Avatar"
#define PASSWORD "qwe456"
  
float Version = 0.1;
int Sfd;    // file descriptor for socket
  
// This is a small wrapper for stand-alone testing
int main(int argc, char *argv[]){
    unsigned char recv_buffer[MAX_MESSAGE_SIZE];
    struct sctp_sndrcvinfo sndrcvinfo;
    int length;
    int flags;
    int stream;
    char notif[9];
     
    // attempt connect to server
    if (tscpt_connect(SERVER_IP, SERVER_PORT) == FAILURE){
        exit(EXIT_FAILURE);
    }
    while(1){
        // check for a reply
        length = sctp_recvmsg(Sfd, (void *)recv_buffer, MAX_MESSAGE_SIZE,
            (struct sockaddr *)NULL, 0, &sndrcvinfo, &flags );
             
        stream = sndrcvinfo.sinfo_stream;
        if(flags & MSG_NOTIFICATION){
            memcpy(notif, recv_buffer, 8);
            notif[8] = '\0';
            printf("Notification: %s\n", notif);
        }else{
            if(length > 0){
                printf("Received %d bytes on stream %d\n", length, stream);
                tscpt_decode(recv_buffer, length);
            }
        }
    }
    exit(EXIT_SUCCESS);
}
  
int tscpt_connect(const char* ip, const char* port){
    struct addrinfo hints;
    struct addrinfo *result, *rp;
    struct sctp_event_subscribe events;
//  struct sctp_status status;
//  int in, ret;
  
    int error;
     
    /* Obtain address(es) matching host/port */
    memset(&hints, 0, sizeof(struct addrinfo));
    hints.ai_family = AF_UNSPEC;    /* Allow IPv4 or IPv6 */
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = 0;
    hints.ai_protocol = IPPROTO_SCTP;
  
    error = getaddrinfo(ip, port, &hints, &result);
    if (error != 0) {
        printf("Error: getaddrinfo: %s\n", gai_strerror(error));
        return(FAILURE);
    }
  
    /* getaddrinfo() returns a list of address structures.
    Try each address until we successfully connect(2).
    If socket(2) (or connect(2)) fails, we (close the socket
    and) try the next address. */
  
    for (rp = result; rp != NULL; rp = rp->ai_next) {
        Sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
        if (Sfd == -1) continue;  // failed
        if (connect(Sfd, rp->ai_addr, rp->ai_addrlen) != -1)
            break;  // Success!
        close(Sfd); // try the next one
    }
  
    if (rp == NULL) { // No address succeeded
        fprintf(stderr, "Could not connect\n");
        return(FAILURE);
    } // else rp conatins the address that we have connected to
  
    freeaddrinfo(result);   // No longer needed
     
    /* Enable receipt of SCTP Snd/Rcv Data via sctp_recvmsg */
    memset( (void *)&events, 0, sizeof(events) );
    events.sctp_data_io_event = 1;
    error = setsockopt( Sfd, SOL_SCTP, SCTP_EVENTS,
                           (const void *)&events, sizeof(events) );
  
    /* Read and emit the status of the Socket (optional step) * /
    in = sizeof(status);
    ret = getsockopt( Sfd, SOL_SCTP, SCTP_STATUS,
                     (void *)&status, (socklen_t *)&in );
    printf("assoc id    = %d\n", status.sstat_assoc_id );
    printf("state    = %d\n", status.sstat_state );
    printf("instrms   = %d\n", status.sstat_instrms );
    printf("outstrms  = %d\n", status.sstat_outstrms );   */
  
    return(SUCCESS);
}
  
  
  
void tscpt_decode(unsigned char* recv_buffer, int length){
    unsigned char* ptr;
    float ver;
    int type;
    int i;
    int l;
    char text[50];
     
    printf("Received:\n");
    print_buffer(recv_buffer, length);
     
    type = 0;
    ptr = recv_buffer;
    memcpy(&type, ptr, 2);
    ptr += 2;
     
    switch(type){
        case 0x0001:
            // version is sent on connect
            // also maybe Public Key, in future
            memcpy(&ver, ptr, 4);
            if(ver != Version){
                printf("Version mismatch, Client=%f Server=%f\n", Version, ver);
            }else{
                printf("Version ok = %f\n", ver);
                try_login();
            }
            break;
        case 0x0003:
            // login result
            i = 0;
            memcpy(&i, ptr, 1);
            ptr ++;
            length = 0;
            memcpy(&l, ptr, 2);
            ptr +=2;
            memcpy(text, ptr, l);
            ptr += l;
             
            printf("%s    Code=%d\n", text, i);
             
            break;
        default:
            printf("Unknown messag type %x\n", type);
            break;
    }
}
  
void try_login(){
//  const char password[17];
    unsigned char passwdhash[32];
    unsigned char message[50];
    unsigned char* ptr;
    int location;
    int length;
    int i;
     
    location = 0;   // start at home
    // hash the pw
    md5(PASSWORD, passwdhash);
printf("PW Hash %s\n",passwdhash); 
    // Future: encode with Public Key
     
    // assemble message
    ptr = message;
    i = 0x0002;     // type login message
    memcpy(ptr, &i, 2);
    ptr += 2;
    strncpy((char *)ptr, "$1$", 3); // pw prefix
    ptr += 3;
    memcpy(ptr, passwdhash, 32); // password
    ptr += 32;
    length = strlen(FIRSTNAME) + strlen(LASTNAME) + 1;
    memcpy(ptr, &length, 1); // length of names
    ptr += 1;
    length = strlen(FIRSTNAME);
    strncpy((char *)ptr, FIRSTNAME, length); //first
    ptr += length;
    strncpy((char *)ptr, ".", 1);           //.
    ptr += 1;
    length = strlen(LASTNAME);      // last
    strncpy((char *)ptr, LASTNAME, length);
    ptr += length;
    memcpy(ptr, &location, 1);      // where
    ptr += 1;
     
    length = ptr - message;
print_buffer(message, length);
    tscpt_send(message, length);   
}
  
/*Encode str to str_enc using md5 algorithm*/
void md5(char *str, unsigned char *str_enc) {
  
    int i = 0;
    unsigned char d[16];
    MD5_CTX ctx;
  
    MD5_Init(&ctx);
    MD5_Update (&ctx, (char *) str, strlen(str));
    MD5_Final(d, &ctx);
  
    for (i = 0; i < 16; i++) {
        sprintf((char *)str_enc + (i*2), "%02X", d[i]);
    }
    str_enc[32] = 0;
}
  
  
  
int tscpt_send( unsigned char* message, int length){
    int ret;
     
    ret = sctp_sendmsg(Sfd, message, (size_t)length,
                         NULL, 0, 0, 0, 0, 0, 0 );
    if(ret == length){
        return(SUCCESS);
    }
    printf("Error: tscpt_send sent %d of %d characters.\n", ret, length);
    return(FAILURE
    );
}
     
     
void print_buffer(unsigned char *buffer, int mlen){
    int n = 0;
    int p = 0;
  
    while(n<mlen){
        printf("%02x ", buffer[n]);
        p = 0;
        n++;
        if(n%8 == 0) printf("   ");
        if(n%16 == 0){
             printf("\n");
             p = 1;
        }
    }
    if(p == 0) printf("\n");
    printf("\n");
}

 

tsctp.h

//tsctp.h
// TPS SCTP header file
  
int tscpt_connect(const char* ip, const char* port);
int tscpt_receive(unsigned char* recv_buffer);
void tscpt_decode(unsigned char* recv_buffer, int length);
void try_login();
void md5(char *str, unsigned char *str_enc);
int tscpt_send( unsigned char* message, int length);
void print_buffer(unsigned char *buffer, int mlen);

 

Makefile

# Makefile for TPS SCTP handler
  
CC = gcc
  
CFLAGS = -Wall -g
  
all:    tsctp
  
tsctp: tsctp.o
    $(CC) $(CFLAGS) -o $@ tsctp.c -L/usr/local/lib -lsctp -lssl -luuid
  
clean:
    rm -f tsctp  *.o

tags: