HavokResponse *db_mysql_save_account( HavokRequest *req ) { MYSQL_BIND *data; pthread_mutex_t *mutex; HavokResponse *resp; ProtectedData_t *protect; volatile int id; if( !req || !req->account_data ) { return; } mutex = CREATE(pthread_mutex_t); thread_mutex_init( mutex ); protect = ProtectedDataCreate(); protect->data = (void *)&id; ProtectedDataLock( protect ); data = CREATEN(MYSQL_BIND, 7); bind_numeric( &data[0], req->account_data->id, MYSQL_TYPE_LONG ); bind_string( &data[1], req->account_data->email, MYSQL_TYPE_VAR_STRING ); bind_string( &data[2], req->account_data->passwd, MYSQL_TYPE_VAR_STRING ); bind_numeric( &data[3], (req->account_data->ansi ? 1 : 0), MYSQL_TYPE_TINY ); bind_numeric( &data[4], (req->account_data->confirmed ? 1 : 0), MYSQL_TYPE_TINY ); bind_string( &data[5], (req->account_data->confcode ? req->account_data->confcode : ""), MYSQL_TYPE_VAR_STRING ); bind_null_blob( &data[6], protect ); db_queue_query( 5, QueryTable, data, 7, NULL, NULL, mutex ); pthread_mutex_unlock( mutex ); pthread_mutex_destroy( mutex ); memfree( mutex ); ProtectedDataLock( protect ); ProtectedDataDestroy( protect ); resp = protobufCreateResponse(); if( !resp ) { return( NULL ); } resp->request_type = REQ_TYPE__SAVE_ACCOUNT; resp->account_data = CREATE(ReqAccountType); req_account_type__init( resp->account_data ); memcpy( resp->account_data, req->account_data, sizeof(ReqAccountType) ); resp->account_data->id = id; resp->account_data->email = memstrlink( req->account_data->email ); resp->account_data->passwd = memstrlink( req->account_data->passwd ); resp->account_data->confcode = memstrlink( req->account_data->confcode ); return( resp ); }
/** * @brief Thread to handle WebService requests * @return never returns until shutdown * * Receives requests over a web socket and acts on them. */ void *WebServiceThread( void *arg ) { char *port; char *logdir; char buf[1024]; char **options; struct mg_context *ctx; pthread_mutex_lock( startupMutex ); port = pb_get_setting( "webServicePort" ); if( !port || !atoi(port) ) { LogPrintNoArg( LOG_CRIT, "No WebService Port defined. Aborting!" ); return; } logdir = pb_get_setting( "webServiceLogDir" ); if( !logdir ) { logdir = memstrlink( "/tmp" ); } LogPrint( LOG_DEBUG, "Web Service listening on port %s", port ); LogPrint( LOG_DEBUG, "Web Logs in %s", logdir ); options = CREATEN(char *, 7); options[0] = memstrlink("ports"); options[1] = memstrdup(port); options[2] = memstrlink("access_log"); sprintf( buf, "%s/access.log", logdir ); options[3] = memstrdup(buf); options[4] = memstrlink("error_log"); sprintf( buf, "%s/error.log", logdir ); options[5] = memstrdup(buf); options[6] = NULL; memfree( port ); memfree( logdir ); mg_set_allocs( &webServiceAllocs ); /* * Initialize mongoose context. * Start listening on port specified. */ ctx = mg_start(webServiceCallback, NULL, (const char **)options); while( !GlobalAbort ) { sleep(1); } mg_stop(ctx); LogPrintNoArg(LOG_INFO, "Ending WebServiceThread"); return( NULL ); }
void result_get_setting( MYSQL_RES *res, MYSQL_BIND *input, void *arg, long insertid ) { HavokResponse **resp; int count; MYSQL_ROW row; resp = (HavokResponse **)arg; if( !res || !(count = mysql_num_rows(res)) ) { *resp = NULL; return; } row = mysql_fetch_row(res); *resp = protobufCreateResponse(); if( !*resp ) { return; } (*resp)->request_type = REQ_TYPE__GET_SETTING; (*resp)->settings_data = CREATE(ReqSettingsType); req_settings_type__init( (*resp)->settings_data ); (*resp)->settings_data->setting_name = memstrlink( input[0].buffer ); (*resp)->settings_data->setting_value = COL_STRING(row, 0); }
HavokResponse *db_mysql_save_pc( HavokRequest *req ) { MYSQL_BIND *data; pthread_mutex_t *mutex; HavokResponse *resp; ProtectedData_t *protect; volatile int id; if( !req || !req->pc_data ) { return( NULL ); } mutex = CREATE(pthread_mutex_t); thread_mutex_init( mutex ); protect = ProtectedDataCreate(); protect->data = (void *)&id; ProtectedDataLock( protect ); data = CREATEN(MYSQL_BIND, 4); bind_numeric( &data[0], req->pc_data->id, MYSQL_TYPE_LONG ); bind_numeric( &data[1], req->pc_data->account_id, MYSQL_TYPE_LONG ); bind_string( &data[2], req->pc_data->name, MYSQL_TYPE_VAR_STRING ); bind_null_blob( &data[3], protect ); db_queue_query( 10, QueryTable, data, 4, NULL, NULL, mutex ); pthread_mutex_unlock( mutex ); pthread_mutex_destroy( mutex ); memfree( mutex ); ProtectedDataLock( protect ); ProtectedDataDestroy( protect ); db_mysql_save_pc_attribs( id, req->pc_data->attribs ); resp = protobufCreateResponse(); if( !resp ) { return( NULL ); } resp->request_type = REQ_TYPE__SAVE_PC; resp->n_pc_data = 1; resp->pc_data = CREATE(ReqPCType *); resp->pc_data[0] = CREATE(ReqPCType); req_pctype__init( resp->pc_data[0] ); memcpy( resp->pc_data[0], req->pc_data, sizeof(ReqPCType) ); resp->pc_data[0]->id = id; resp->pc_data[0]->name = memstrlink( req->pc_data->name ); return( resp ); }
void StartThreads( void ) { pthread_mutex_t spinLockMutex; pid_t childPid; struct sigaction sa; sigset_t sigmsk; size_t len; ThreadCallback_t callbacks; GlobalAbort = FALSE; #ifndef __CYGWIN__ len = confstr( _CS_GNU_LIBPTHREAD_VERSION, NULL, 0 ); if( len ) { pthreadsVersion = CREATEN(char, len); confstr( _CS_GNU_LIBPTHREAD_VERSION, pthreadsVersion, len ); } #else (void)len; pthreadsVersion = memstrlink( "Cygwin" ); #endif if( !pthreadsVersion || strstr( pthreadsVersion, "linuxthreads" ) ) { fprintf( stderr, "havokmud requires NPTL to operate correctly.\n\n" "The signal handling in linuxthreads is just too " "broken to use.\n\n" ); exit( 1 ); } /* Do we need to detach? */ if( Daemon ) { childPid = fork(); if( childPid < 0 ) { perror( "Couldn't detach in daemon mode" ); _exit( 1 ); } if( childPid != 0 ) { /* This is still the parent, report the child's pid and exit */ printf( "[Detached as PID %d]\n", childPid ); /* And exit the parent */ _exit( 0 ); } /* After this is in the detached child */ /* Close stdin, stdout, stderr to release the tty */ close(0); close(1); close(2); } LoggingQ = QueueCreate( 1024 ); ConnectInputQ = QueueCreate( 256 ); ConnectDnsQ = QueueCreate( 64 ); InputLoginQ = QueueCreate( 256 ); InputEditorQ = QueueCreate( 256 ); InputPlayerQ = QueueCreate( 256 ); InputImmortQ = QueueCreate( 256 ); MailQ = QueueCreate( 128 ); QueryQ = QueueCreate( 1024 ); ProtobufQ = QueueCreate( 1024 ); mainThreadId = pthread_self(); /* * Setup the sigmasks for this thread (which is the parent to all others). * This will propogate to all children. */ sigfillset( &sigmsk ); sigdelset( &sigmsk, SIGUSR1 ); sigdelset( &sigmsk, SIGUSR2 ); sigdelset( &sigmsk, SIGHUP ); sigdelset( &sigmsk, SIGWINCH ); sigdelset( &sigmsk, SIGINT ); sigdelset( &sigmsk, SIGSEGV ); sigdelset( &sigmsk, SIGILL ); sigdelset( &sigmsk, SIGFPE ); pthread_sigmask( SIG_SETMASK, &sigmsk, NULL ); memset( &callbacks, 0, sizeof(ThreadCallback_t) ); callbacks.sighupFunc = mainSighup; thread_register( &mainThreadId, "MainThread", NULL ); /* Setup signal handler for SIGUSR1 (toggles Debug) */ sa.sa_sigaction = (sigAction_t)logging_toggle_debug; sigemptyset( &sa.sa_mask ); sa.sa_flags = SA_RESTART; sigaction( SIGUSR1, &sa, NULL ); /* Setup the exit handler */ atexit( MainDelayExit ); /* Setup signal handler for SIGINT (shut down cleanly) */ sa.sa_sigaction = (sigAction_t)signal_interrupt; sigemptyset( &sa.sa_mask ); sa.sa_flags = SA_RESTART; sigaction( SIGINT, &sa, NULL ); /* Setup signal handlers that are to be propogated to all threads */ sa.sa_sigaction = (sigAction_t)signal_everyone; sigemptyset( &sa.sa_mask ); sa.sa_flags = SA_RESTART | SA_SIGINFO; sigaction( SIGUSR2, &sa, NULL ); sigaction( SIGHUP, &sa, NULL ); sigaction( SIGWINCH, &sa, NULL ); /* Setup signal handlers for SEGV, ILL, FPE */ sa.sa_sigaction = (sigAction_t)signal_death; sigemptyset( &sa.sa_mask ); sa.sa_flags = SA_RESTART | SA_SIGINFO; sigaction( SIGSEGV, &sa, NULL ); sigaction( SIGILL, &sa, NULL ); sigaction( SIGFPE, &sa, NULL ); versionAdd( "pthreads", pthreadsVersion ); versionAdd( "TERM", getenv("TERM") ); thread_create( &loggingThreadId, LoggingThread, NULL, "LoggingThread", NULL ); #if 0 curses_start(); cursesMenuItemAdd( 2, MENU_SYSTEM, "About", mainAbout, NULL ); cursesMenuItemAdd( 2, MENU_SYSTEM, "Licensing", mainLicensing, NULL ); cursesMenuItemAdd( 2, MENU_SYSTEM, "Versions", mainVersions, NULL ); cursesMenuItemAdd( 2, MENU_SYSTEM, "Reload All", mainReloadAll, NULL ); #endif LogBanner(); db_init(); db_mysql_init(); memset( &callbacks, 0, sizeof(ThreadCallback_t) ); callbacks.sigusr2Func = memoryStats; thread_create( &memoryThreadId, MemoryCoalesceThread, NULL, "MemoryCoalesceThread", &callbacks ); thread_create( &dnsThreadId, DnsThread, NULL, "DnsThread", NULL ); thread_create( &inputThreadId, InputThread, NULL, "InputThread", NULL ); thread_create( &loginThreadId, LoginThread, NULL, "LoginThread", NULL ); thread_create( &editorThreadId, EditorThread, NULL, "EditorThread", NULL ); mortalPlayingArgs.inputQ = InputPlayerQ; thread_create( &mortalPlayingThreadId, PlayingThread, &mortalPlayingArgs, "MortalPlayingThread", NULL ); immortPlayingArgs.inputQ = InputImmortQ; thread_create( &immortPlayingThreadId, PlayingThread, &immortPlayingArgs, "ImmortPlayingThread", NULL ); thread_create( &mysqlThreadId, MysqlThread, NULL, "MySQLThread", NULL ); thread_create( &protobufThreadId, ProtobufThread, NULL, "ProtobufThread", NULL ); pthread_mutex_lock( startupMutex ); pthread_mutex_unlock( startupMutex ); db_check_schema_main(); thread_create( &smtpThreadId, SmtpThread, NULL, "SMTPThread", NULL ); connectThreadArgs.port = mud_port; connectThreadArgs.timeout_sec = 0; connectThreadArgs.timeout_usec = 100000; thread_create( &connectionThreadId, ConnectionThread, &connectThreadArgs, "ConnectionThread", NULL ); pthread_mutex_lock( startupMutex ); pthread_mutex_unlock( startupMutex ); /* Sit on this and rotate - this causes an intentional deadlock, this * thread should stop dead in its tracks */ thread_mutex_init( &spinLockMutex ); pthread_mutex_lock( &spinLockMutex ); pthread_mutex_lock( &spinLockMutex ); }