📄 server.c
字号:
/*************************************************************************** server.c - A channel server ------------------- begin : 2002 authors : Linus Gasser emails : linus.gasser@epfl.ch ***************************************************************************//*************************************************************************** Changes ------- date - name - description 02-12-13 - ineiti - begin, ripped of from PLATON_2002 03-05-19 - ineiti - added support for multiple ports 03-11-27 - phil - added group id for mimo **************************************************************************//*************************************************************************** * * * 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. * * * ***************************************************************************//** * A very simple server that allows multiple clients to connect and to * communicate through a fade-only channel. */#include <pthread.h>#include <sys/socket.h>#include <time.h>#include <netdb.h>#include <stdlib.h>#include <math.h>#include <sys/stat.h>#include <sys/types.h>#include "system.h"#include "channel_net.h"#include "antenna.h"#include "debugging.h"#include "server.h"#include "fading.h"#include "fading_multi.h"#include "fading_multi_complex.h"#include "flat.h"#include "command.h"#define DBG_LVL 0pthread_mutex_t mutex_rcv, mutex_send;pthread_cond_t cond_rcv, cond_send;struct client_params client[MAX_CLIENTS];double rx_gain[MAX_CLIENTS], tx_gain[MAX_CLIENTS];char tx_signal_buffer[MAX_CLIENTS][BLOCK_BUFFER+1][DAQ_DMA_BLOCK_SIZE_BYTES]__attribute__ ((aligned(8)));char rx_signal_buffer[MAX_CLIENTS][BLOCK_BUFFER+1][DAQ_DMA_BLOCK_SIZE_BYTES]__attribute__ ((aligned(8)));double channel_tap[MAX_CLIENTS+1][MAX_CLIENTS+1][CHANNEL_LENGTH];double complex channel_tap_cplx[MAX_CLIENTS+1][MAX_CLIENTS+1][CHANNEL_LENGTH];int nbr_ready_to_rcv, nbr_ready_to_send, nbr_clients, slot;int ready_to_rcv, ready_to_xmit, tx_block;int serving, got_rcv_mutex, is_complex,gid;/** * Handles the stream from/to one client. If a client drops the connection, * the thread ends. */static void * t_client(void * arg) { int nbr_bytes, block; transmission_t temp; struct client_params *p = arg; // Initialisation PR_DBG( 2,"Connected client %d\n", p->id ); while ( 1 ) { // Receive pthread_mutex_lock( &mutex_rcv ); block = tx_block; nbr_bytes = recv( p->sockfd, &temp, sizeof( transmission_t ), MSG_WAITALL ); if ( nbr_bytes != sizeof( transmission_t ) ) { // The connection failed or the client sent some bogus data PR_DBG( 2, "client(%i) disconnecting\n", p->id ); break; } else { // Update the gains, get_data_type(real or cpmx) and copy the data is_complex=temp.is_complex; rx_gain[p->id] = pow( 10.0, temp.rx_gain / 10 ); tx_gain[p->id] = pow( 10.0, temp.tx_gain / 10 ); PR_DBG( 4,"client(%i): slot:%i, block_count: %i, rcvd:%i, " "rx_gain =%e, tx_gain =%e\n", p->id, slot, temp.block_count, nbr_bytes, temp.rx_gain, temp.tx_gain ); memcpy( tx_signal_buffer[p->id][BLOCK_ACT_TX(block)], temp.signal, DAQ_DMA_BLOCK_SIZE_BYTES ); if ( BLOCK_ACT_TX(block) == BLOCK_BUFFER ) { // The end of the buffer, copy to the beginning memcpy( tx_signal_buffer[p->id][0], temp.signal, DAQ_DMA_BLOCK_SIZE_BYTES ); } nbr_ready_to_send++; pthread_cond_broadcast( &cond_rcv ); } // Send pthread_mutex_lock( &mutex_send ); pthread_mutex_unlock( &mutex_rcv ); pthread_cond_wait( &cond_send, &mutex_send ); nbr_bytes = send( p->sockfd, rx_signal_buffer[p->id][BLOCK_ACT_TX(block)], DAQ_DMA_BLOCK_SIZE_BYTES, 0 ); PR_DBG( 4,"client(%i): slot:%i, sent:%i\n", p->id, slot, nbr_bytes ); pthread_mutex_unlock( &mutex_send ); } // Cleanup and tell master-thread close( p->sockfd ); nbr_clients--; p->id = -1; pthread_cond_broadcast( &cond_rcv ); pthread_mutex_unlock( &mutex_rcv ); if ( !nbr_clients ) { serving = 0; } return NULL;}/** * Master-thread, makes sure that everybody is in synch, and that no users * get added at undue time. */static void *t_master() { pthread_mutex_lock( &mutex_rcv ); nbr_ready_to_send = 0; while( 1 ) { PR_DBG( 4, "\n" ); PR_DBG( 4, "master: Sending ready to receive : nbr_clients = %d\n", nbr_clients ); // Clients receive data do { pthread_cond_wait( &cond_rcv, &mutex_rcv ); PR_DBG( 4, "master: Received %i out of %i\n", nbr_ready_to_send, nbr_clients ); } while ( nbr_ready_to_send < nbr_clients ); nbr_ready_to_send = 0; PR_DBG( 4, "Going to calculate channel\n" ); // Calculate the channel switch( 2 ) { case 0: // Flat channel, only sum of signals flat_calc( nbr_clients ); break; case 1: // Fading channel, no reflexions fading_calc( nbr_clients ); break; case 2: // Fading, multi-path channel with noise if(is_complex){ fading_multi_complex_calc( nbr_clients,gid ); }else{ fading_multi_calc( nbr_clients,gid ); } break; } if ( !( slot % 1000 ) ) { PR_DBG( 3, "master: Generated slot %d for %d clients\n", slot, nbr_clients ); } pthread_mutex_lock( &mutex_send ); // Clients send data PR_DBG( 4, "master: Broadcast RTX\n" ); pthread_cond_broadcast( &cond_send ); pthread_mutex_unlock( &mutex_send ); tx_block++; slot++; }}int new_client( int fd ) { struct client_params *p; int i; int nbr_bytes; connect_t conn; // If we get mutex_rcv, t_master must be in it's cond_wait, // and thus we can add clients without messing things up. if( !got_rcv_mutex ){ pthread_mutex_lock( &mutex_rcv ); PR_DBG( 2, "Got mutex_rcv!!!\n"); } got_rcv_mutex=1; // Search for an empty entry for ( i=0; ( client[i].id != -1 ) && ( i < MAX_CLIENTS ); i++ ){} if ( i >= MAX_CLIENTS ) { PR_DBG( 0, "Server-table is full. Disconnect clients or higher MAX_CLIENTS\n" ); pthread_mutex_unlock( &mutex_rcv ); return -1; } PR_DBG( 2, "Getting new client at %i%%BLOCK_BUFFER=%i, block is %i\n", tx_block, tx_block % BLOCK_BUFFER, BLOCK_ACT_TX( tx_block ) ); p = &client[i]; p->sockfd = fd; p->id = i; nbr_clients++; nbr_bytes = recv( p->sockfd, &conn, sizeof( connect_t ), MSG_WAITALL ); PR_DBG( 3, "Received client %d info (%d bytes of %d)\n", p->id, nbr_bytes, sizeof( connect_t ) ); if ( conn.indicator != INDICATOR_ID ) { PR_DBG( 0, "Wrong indicator. Killing client %d\n",p->id); return -1; } else { if( conn.gid==-1 ){ conn.gid=gid; } p->gid=gid; PR_DBG( 2, "client[%i] has gid[%i]\n",p->id,p->gid); nbr_bytes = send( p->sockfd, &conn, sizeof( connect_t ), MSG_WAITALL ); pthread_create( &p->thr, NULL, t_client, p ); PR_DBG( 2, "nbr_clients=%i, total_channels=%i, cond=%d\n", nbr_clients, conn.total_channels, !((nbr_clients)%conn.total_channels)); if( !((nbr_clients)%conn.total_channels) ){ pthread_mutex_unlock( &mutex_rcv ); PR_DBG( 4, "Released mutex_rcv!!!\n"); got_rcv_mutex=0; PR_DBG( 2, "gid=%i\n", gid ); gid++; } } return p->id;}/** * Initialise all variables */int init_server() { int listenfd, i; struct sockaddr_in servaddr; int port; FILE *f_port; char path[256]; fading_multi_complex_init(); fading_multi_init(); fading_init(); flat_init(); init_command(); nbr_ready_to_rcv = 0; nbr_ready_to_send = 0; nbr_clients = 0; slot = 0; ready_to_rcv = 0; ready_to_xmit = 0; tx_block = 0; serving = 1; got_rcv_mutex = 0; pthread_mutex_init( &mutex_rcv, NULL ); pthread_mutex_init( &mutex_send, NULL ); pthread_cond_init( &cond_rcv, NULL ); pthread_cond_init( &cond_rcv, NULL ); if ( (listenfd = socket( AF_INET, SOCK_STREAM, 0 ) ) < 0 ) { return -1; } // Search for a free port for ( port = SERV_PORT; port < SERV_PORT + 0x100; port++ ) { memset( &servaddr, 0, sizeof(servaddr) ); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl( INADDR_ANY ); servaddr.sin_port = htons( port ); if ( bind( listenfd, (struct sockaddr*) &servaddr, sizeof( servaddr ) ) >= 0 ) { break; } } if ( port < SERV_PORT + 0x100 ) { PR_DBG( 1, "Found port %i to be free\n", port ); // And write it to the config-file snprintf( path, 256, "/tmp/%s", getenv( "USER" ) ); mkdir( path, 0777 ); strcat( path, "/server_port" ); f_port = fopen( path, "w" ); if ( !f_port ) { PR_DBG( 0, "Error while opening %s. Stopping\n", path ); return -1; } fprintf( f_port, "%i\n", port ); fclose( f_port ); } else { PR_DBG( 0, "No ports free anymore. Try again later\n" ); return -1; } if ( listen( listenfd, SOMAXCONN ) < 0 ) { return -1; } for ( i=0; i < MAX_CLIENTS; i++ ) { client[i].id = -1; } return listenfd;}/** * Initialises the server and waits for new connections */int main(int argc, char **argv) { int listenfd, fd, id; pthread_t master_thread; socklen_t clilen; struct sockaddr_in cliaddr; if ( ( listenfd = init_server() ) < 0 ) { PR_DBG( 0, "Couldn't create socket. Another server running here?\n" ); return 0; } pthread_create( &master_thread, NULL, &t_master, NULL ); while ( 1 ) { clilen = sizeof( cliaddr ); PR_DBG( 3, "Waiting for new client\n" ); fd = accept( listenfd, (struct sockaddr*)&cliaddr, &clilen ); if ( fd > 0 ) { PR_DBG( 1,"new client connected. ID=%i with fd #%d, block is %i\n", id, fd, BLOCK_ACT_TX( tx_block ) ); id = new_client( fd ); } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -