Esempio n. 1
0
/*
* QBufPipe_Wait
*/
void QBufPipe_Wait( qbufPipe_t *pipe, int (*read)( qbufPipe_t *, unsigned( ** )(const void *), bool ), 
	unsigned (**cmdHandlers)( const void * ), unsigned timeout_msec )
{
	while( !pipe->terminated ) {
		int res;
		bool result = false;

		while( Sys_Atomic_CAS( &pipe->cmdbuf_len, 0, 0, pipe->cmdbuf_mutex ) == true ) {
			QMutex_Lock( pipe->nonempty_mutex );

			result = QCondVar_Wait( pipe->nonempty_condvar, pipe->nonempty_mutex, timeout_msec );

			// don't hold the mutex, changes to cmdbuf_len are atomic anyway
			QMutex_Unlock( pipe->nonempty_mutex );
			break;
		}

		// we're guaranteed at this point that either cmdbuf_len is > 0
		// or that waiting on the condition variable has timed out
		res = read( pipe, cmdHandlers, result );
		if( res < 0 ) {
			// done
			return;
		}
	}
}
Esempio n. 2
0
/*
* QBufPipe_Finish
*
* Blocks until the reader thread handles all commands
* or terminates with an error.
*/
void QBufPipe_Finish( qbufPipe_t *pipe ) {
	while( Sys_Atomic_CAS( &pipe->cmdbuf_len, 0, 0, pipe->cmdbuf_mutex ) == false && !pipe->terminated ) {
		QMutex_Lock( pipe->nonempty_mutex );
		QBufPipe_Wake( pipe );
		QMutex_Unlock( pipe->nonempty_mutex );
		QThread_Yield();
	}
}
Esempio n. 3
0
static void wswcurl_crypto_lockcallback( int mode, int type, const char *file, int line ) {
	( void )file;
	( void )line;
	if( mode & CRYPTO_LOCK ) {
		QMutex_Lock( crypto_mutexes[type] );
	} else {
		QMutex_Unlock( crypto_mutexes[type] );
	}
}
Esempio n. 4
0
void _Mem_Free( void *data, int musthave, int canthave, const char *filename, int fileline )
{
	void *base;
	memheader_t *mem;
	mempool_t *pool;

	if( data == NULL )
		//_Mem_Error( "Mem_Free: data == NULL (called at %s:%i)", filename, fileline );
		return;

	mem = ( memheader_t * )( (qbyte *) data - sizeof( memheader_t ) );

	assert( mem->sentinel1 == MEMHEADER_SENTINEL1 );
	assert( *( (qbyte *) mem + sizeof( memheader_t ) + mem->size ) == MEMHEADER_SENTINEL2 );

	if( mem->sentinel1 != MEMHEADER_SENTINEL1 )
		_Mem_Error( "Mem_Free: trashed header sentinel 1 (alloc at %s:%i, free at %s:%i)", mem->filename, mem->fileline, filename, fileline );
	if( *( (qbyte *)mem + sizeof( memheader_t ) + mem->size ) != MEMHEADER_SENTINEL2 )
		_Mem_Error( "Mem_Free: trashed header sentinel 2 (alloc at %s:%i, free at %s:%i)", mem->filename, mem->fileline, filename, fileline );

	pool = mem->pool;
	if( musthave && ( ( pool->flags & musthave ) != musthave ) )
		_Mem_Error( "Mem_Free: bad pool flags (musthave) (alloc at %s:%i)", filename, fileline );
	if( canthave && ( pool->flags & canthave ) )
		_Mem_Error( "Mem_Free: bad pool flags (canthave) (alloc at %s:%i)", filename, fileline );

	if( developerMemory && developerMemory->integer )
		Com_DPrintf( "Mem_Free: pool %s, alloc %s:%i, free %s:%i, size %i bytes\n", pool->name, mem->filename, mem->fileline, filename, fileline, mem->size );

	QMutex_Lock( memMutex );

	// unlink memheader from doubly linked list
	if( ( mem->prev ? mem->prev->next != mem : pool->chain != mem ) || ( mem->next && mem->next->prev != mem ) )
		_Mem_Error( "Mem_Free: not allocated or double freed (free at %s:%i)", filename, fileline );

	if( mem->prev )
		mem->prev->next = mem->next;
	else
		pool->chain = mem->next;
	if( mem->next )
		mem->next->prev = mem->prev;

	// memheader has been unlinked, do the actual free now
	pool->totalsize -= mem->size;

	base = mem->baseaddress;
	pool->realsize -= mem->realsize;

	QMutex_Unlock( memMutex );

#ifdef MEMTRASH
	memset( mem, 0xBF, sizeof( memheader_t ) + mem->size + sizeof( int ) );
#endif

	free( base );
}
Esempio n. 5
0
void Com_EndRedirect( void )
{
	rd_flush( rd_target, rd_buffer, rd_extra );

	rd_target = 0;
	rd_buffer = NULL;
	rd_buffersize = 0;
	rd_flush = NULL;
	rd_extra = NULL;

	QMutex_Unlock( com_print_mutex );
}
Esempio n. 6
0
/*
* CL_ResolveMasterAddress
*/
static void CL_ResolveMasterAddress( const char *master )
{
	netadr_t adr, *padr;

	if( master && *master ) {
		NET_StringToAddress( master, &adr );

		QMutex_Lock( resolveLock );

		padr = ( netadr_t * )malloc( sizeof( adr ) );
		*padr = adr;

		Trie_Insert( serverlist_masters_trie, master, padr );

		QMutex_Unlock( resolveLock );
	}
}
Esempio n. 7
0
void wswcurl_urlencode( const char *src, char *dst, size_t size ) {
	char *curl_esc;

	assert( src );
	assert( dst );

	if( !src || !dst ) {
		return;
	}
	if( !curldummy ) {
		return;
	}

	QMutex_Lock( curldummy_mutex );
	curl_esc = qcurl_easy_escape( curldummy, src, 0 );
	QMutex_Unlock( curldummy_mutex );

	Q_strncpyz( dst, curl_esc, size );
	qcurl_free( curl_esc );
}
Esempio n. 8
0
size_t wswcurl_urldecode( const char *src, char *dst, size_t size ) {
	int unesc_len;
	char *curl_unesc;

	assert( src );
	assert( dst );

	if( !src || !dst ) {
		return 0;
	}
	if( !curldummy ) {
		return 0;
	}

	QMutex_Lock( curldummy_mutex );
	curl_unesc = qcurl_easy_unescape( curldummy, src, 0, &unesc_len );
	QMutex_Unlock( curldummy_mutex );

	Q_strncpyz( dst, curl_unesc, size );
	qcurl_free( curl_unesc );

	return (size_t)unesc_len;
}
Esempio n. 9
0
/*
* CL_GetServers_f
*/
void CL_GetServers_f( void )
{
	netadr_t adr, *padr;
	char *requeststring;
	int i;
	char *modname, *master;
	trie_error_t err;

	filter_allow_full = qfalse;
	filter_allow_empty = qfalse;
	for( i = 2; i < Cmd_Argc(); i++ )
	{
		if( !Q_stricmp( "full", Cmd_Argv( i ) ) )
			filter_allow_full = qtrue;

		if( !Q_stricmp( "empty", Cmd_Argv( i ) ) )
			filter_allow_empty = qtrue;
	}

	if( !Q_stricmp( Cmd_Argv( 1 ), "local" ) )
	{
		if( localQueryTimeStamp + LAN_SERVER_PINGING_TIMEOUT > Sys_Milliseconds() ) {
			return;
		}

		padr = &adr;
		localQueryTimeStamp = Sys_Milliseconds();

		// send a broadcast packet
		Com_DPrintf( "pinging broadcast...\n" );

		// erm... modname isn't sent in local queries?

		requeststring = va( "info %i %s %s", SERVERBROWSER_PROTOCOL_VERSION,
			filter_allow_full ? "full" : "",
			filter_allow_empty ? "empty" : "" );

		for( i = 0; i < NUM_BROADCAST_PORTS; i++ )
		{
			NET_BroadcastAddress( padr, PORT_SERVER + i );
			Netchan_OutOfBandPrint( &cls.socket_udp, padr, requeststring );
		}
		return;
	}

	//get what master
	master = Cmd_Argv( 2 );
	if( !master || !( *master ) )
		return;

	modname = Cmd_Argv( 3 );
	// never allow anyone to use DEFAULT_BASEGAME as mod name
	if( !modname || !modname[0] || !Q_stricmp( modname, DEFAULT_BASEGAME ) )
		modname = APPLICATION;

	assert( modname[0] );

	// check memory cache
	QMutex_Lock( resolveLock );
	err = Trie_Find( serverlist_masters_trie, master, TRIE_EXACT_MATCH, (void **)&padr );
	QMutex_Unlock( resolveLock );

	if( err == TRIE_OK && ( padr->type == NA_IP || padr->type == NA_IP6 ) )
	{
		const char *cmdname;
		socket_t *socket;

		if ( padr->type == NA_IP )
		{
			cmdname = "getservers";
			socket = &cls.socket_udp;
		}
		else
		{
			cmdname = "getserversExt";
			socket = &cls.socket_udp6;
		}

		// create the message
		requeststring = va( "%s %c%s %i %s %s", cmdname, toupper( modname[0] ), modname+1, SERVERBROWSER_PROTOCOL_VERSION,
			filter_allow_full ? "full" : "",
			filter_allow_empty ? "empty" : "" );

		if( NET_GetAddressPort( padr ) == 0 )
			NET_SetAddressPort( padr, PORT_MASTER );

		Netchan_OutOfBandPrint( socket, padr, requeststring );

		Com_DPrintf( "quering %s...%s: %s\n", master, NET_AddressToString(padr), requeststring );
	}
	else
	{
		Com_Printf( "Bad address: %s\n", master );
	}
}
Esempio n. 10
0
/*
* QBufPipe_WriteCmd
*
* Add new command to buffer. Never allow the distance between the reader
* and the writer to grow beyond the size of the buffer.
*
* Note that there are race conditions here but in the worst case we're going
* to erroneously drop cmd's instead of stepping on the reader's toes.
*/
void QBufPipe_WriteCmd( qbufPipe_t *pipe, const void *cmd, unsigned cmd_size )
{
	void *buf;
	unsigned write_remains;
	bool was_empty;
	
	if( !pipe ) {
		return;
	}
	if( pipe->terminated ) {
		return;
	}

	assert( pipe->bufSize >= pipe->write_pos );
	if( pipe->bufSize < pipe->write_pos ) {
		pipe->write_pos = 0;
	}

	was_empty = Sys_Atomic_CAS( &pipe->cmdbuf_len, 0, 0, pipe->cmdbuf_mutex ) == true;
	write_remains = pipe->bufSize - pipe->write_pos;

	if( sizeof( int ) > write_remains ) {
		while( pipe->cmdbuf_len + cmd_size + write_remains > pipe->bufSize ) {
			if( pipe->blockWrite ) {
				QThread_Yield();
				continue;
			}
			return;
		}

		// not enough space to enpipe even the reset cmd, rewind
		QBufPipe_BufLenAdd( pipe, write_remains ); // atomic
		pipe->write_pos = 0;
	} else if( cmd_size > write_remains ) {
		int *cmd;

		while( pipe->cmdbuf_len + sizeof( int ) + cmd_size + write_remains > pipe->bufSize ) {
			if( pipe->blockWrite ) {
				QThread_Yield();
				continue;
			}
			return;
		}

		// explicit pointer reset cmd
		cmd = QBufPipe_AllocCmd( pipe, sizeof( int ) );
		*cmd = -1;

		QBufPipe_BufLenAdd( pipe, sizeof( *cmd ) + write_remains ); // atomic
		pipe->write_pos = 0;
	}
	else
	{
		while( pipe->cmdbuf_len + cmd_size > pipe->bufSize ) {
			if( pipe->blockWrite ) {
				QThread_Yield();
				continue;
			}
			return;
		}
	}

	buf = QBufPipe_AllocCmd( pipe, cmd_size );
	memcpy( buf, cmd, cmd_size );
	QBufPipe_BufLenAdd( pipe, cmd_size ); // atomic

	// wake the other thread waiting for signal
	if( was_empty ) {
		QMutex_Lock( pipe->nonempty_mutex );
		QBufPipe_Wake( pipe );
		QMutex_Unlock( pipe->nonempty_mutex );
	}
}
Esempio n. 11
0
/*
* Com_Printf
* 
* Both client and server can use this, and it will output
* to the apropriate place.
*/
void Com_Printf( const char *format, ... )
{
	va_list	argptr;
	char msg[MAX_PRINTMSG];

	time_t timestamp;
	char timestamp_str[MAX_PRINTMSG];
	struct tm *timestampptr;
	timestamp = time( NULL );
	timestampptr = gmtime( &timestamp );
	strftime( timestamp_str, MAX_PRINTMSG, "%Y-%m-%dT%H:%M:%SZ ", timestampptr );

	va_start( argptr, format );
	Q_vsnprintfz( msg, sizeof( msg ), format, argptr );
	va_end( argptr );

	if( rd_target )
	{
		if( (int)( strlen( msg ) + strlen( rd_buffer ) ) > ( rd_buffersize - 1 ) )
		{
			rd_flush( rd_target, rd_buffer, rd_extra );
			*rd_buffer = 0;
		}
		strcat( rd_buffer, msg );
		return;
	}

	QMutex_Lock( com_print_mutex );

	Con_Print( msg );

	// also echo to debugging console
	Sys_ConsoleOutput( msg );

	// logconsole
	if( logconsole && logconsole->modified )
	{
		logconsole->modified = qfalse;

		if( log_file )
		{
			FS_FCloseFile( log_file );
			log_file = 0;
		}

		if( logconsole->string && logconsole->string[0] )
		{
			size_t name_size;
			char *name;

			name_size = strlen( logconsole->string ) + strlen( ".log" ) + 1;
			name = ( char* )Mem_TempMalloc( name_size );
			Q_strncpyz( name, logconsole->string, name_size );
			COM_DefaultExtension( name, ".log", name_size );

			if( FS_FOpenFile( name, &log_file, ( logconsole_append && logconsole_append->integer ? FS_APPEND : FS_WRITE ) ) == -1 )
			{
				log_file = 0;
				Com_Printf( "Couldn't open: %s\n", name );
			}

			Mem_TempFree( name );
		}
	}

	if( log_file )
	{
		if( logconsole_timestamp && logconsole_timestamp->integer )
			FS_Printf( log_file, "%s", timestamp_str );
		FS_Printf( log_file, "%s", msg );
		if( logconsole_flush && logconsole_flush->integer )
			FS_Flush( log_file ); // force it to save every time
	}

	QMutex_Unlock( com_print_mutex );
}
Esempio n. 12
0
void *_Mem_AllocExt( mempool_t *pool, size_t size, size_t alignment, int z, int musthave, int canthave, const char *filename, int fileline )
{
	void *base;
	size_t realsize;
	memheader_t *mem;

	if( size <= 0 )
		return NULL;

	// default to 16-bytes alignment
	if( !alignment )
		alignment = MEMALIGNMENT_DEFAULT;

	assert( pool != NULL );

	if( pool == NULL )
		_Mem_Error( "Mem_Alloc: pool == NULL (alloc at %s:%i)", filename, fileline );
	if( musthave && ( ( pool->flags & musthave ) != musthave ) )
		_Mem_Error( "Mem_Alloc: bad pool flags (musthave) (alloc at %s:%i)", filename, fileline );
	if( canthave && ( pool->flags & canthave ) )
		_Mem_Error( "Mem_Alloc: bad pool flags (canthave) (alloc at %s:%i)", filename, fileline );

	if( developerMemory && developerMemory->integer )
		Com_DPrintf( "Mem_Alloc: pool %s, file %s:%i, size %i bytes\n", pool->name, filename, fileline, size );

	QMutex_Lock( memMutex );

	pool->totalsize += size;
	realsize = sizeof( memheader_t ) + size + alignment + sizeof( int );

	pool->realsize += realsize;

	base = malloc( realsize );
	if( base == NULL )
		_Mem_Error( "Mem_Alloc: out of memory (alloc at %s:%i)", filename, fileline );

	// calculate address that aligns the end of the memheader_t to the specified alignment
	mem = ( memheader_t * )((((size_t)base + sizeof( memheader_t ) + (alignment-1)) & ~(alignment-1)) - sizeof( memheader_t ));
	mem->baseaddress = base;
	mem->filename = filename;
	mem->fileline = fileline;
	mem->size = size;
	mem->realsize = realsize;
	mem->pool = pool;
	mem->sentinel1 = MEMHEADER_SENTINEL1;

	// we have to use only a single byte for this sentinel, because it may not be aligned, and some platforms can't use unaligned accesses
	*( (qbyte *) mem + sizeof( memheader_t ) + mem->size ) = MEMHEADER_SENTINEL2;

	// append to head of list
	mem->next = pool->chain;
	mem->prev = NULL;
	pool->chain = mem;
	if( mem->next )
		mem->next->prev = mem;

	QMutex_Unlock( memMutex );

	if( z )
		memset( (void *)( (qbyte *) mem + sizeof( memheader_t ) ), 0, mem->size );

	return (void *)( (qbyte *) mem + sizeof( memheader_t ) );
}
Esempio n. 13
0
void wswcurl_delete(wswcurl_req *req)
{
	if ( (!req) || (!wswcurl_isvalidhandle(req)) )
	{
		return;
	}

	// if (req->callback_done && req->active )
	//	req->callback_done ( req, 0, req->customp );

	if (req->txhead)
	{
		curl_slist_free_all(req->txhead);
		req->txhead = NULL;
	}

	if (req->post)
	{
		curl_formfree(req->post);
		req->post      = NULL;
		req->post_last = NULL;
	}

	if (req->url)
	{
		WFREE(req->url);
	}

	if( req->bhead )
	{
		chained_buffer_t *cb = req->bhead;
		chained_buffer_t *next = cb->next;

		while( cb ) {
			WFREE( cb );
			cb = next;
			if( cb )
				next = cb->next;
		}
	}

	// remove from list
	QMutex_Lock( http_requests_mutex );

	if (req->curl)
	{
		if (curlmulti && req->status && req->status != WSTATUS_QUEUED) {
			curl_multi_remove_handle(curlmulti, req->curl);
			curlmulti_num_handles--;
		}
		curl_easy_cleanup(req->curl);
		req->curl = NULL;
	}

	if (http_requests_hnode == req) http_requests_hnode = req->prev;
	if (http_requests == req) http_requests = req->next;
	if (req->prev) req->prev->next = req->next;
	if (req->next) req->next->prev = req->prev;

	QMutex_Unlock( http_requests_mutex );

	WFREE(req);
}
Esempio n. 14
0
wswcurl_req *wswcurl_create( const char *iface, const char *furl, ... )
{
	wswcurl_req *retreq;
	CURL *curl;
	CURLcode res;
	char url[4 * 1024]; // 4kb url buffer?
	va_list arg;
	const char *proxy = http_proxy->string;
	const char *proxy_userpwd = http_proxyuserpwd->string;

	// Prepare url formatting with variable arguments
	va_start( arg, furl );
	Q_vsnprintfz( url, sizeof( url ), furl, arg );
	va_end( arg );

	// Initialize structure
	if( !(curl = curl_easy_init()) ) {
		return NULL;
	}

	// allocate, copy
	retreq = ( wswcurl_req * )WMALLOC( sizeof( wswcurl_req ) );
	memset( retreq, 0, sizeof( *retreq ) );

	retreq->curl = curl;
	retreq->url = ( char* )WMALLOC( strlen( url ) + 1 );
	memcpy( retreq->url, url, strlen( url ) + 1 );

	CURLSETOPT( curl, res, CURLOPT_URL, retreq->url );
	CURLSETOPT( curl, res, CURLOPT_WRITEFUNCTION, wswcurl_write );
	CURLSETOPT( curl, res, CURLOPT_NOPROGRESS, 1 );
	CURLSETOPT( curl, res, CURLOPT_FOLLOWLOCATION, 1 );
	CURLSETOPT( curl, res, CURLOPT_HEADERFUNCTION, wswcurl_readheader );
	CURLSETOPT( curl, res, CURLOPT_CONNECTTIMEOUT, WCONNECTTIMEOUT );
#if defined( APPLICATION ) && defined( APP_VERSION_STR ) && defined( OSNAME ) && defined( CPUSTRING )
	CURLSETOPT( curl, res, CURLOPT_USERAGENT, APPLICATION"/"APP_VERSION_STR" (compatible; N; "OSNAME"; "CPUSTRING")" );
#endif
	CURLSETOPT( curl, res, CURLOPT_WRITEDATA, ( void * )retreq );
	CURLSETOPT( curl, res, CURLOPT_WRITEHEADER, ( void * )retreq );
	CURLSETOPT( curl, res, CURLOPT_PRIVATE, ( void * )retreq );
	if( iface && *iface ) {
		CURLSETOPT( curl, res, CURLOPT_INTERFACE, ( void * )iface );
	}

	if( developer->integer ) {
		CURLSETOPT( curl, res, CURLOPT_DEBUGFUNCTION, &wswcurl_debug_callback );
		CURLSETOPT( curl, res, CURLOPT_DEBUGDATA, ( void * )retreq );
		CURLSETOPT( curl, res, CURLOPT_VERBOSE, 1 );
	}

	// HTTP proxy settings
	if( proxy && *proxy ) {
		CURLSETOPT( curl, res, CURLOPT_PROXYTYPE, CURLPROXY_HTTP );

		CURLSETOPT( curl, res, CURLOPT_PROXY, proxy );
		if( proxy_userpwd && *proxy_userpwd ) {
			CURLSETOPT( curl, res, CURLOPT_PROXYUSERPWD, proxy_userpwd );
		}
	}

	wswcurl_set_timeout( retreq, WTIMEOUT );

	// link
	QMutex_Lock( http_requests_mutex );

	retreq->prev = NULL;
	retreq->next = http_requests;
	if( retreq->next ) {
		retreq->next->prev = retreq;
	}
	else {
		http_requests_hnode = retreq;
	}
	http_requests = retreq;

	CURLDBG((va("   CURL CREATE %s\n", url)));

	QMutex_Unlock( http_requests_mutex );

	return retreq;
}
Esempio n. 15
0
int wswcurl_perform()
{
	int ret = 0;
	wswcurl_req *r, *next;

	if (!curlmulti) return 0;

	// process requests in FIFO manner

	QMutex_Lock( http_requests_mutex );

	// check for timed out requests and requests that need to be paused
	r = http_requests_hnode;
	while( r )
	{
		next = r->prev;

		if (r->status == WSTATUS_QUEUED) {
			// queued
			if (curlmulti_num_handles < WMAXMULTIHANDLES) {
				if (curl_multi_add_handle(curlmulti, r->curl)) {
					CURLDBG(("OOPS: CURL MULTI ADD HANDLE FAIL!!!"));
				}
				r->status = WSTATUS_STARTED;
				r->last_action = wswcurl_now();
				curlmulti_num_handles++;
			}
			else {
				// stay in queue
			}
		}

		// handle pauses for synchronous requests
		if( r->status == WSTATUS_STARTED && !r->callback_read ) {
			if( r->rxreceived >= r->rxreturned + WMAXBUFFERING ) {
				wswcurl_pause( r );
			}
		}

		// handle timeouts
		if( r->status == WSTATUS_STARTED ) {
			time_t now = wswcurl_now();

			if( r->paused ) {
				// paused
				r->last_action = now;
			} else if( r->timeout && ( r->last_action + r->timeout <= now ) ) {
				// timed out
				r->respcode = -1;
				r->status = -CURLE_OPERATION_TIMEDOUT;
				if( r->callback_done ) {
					r->callback_done( r, r->status, r->customp );
				}
			}
		}

		r = next;
	}

	QMutex_Unlock( http_requests_mutex );

	//CURLDBG(("CURL BEFORE MULTI_PERFORM\n"));
	while ( curl_multi_perform(curlmulti, &ret) == CURLM_CALL_MULTI_PERFORM) {
		CURLDBG(("   CURL MULTI LOOP\n"));
	}
	ret += wswcurl_checkmsg();
	//CURLDBG(("CURL after checkmsg\n"));

	return ret;
}