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 + -
显示快捷键?