void regexp_remove( char *channelRegexp, char *contentRegexp ) { LinkedListItem_t *item; Regexp_t *regexp; if( !channelRegexp ) { channelRegexp = channelsAll; } LinkedListLock( regexpList ); for( item = regexpList->head; item; item = item->next ) { regexp = (Regexp_t *)item; if( !strcmp( channelRegexp, regexp->channelRegexp ) && !strcmp( contentRegexp, regexp->contentRegexp ) ) { LinkedListRemove( regexpList, item, LOCKED ); free( regexp->reChannel ); free( regexp->peChannel ); free( regexp->reContent ); free( regexp->peContent ); free( item ); LinkedListUnlock( regexpList ); return; } } LinkedListUnlock( regexpList ); }
void serverUnvisit( BalancedBTreeItem_t *node ) { IRCServer_t *server; IRCChannel_t *channel; LinkedListItem_t *item; if( !node ) { return; } serverUnvisit( node->left ); server = (IRCServer_t *)node->item; server->visited = FALSE; if( server->channels ) { LinkedListLock( server->channels ); for( item = server->channels->head; item; item = item->next ) { channel = (IRCChannel_t *)item; channel->visited = FALSE; } LinkedListUnlock( server->channels ); } serverUnvisit( node->right ); }
void ProcOnDisconnected(BN_PInfo I, const char Msg[]) { LinkedListItem_t *item; IRCServer_t *server; IRCChannel_t *channel; server = (IRCServer_t *)I->User; if( verbose ) { LogPrint( LOG_DEBUG, "Event Disconnected : (%s)", Msg); } if( GlobalAbort ) { if( server->channels ) { LinkedListLock( server->channels ); for( item = server->channels->head; item ; item = item->next ) { channel = (IRCChannel_t *)item; if( channel->enabled ) { db_nick_history( channel, "", HIST_END ); } } LinkedListUnlock( server->channels ); } LogPrint( LOG_NOTICE, "Killing thread for %s@%s:%d", server->nick, server->server, server->port ); pthread_exit( NULL ); } }
void ProcOnJoinChannel(BN_PInfo I, const char Chan[]) { bool found; LinkedListItem_t *item; IRCServer_t *server; IRCChannel_t *channel; server = (IRCServer_t *)I->User; LogPrint( LOG_NOTICE, "Joined channel %s on server %s", Chan, server->server); if( server->channels ) { LinkedListLock( server->channels ); for( found = false, item = server->channels->head; item && !found; item = item->next ) { channel = (IRCChannel_t *)item; if( channel->joined || !channel->enabled ) { continue; } if( !strcasecmp(Chan, channel->channel) ) { channel->joined = TRUE; channel->newChannel = FALSE; db_flush_nicks( channel ); continue; } transmitMsg( server, TX_JOIN, channel->channel, NULL ); found = true; } LinkedListUnlock( server->channels ); } }
void ProcOnRegistered(BN_PInfo I) { bool found; LinkedListItem_t *item; IRCServer_t *server; IRCChannel_t *channel; server = (IRCServer_t *)I->User; if( verbose ) { LogPrintNoArg( LOG_DEBUG, "Event Registered"); } if( strcmp(server->nickserv, "") ) { /* We need to register with nickserv */ transmitMsg( server, TX_PRIVMSG, server->nickserv, server->nickservmsg ); } if( server->channels ) { LinkedListLock( server->channels ); for( found = false, item = server->channels->head; item && !found; item = item->next ) { channel = (IRCChannel_t *)item; if( channel->joined || !channel->enabled ) { continue; } transmitMsg( server, TX_JOIN, channel->channel, NULL ); found = true; } LinkedListUnlock( server->channels ); } }
void regexp_parse( IRCServer_t *server, IRCChannel_t *channel, char *who, char *msg, IRCMsgType_t type ) { LinkedListItem_t *item; Regexp_t *regexp; int rc; int lenMsg; int lenChan; int ovector[30]; int start; if( !channel ) { return; } lenMsg = strlen( msg ); lenChan = strlen( channel->fullspec ); LinkedListLock( regexpList ); for( item = regexpList->head; item; item = item->next ) { regexp = (Regexp_t *)item; rc = pcre_exec( regexp->reChannel, regexp->peChannel, channel->fullspec, lenChan, 0, 0, ovector, 30 ); if( rc < 0 ) { /* Channels don't match */ continue; } for( rc = 1, start = 0; rc > 0; start = ovector[1] ) { rc = pcre_exec( regexp->reContent, regexp->peContent, msg, lenMsg, start, 0, ovector, 30 ); if( rc >= 0 ) { /* We got a channel and content match, call the function */ regexp->func( server, channel, who, msg, type, ovector, rc, regexp->tag ); } } } LinkedListUnlock( regexpList ); }
void QueueKillAll( void ) { LinkedListItem_t *listItem; QueueObject_t *queue; LinkedListLock(QueueList); for (listItem = QueueList->head; listItem; listItem = listItem->next) { queue = (QueueObject_t *) listItem; /* We don't want to flush the log messages */ if( queue == LoggingQ ) { continue; } /* * To allow all listeners to wake up and hear the GlobalAbort, * signal both the cNotEmpty and the cNotFull to all */ pthread_cond_broadcast(queue->cNotEmpty); pthread_cond_broadcast(queue->cNotFull); } LinkedListUnlock(QueueList); }
bool LogFileRemove( char *filename ) { LogFileChain_t *logfile; LinkedListItem_t *listItem; bool found; if( filename == NULL ) { return( FALSE ); } LinkedListLock( LogList ); for( listItem = LogList->head, found = FALSE; listItem != NULL; listItem = listItem->next ) { logfile = (LogFileChain_t *)listItem; if( logfile->type == LT_FILE && strcmp( filename, logfile->identifier.filename ) == 0 ) { LogOutputRemove( logfile ); LogPrint( LOG_INFO, "Removed log file: %s", filename ); found = TRUE; /* Take an early exit from the loop */ break; } } if( found == FALSE ) { LogPrint( LOG_UNKNOWN, "Can't find log file: %s", filename ); } LinkedListUnlock( LogList ); return( found ); }
/** * @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 ); } }
void *bot_server_thread(void *arg) { BN_TInfo *Info; IRCServer_t *server; IRCChannel_t *channel; LinkedListItem_t *item; sigset_t sigmsk; server = (IRCServer_t *)arg; if( !server ) { return(NULL); } sigemptyset( &sigmsk ); pthread_sigmask( SIG_SETMASK, &sigmsk, NULL ); Info = &server->ircInfo; memset(Info, 0, sizeof(BN_TInfo)); Info->User = (void *)server; Info->CB.OnConnected = ProcOnConnected; Info->CB.OnJoinChannel = ProcOnJoinChannel; Info->CB.OnRegistered = ProcOnRegistered; Info->CB.OnUnknown = ProcOnUnknown; Info->CB.OnDisconnected = ProcOnDisconnected; Info->CB.OnError = ProcOnError; Info->CB.OnNotice = ProcOnNotice; Info->CB.OnStatus = ProcOnStatus; Info->CB.OnCTCP = ProcOnCTCP; Info->CB.OnCTCPReply = ProcOnCTCPReply; Info->CB.OnWhois = ProcOnWhois; Info->CB.OnMode = ProcOnMode; Info->CB.OnModeIs = ProcOnModeIs; Info->CB.OnNames = ProcOnNames; Info->CB.OnWho = ProcOnWho; Info->CB.OnBanList = ProcOnBanList; Info->CB.OnList = ProcOnList; Info->CB.OnKill = ProcOnKill; Info->CB.OnInvite = ProcOnInvite; Info->CB.OnTopic = ProcOnTopic; Info->CB.OnKick = ProcOnKick; Info->CB.OnPrivateTalk = ProcOnPrivateTalk; Info->CB.OnAction = ProcOnAction; Info->CB.OnChannelTalk = ProcOnChannelTalk; Info->CB.OnNick = ProcOnNick; Info->CB.OnJoin = ProcOnJoin; Info->CB.OnPart = ProcOnPart; Info->CB.OnQuit = ProcOnQuit; Info->CB.OnExcessFlood = ProcOnExcessFlood; LogPrint( LOG_NOTICE, "Connecting to %s:%d as %s...", server->server, server->port, server->nick); while (BN_Connect(Info, server->server, server->port, 0) != true) { LogPrint( LOG_NOTICE, "Disconnected from %s:%d as %s.", server->server, server->port, server->nick); if( GlobalAbort || server->threadAbort ) { break; } sleep(10); /* Clear the joined flags so we will rejoin on reconnect */ if( server->channels ) { LinkedListLock( server->channels ); for( item = server->channels->head; item ; item = item->next ) { channel = (IRCChannel_t *)item; channel->joined = FALSE; } LinkedListUnlock( server->channels ); } LogPrint( LOG_NOTICE, "Reconnecting to %s:%d as %s...", server->server, server->port, server->nick); } if( server->channels ) { LinkedListLock( server->channels ); for( item = server->channels->head; item ; item = item->next ) { channel = (IRCChannel_t *)item; db_nick_history( channel, "", HIST_END ); } LinkedListUnlock( server->channels ); } LogPrint( LOG_NOTICE, "Exiting thread for %s@%s:%d", server->nick, server->server, server->port ); return(NULL); }
void botSighup( int signum, void *arg ) { IRCServer_t *server; LinkedListItem_t *listItem, *next; BalancedBTreeItem_t *item; IRCChannel_t *channel; bool newChannel = FALSE; server = (IRCServer_t *)arg; if( !server ) { return; } /* * Check each channel on the server, leave those no longer needed */ if( server->channels ) { LinkedListLock( server->channels ); BalancedBTreeLock( server->channelName ); BalancedBTreeLock( server->channelNum ); for( listItem = server->channels->head; listItem; listItem = next ) { next = listItem->next; channel = (IRCChannel_t *)listItem; if( !channel->visited ) { channelLeave( server, channel, channel->channel ); regexpBotCmdRemove( server, channel ); LinkedListRemove( server->channels, listItem, LOCKED ); item = BalancedBTreeFind( server->channelName, &channel->channel, LOCKED ); if( item ) { BalancedBTreeRemove( server->channelName, item, LOCKED, FALSE ); } item = BalancedBTreeFind( server->channelNum, &channel->channelId, LOCKED ); if( item ) { BalancedBTreeRemove( server->channelNum, item, LOCKED, FALSE ); } ThreadAllNotifyChannel( channel ); cursesMenuItemRemove( 2, MENU_CHANNELS, channel->menuText ); free( channel->menuText ); free( channel->channel ); free( channel->fullspec ); free( channel->url ); free( channel ); } else if( channel->newChannel && channel->enabled && !channel->joined && !newChannel ) { newChannel = TRUE; transmitMsg( server, TX_JOIN, channel->channel, NULL ); } else if( channel->newChannel && !channel->enabled ) { channel->newChannel = FALSE; } } BalancedBTreeUnlock( server->channelNum ); BalancedBTreeUnlock( server->channelName ); LinkedListUnlock( server->channels ); } }
void LogItemOutput( void *vitem ) { LoggingItem_t *item; struct tm ts; char line[MAX_STRING_LENGTH]; char usPart[9]; char timestamp[TIMESTAMP_MAX]; int length; LinkedListItem_t *listItem, *next; LogFileChain_t *logFile; static char *unknown = "thread_unknown"; char *threadName; if( !vitem ) { return; } item = (LoggingItem_t *)vitem; localtime_r( (const time_t *)&(item->tv.tv_sec), &ts ); strftime( timestamp, TIMESTAMP_MAX-8, "%Y-%b-%d %H:%M:%S", (const struct tm *)&ts ); snprintf( usPart, 9, ".%06d ", (int)(item->tv.tv_usec) ); strcat( timestamp, usPart ); length = strlen( timestamp ); LinkedListLock( LogList ); for( listItem = LogList->head; listItem; listItem = next ) { logFile = (LogFileChain_t *)listItem; next = listItem->next; switch( logFile->type ) { case LT_SYSLOG: syslog( item->level, "%s", item->message ); break; case LT_CONSOLE: sprintf( line, "%s %s\n", timestamp, item->message ); LogWrite( logFile, line, strlen(line) ); break; case LT_FILE: threadName = thread_name( item->threadId ); if( !threadName ) { threadName = unknown; } sprintf( line, "%s %s %s:%d (%s) - %s\n", timestamp, threadName, item->file, item->line, item->function, item->message ); LogWrite( logFile, line, strlen(line) ); break; case LT_NCURSES: sprintf( line, "%s %s\n", timestamp, item->message ); cursesLogWrite( line ); break; default: break; } if( logFile->aborted ) { LogOutputRemove( logFile ); } } LinkedListUnlock( LogList ); free( item->message ); free( item ); }
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 ); }