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 ); }
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 ); }
/** * @brief Handles all network connections * @param arg a pointer to a structure containing port number and timeout * @return never returns until shutdown * * @todo be sure this handles linkdead without removing all player structures * so the player can log back in and be where they were * * Brings up a TCP listener on the MUD's assigned port and accepts connections. * Also reads all data from connected clients and hands the data off to the * Input thread. When there is output to be sent, this thread handles writing * to the sockets after the first write has completed. This thread also * handles the disconnection of clients gracefully. */ void *ConnectionThread( void *arg ) { connectThreadArgs_t *argStruct; int portNum; char *port; struct sockaddr_in6 sa; int count; int fdCount; int newFd; socklen_t salen; struct timeval timeout; ConnectionItem_t *item; PlayerStruct_t *player; ConnInputItem_t *connItem; ConnDnsItem_t *dnsItem; uint32 i; int on; int retval; char ch; argStruct = (connectThreadArgs_t *)arg; portNum = argStruct->port; pthread_mutex_lock( startupMutex ); if( portNum == -1 ) { port = pb_get_setting( "listenPort" ); if( !port ) { portNum = 4000; } else { portNum = atoi(port); memfree(port); } } /* * Start listening */ listenFd = socket( AF_INET6, SOCK_STREAM, 0 ); if( listenFd < 0 ) { perror("Opening listener socket"); exit(1); } on = 1; if( setsockopt( listenFd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) ) ) { perror("Setting socket to reuse"); exit(1); } memset(&sa, 0, sizeof(sa)); sa.sin6_family = AF_INET6; sa.sin6_port = htons(portNum); sa.sin6_addr = in6addr_any; if (bind(listenFd, (struct sockaddr *)&sa, sizeof(sa)) < 0) { perror("Binding listener socket"); close(listenFd); exit(1); } if (listen(listenFd, 10)) { perror("Listening to socket"); close(listenFd); exit(1); } FD_ZERO(&saveReadFds); FD_ZERO(&saveWriteFds); FD_ZERO(&saveExceptFds); connAddFd(listenFd, &saveReadFds); ConnectionList = LinkedListCreate(NULL); LogPrint( LOG_NOTICE, "Listening on port %d", portNum ); pthread_mutex_unlock( startupMutex ); while( !GlobalAbort ) { /* * Select on connected and listener */ readFds = saveReadFds; writeFds = saveWriteFds; exceptFds = saveExceptFds; timeout.tv_sec = argStruct->timeout_sec; timeout.tv_usec = argStruct->timeout_usec; fdCount = select(maxFd+1, &readFds, &writeFds, &exceptFds, &timeout); if( GlobalAbort ) { continue; } recalcMaxFd = FALSE; /* * Open a connection for listener */ if( FD_ISSET(listenFd, &readFds) ) { salen = sizeof(struct sockaddr_in6); newFd = accept(listenFd, (struct sockaddr *)&sa, &salen); connAddFd(newFd, &saveReadFds); connAddFd(newFd, &saveExceptFds); item = CREATE(ConnectionItem_t); if( !item ) { /* * No memory! */ LogPrintNoArg( LOG_EMERG, "Out of memory!" ); close(newFd); } else { item->fd = newFd; item->buffer = BufferCreate(MAX_BUFSIZE); item->hostName = ProtectedDataCreate(); ProtectedDataLock( item->hostName ); item->hostName->data = CREATEN(char, 50); inet_ntop(AF_INET6, &sa.sin6_addr, item->hostName->data, 50); if( !strncmp(item->hostName->data, "::ffff:", 7) ) { bcopy((char *)item->hostName->data + 7, item->hostName->data, 43); } ProtectedDataUnlock( item->hostName ); if (!IS_SET(SystemFlags, SYS_SKIPDNS)) { dnsItem = CREATE(ConnDnsItem_t); if( dnsItem ) { dnsItem->connection = item; memcpy(dnsItem->ipAddr, &sa.sin6_addr, 16); QueueEnqueueItem(ConnectDnsQ, dnsItem); } } player = CREATE(PlayerStruct_t); if( !player ) { /* * No memory! */ LogPrintNoArg( LOG_EMERG, "Out of memory!" ); BufferDestroy(item->buffer); close(newFd); memfree(item); } else { item->player = player; player->connection = item; player->in_buffer = item->buffer; LinkedListAdd( ConnectionList, (LinkedListItem_t *)item, UNLOCKED, AT_TAIL ); /* * Pass the info on to the other threads... */ #ifdef DEBUG_CONNECT LogPrint( LOG_INFO, "New connection: %p", player ); #endif connItem = CREATE(ConnInputItem_t); if( connItem ) { connItem->type = CONN_NEW_CONNECT; connItem->player = player; QueueEnqueueItem(ConnectInputQ, (QueueItem_t)connItem); } } } fdCount--; } if( fdCount ) { LinkedListLock( ConnectionList ); for( item = (ConnectionItem_t *)(ConnectionList->head); item && fdCount; item = (item ? (ConnectionItem_t *)item->link.next : (ConnectionItem_t *)ConnectionList->head) ) { if( FD_ISSET( item->fd, &exceptFds ) ) { /* * This connection's borked, close it, remove it, move on */ if( FD_ISSET( item->fd, &readFds ) ) { fdCount--; } if( FD_ISSET( item->fd, &writeFds ) ) { fdCount--; } BufferLock( item->buffer ); item = connRemove(item); fdCount--; continue; } if( item && FD_ISSET( item->fd, &readFds ) ) { /* * This connection has data ready */ count = BufferAvailWrite( item->buffer, TRUE ); if( !count ) { /* * No buffer space, the buffer's unlocked, move on */ LogPrint( LOG_INFO, "No buffer space: %p", item ); continue; } /* * The buffer's locked */ count = read( item->fd, BufferGetWrite( item->buffer ), count ); if( !count ) { LogPrint( LOG_DEBUG, "EOF on %d", item->fd ); /* * We hit EOF, close and remove */ if( FD_ISSET( item->fd, &writeFds ) ) { fdCount--; } item = connRemove(item); fdCount--; continue; } BufferWroteBytes( item->buffer, count ); BufferUnlock( item->buffer ); /* * Tell the input thread */ connItem = CREATE(ConnInputItem_t); if( connItem ) { #ifdef DEBUG_INPUT LogPrint( LOG_INFO, "New data: %p", item->player ); #endif connItem->type = CONN_INPUT_AVAIL; connItem->player = item->player; QueueEnqueueItem(ConnectInputQ, (QueueItem_t)connItem); } } if( item && FD_ISSET( item->fd, &writeFds ) ) { /* * We have space to output, so write if we have anything * to write */ #ifdef DEBUG_OUTPUT LogPrint( LOG_INFO, "Output sent to: %p", item ); #endif if( item->outBufDesc ) { /* TODO: deal with partial block writes */ retval = write( item->fd, item->outBufDesc->buf, item->outBufDesc->len ); memfree( item->outBufDesc->buf ); memfree( item->outBufDesc ); item->outBufDesc = NULL; } /* * Kick the next output */ connKickOutput( item ); fdCount--; } } LinkedListUnlock( ConnectionList ); } if( recalcMaxFd ) { LinkedListLock( ConnectionList ); maxFd = listenFd; for( item = (ConnectionItem_t *)(ConnectionList->head); item; item = (ConnectionItem_t *)item->link.next ) { if( item->fd > maxFd ) { maxFd = item->fd; } } LinkedListUnlock( ConnectionList ); } }
LinkedList_t *pluginFindPlugins( char *prefix, char *extension ) { LinkedList_t *list; PluginItem_t *item; struct dirent **namelist; int n; int i; int len; PluginSpec_t *spec; char *name; list = LinkedListCreate(); LinkedListLock( list ); ProtectedDataLock( extBlock ); if( extBlock->data ) { spec = (PluginSpec_t *)extBlock->data; if( spec->prefix ) { free( spec->prefix ); } if( spec->extension ) { free( spec->extension ); } free( extBlock->data ); } spec = (PluginSpec_t *)malloc(sizeof(PluginSpec_t)); memset( spec, 0, sizeof(PluginSpec_t) ); extBlock->data = (void *)spec; if( prefix ) { spec->prefix = strdup( prefix ); spec->prefLen = strlen( prefix ); } spec->extension = strdup( extension ); spec->extLen = strlen( extension ); n = scandir( PLUGIN_PATH, &namelist, filterFile, alphasort ); for( i = 0; i < n; i++ ) { item = (PluginItem_t *)malloc(sizeof(PluginItem_t)); name = namelist[i]->d_name; len = strlen(name); item->plugin = strndup( &name[spec->prefLen], len - spec->prefLen - spec->extLen ); item->script = strdup( name ); LinkedListAdd( list, (LinkedListItem_t*)item, LOCKED, AT_TAIL ); free( namelist[i] ); } ProtectedDataUnlock( extBlock ); if( n >= 0 ) { free( namelist ); } LinkedListUnlock( list ); return( list ); }