iPDC-suite/iPDC/connections.c

624 lines
17 KiB
C
Executable File

/* -----------------------------------------------------------------------------
* connections.c
*
* iPDC - Phasor Data Concentrator
*
* Copyright (C) 2011-2012 Nitesh Pandit
* Copyright (C) 2011-2012 Kedar V. Khandeparkar
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Authors:
* Nitesh Pandit <panditnitesh@gmail.com>
* Kedar V. Khandeparkar <kedar.khandeparkar@gmail.com>
*
* ----------------------------------------------------------------------------- */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>
#include <pthread.h>
#include <gtk/gtk.h>
#include "ipdcGui.h"
#include "connections.h"
#include "parser.h"
#include "global.h"
#include "new_pmu_or_pdc.h"
#include "align_sort.h"
/* ---------------------------------------------------------------------*/
/* Functions defined in connections.c */
/* ---------------------------------------------------------------------*/
/* 1. void setup() */
/* 2. void* UL_udp() */
/* 3. void* UL_tcp() */
/* 4. void* UL_tcp_connection() */
/* 5. void PMU_process_UDP() */
/* 6. void PMU_process_TCP() */
/* 7. void sigchld_handler() */
/* -------------------------------------------------------------------- */
/* ---------------------------------------------------------------- */
/* global variables */
/* ---------------------------------------------------------------- */
int yes = 1; /* argument to setsockopt */
char display_buf[200];
/* ---------------------------------------------------------------------------- */
/* FUNCTION setup(): */
/* It creates two threads by calling tcp() and udp() in each thread. */
/* ---------------------------------------------------------------------------- */
void setup(){
/* ---------------------------------------------------------------- */
/* Initialize Global Mutex Variables from global.h */
/* ---------------------------------------------------------------- */
int err;
/* Create UDP socket and bind to port */
if ((UL_UDP_sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
perror("socket");
exit(1);
} else {
printf("UDP Socket:Sucessfully created\n");
}
if (setsockopt(UL_UDP_sockfd,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) {
perror("setsockopt");
exit(1);
}
UDP_my_addr.sin_family = AF_INET; // host byte order
UDP_my_addr.sin_port = htons(UDPPORT); // short, network byte order
UDP_my_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP
memset(&(UDP_my_addr.sin_zero),'\0', 8); // zero the rest of the struct
if (bind(UL_UDP_sockfd, (struct sockaddr *)&UDP_my_addr,
sizeof(struct sockaddr)) == -1) {
perror("bind");
exit(1);
} else {
printf("UDP Socket Bind :Sucessfull\n");
}
/* Created socket and bound to port */
/* Create TCP socket and bind and listen on port */
if ((UL_TCP_sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(1);
} else {
printf("TCP Socket:Sucessfully created\n");
}
if (setsockopt(UL_TCP_sockfd,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) {
perror("setsockopt");
exit(1);
}
TCP_my_addr.sin_family = AF_INET; // host byte order
TCP_my_addr.sin_port = htons(TCPPORT); // short, network byte order
TCP_my_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP
memset(&(TCP_my_addr.sin_zero), '\0', 8); // zero the rest of the struct
if (bind(UL_TCP_sockfd, (struct sockaddr *)&TCP_my_addr, sizeof(struct sockaddr))
== -1) {
perror("bind");
exit(1);
} else {
printf("TCP Socket Bind :Sucessfull\n");
}
if (listen(UL_TCP_sockfd, BACKLOG) == -1) {
perror("listen");
exit(1);
} else {
printf("TCP Listen :Sucessfull\n");
}
sa.sa_handler = sigchld_handler; // reap all dead processes
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
if (sigaction(SIGCHLD, &sa, NULL) == -1) {
perror("sigaction");
exit(1);
}
/* TCP created socket and is litening for connections */
printf("\nUDP Listening on port %d for command frames from Upper PDC\n",UDPPORT);
printf("\nTCP Listening on port %d for command frames from Upper PDC\n",TCPPORT);
printf("\nPort %d for Sending the data frames for archival from iPDC\n",DBPORT);
UL_TCP_sin_size = sizeof(struct sockaddr_in);
UL_UDP_addr_len = sizeof(struct sockaddr);
DB_addr_len = sizeof(struct sockaddr);
/* Threads are created for UDP and TCP to listen on port 6001 and 6000 respectively in default attr mode*/
if((err = pthread_create(&UDP_thread,NULL,UL_udp,NULL))) {
perror(strerror(err));
exit(1);
}
if((err = pthread_create(&TCP_thread,NULL,UL_tcp,NULL))) {
perror(strerror(err));
exit(1);
}
}
/* ---------------------------------------------------------------------------- */
/* FUNCTION UL_udp(): */
/* Handles upper layer PDC command frames */
/* ---------------------------------------------------------------------------- */
void* UL_udp(){
/* UDP data Received */
while(1) {
memset(UL_udp_command,'\0',19);
memset(display_buf,'\0',200);
if ((numbytes = recvfrom(UL_UDP_sockfd,UL_udp_command, 18, 0,(struct sockaddr *)&UL_UDP_addr, (socklen_t *)&UL_UDP_addr_len)) == -1) {
// Main if
perror("recvfrom");
exit(1);
} else { /* New datagram has been received */
int pdc_flag = 0;
pthread_mutex_lock(&mutex_Upper_Layer_Details);
struct Upper_Layer_Details *temp_pdc = ULfirst;
if(ULfirst == NULL) {
pdc_flag = 0;
} else {
while(temp_pdc != NULL ) {
if((!strcmp(temp_pdc->ip,inet_ntoa(UL_UDP_addr.sin_addr))) &&
(!strncasecmp(temp_pdc->protocol,"UDP",3)) && (temp_pdc->port == UDPPORT)) {
pdc_flag = 1;
break;
} else {
temp_pdc = temp_pdc->next;
}
}
}
if(pdc_flag){
unsigned char c = UL_udp_command[1];
c <<= 1;
c >>= 5;
temp_pdc->sockfd = UL_UDP_sockfd;
if(c == 0x04) { /* Check if it is a command frame from Upper PDC */
printf("\nCommand frame Received at iPDC.\n");
c = UL_udp_command[15];
if((c & 0x05) == 0x05){ //Send CFg frame to PDC
printf("\nCommand frame for CFG Received\n");
while(root_pmuid != NULL); // Wait till all the status change has been cleared
printf("sockfd = %d,ipaddress = %s\n",temp_pdc->sockfd,inet_ntoa(temp_pdc->pdc_addr.sin_addr));
if(temp_pdc->address_set == 0) {
memcpy(&temp_pdc->pdc_addr,&UL_UDP_addr,sizeof(UL_UDP_addr));
}
numbytes = create_cfgframe();
if ((numbytes = sendto (temp_pdc->sockfd,cfgframe, numbytes, 0,
(struct sockaddr *)&temp_pdc->pdc_addr,sizeof(temp_pdc->pdc_addr)) == -1)) {
perror("sendto");
} else {
printf("Sent iPDC Configuration Frame\n");
}
free(cfgframe);
temp_pdc->UL_upper_pdc_cfgsent = 1;
temp_pdc->config_change = 0;
} else if((c & 0x02) == 0x02) { // if data frame
if(temp_pdc->UL_upper_pdc_cfgsent == 1) { // Only if cfg is sent send the data
temp_pdc->UL_data_transmission_off = 0;
} else {
printf("Data cannot be sent as CMD for CFG not received\n");
}
} else if ((c & 0x01) == 0x01){
temp_pdc->UL_data_transmission_off = 1;
}
} else { /* If it is a frame other than command frame */
printf("Not a command frame\n");
}
} else { /* If the command frame is not from authentic PDC*/
printf("Command frame from un-authentic PDC\n");
}
} // Main if ends
pthread_mutex_unlock(&mutex_Upper_Layer_Details);
} // while ends
}
/* ---------------------------------------------------------------------------- */
/* FUNCTION UL_tcp(): */
/* It Handles Upper Layer PDC connections. */
/* ---------------------------------------------------------------------------- */
void* UL_tcp() {
int err;
// A new thread is created for each TCP connection in 'detached' mode. Thus allowing any number of threads to be created.
pthread_attr_t attr;
pthread_attr_init(&attr);
if((err = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED))) { // In the detached state, the thread resources are
// immediately freed when it terminates, but
perror(strerror(err)); // pthread_join(3) cannot be used to synchronize
exit(1); // on the thread termination.
}
if((err = pthread_attr_setschedpolicy(&attr,SCHED_FIFO))) { // Shed policy = SCHED_FIFO (realtime, first-in first-out)
perror(strerror(err));
exit(1);
}
int sin_size,new_fd,pdc_flag = 0;
while (1) {
sin_size = sizeof(struct sockaddr_in);
if (((new_fd = accept(UL_TCP_sockfd, (struct sockaddr *)&UL_TCP_addr,
(socklen_t *)&sin_size)) == -1)) { // main if starts
perror("accept");
} else { /* New TCP connection has been received*/
pthread_mutex_lock(&mutex_Upper_Layer_Details);
struct Upper_Layer_Details *temp_pdc = ULfirst;
if(ULfirst == NULL) {
pdc_flag = 0;
} else {
while(temp_pdc != NULL ) {
if((!strcmp(temp_pdc->ip,inet_ntoa(UL_TCP_addr.sin_addr))) &&
(!strncasecmp(temp_pdc->protocol,"TCP",3)) && (temp_pdc->port == TCPPORT)) {
pdc_flag = 1;
break;
} else {
temp_pdc = temp_pdc->next;
}
}
}
if(pdc_flag) {
temp_pdc->sockfd = new_fd;
pthread_t t;
/* PDC is authentic. Send the command frame for cfg frame */
printf("server: got connection from %s\n",
inet_ntoa(temp_pdc->pdc_addr.sin_addr));
/* Creates a new thread for each TCP connection. */
if((err = pthread_create(&t,&attr,UL_tcp_connection,(void *)temp_pdc))) {
perror(strerror(err));
exit(1);
}
} else { /* If PMU ip is not in the ipdcINFO.bin */
printf("Request from %s TCP which is un-authentic\n",
inet_ntoa(UL_TCP_addr.sin_addr));
}
pthread_mutex_unlock(&mutex_Upper_Layer_Details);
} // main if ends
} // While ends
pthread_attr_destroy(&attr);
}
/* ---------------------------------------------------------------------------- */
/* FUNCTION UL_tcp_connection(): */
/* It handles command frames from upper layer PDC on TCP . */
/* ---------------------------------------------------------------------------- */
void* UL_tcp_connection(void * temp_pdc) {
struct Upper_Layer_Details *udetails = (struct Upper_Layer_Details *) temp_pdc;
int UL_new_fd = udetails->sockfd;
udetails->thread_id = pthread_self();
while(1) {
memset(UL_tcp_command,19,0);
int bytes_read = recv(UL_new_fd,UL_tcp_command,18,0);
if(bytes_read == -1) {
perror("recv");
udetails->tcpup = 0;
pthread_exit(NULL);
} else if(bytes_read == 0){
printf("The Client connection exit.\n");
udetails->tcpup = 0;
pthread_exit(NULL);
} else {
pthread_mutex_lock(&mutex_Upper_Layer_Details);
unsigned char c = UL_tcp_command[1];
c <<= 1;
c >>= 5;
if(c == 0x04) { /* Check if it is a command frame from Upper PDC*/
printf("Command frame Received\n"); // Need to further check if the command is for cfg or data
c = UL_tcp_command[15];
if((c & 0x05) == 0x05){ //Send CFg frame to PDC
while(root_pmuid != NULL); // Wait till the staus chage list becomes empty
numbytes = create_cfgframe();
udetails->tcpup = 1;
if (send(UL_new_fd,cfgframe,numbytes, 0)== -1)
perror("send");
free(cfgframe);
udetails->UL_upper_pdc_cfgsent = 1;
udetails->config_change = 0;
} else if((c & 0x02) == 0x02) {
if(udetails->UL_upper_pdc_cfgsent == 1) { // Only if cfg is sent send the data
udetails->UL_data_transmission_off = 0;
} else {
printf("Data cannot be sent as CMD for CFG not received\n");
}
} else if ((c & 0x01) == 0x01){ // Put the data transmission off
udetails->UL_data_transmission_off = 1;
}
} else { /* If it is a frame other than command frame */
printf("Not a command frame\n");
}
pthread_mutex_unlock(&mutex_Upper_Layer_Details);
}
} // while
close(UL_new_fd);
pthread_exit(NULL);
}
/* ---------------------------------------------------------------------------- */
/* FUNCTION PMU_process_UDP(): */
/* This function processes the frames as per their type( data, config). */
/* The received frames are from Lower Layer PMU/PDC on UDP. */
/* ---------------------------------------------------------------------------- */
void PMU_process_UDP(unsigned char *udp_buffer,struct sockaddr_in PMU_addr,int sockfd){
int stat_status;
unsigned int id;
unsigned char id_char[2];
id_char[0] = udp_buffer[4];
id_char[1] = udp_buffer[5];
id = to_intconvertor(id_char);
unsigned char c = udp_buffer[1];
c <<= 1;
c >>= 5;
if(c == 0x00){ /* If data frame */
stat_status = dataparser(udp_buffer);
/* Change in cfg frame is handled */
if((stat_status == 10)||(stat_status == 14)) {
unsigned char *cmdframe = malloc(19);
cmdframe[18] = '\0';
create_command_frame(1,id,(char *)cmdframe);
if (sendto(sockfd,cmdframe,18, 0,
(struct sockaddr *)&PMU_addr,sizeof(PMU_addr)) == -1)
perror("sendto");
free(cmdframe);
} else if (stat_status == 15) { /* Data Invalid */
printf("Data Invalid\n");
}
} else if(c == 0x03) { /* If configuration frame */
printf("\nConfiguration frame received.\n");
cfgparser(udp_buffer);
unsigned char *cmdframe = malloc(19);
cmdframe[18] = '\0';
create_command_frame(2,id,(char *)cmdframe);
printf("\nReturn from create_command_frame\n");
/* Command frame sent to send the data frames */
if (sendto(sockfd,cmdframe, 18, 0,
(struct sockaddr *)&PMU_addr,sizeof(PMU_addr)) == -1)
perror("sendto");
free(cmdframe);
} else {
printf("Erroneous frame\n");
}
fflush(stdout);
}
/* ---------------------------------------------------------------------------- */
/* FUNCTION PMU_process_TCP(): */
/* This function processes the frames as per their type( data, config). */
/* The received frames are from Lower Layer PMU/PDC on TCP. */
/* ---------------------------------------------------------------------------- */
void PMU_process_TCP(unsigned char tcp_buffer[],int sockfd) {
int stat_status;
unsigned int id;
unsigned char id_char[2];
id_char[0] = tcp_buffer[4];
id_char[1] = tcp_buffer[5];
id = to_intconvertor(id_char);
unsigned char c = tcp_buffer[1];
c <<= 1;
c >>= 5;
if(c == 0x00){ /* If data frame */
stat_status = dataparser(tcp_buffer);
/* Handle the Stat word */
if((stat_status == 10)||(stat_status == 14)) {
unsigned char *cmdframe = malloc(19);
cmdframe[18] = '\0';
create_command_frame(1,id,(char *)cmdframe);
if (send(sockfd,cmdframe,18, 0)== -1)
perror("send");
free(cmdframe);
} else if (stat_status == 15) { /* Data Invalid */
printf("Data Invalid\n");
}
} else if(c == 0x03) { /* If configuration frame */
printf("\nConfiguration frame received.\n");
cfgparser(tcp_buffer);
unsigned char *cmdframe = malloc(19);
cmdframe[18] = '\0';
create_command_frame(2,id,(char *)cmdframe);
printf("Return from create_command_frame().\n");
/* Command frame sent to send the data frames */
if (send(sockfd,cmdframe,18, 0)== -1)
perror("send");
free(cmdframe);
} else {
printf("\nErroneous frame\n");
}
fflush(stdout);
}
/* ---------------------------------------------------------------------------- */
/* FUNCTION sigchld_handler(): */
/* ---------------------------------------------------------------------------- */
void sigchld_handler(int s) {
while(wait(NULL) > 0);
}
/**************************************** End of File *******************************************************/