home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 2002 March
/
Chip_2002-03_cd2.bin
/
dmbsck.cab
/
dumb_socket.c
next >
Wrap
C/C++ Source or Header
|
2001-11-14
|
21KB
|
930 lines
/*
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 */
/* dumb sockets */
#define DUMB_SOCKET_EXPORTS
//#define _WATCH_POMALA
#include <windows.h>
//#include <winbase.h>
#include <stdlib.h>
#include <memory.h>
#include <assert.h>
#include <stdio.h>
#include "watcha.h"
#include "dumb_socket.h"
#include "pchfree.h"
/* muzu vypnout inline */
#define INLINE __inline
/* count u semaforu */
#define MAX_SEM_COUNT 10000
#ifdef _DEBUG
static int pocet_spojeni = 0;
static int pipe_counter = 0;
#endif
static int dumbs_item_empty (dumbs_item* me); /* je empty? */
static void delete_dumb_pipe (dumb_pipe* p);
static dumb_socket* new_dumb_socket ();
static void dumb_socket_push (dumb_socket* me, void* data, int size);
static int dumb_socket_pop (dumb_socket* me, void* data, int size);
static void dumb_socket_unpop (dumb_socket* me, void* _data, int _size);
static int dumb_socket_empty (dumb_socket* me);
static void delete_dumb_socket (dumb_socket* me);
static int dumb_socket_pop_size (dumb_socket* me);
static void dumb_socket_lock (dumb_socket* me);
static void dumb_socket_unlock (dumb_socket* me);
static void wait_for_data (dumb_socket* me);
static void signal_data (dumb_socket* me);
static dumb_pipe* remove_dumb_pipe(dumb_pipe* p);
static dumb_pipe* new_dumb_pipe(dumb_pipe* chain, short blocking, char* name);
static void delete_dumbs_item(dumbs_item* me);
static dumbs_item* new_dumbs_item(void* _data, int _size);
static void dumbs_item_append(dumbs_item* me,dumbs_item* i);
static void dumbs_item_prepend(dumbs_item* me,dumbs_item* i);
static void unlocked_item_remove(dumbs_item* me);
static int dumbs_item_get(dumbs_item* me, void* buf, int bufsize);
static dumb_pipe* pipe_chain = NULL;
CRITICAL_SECTION create_pipe_lock;
CRITICAL_SECTION hdumb_lock;
#define WBUFMAX 48
#define WBUFMAXHEX 16
void wbuf( char* buf, int size)
{
char wbuf[512];
char* wp = wbuf;
int i;
if( size > WBUFMAX) size = WBUFMAX;
for( i = 0; i < size; i++) {
if( buf[i] >= ' ' && buf[i] < 128)
*wp++ = buf[i];
else
*wp++ = '.';
}
while( i++ < WBUFMAX)
*wp++ = ' ';
if( size > WBUFMAXHEX) size = WBUFMAXHEX;
for( i = 0; i < size; i++) {
wp += sprintf( wp, " %02X", buf[i] & 0xFF);
}
*wp = 0;
w( wbuf);
}
//prace se semaphorama
static void wait_for(HANDLE h) // vola se jen z connectu a z wait_for_data a to zase jen z read_dumb_pipe
{
DWORD res;
assert(h != NULL);
#ifdef _WATCH_POMALA
watch_in( "wait for %08X ...", h);
#endif
res = WaitForSingleObject(h,INFINITE);
#ifdef _WATCH_POMALA
watch_out( "wait for %08X OK (%d)", h, res);
#endif
assert(res == WAIT_OBJECT_0);
}
static void release(HANDLE h)
{
BOOL res;
assert(h);
#ifdef _WATCH_POMALA
w( "release %08X", h);
#endif
res = ReleaseSemaphore(h,1,NULL);
if( ! res) {
DWORD errc = GetLastError();
w( "!!!! Release semaphor %08X FAILED - errc: %d !!!!", h, errc);
}
assert( res);
}
static void hlock( int c)
{
watch_in( "hlock %c", c);
EnterCriticalSection(&hdumb_lock);
}
static void hunlock( int c)
{
LeaveCriticalSection(&hdumb_lock);
watch_out( "hunlock %c", c);
}
static void clock( int c)
{
watch_in( "clock %c", c);
EnterCriticalSection(&create_pipe_lock);
}
static void cunlock( int c)
{
LeaveCriticalSection(&create_pipe_lock);
watch_out( "cunlock %c", c);
}
void dumb_socket_lock(dumb_socket* me)
{
assert( me);
// watch_in( "Lock sock %08X", me);
EnterCriticalSection(&me->lock);
#if _DEBUG
me->locked = 1;
#endif
}
void dumb_socket_unlock(dumb_socket* me)
{
assert( me);
// watch_out( "Lock sock %08X", me);
#if _DEBUG
me->locked = 0;
#endif
LeaveCriticalSection(&me->lock);
}
void wait_for_data(dumb_socket* me)
{
// w( "Wait for data S:%08X", me);
wait_for(me->block_sem);
}
void signal_data(dumb_socket* me)
{
// w( "Signal data S:%08X", me);
release(me->block_sem);
}
static HANDLE create_semaphore()
{
HANDLE h;
h = CreateSemaphore(NULL,0,MAX_SEM_COUNT,NULL);
w( "Sem %08X crtd", h);
assert( h);
return h;
}
static void delete_semaphore(HANDLE h)
{
int r;
r = CloseHandle( h);
#ifdef _DEBUG
if( ! r)
w( "!!! Sem %08X delete FAILED - error %d", h, GetLastError());
else
w( "Sem %08X deleted", h);
assert(r);
#endif
}
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
HANDLE podivny_creatovac;
HANDLE podivny_konektovac;
////////////////////////////////////////////////////////////////////
// Volne funkce
static hdumb_pipe* new_hdumb_pipe(dumb_pipe* p,short i_am_server)
{
hdumb_pipe* n = (hdumb_pipe*) malloc(sizeof(hdumb_pipe));
// watch("new_hdumb_pipe");
//@F hlock( 'n');
memset((void*)n,0,sizeof(hdumb_pipe));
n->pipe = p;
n->server = i_am_server;
//@F hunlock( 'N');
return n;
}
/* vola server */
int connect_hdumb_pipe(hdumb_pipe* h)
{
watch_in("connect_hdumb_pipe");
//rekni_ze_cekam();
ReleaseSemaphore(podivny_konektovac,1,NULL);
wait_for(h->pipe->connect_synchro);
watch_out("connect_hdumb_pipe");
return 1;
}
/*
// vola client .... uz nevola
int wait_hdumb_pipe(char *name,int timeout)
{
DWORD res = WaitForSingleObject(podivny_konektovac,0);
if(res == WAIT_OBJECT_0){
ReleaseSemaphore(podivny_konektovac,1,NULL);
return 1;
}
return 0;
}
*/
////////////////////////////////////////////////////////////////////
// Funkce pristupujici ke globalnim promennym (pipechain), tudiz v nich musi bejt lock
// hlock
void destroy_dumb_pipe(hdumb_pipe* h)
{
hlock( 'd');
assert( h);
assert( h->pipe);
watch_in( "destroy_dumb_pipe h:%08X %c p:%08X s:[%08X,%08X]", h, h->server ? 'S' : 'C',
h->pipe, h->pipe->dumb_sock[0], h->pipe->dumb_sock[1]);
// EnterCriticalSection(&create_pipe_lock);
if(h && h->pipe) {
remove_dumb_pipe( h->pipe);
delete_dumb_pipe( h->pipe);
pchfree(h);
}
// LeaveCriticalSection(&create_pipe_lock);
watch_out("destroy_dumb_pipe");
hunlock( 'D');
}
////////////////////////////////////////////////////////////////////
// Funkce pristupujici ke globalnim promennym (pipechain), tudiz v nich musi bejt lock
// clock
hdumb_pipe* create_server_dumbpipe(short blocking, char *name)
{
hdumb_pipe* h;
clock( 's');
pipe_chain = new_dumb_pipe(pipe_chain,blocking,name);
h = new_hdumb_pipe(pipe_chain,I_AM_SERVER);
assert( h);
assert(++pocet_spojeni<2);
w( "create S dumbpipe [%s] H:%08X P:%08X S:[%08X,%08X]", name, h, h->pipe,
h->pipe ? h->pipe->dumb_sock[0] : 0, h->pipe ? h->pipe->dumb_sock[1] : 0);
//ReleaseSemaphore(podivny_creatovac,1,NULL);
cunlock( 'S');
return h;
}
hdumb_pipe* create_client_dumbpipe(char *name)
{
dumb_pipe* pom;
hdumb_pipe* h;
DWORD res;
//WaitForSingleObject(podivny_creatovac,INFINITE);
res = WaitForSingleObject(podivny_konektovac,INFINITE);
if(res == WAIT_TIMEOUT){
SetLastError(ERROR_PIPE_BUSY);
return INVALID_HANDLE_VALUE;
}
clock( 'c');
watch_in("create_client_dumbpipe");
pom = pipe_chain;
while(pom != NULL){
//watch("step");
#ifndef NONAME_PIPE
assert(pom->name != NULL);
if(pom->name != NULL){
if(0==strcmp(pom->name,name)){
#endif
assert(--pocet_spojeni >= 0);
assert(pom->connected != 1);
pom->connected=1;
h = new_hdumb_pipe(pom,I_AM_CLIENT);
w("create C dumbpipe [%s] H:%08X P:%08X S:[%08X,%08X]", name, h, h->pipe,
h->pipe ? h->pipe->dumb_sock[0] : 0, h->pipe ? h->pipe->dumb_sock[1] : 0);
release(h->pipe->connect_synchro);
watch_out("create_client_pipe OK");
cunlock( 'C');
return h;
#ifndef NONAME_PIPE
}
}
#endif
pom = pom->next;
}
watch_out("create_client_pipe ERR");
cunlock( 'C');
assert(0);
SetLastError(ERROR_BAD_PIPE);
return INVALID_HANDLE_VALUE;
}
////////////////////////////////////////////////////////////////////
// Funkce, ktery jsou uz volany z hlock
static dumb_pipe* remove_dumb_pipe(dumb_pipe* p)
{
dumb_pipe* c = pipe_chain;
dumb_pipe* last = NULL; //@petr dame nejakou rozumnou hodnotu
while(c != NULL){
if(c == p){
if(c==pipe_chain){
pipe_chain=pipe_chain->next;
return c;
}else{
assert(last != NULL);
last->next = c->next;
return c;
}
}
last = c;
c = c->next;
}
return NULL;
}
////////////////////////////////////////////////////////////////////
// Funkce, ktery jsou uz volany z clock
static dumb_pipe* new_dumb_pipe(dumb_pipe* chain, short blocking, char* name)
{
dumb_pipe* n = (dumb_pipe*) malloc(sizeof(dumb_pipe));
// int len;
memset((void*)n,0,sizeof(dumb_pipe));
#ifndef NONAME_PIPE
len = strlen(name);
n->name = malloc(len * sizeof(char)+1);
strcpy(n->name,name);
#endif
n->next = chain;
n->dumb_sock[0] = new_dumb_socket(blocking);
n->dumb_sock[1] = new_dumb_socket(blocking);
n->blocking = blocking;
n->connected = 0;
n->connect_synchro = create_semaphore();
chain = n;
return n;
}
////////////////////////////////////////////////////////////////////
// Funkce pristupujici k retizku uvnitr socketu, musi byt lock(sock)
int write_dumb_pipe(hdumb_pipe* h,char* buff,int size)
{
dumb_socket* sock;
//@F hlock( 'w'); - to tu podle mne nema bejt
assert( h);
assert( h->pipe);
assert( h->pipe->dumb_sock[h->server]);
assert( buff);
/*if(!h->pipe->full){
wait_for(h->pipe->connect_synchro);
}*/
// assert(h->pipe->full);
sock = h->pipe->dumb_sock[h->server];
dumb_socket_lock( sock);
dumb_socket_push( sock, buff, size);
signal_data( sock);
dumb_socket_unlock( sock);
w( "W H:%08X %c P:%08X S:%08X size %d", h, h->server ? 'S' : 'C', h->pipe, sock, size);
//wbuf( buff, size);
//@F hunlock( 'W');
return size;
}
int read_dumb_pipe(hdumb_pipe* h,char* buff,int buf_size)
{
int pop_size;
dumb_socket* sock;
char* tmpbuf;
assert(h != NULL);
assert(h->pipe != NULL);
assert(h->pipe->dumb_sock[!h->server] != NULL);
assert(buff != NULL);
assert(buf_size);
sock = h->pipe->dumb_sock[!h->server];
assert( ! sock->next_zombie);
#ifdef WITH_TIMEOUT
if(!wait_for_data(sock)){
return 0;
}
#else
wait_for_data(sock);
#endif
//@F hlock( 'r');
dumb_socket_lock(sock);
//watch("lock");
pop_size = dumb_socket_pop_size(sock);
if(pop_size <= buf_size){
// watch("pop");
dumb_socket_pop(sock,buff,buf_size);
dumb_socket_unlock(sock);
//@ hunlock( 'P'); - to tu podle mne nema bejt
w( "RP h:%08X %c p:%08X s:%08X size %d", h, h->server ? 's' : 'c', h->pipe, sock, buf_size);
//wbuf( buff, buf_size);
return pop_size;
}else{
// watch("unpop");
tmpbuf = malloc(pop_size);
dumb_socket_pop(sock,tmpbuf,pop_size);
if(buf_size) {
memcpy(buff,tmpbuf,buf_size);
}
#ifdef _WATCH_POMALA
w( "RU h:%08X %c p:%08X s:%08X size %d", h, h->server ? 's' : 'c', h->pipe, sock, buf_size);
//wbuf( buff, buf_size);
#endif
dumb_socket_unpop(sock,tmpbuf+buf_size,pop_size-buf_size);
signal_data(sock);
pchfree(tmpbuf);
dumb_socket_unlock(sock);
// watch_out("read_dumb_pipe (unpop)");
//@F hunlock( 'U');
// watch("unlock");
return buf_size;
}
}
//@F
void make_empty_dumb_socket( dumb_socket* me)
{
dumb_socket_lock(me);
// DeleteCriticalSection(&me->lock); - az v totally kill
// puvodne: se vola az s detache dllka, kdyz se dezombizuje ;)
//delete_semaphore(me->block_sem);
while( ! dumb_socket_empty( me)) {
dumbs_item* tmp = me->first;
if(me->last == me->first) {
me->last = NULL;
}
me->first = me->first->next;
delete_dumbs_item(tmp);
}
dumb_socket_unlock(me);
}
////////////////////////////////////////////////////////////////////
// Funkce pristupujici k retizku uvnitr zalockovaneho socketu
void dumb_socket_push(dumb_socket* me,void* data,int size)
{
dumbs_item* i;
// char buff[500];
assert( me);
assert( data);
assert( size > 0);
// sprintf(buff,"dumb_socket_push #%s#(%d)",data,size);
// watch(buff);
i = new_dumbs_item( data, size);
assert( i);
if(dumb_socket_empty(me)){
me->first = i;
me->last = i;
}else{
dumbs_item_append(i,me->last);
me->last=i;
}
}
void dumb_socket_unpop(dumb_socket* me, void* _data, int _size)
{
dumbs_item* i;
assert( me);
assert( _data);
i = new_dumbs_item(_data,_size);
assert( i);
if(dumb_socket_empty(me)){
me->first = i;
me->last = i;
}else{
dumbs_item_prepend(i,me->first);
me->first = i;
}
}
int dumb_socket_pop(dumb_socket* me, void* _data, int _size)
{
dumbs_item* tmp;
int read;
assert( me);
assert( _data);
if( ! dumb_socket_empty( me)){
read = dumbs_item_get( me->first, _data, _size);
// w("%d = dumb_socket_pop (%s,%d)",read,_data,_size);
tmp = me->first;
if(me->last == me->first){
me->last = NULL;
}
me->first = me->first->next;
// dumbs_item_remove(tmp);
delete_dumbs_item(tmp);
return read;
}
return 0;
}
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
static void delete_dumb_pipe(dumb_pipe* p)
{
int i;
clock( 'd');
assert( p);
assert( p->dumb_sock[0]);
assert( p->dumb_sock[1]);
w( "delete_dumb_pipe p:%08X s:[%08X,%08X]", p, p->dumb_sock[0], p->dumb_sock[1]);
// release(p->exclusive_synchro);
//EnterCriticalSection(&create_pipe_lock);
if(p != NULL)
for(i = 0; i <=1; i++)
if(p->dumb_sock[i] != NULL)
delete_dumb_socket(p->dumb_sock[i]);
delete_semaphore(p->connect_synchro);
pchfree(p);
cunlock( 'D');
}
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
void dumbs_item_free(dumbs_item* me)
{
assert(!dumbs_item_empty(me));
if(!dumbs_item_empty(me)){
pchfree(me->data);
me->data = NULL;
me->size = 0;
}
//watch_out("dumb_item_free");
}
static void dumbs_item_set(dumbs_item* me, void* _data, int _size)
{
if(!dumbs_item_empty(me)){
dumbs_item_free(me);
}
me->size = _size;
if(_size)
me->data = malloc(_size);
else
me->data = NULL;
assert(me->data != NULL);
if(me->data != NULL)
{
// w( "dumbs_item_set(%08X,%08X) MEMCPY(%08X,%08X,%d)", me, me->data, me->data, _data, _size);
memcpy (me->data,_data,_size);
}
}
static int dumbs_item_get(dumbs_item* me, void* buf, int bufsize)
{
int r;
assert(me != NULL);
assert(buf != NULL);
if(me == NULL || buf == NULL)
return 0;
if(bufsize < me->size){
r = bufsize;
}else{
r = me->size;
}
if(r){
//w("dumbs_item_get %08x,size=%d",buf,r);
memcpy(buf,me->data, r);
}
return r;
}
static dumbs_item* new_dumbs_item(void* _data, int _size)
{
dumbs_item* n = (dumbs_item*) malloc(sizeof(dumbs_item));
assert(n != NULL);
n->prev = NULL;
n->next = NULL;
n->data = NULL;
n->size = 0;
#if _DEBUG
n->locked = 0;
#endif
InitializeCriticalSection(&n->lock);
assert( _data);
dumbs_item_set(n, _data, _size);
return n;
}
static void dumbs_item_append(dumbs_item* me,dumbs_item* i)
{
assert(me != NULL);
assert(i != NULL);
if(i != NULL) {
if( i->next)
w( "!!!! i->next not empty - i: %08X, i->next: %08X", i, i->next);
assert( ! i->next);
i->next = me;
}
me->prev = i;
}
static void dumbs_item_prepend(dumbs_item* me,dumbs_item* i)
{
assert( me);
assert( i);
if( i) {
if( i->prev)
w( "!!!! i->prev not empty - i: %08X, i->prev: %08X", i, i->prev);
assert( ! i->prev);
i->prev = me;
}
me->next = i;
}
/* remove z locknuty struktury */
static void unlocked_item_remove(dumbs_item* me)
{
if(me->prev != NULL)
me->prev->next = me->next;
if(me->next != NULL)
me->next->prev = me->prev;
me->prev = NULL;
me->next = NULL;
}
INLINE void dumbs_item_remove(dumbs_item* me)
{
assert(me != NULL);
unlocked_item_remove(me);
}
INLINE int dumbs_item_size(dumbs_item* me)
{
int s;
assert(me != NULL);
s = me->size;
return s;
}
INLINE int dumbs_item_empty(dumbs_item* me)
{
int r = 0;
assert(me != NULL);
if(me != NULL){
if(me->data == NULL)
r = 1;
else
r = 0;
}
return r;
}
static void delete_dumbs_item(dumbs_item* me)
{
#if _DEBUG
// w( "delete_dumbs_item(%08X)", me);
#endif
assert(me != NULL);
if(me != NULL){
unlocked_item_remove(me);
if(!me->size == 0){
dumbs_item_free(me);
}
pchfree(me);
}
}
//////////////////////////////////////////////
static dumb_socket* dumb_socket_zombie = NULL;
INLINE int dumb_socket_pop_size(dumb_socket* me)
{
return me->first ? me->first->size : 0;
}
INLINE int dumb_socket_empty(dumb_socket* me)
{
return ! me->first;
}
dumb_socket* new_dumb_socket(short blocking)
{
//char kbuf[256];
dumb_socket* n = malloc(sizeof(dumb_socket));
assert(n != NULL);
if(n != NULL){
n->first = NULL;
n->last = NULL;
n->blocking = blocking;
n->block_sem = create_semaphore();
InitializeCriticalSection(&n->lock);
#if _DEBUG
n->locked = 0;
#endif
n->next_zombie = NULL;
}
/*sprintf(kbuf, "new_dumb_socket(%08X)", n);
watch(kbuf);*/
return n;
}
//@F
void totally_kill_dumb_socket( dumb_socket* me)
{
/* tohle uz se nevola, ted uz se o to nema kdo hadat
dumb_socket_lock(me);
dumb_socket_unlock(me);
*/
w( "totally_kill_dumb_socket S:%08X", me);
make_empty_dumb_socket( me); // pro sichr
DeleteCriticalSection(&me->lock);
delete_semaphore(me->block_sem);
// me->block_sem = INVALID_HANDLE_VALUE; to uz tu taky nema co delat
pchfree(me);
}
//@F
#define NO_ZOMBIE_CHAIN
#ifdef NO_ZOMBIE_CHAIN
static dumb_socket* zombie_next = 0;
#endif
void delete_dumb_socket(dumb_socket* me)
{
w( "delete_dumb_socket S:%08X", me);
assert(me != NULL);
make_empty_dumb_socket( me); // pozor, lock musi byt az za tim, tady vevnitr lock je
dumb_socket_lock(me);
#ifdef NO_ZOMBIE_CHAIN
// jedna pipa ma dva sockety, pamatuje si to vzdycky posledni dvojici, protoze to je serializovany
// jakmile pride delete, tak se smazou ty predchozi
if( dumb_socket_zombie) {
if( zombie_next) {
totally_kill_dumb_socket( dumb_socket_zombie);
dumb_socket_zombie = zombie_next;
}
zombie_next = me;
} else {
dumb_socket_zombie = me;
}
#else
me->next_zombie = dumb_socket_zombie;
dumb_socket_zombie = me;
#endif
//!!! DeleteCriticalSection(&me->lock); se vola az s detache dllka, kdyz se dezombizuje ;)
//delete_semaphore(me->block_sem);
dumb_socket_unlock(me);
}
HANDLE hinstance;
BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
int n = 0;
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
hinstance = hModule;
InitializeCriticalSection(&create_pipe_lock);
InitializeCriticalSection(&hdumb_lock);
podivny_konektovac = CreateSemaphore(NULL,0,1,NULL);
podivny_creatovac = CreateSemaphore(NULL,0,1,NULL);
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
while( dumb_socket_zombie){
dumb_socket* me = dumb_socket_zombie;
dumb_socket_zombie = me->next_zombie;
n++;
totally_kill_dumb_socket( me);
}
#ifdef NO_ZOMBIE_CHAIN
if( zombie_next) {
totally_kill_dumb_socket( zombie_next);
n++;
}
#endif
DeleteCriticalSection(&create_pipe_lock);
DeleteCriticalSection(&hdumb_lock);
w( "zombie sockets: %d", n);
break;
}
return TRUE;
}