/* Copyright 2016 Giovanni Franza - HB9EIK 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 3 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, see . 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 3 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, see . */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define BUFFERSIZE 512*24 typedef struct _payload { int port; char *portc; char *hostname; pthread_cond_t *con; pthread_mutex_t *mut; pthread_cond_t *con_a; pthread_mutex_t *mut_a; char *buf_a; int *lung_a; char *buf_b; int *lung_b; char *buf; int *lung; int *outfile; key_t shm_key; long *freq; short *att_lowpass_rate; char *passphrase; } payload, *payloadp; #ifndef XtNumber #define XtNumber(x) sizeof(x)/sizeof(x[0]) #endif static char *requestHeader[] = { "GET ", "Host: ", "Sec-WebSocket-Version: ", "Sec-WebSocket-Protocol: ", "Sec-WebSocket-Key: ", "Connection: keep-alive, Upgrade", "Upgrade: websocket" }; static char *keyHeader="Sec-WebSocket-Key: "; void *wsManage( void *payload ) { int pfd; struct sockaddr_in saddr; int chfd; FILE *bchfd; // struct hostent *host; struct sockaddr_in cliaddr; unsigned int clilun; char mybuf[1024]; char *hp, *pp; int j, n, k; payloadp payl = (payloadp)payload; int status; char keys[100]; static int isFirst=1; // socket: create the socket pfd = socket( AF_INET, SOCK_STREAM, 0 ); if( pfd == -1 ) { fprintf( stderr, "Socket open error\n" ); exit( 7 ); } int opt = 1; setsockopt( pfd, SOL_SOCKET, SO_REUSEADDR, (const void *)&opt , sizeof(int) ); memset( &saddr, 0, sizeof(saddr) ); saddr.sin_family = AF_INET; saddr.sin_addr.s_addr = htonl( INADDR_ANY ); saddr.sin_port = htons( (unsigned short)payl->port ); if( bind( pfd, (struct sockaddr *) &saddr, sizeof( saddr ) ) == -1 ) { fprintf( stderr, "Binding Error\n" ); exit( 8 ); } if( listen( pfd, 1 ) == -1 ) { fprintf( stderr, "Listening Error\n" ); exit( 10 ); } fprintf( stderr, "Listening on port %d\n", payl->port ); clilun = sizeof( cliaddr ); for( ;; ) { // wait for a connection request chfd = accept( pfd, (struct sockaddr *) &cliaddr, &clilun ); if( chfd == -1 ) { fprintf( stderr, "Accept-ing Error\n" ); exit( 11 ); } bchfd=fdopen( chfd, "r+" ); if( !bchfd ) { fprintf( stderr, "Reopen-ing Error\n" ); exit( 12 ); } hp = inet_ntoa(cliaddr.sin_addr); if( !hp ) { fprintf( stderr, "inet_ntoa Error\n" ); exit( 14 ); } else { fprintf( stderr, "Connected by %s\n", hp ); } for( status=0,pp=NULL;;pp=NULL ) { memset( mybuf, 0, sizeof( mybuf ) ); if( pp==NULL ) { pp = fgets( mybuf, sizeof(mybuf), bchfd ); } if( !pp && errno ) { fprintf( stderr, "TCP read Error\n" ); exit( 15 ); } if( !pp ) { fprintf( stderr, "TCP read 0 bytes \n" ); continue; } if( mybuf[strlen(mybuf)-1]=='\n' ) { fprintf( stderr, "Received %d bytes %s", (int)strlen( mybuf ), mybuf ); for( j=0; j= XtNumber(requestHeader)+1 ) { break; } } n=fprintf( bchfd, "HTTP/1.1 101 Switching Protocols\r\n" ); fprintf( stderr, "sent %d bytes error %d\n", n, errno ); fprintf( stderr, "HTTP/1.1 101 Switching Protocols\r\n" ); n=fprintf( bchfd, "Upgrade: websocket\r\n" ); fprintf( stderr, "sent %d bytes error %d\n", n, errno ); fprintf( stderr, "Upgrade: websocket\r\n" ); n=fprintf( bchfd, "Connection: Upgrade\r\n" ); fprintf( stderr, "sent %d bytes error %d\n", n, errno ); fprintf( stderr, "Connection: Upgrade\r\n" ); // strcpy( keys, (const char *)"dGhlIHNhbXBsZSBub25jZQ==" ); sprintf( mybuf, "%s%s", keys, "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" ); memset( keys, 0, sizeof( keys ) ); SHA1( (unsigned const char *)mybuf, strlen(mybuf), (unsigned char *)keys ); pp=g_base64_encode( (const guchar *)keys, strlen(keys) ); memset( keys, 0, sizeof( keys ) ); strcpy( keys, (const char *)pp ); g_free( pp ); n=fprintf( bchfd, "Sec-WebSocket-Accept: %s\r\n", keys ); fprintf( stderr, "Sec-WebSocket-Accept: %s\r\n", keys ); n=fprintf( bchfd, "Sec-WebSocket-Protocol: chat\r\n\r\n" ); fprintf( stderr, "Sec-WebSocket-Protocol: chat\r\n\r\n" ); fprintf( stderr, "sent %d bytes error %d\n", n, errno ); fflush( bchfd ); // fprintf( stderr, "sent %s %d bytes error %d\n", keys, n, errno ); // fflush( stderr ); *payl->outfile=chfd; pthread_cond_signal( payl->con ); for( isFirst=1;; ) { fflush( stderr ); memset( mybuf, 0, sizeof( mybuf ) ); n = read( chfd, mybuf, sizeof(mybuf) ); if( n<1 ) { fprintf( stderr, "TCP read Error\n" ); break; } if( !n ) { fprintf( stderr, "TCP read 0 bytes \n" ); continue; } fprintf( stderr, "Received %d bytes : ", n); for( j=0; jpassphrase ) ) { fprintf( stderr, "required >%s< differ from >%s<\n", payl->passphrase, mybuf+6 ); *payl->outfile=0; pp=mybuf; status=0; break; } } else { strcpy( payl->buf, mybuf+6 ); pthread_cond_signal( payl->con_a ); fprintf( stderr, "%s\n", mybuf+6 ); } } else { fprintf( stderr, "wrong message length: is %d instead of %d\n", j, n-6 ); *payl->outfile=0; pp=mybuf; status=0; break; } } else { fprintf( stderr, "wrong message type: %x\n", mybuf[0] ); *payl->outfile=0; pp=mybuf; status=0; break; } } n = close( chfd ); if( n == -1 ) { fprintf( stderr, "TCP close Error\n" ); exit( 17 ); } fprintf( stderr, "TCP closed\n" ); } return( NULL ); } void *tcpManage( void *pay ) { int sfd; struct sockaddr_in saddr; struct hostent *server; char buf[1024]; int j, n; int closure = 0; int connected = 0; payloadp payl=(payloadp)pay; int port = payl->port; char *hostname = payl->hostname; fprintf( stderr, "Parameters for TCP received\n" ); for( ;; ) { // socket: create the socket sfd = socket( AF_INET, SOCK_STREAM, 0 ); if( sfd == -1 ) { fprintf( stderr, "Socket error\n" ); exit( 1 ); } fprintf( stderr, "Socket for TCP created\n" ); server = gethostbyname( hostname ); if (server == NULL) { fprintf( stderr, "ERROR, no such host as %s\n", hostname ); exit( 2 ); } memset( &saddr, 0, sizeof(saddr) ); saddr.sin_family = AF_INET; saddr.sin_addr.s_addr = htonl( INADDR_ANY ); memmove( (char *)&saddr.sin_addr.s_addr, (char *)server->h_addr, server->h_length); saddr.sin_port = htons( (unsigned short)port ); /* connect: create a connection with the server */ if( connect( sfd, (struct sockaddr *)&saddr, sizeof( saddr ) ) == -1 ) { fprintf( stderr, "Connect Error\n" ); sleep( 5 ); continue; } connected = 1; fprintf( stderr, "Connected\n" ); for( ;; ) { pthread_cond_wait(payl->con, payl->mut); fprintf( stderr, "FIFO message received: <%s>\n", payl->buf ); n = write( sfd, payl->buf, strlen( payl->buf ) ); if( n == -1 ) { fprintf( stderr, "TCP write Error\n" ); exit( 5 ); } fprintf( stderr, "TCP write %d bytes\n", n ); for( closure = 0;; ) { memset( buf, 0, sizeof( buf ) ); for( j=0, n=0; ; j++ ) { n = read( sfd, buf+j, 1 ); if( n == 0 ) { fprintf( stderr, "TCP disconnected\n" ); connected = 0; break; } if( n == -1 ) { fprintf( stderr, "TCP read Error\n" ); break; } if( buf[j]=='\n' ) { fprintf( stderr, "TCP closure received\n" ); closure = 1; break; } if( buf[j]==';' ) { fprintf( stderr, "TCP message received: %s\n", buf ); break; } } if( connected == 0 ) { fprintf( stderr, "TCP disconnected 1\n" ); break; } if( closure == 1 ) { fprintf( stderr, "TCP closure exited 1\n" ); break; } } if( connected == 0 ) { fprintf( stderr, "TCP disconnected 1\n" ); break; } } } close( sfd ); return NULL; } void *udpReceive( void *pay ) { int sfd; unsigned int clilen; struct sockaddr_in saddr; struct sockaddr_in cliaddr; int a = 0; int j; int res; pthread_cond_t *con; char *buff; int *lung; static char recvBuffer[1034]; static long counter=0; static long tempCounter=0; static long oldTempCounter=0; struct timeval start, stop; payloadp payl=(payloadp)pay; int port = payl->port; int shm_id; char* shmaddr; char* shmaddr1; char* shmaddr2; char* shm_cond; char* shm_cond1; char* shm_cond2; pthread_condattr_t cond_attr1; pthread_condattr_t cond_attr2; fprintf( stderr, "Parameters for UDP received\n" ); // Allocate and attach a shared memory segment shm_id = shmget ( payl->shm_key, (BUFFERSIZE+sizeof( pthread_cond_t )+6)*2, IPC_CREAT | S_IRUSR | S_IWUSR | 0666 ); if( shm_id==-1 ) { fprintf( stderr, "erro allocating shmem %d %s\n", errno, strerror(errno) );fflush( stderr ); } shm_cond1 = (char*) shmat (shm_id, 0, 0); shmaddr1 = shm_cond1 + sizeof( pthread_cond_t ); shm_cond2 = shmaddr1 + BUFFERSIZE + 6; shmaddr2 = shm_cond2 + sizeof( pthread_cond_t ); fprintf( stderr, "Shared %x memory attached at address %p\n", shm_id, shm_cond1 ); // allocate and attach a shared memory condidion pthread_condattr_init( &cond_attr1 ); pthread_condattr_init( &cond_attr2 ); pthread_condattr_setpshared( &cond_attr1, PTHREAD_PROCESS_SHARED ); pthread_condattr_setpshared( &cond_attr2, PTHREAD_PROCESS_SHARED ); pthread_cond_init( (pthread_cond_t *)shm_cond1, &cond_attr1 ); pthread_cond_init( (pthread_cond_t *)shm_cond2, &cond_attr2 ); pthread_condattr_destroy( &cond_attr1 ); pthread_condattr_destroy( &cond_attr2 ); // socket: create the socket sfd = socket( AF_INET, SOCK_DGRAM, 0 ); if( sfd == -1 ) { fprintf( stderr, "socket error\n" ); exit( 8 ); } fprintf( stderr, "Socket for udp created\n" ); // reuse socket int opt = 1; setsockopt( sfd, SOL_SOCKET, SO_REUSEADDR, (const void *)&opt, sizeof( int ) ); // set server address memset( (char *)&saddr, 0, sizeof( saddr ) ); saddr.sin_family = AF_INET; saddr.sin_addr.s_addr = htonl(INADDR_ANY); saddr.sin_port = htons( (unsigned short)port ); // associate socket to a port if( bind( sfd, (struct sockaddr *)&saddr, sizeof( saddr ) ) == -1 ) { fprintf( stderr, "binding Error\n" ); exit( 9 ); } fprintf( stderr, "Socket for udp binded\n" ); lung=payl->lung_a; gettimeofday( &start, NULL ); for( ;; ) { // receive UDP datagrams a=1-a; if( a==1 ) { con = payl->con; buff=payl->buf_a; shm_cond=shm_cond1; shmaddr=shmaddr1; } else { con=NULL; buff=NULL; shm_cond=shm_cond2; shmaddr=shmaddr2; } if( buff ) { memset( buff, 0, BUFFERSIZE ); } for( j=0, *lung=0; jfreq, recvBuffer+4, 4 ); memcpy( (char *)payl->att_lowpass_rate, recvBuffer+8, 2 ); memcpy( shmaddr, recvBuffer+4, 6 ); memcpy( shmaddr+6+j, recvBuffer+10, res-10 ); tempCounter = ntohl ( *(long *)recvBuffer ); counter++; if( counter!=tempCounter ) { gettimeofday( &stop, NULL ); fprintf( stderr, "Counter (%ld) differs from received counter (%ld) diff %ld %%=%f time=%f\n", counter, tempCounter, tempCounter-counter, (tempCounter-counter)*100.0/(tempCounter-oldTempCounter), (stop.tv_sec-start.tv_sec)+0.000001*(stop.tv_usec-start.tv_usec) ); counter=tempCounter; oldTempCounter=tempCounter; gettimeofday( &start, NULL ); } *lung += res-10; if ( res == -1 ) { fprintf( stderr,"Recvfrom Error\n" ); exit( 10 ); } } pthread_cond_broadcast( (pthread_cond_t *)shm_cond ); if( con ) { pthread_cond_signal( con ); } } return NULL; } void *FFTSend( void *pay ) { double *co = NULL; double *si = NULL; double *fftr = NULL; double *ffti = NULL; double *coeff = NULL; unsigned char *fftout = NULL; int N; double co1, si1; double pi=3.141592653589793238462643383279502884197169399375105820974944592; double fftdr, fftdi; int j, k; int m, p, md, ng, ig, i, ind, i1, i2, jd, kp; long val; char buf[1050]; struct timeval start, stop; payloadp payl=(payloadp)pay; p=10; N=1<con_a, payl->mut_a); fprintf( stderr, "FFT unlocked\n" ); fflush( stderr ); for( ;; ) { pthread_cond_wait(payl->con, payl->mut); // Time measurement gettimeofday( &start, NULL ); // Read input data for( j=0; jbuf)[2*j]*coeff[j]; ffti[j]=((float *)payl->buf)[2*j+1]*coeff[j]; } m = N/2; p = 10; // FFT Compute for( j=0,ng=1,md=m; j>= 1; ng <<= 1; } // Coefficients reordering for( j=0; j>= 1; kp >>= 1; } if( k>j ) { fftdr = fftr[j]; fftdi = ffti[j]; fftr[j] = fftr[k]; ffti[j] = ffti[k]; fftr[k] = fftdr; ffti[k] = fftdi; } } // Absolute value for( j=0; jfreq, 4 ); memcpy( buf+8, payl->att_lowpass_rate, 2 ); memcpy( buf+10, fftout+512+64, 512-64 ); memcpy( buf+512+10-64, fftout, 512-64 ); if( *payl->outfile ) { j=write( *payl->outfile, buf, 1024+10-128 ); if( j<0 ) { fprintf( stderr, "sent error %d %s\n", errno, strerror(errno) );fflush( stderr ); } } usleep( 100000 ); } return NULL; } int main( int ac, char *av[], char **ev ) { int res; char *host, *port, *ports; int portn, portsn; int outfile; char cmdbuffer[1024]; key_t shm_key = 6166530; long freq; short att_lowpass_rate; pthread_t pthread0; pthread_attr_t attr0; struct sched_param prio0; payload payl0; pthread_t pthread1; pthread_attr_t attr1; payload payl1; pthread_t pthread2; pthread_attr_t attr2; struct sched_param prio2; payload payl2; pthread_t pthread3; pthread_attr_t attr3; struct sched_param prio3; payload payl3; char *passphrase; // cond variables for FFT buffer unlock pthread_cond_t con_a = PTHREAD_COND_INITIALIZER; pthread_mutex_t mut_a = PTHREAD_MUTEX_INITIALIZER; // cond varables for WebSocket unlock FFT pthread_cond_t con_b = PTHREAD_COND_INITIALIZER; pthread_mutex_t mut_b = PTHREAD_MUTEX_INITIALIZER; // cond variables for commands received; pthread_cond_t con_c = PTHREAD_COND_INITIALIZER; pthread_mutex_t mut_c = PTHREAD_MUTEX_INITIALIZER; static char buf_a[BUFFERSIZE]; int lung_a; fprintf( stderr, "Operations init elad-server version 1.0\n" ); // Read host from Argument, if not localhost if( ac<2 ) { host = "localhost"; } else { host = av[1]; } fprintf( stderr, "host: %s\n", host ); // Read portnumber from Argument, if not 6666 if( ac<3 ) { port = "6666"; } else { port = av[2]; } portn=atoi( port ); fprintf( stderr, "portnumber: %s (%d)\n", port, portn ); // Read shm_key from Argument, if not 6166530 if( ac<4 ) { shm_key = 6166530; } else { shm_key = atol( av[3] ); } if( ac<5 ) { passphrase="accattatevillo"; } else { passphrase = av[4]; } // Read portnumber from Argument, if not 6666 if( ac<6 ) { ports = port; } else { ports = av[5]; } portsn=atoi( ports ); fprintf( stderr, "receive portnumber: %s (%d)\n", ports, portsn ); // create thread that reads data using udp memset( &payl0, 0, sizeof( payl0 ) ); payl0.port=portsn; payl0.portc=ports; payl0.hostname=host; payl0.con=&con_a; payl0.buf_a=buf_a; payl0.lung_a=&lung_a; payl0.shm_key=shm_key; payl0.freq=&freq; payl0.att_lowpass_rate=&att_lowpass_rate; prio0.sched_priority=99; res=pthread_attr_init( &attr0 ); if( res ) { fprintf( stderr, "pthread_attr_init attr0 failed\n" ); } res=pthread_create( &pthread0, &attr0, udpReceive, &payl0 ); if( res ) { fprintf( stderr, "pthread_create pthread 0 failed\n" ); } res=pthread_setschedparam( pthread0, SCHED_RR, &prio0 ); if( res ) { fprintf( stderr, "pthread_setschedparam pthread 0 failed\n" ); } fprintf( stderr, "udp Receive thread created\n" ); // create thread that sends commands using tcp memset( &payl1, 0, sizeof( payl1 ) ); payl1.con=&con_c; payl1.mut=&mut_c; payl1.buf=cmdbuffer; payl1.port=portsn; payl1.portc=ports; payl1.hostname=host; res=pthread_attr_init( &attr1 ); if( res ) { fprintf( stderr, "pthread_attr_init attr1 failed\n" ); } res=pthread_create( &pthread1, &attr1, tcpManage, (void *)&payl1 ); if( res ) { fprintf( stderr, "pthread_create pthread 1 failed\n" ); } fprintf( stderr, "Tcp manage thread created\n" ); // create thread that sends FFT memset( &payl2, 0, sizeof( payl2 ) ); payl2.port=portn; payl2.portc=port; payl2.hostname=host; payl2.con=&con_a; payl2.mut=&mut_a; payl2.con_a=&con_b; payl2.mut_a=&mut_b; payl2.outfile=&outfile; payl2.buf=buf_a; payl2.lung=&lung_a; payl2.freq=&freq; payl2.att_lowpass_rate=&att_lowpass_rate; prio2.sched_priority=80; res=pthread_attr_init( &attr2 ); if( res ) { fprintf( stderr, "pthread_attr_init attr2 failed\n" ); } res=pthread_create( &pthread2, &attr2, FFTSend, (void *)&payl2 ); if( res ) { fprintf( stderr, "pthread_create pthread 2 failed\n" ); } res=pthread_setschedparam( pthread2, SCHED_RR, &prio2 ); if( res ) { fprintf( stderr, "pthread_setschedparam pthread 2 failed\n" ); } fprintf( stderr, "shared Send FFT thread created\n" ); // create thread that manages websocket creation memset( &payl3, 0, sizeof( payl3 ) ); payl3.port=portn; payl3.con=&con_b; payl3.mut=&mut_b; payl3.con_a=&con_c; payl3.mut_a=&mut_c; payl3.outfile=&outfile; payl3.buf=cmdbuffer; payl3.passphrase=passphrase; prio3.sched_priority=50; res=pthread_attr_init( &attr3 ); if( res ) { fprintf( stderr, "pthread_attr_init attr3 failed\n" ); } res=pthread_create( &pthread3, &attr3, wsManage, (void *)&payl3 ); if( res ) { fprintf( stderr, "pthread_create pthread 3 failed\n" ); } res=pthread_setschedparam( pthread3, SCHED_RR, &prio3 ); if( res ) { fprintf( stderr, "pthread_setschedparam pthread 3 failed\n" ); } fprintf( stderr, "websocket Processing thread a created\n" ); // main loop for( ;; ) { sleep( 10 ); } // dirty exit fprintf( stderr, "Operations end\n" ); return 0; }