proto.c

来自「Windows NT声卡驱动VXD」· C语言 代码 · 共 936 行 · 第 1/2 页

C
936
字号
#include "esd-server.h"#include <errno.h>/*******************************************************************//* globals */int esd_forced_standby = 0;	/* whether we're forcing the standby *//*******************************************************************//* prototypes */int esd_check_endian( esd_client_t *client, unsigned int *endian );int esd_validate_source( esd_client_t *client, 			 octet *submitted_key, int owner_only );int esd_proto_unimplemented( esd_client_t *client );int esd_proto_connect( esd_client_t *client );int esd_proto_lock( esd_client_t *client );int esd_proto_unlock( esd_client_t *client );int esd_proto_standby( esd_client_t *client );int esd_proto_resume( esd_client_t *client );int esd_proto_stream_play( esd_client_t *client );int esd_proto_stream_recorder( esd_client_t *client );int esd_proto_stream_monitor( esd_client_t *client );int esd_proto_stream_filter( esd_client_t *client );int esd_proto_sample_cache( esd_client_t *client );int esd_proto_sample_getid(esd_client_t *client);int esd_proto_sample_free( esd_client_t *client );int esd_proto_sample_play( esd_client_t *client );int esd_proto_sample_loop( esd_client_t *client );int esd_proto_sample_stop( esd_client_t *client );int esd_proto_server_info( esd_client_t *client );int esd_proto_all_info( esd_client_t *client );int esd_proto_stream_pan( esd_client_t *client );int esd_proto_sample_pan( esd_client_t *client );int esd_proto_standby_mode( esd_client_t *client );int poll_client_requests(void);/*******************************************************************//* protocol handlers as function pointers: synch with esd_proto_t enum */typedef int esd_proto_handler_t( esd_client_t *client );/* data type to hold the per protocol handler info */typedef struct esd_proto_handler_info {    int 		data_length;    esd_proto_handler_t *handler;    const char *        description;} esd_proto_handler_info_t;/* the big map of protocol handler info */esd_proto_handler_info_t esd_proto_map[ ESD_PROTO_MAX ] = {    { ESD_KEY_LEN + sizeof(int), &esd_proto_connect, "connect" },    { ESD_KEY_LEN + sizeof(int), &esd_proto_lock, "lock" },    { ESD_KEY_LEN + sizeof(int), &esd_proto_unlock, "unlock" },    { ESD_NAME_MAX + 2 * sizeof(int), &esd_proto_stream_play, "stream play" },    { ESD_NAME_MAX + 2 * sizeof(int), &esd_proto_stream_recorder, "stream rec" },    { ESD_NAME_MAX + 2 * sizeof(int), &esd_proto_stream_monitor, "stream mon" },    { ESD_NAME_MAX + 3 * sizeof(int), &esd_proto_sample_cache, "sample cache" },    { sizeof(int), &esd_proto_sample_free, "sample free" },    { sizeof(int), &esd_proto_sample_play, "sample play" },    { sizeof(int), &esd_proto_sample_loop, "sample loop" },    { sizeof(int), &esd_proto_sample_stop, "sample stop" },    { -1, &esd_proto_unimplemented, "TODO: sample kill" },    { ESD_KEY_LEN + sizeof(int), &esd_proto_standby, "standby" },    { ESD_KEY_LEN + sizeof(int), &esd_proto_resume, "resume" },    { ESD_NAME_MAX, &esd_proto_sample_getid, "sample getid" },    { ESD_KEY_LEN + 2 * sizeof(int), &esd_proto_stream_filter, "stream filter" },    { sizeof(int), &esd_proto_server_info, "server info" },    { sizeof(int), &esd_proto_all_info, "all info" },    { -1, &esd_proto_unimplemented, "TODO: subscribe" },    { -1, &esd_proto_unimplemented, "TODO: unsubscribe" },    { 3 * sizeof(int), &esd_proto_stream_pan, "stream pan"},    { 3 * sizeof(int), &esd_proto_sample_pan, "sample pan" },    { sizeof(int), &esd_proto_standby_mode, "standby mode" }};/*******************************************************************//* checks for client/server endianness */int esd_check_endian( esd_client_t *client, unsigned int *endian ){    if ( *endian == ESD_ENDIAN_KEY ) {	ESDBG_TRACE( printf( "(%02d) same endian order.\n", client->fd ); );	client->swap_byte_order = 0;    } else if ( *endian == ESD_SWAP_ENDIAN_KEY ) {	ESDBG_TRACE( printf( "(%02d) different endian order!\n", client->fd ); );	client->swap_byte_order = 1;    } else {	ESDBG_TRACE( 	    printf( "(%02d) unknown endian key: 0x%08x"		    " (same = 0x%08x, diff = 0x%08x)\n",		    client->fd, *endian, 		    ESD_ENDIAN_KEY, ESD_SWAP_ENDIAN_KEY ); );	return 0;    }    /* now we're done */    return 1;}/*******************************************************************//* checks for authorization to use the sound daemon */int esd_validate_source( esd_client_t *client, 			 octet *submitted_key,			 int owner_only ){    if( !esd_is_owned ) {	/* noone owns it yet, the first client claims ownership */	ESDBG_TRACE( printf( "(%02d) esd auth: claiming ownership of esd, auth ok\n", 			     client->fd ); );	esd_is_locked = 1;	memcpy( esd_owner_key, submitted_key, ESD_KEY_LEN );	esd_is_owned = 1;	return 1;    }    if( !esd_is_locked && !owner_only ) {	/* anyone can connect to it */	ESDBG_TRACE( printf( "(%02d) esd auth: not locked nor owner only, auth ok.\n", 			     client->fd ); );	return 1;    }    if( !memcmp( esd_owner_key, submitted_key, ESD_KEY_LEN ) ) {	/* the client key matches the owner, trivial acceptance */	ESDBG_TRACE( printf( "(%02d) esd auth: key matches, auth ok.\n", 			     client->fd ); );	return 1;    }    /* TODO: maybe check based on source ip? */     /* done with LIBWRAP when client first connects to daemon */    /* if ( !owner_only ) { check_ip_etc( client->source ); } */    /* the client is not authorized to connect to the server */    ESDBG_TRACE( printf( "(%02d) esd auth: NOT authorized to use esd, closing conn.\n",			 client->fd ); );    return 0;}/*******************************************************************//* place holder during development */int esd_proto_unimplemented( esd_client_t *client ){    fprintf( stderr, 	     "(%02d) proto: unimplemented protocol request:  0x%08x\n",	     client->fd, client->request );    return 0;}/*******************************************************************//* initial connection handler, return boolean ok */int esd_proto_connect( esd_client_t *client ){    int ok;    if ( esd_validate_source( client, client->proto_data, 0 ) )    {	ok = esd_check_endian( client, (int*)(client->proto_data + ESD_KEY_LEN) );    } else {	ok = 0;    }        ESDBG_TRACE( printf( "(%02d) connecting to sound daemon = %d\n", 			 client->fd, ok ); );    return ok;}/*******************************************************************//* daemon rejects untrusted clients, return boolean ok */int esd_proto_lock( esd_client_t *client ){    int ok, client_ok, actual;    ok = esd_validate_source( client, client->proto_data, 1 );    client_ok = maybe_swap_32( client->swap_byte_order, ok );    if ( ok ) {	ESDBG_TRACE( printf( "(%02d) locking sound daemon\n", client->fd ); );	esd_is_locked = 1;    }    ESD_WRITE_INT( client->fd, &client_ok, sizeof(client_ok), 		   actual, "lock ok" );        return ok;}/*******************************************************************//* allows anyone to connect to the sound daemon, return boolean ok */int esd_proto_unlock( esd_client_t *client ){    int ok, client_ok, actual;    ok = esd_validate_source( client, client->proto_data, 1 );    client_ok = maybe_swap_32( client->swap_byte_order, ok );    if ( ok ) {	ESDBG_TRACE( printf( "(%02d) unlocking sound daemon\n", client->fd ); );	esd_is_locked = 0;    }    ESD_WRITE_INT( client->fd, &client_ok, sizeof(client_ok), 		   actual, "unlock ok" );    return ok;}/*******************************************************************//* daemon eats sound data, without playing anything, return boolean ok */int esd_proto_standby( esd_client_t *client ){    int ok, client_ok, actual;    ok = esd_validate_source( client, client->proto_data, 1 );    if ( ok ) ok = esd_server_standby();    esd_forced_standby = 1;    client_ok = maybe_swap_32( client->swap_byte_order, ok );    ESD_WRITE_INT( client->fd, &client_ok, sizeof(client_ok), 		   actual, "stdby ok" );    return ok;}/*******************************************************************//* daemon eats sound data, without playing anything, return boolean ok */int esd_proto_resume( esd_client_t *client ){    int ok, client_ok, actual;    ok = esd_validate_source( client, client->proto_data, 1 );    if ( ok ) ok = esd_server_resume();    if ( ok ) esd_forced_standby = 0;    client_ok = maybe_swap_32( client->swap_byte_order, ok );    ESD_WRITE_INT( client->fd, &client_ok, sizeof(client_ok), 		   actual, "resum ok" );    return ok;}/*******************************************************************//* add another stream player to the list, returns boolean ok */int esd_proto_stream_play( esd_client_t *client ){    /* spawn a new player to handle this stream */    esd_player_t *player = NULL;    player = new_stream_player( client );        /* we got one, right? */    if ( !player ) {	return 0;    }        /* add to the list of players */    player->parent = client;    add_player( player );    client->state = ESD_STREAMING_DATA;    return 1;}/*******************************************************************//* manage the single recording client, return boolean ok */int esd_proto_stream_recorder( esd_client_t *client ){    /* wake up if we're asleep */    if ( esd_on_autostandby  && !esd_forced_standby ) {	ESDBG_TRACE( printf( "stuff to record, waking up.\n" ); );	esd_server_resume();    }    /* if we're already recording, or (still) in standby mode, go away */    if ( esd_recorder || esd_on_standby ) {	return 0;    }    /* sign up the new recorder client */    esd_recorder = new_stream_player( client );    if ( esd_recorder != NULL ) {	/* let the device know we want to record */	ESDBG_TRACE( printf( "closing audio for a sec...\n" ); );	esd_audio_close();	sleep(1);	esd_audio_format |= ESD_RECORD;	ESDBG_TRACE( printf( "reopening audio to record...\n" ); );	esd_audio_open();	ESDBG_TRACE( printf( "reopened?\n" ); );	/* flesh out the recorder */	esd_recorder->parent = client;	esd_recorder->translate_func 	    = get_translate_func( esd_audio_format, esd_audio_rate,				  esd_recorder->format, esd_recorder->rate );	ESDBG_TRACE( printf ( "(%02d) recording on client\n", client->fd ); );    } else {	/* failed to initialize the recorder, kill its client */	return 0;    }    client->state = ESD_STREAMING_DATA;    return 1;}/*******************************************************************//* manage the single monitoring client, return boolean ok */int esd_proto_stream_monitor( esd_client_t *client ){    esd_player_t *monitor;    /* sign up the new monitor client */    monitor = new_stream_player( client );    if ( monitor != NULL ) {	/* flesh out the monitor */	monitor->parent = client;	monitor->next = esd_monitor_list;	esd_monitor_list = monitor;	monitor->translate_func 	    = get_translate_func( esd_audio_format, esd_audio_rate,				  monitor->format, monitor->rate );	ESDBG_TRACE( printf ( "(%02d) monitoring on client\n", client->fd ); );    } else {	/* failed to initialize the recorder, kill its client */	return 0;    }    client->state = ESD_STREAMING_DATA;    return 1;}/*******************************************************************//* manage the filter client, return boolean ok */int esd_proto_stream_filter( esd_client_t *client ){    esd_player_t *filter;        /* sign up the new filter client */    filter = new_stream_player( client );    if ( filter != NULL ) {	/* flesh out the filter */	filter->parent = client;	filter->next = esd_filter_list;	esd_filter_list = filter;	ESDBG_TRACE( printf ( "(%02d) filter on client\n", client->fd ); );    } else {	/* failed to initialize the filter, kill its client */	return 0;    }    client->state = ESD_STREAMING_DATA;    return 1;}/*******************************************************************//* cache a sample from the client, return boolean ok  */int esd_proto_sample_cache( esd_client_t *client ){    esd_sample_t *sample;    int length;    int client_id;    ESDBG_TRACE( printf( "(%02d) proto: caching sample\n", client->fd ); );    if ( client->state == ESD_CACHING_SAMPLE ) {	sample = find_caching_sample( client );    } else {	sample = new_sample( client );	add_sample( sample );    }    /* add to the list of sample */    if ( sample != NULL ) {	sample->parent = client;	if ( !read_sample( sample ) )	{	    return 0;	/* something failed during the read, just bail */	}	if ( sample->cached_length < sample->sample_length ) {	    client->state = ESD_CACHING_SAMPLE;	    ESDBG_TRACE( printf( "(%02d) continue caching sample next trip\n", 				 client->fd ); );	    return 1;	} else {	    ESDBG_TRACE( printf( "(%02d) sample cached, moving on\n", 				 client->fd ); );	    client->state = ESD_NEXT_REQUEST;	}    } else {	fprintf( stderr, "(%02d) not enough mem for sample, closing\n", 		 client->fd );	return 0;    }    client_id = maybe_swap_32( client->swap_byte_order, 			       sample->sample_id );    ESD_WRITE_INT( client->fd, &client_id, sizeof(client_id), 		   length, "smp cach" );    return 1;}/*******************************************************************//* check for an existing sample name */int esd_proto_sample_getid(esd_client_t *client){    int client_id, length;    esd_sample_t *sample = esd_samples_list;    char namebuf[ESD_NAME_MAX];    strncpy( namebuf, client->proto_data, ESD_NAME_MAX );    namebuf[ESD_NAME_MAX - 1] = '\0';    ESDBG_TRACE( printf( "(%02d) proto: getting sample ID: %s\n", 			 client->fd, namebuf ); );    while(sample) {	if(!strcmp(sample->name, namebuf))	    break;	sample = sample->next;    }    if(sample)	client_id = maybe_swap_32( client->swap_byte_order, 				   sample->sample_id );    else	client_id = maybe_swap_32(client->swap_byte_order, -1);    ESD_WRITE_INT( client->fd, &client_id, sizeof(client_id), 		   length, "smp getid" );    return 1;}/*******************************************************************//* free a sample cached by the client, return boolean ok */int esd_proto_sample_free( esd_client_t *client ){    int sample_id, client_id, actual;    client_id = *(int*)(client->proto_data);    sample_id = maybe_swap_32( client->swap_byte_order, client_id );    ESDBG_TRACE( printf( "(%02d) proto: erasing sample <%d>\n", 			 client->fd, sample_id ); );    erase_sample( sample_id, 0 );    ESD_WRITE_INT( client->fd, &client_id, sizeof(client_id), 		   actual, "smp free" );    if ( sizeof( client_id ) != actual )	return 0;    return 1;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?