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