void t_flushed (transfer * const t) { ir_uint64 timetookms; char *tempstr; updatecontext(); if (t->lastack < t->xpack->st_size) { return; } tempstr = mymalloc(maxtextlength); tempstr[0] = 0; timetookms = gdata.curtimems - t->connecttimems; if (timetookms < 1U) { timetookms = 1; } if (timetookms > (60*60*1000U)) { snprintf(tempstr+strlen(tempstr), maxtextlength-strlen(tempstr), " %" LLPRINTFMT "u hr", timetookms/60/60/1000); } if ((timetookms%(60*60*1000U)) > (60*1000U)) { snprintf(tempstr+strlen(tempstr), maxtextlength-strlen(tempstr), " %" LLPRINTFMT "u min", (timetookms%(60*60*1000))/60/1000); } snprintf(tempstr+strlen(tempstr), maxtextlength-strlen(tempstr), " %" LLPRINTFMT "u.%03" LLPRINTFMT "u sec", (timetookms%(60*1000))/1000, (timetookms%1000)); ioutput(OUT_S|OUT_L|OUT_D, COLOR_YELLOW, "XDCC [%02i:%s on %s]: Transfer Completed (%" LLPRINTFMT "d kB,%s, %0.1f kB/sec)", t->id, t->nick, gdata.networks[ t->net ].name, (t->xpack->st_size-t->startresume)/1024, tempstr, ((float)(t->xpack->st_size-t->startresume))/1024.0/((float)timetookms/1000.0)); ioutput(OUT_S|OUT_L|OUT_D, COLOR_YELLOW, "Log: Pack %u, Nick %s" ", Network %s" ", Sent %" LLPRINTFMT "d kB" ", Recv %" LLPRINTFMT "d kB" ", File %s", number_of_pack(t->xpack), t->nick, gdata.networks[ t->net ].name, (t->xpack->st_size-t->startresume)/1024, t->bytesgot/1024, t->xpack->desc ); if (t->quietmode == 0) { if (t->xpack->has_md5sum) { notice(t->nick, "** Transfer Completed (%" LLPRINTFMT "d kB,%s, %0.1f kB/sec, md5sum: " MD5_PRINT_FMT ")", (t->xpack->st_size-t->startresume)/1024, tempstr, ((float)(t->xpack->st_size-t->startresume))/1024.0/((float)timetookms/1000.0), MD5_PRINT_DATA(t->xpack->md5sum)); } else { notice(t->nick, "** Transfer Completed (%" LLPRINTFMT "d kB,%s, %0.1f kB/sec)", (t->xpack->st_size-t->startresume)/1024, tempstr, ((float)(t->xpack->st_size-t->startresume))/1024.0/((float)timetookms/1000.0)); } } if (gdata.download_completed_msg) { notice_slow(t->nick, "%s", gdata.download_completed_msg); } if ( ((float)(t->xpack->st_size-t->startresume))/1024.0/((float)timetookms/1000.0) > gdata.record ) { gdata.record = ((float)(t->xpack->st_size-t->startresume))/1024.0/((float)timetookms/1000.0); } if (gdata.debug > 0) { ioutput(OUT_S, COLOR_YELLOW, "clientsock = %d", t->con.clientsocket); } shutdown_close(t->con.clientsocket); t->xpack->file_fd_count--; if (!t->xpack->file_fd_count && (t->xpack->file_fd != FD_UNUSED)) { close(t->xpack->file_fd); t->xpack->file_fd = FD_UNUSED; t->xpack->file_fd_location = 0; } t->tr_status = TRANSFER_STATUS_DONE; t->xpack->gets++; if ((t->xpack->dlimit_max != 0) && (t->xpack->gets >= t->xpack->dlimit_used)) { ioutput(OUT_S|OUT_L|OUT_D, COLOR_YELLOW, "Reached Pack Download Limit %u for %s", t->xpack->dlimit_max, t->xpack->desc); /* remove queued users */ queue_pack_limit(&gdata.mainqueue, t->xpack); queue_pack_limit(&gdata.idlequeue, t->xpack); } mydelete(tempstr); }
static void mainloop (void) { /* data is persistant across calls */ static struct timeval timestruct; static int changequartersec, changesec, changemin, changehour; static time_t lasttime, lastmin, lasthour, last4sec, last5sec, last20sec; static time_t lastautoadd; static time_t last3min, last2min, lastignoredec; static int first_loop = 1; static ir_uint64 last250ms; userinput *pubplist; userinput *urehash; ir_uint64 xdccsent; unsigned int i; int highests; unsigned int ss; upload *ul; transfer *tr; channel_t *ch; xdcc *xd; dccchat_t *chat; updatecontext(); gnetwork = NULL; if (first_loop) { /* init if first time called */ FD_ZERO(&gdata.readset); FD_ZERO(&gdata.writeset); changehour=changemin=changesec=changequartersec=0; gettimeofday(×truct, NULL); last250ms = gdata.curtimems; gdata.curtimems = timeval_to_ms(×truct); ioutput(OUT_S|OUT_L|OUT_D, COLOR_NO_COLOR, "Startup" " running: %ld ms", (long)(gdata.curtimems - last250ms)); gdata.curtime = timestruct.tv_sec; lasttime=gdata.curtime; last250ms = gdata.curtimems; lastmin=(lasttime/60)-1; lasthour=(lasttime/60/60)-1; last4sec = last5sec = last20sec = last2min = last3min = lasttime; lastignoredec = lasttime; for (ss=0; ss<gdata.networks_online; ss++) { gdata.networks[ss].lastnotify = lasttime; gdata.networks[ss].lastslow = lasttime; gdata.networks[ss].server_input_line[0] = '\0'; } gdata.cursendptr = 0; lastautoadd = gdata.curtime + 60; first_loop = 0; } updatecontext(); FD_ZERO(&gdata.readset); FD_ZERO(&gdata.writeset); FD_ZERO(&gdata.execset); highests = 0; #ifdef USE_CURL fetch_multi_fdset(&gdata.readset, &gdata.writeset, &gdata.execset, &highests); #endif /* USE_CURL */ highests = irc_select(highests); if (!gdata.background) { FD_SET(fileno(stdin), &gdata.readset); highests = max2(highests, fileno(stdin)); } highests = chat_select_fdset(highests); highests = t_select_fdset(highests, changequartersec); highests = l_select_fdset(highests, changequartersec); #ifndef WITHOUT_TELNET highests = telnet_select_fdset(highests); #endif /* WITHOUT_TELNET */ #ifndef WITHOUT_HTTP highests = h_select_fdset(highests, changequartersec); #endif /* WITHOUT_HTTP */ if (gdata.md5build.file_fd != FD_UNUSED) { assert(gdata.md5build.xpack); FD_SET(gdata.md5build.file_fd, &gdata.readset); highests = max2(highests, gdata.md5build.file_fd); } updatecontext(); if (gdata.debug > 81) { select_dump("try", highests); } if (gdata.attop) gotobot(); tostdout_write(); gettimeofday(×truct, NULL); gdata.selecttimems = timeval_to_ms(×truct); if (ir_kqueue_select(highests+1, &gdata.readset, &gdata.writeset, &gdata.execset) < 0) { if (errno != EINTR) { outerror(OUTERROR_TYPE_WARN,"Select returned an error: %s",strerror(errno)); usleep(10000); /* prevent fast spinning */ } /* data is undefined on error, zero and continue */ FD_ZERO(&gdata.readset); FD_ZERO(&gdata.writeset); FD_ZERO(&gdata.execset); } if (gdata.debug > 81) { select_dump("got", highests); } /*----- one second check ----- */ updatecontext(); if (gettimeofday(×truct, NULL) < 0) { outerror(OUTERROR_TYPE_CRASH,"gettimeofday() failed! %s\n",strerror(errno)); } gdata.curtimems = timeval_to_ms(×truct); gdata.curtime = timestruct.tv_sec; if (gdata.curtimems > gdata.selecttimems + 1000) outerror(OUTERROR_TYPE_WARN, "Iroffer was blocked for %lims", (long)(gdata.curtimems - gdata.selecttimems)); /* adjust for drift and cpu usage */ if ((gdata.curtimems > (last250ms+1000)) || (gdata.curtimems < last250ms)) { /* skipped forward or backwards, correct */ last250ms = gdata.curtimems-250; } if (gdata.curtimems >= (last250ms+250)) { changequartersec = 1; /* note bandwidth limiting requires no drift! */ last250ms += 250; } else { changequartersec = 0; } changesec = 0; if (gdata.curtime != lasttime) { if (gdata.curtime < lasttime - MAX_WAKEUP_WARN) { outerror(OUTERROR_TYPE_WARN, "System Time Changed Backwards %lim %lis!!\n", (long)(lasttime-gdata.curtime)/60, (long)(lasttime-gdata.curtime)%60); } if (gdata.curtime > lasttime + MAX_WAKEUP_WARN) { outerror(OUTERROR_TYPE_WARN, "System Time Changed Forward or Mainloop Skipped %lim %lis!!\n", (long)(gdata.curtime-lasttime)/60, (long)(gdata.curtime-lasttime)%60); if (gdata.debug > 0) { dump_slow_context(); } } if (gdata.curtime > lasttime + MAX_WAKEUP_ERR) { outerror(OUTERROR_TYPE_WARN, "System Time Changed Forward or Mainloop Skipped %lim %lis!!\n", (long)(gdata.curtime-lasttime)/60, (long)(gdata.curtime-lasttime)%60); if (gdata.debug > 0) { dumpcontext(); } } lasttime = gdata.curtime; changesec = 1; } if (changesec && lasttime/60/60 != lasthour) { lasthour = lasttime/60/60; changehour = 1; } if (changesec && lasttime/60 != lastmin) { lastmin = lasttime/60; changemin = 1; } if (gdata.needsshutdown) { gdata.needsshutdown = 0; shutdowniroffer(); } if (gdata.needsreap) { gdata.needsreap = 0; irc_resolved(); } #ifdef USE_CURL fetch_perform(); #endif /* USE_CURL */ updatecontext(); if (changesec) { gdata.totaluptime++; gdata.xdccsent[(gdata.curtime+1)%XDCC_SENT_SIZE] = 0; gdata.xdccrecv[(gdata.curtime+1)%XDCC_SENT_SIZE] = 0; xdccsent = 0; for (i=0; i<XDCC_SENT_SIZE; i++) xdccsent += (ir_uint64)gdata.xdccsum[i]; if (((float)xdccsent)/XDCC_SENT_SIZE/1024.0 > gdata.sentrecord) gdata.sentrecord = ((float)xdccsent)/XDCC_SENT_SIZE/1024.0; gdata.xdccsum[(gdata.curtime+1)%XDCC_SENT_SIZE] = 0; run_delayed_jobs(); } updatecontext(); /*----- see if anything waiting on console ----- */ gdata.needsclear = 0; if (!gdata.background && FD_ISSET(fileno(stdin), &gdata.readset)) parseconsole(); irc_perform(changesec); l_perform(changesec); chat_perform(); t_perform(changesec, changequartersec); #ifndef WITHOUT_TELNET telnet_perform(); #endif /* WITHOUT_TELNET */ #ifndef WITHOUT_HTTP h_perform(changesec, changequartersec); #endif /* WITHOUT_HTTP */ /*----- time for a delayed shutdown? ----- */ if (changesec && gdata.delayedshutdown) { if (!irlist_size(&gdata.trans)) { ioutput(OUT_S|OUT_L|OUT_D, COLOR_NO_COLOR, "Delayed Shutdown Activated, No Transfers Remaining"); shutdowniroffer(); } } updatecontext(); for (ss=0; ss<gdata.networks_online; ss++) { gnetwork = &(gdata.networks[ss]); /*----- send server stuff ----- */ if (changesec) { sendserver(); if (gdata.curtime%INAMNT_SIZE == (INAMNT_SIZE-1)) gnetwork->inamnt[0] = 0; else gnetwork->inamnt[gdata.curtime%INAMNT_SIZE+1] = 0; } /*----- see if we can send out some xdcc lists */ if (changesec && gnetwork->serverstatus == SERVERSTATUS_CONNECTED) { if (!irlist_size((&gnetwork->serverq_normal)) && !irlist_size(&(gnetwork->serverq_slow))) sendxdlqueue(); } } gnetwork = NULL; /*----- see if its time to change maxb */ if (changehour) { gdata.maxb = gdata.overallmaxspeed; if (gdata.overallmaxspeeddayspeed != gdata.overallmaxspeed) { struct tm *localt; localt = localtime(&gdata.curtime); if ((unsigned int)localt->tm_hour >= gdata.overallmaxspeeddaytimestart && (unsigned int)localt->tm_hour < gdata.overallmaxspeeddaytimeend && ( gdata.overallmaxspeeddaydays & (1 << (unsigned int)localt->tm_wday)) ) gdata.maxb = gdata.overallmaxspeeddayspeed; } isrotatelog(); expire_options(); } /*----- see if we've hit a transferlimit or need to reset counters */ if (changesec) { unsigned int ii; unsigned int transferlimits_over = 0; for (ii=0; ii<NUMBER_TRANSFERLIMITS; ii++) { /* reset counters? */ if ((!gdata.transferlimits[ii].ends) || (gdata.transferlimits[ii].ends < gdata.curtime)) { struct tm *localt; if (gdata.transferlimits[ii].limit && gdata.transferlimits[ii].ends) { ioutput(OUT_S|OUT_L|OUT_D, COLOR_NO_COLOR, "Resetting %s transfer limit, used %" LLPRINTFMT "uMB of the %" LLPRINTFMT "uMB limit", transferlimit_type_to_string(ii), gdata.transferlimits[ii].used / 1024 / 1024, gdata.transferlimits[ii].limit / 1024 / 1024); } /* find our next end time */ localt = localtime(&gdata.curtime); localt->tm_sec = localt->tm_min = localt->tm_hour = 0; /* midnight */ switch (ii) { case TRANSFERLIMIT_DAILY: /* tomorrow */ localt->tm_mday++; break; case TRANSFERLIMIT_WEEKLY: /* next sunday morning */ localt->tm_mday += 7 - localt->tm_wday; break; case TRANSFERLIMIT_MONTHLY: /* next month */ localt->tm_mday = gdata.start_of_month; localt->tm_mon++; break; default: outerror(OUTERROR_TYPE_CRASH, "unknown type %u", ii); } /* tm_wday and tm_yday are ignored in mktime() */ gdata.transferlimits[ii].ends = mktime(localt); gdata.transferlimits[ii].used = 0; if ( ii == TRANSFERLIMIT_DAILY ) reset_download_limits(); } if (!transferlimits_over && gdata.transferlimits[ii].limit && (gdata.transferlimits[ii].used >= gdata.transferlimits[ii].limit)) { transferlimits_over = 1 + ii; if (!gdata.transferlimits_over) { char *tempstr = transfer_limit_exceeded_msg(ii); ioutput(OUT_S|OUT_L|OUT_D, COLOR_NO_COLOR, "All %" LLPRINTFMT "uMB of the %s transfer limit used. Stopping transfers.", gdata.transferlimits[ii].limit / 1024 / 1024, transferlimit_type_to_string(ii)); /* remove queued users */ queue_all_remove(&gdata.mainqueue, tempstr); queue_all_remove(&gdata.idlequeue, tempstr); /* stop transfers */ for (tr = irlist_get_head(&gdata.trans); tr; tr = irlist_get_next(tr)) { if (tr->tr_status != TRANSFER_STATUS_DONE) { gnetwork = &(gdata.networks[tr->net]); t_closeconn(tr,tempstr,0); } } gnetwork = NULL; mydelete(tempstr); } } } if (gdata.transferlimits_over != transferlimits_over) { if (!transferlimits_over) { ioutput(OUT_S|OUT_L|OUT_D, COLOR_NO_COLOR, "No longer over any transfer limits. Transfers are now allowed."); } gdata.transferlimits_over = transferlimits_over; } } /*----- gdata.autoignore_threshold seconds ----- */ if (changesec && ((unsigned)gdata.curtime > (lastignoredec + gdata.autoignore_threshold))) { igninfo *ignore; lastignoredec += gdata.autoignore_threshold; ignore = irlist_get_head(&gdata.ignorelist); while(ignore) { ignore->bucket--; if ((ignore->flags & IGN_IGNORING) && (ignore->bucket == 0)) { ignore->flags &= ~IGN_IGNORING; ioutput(OUT_S|OUT_L|OUT_D, COLOR_NO_COLOR, "Ignore removed for %s",ignore->hostmask); write_statefile(); } if (ignore->bucket == 0) { mydelete(ignore->hostmask); ignore = irlist_delete(&gdata.ignorelist, ignore); } else { ignore = irlist_get_next(ignore); } } } /*----- periodicmsg_time seconds ----- */ if (changesec) { send_periodicmsg(); } updatecontext(); /*----- 5 seconds ----- */ if (changesec && (gdata.curtime - last5sec > 4)) { last5sec = gdata.curtime; updatecontext(); /*----- server timeout ----- */ for (ss=0; ss<gdata.networks_online; ss++) { gnetwork = &(gdata.networks[ss]); if (gdata.needsshutdown) continue; if ((gnetwork->serverstatus == SERVERSTATUS_CONNECTED) && (gdata.curtime > gnetwork->lastservercontact + SRVRTOUT)) { if (gnetwork->servertime < 3) { const char *servname = gnetwork->curserveractualname ? gnetwork->curserveractualname : gnetwork->curserver.hostname; size_t len = 6 + strlen(servname); char *tempstr3 = mymalloc(len + 1); snprintf(tempstr3, len + 1, "PING %s\n", servname); writeserver_ssl(tempstr3, len); if (gdata.debug > 0) { tempstr3[len-1] = '\0'; len--; ioutput(OUT_S, COLOR_MAGENTA, "<NORES<: %s", tempstr3); } mydelete(tempstr3); gnetwork->servertime++; } else if (gnetwork->servertime == 3) { ioutput(OUT_S|OUT_L|OUT_D, COLOR_RED, "Closing Server Connection on %s: No Response for %u minutes.", gnetwork->name, SRVRTOUT/60); close_server(); gnetwork->servertime = 0; } } /*----- ping server ----- */ if (gnetwork->recentsent) { pingserver(); gnetwork->recentsent--; } } } /* networks */ gnetwork = NULL; /*----- 4 seconds ----- */ if (changesec && (gdata.curtime - last4sec > 3)) { /*----- update lastspeed, check minspeed ----- */ tr = irlist_get_head(&gdata.trans); while(tr) { if ( tr->con.connecttime+(MIN_TL/2) > gdata.curtime ) /* initial */ { tr->lastspeed = (tr->lastspeed)*DCL_SPDW_I + (((float)(tr->bytessent-tr->lastspeedamt))/1024.0)*(1.0-DCL_SPDW_I)/((float)(gdata.curtime-last4sec)*1.0); } else /* ongoing */ { tr->lastspeed = (tr->lastspeed)*DCL_SPDW_O + (((float)(tr->bytessent-tr->lastspeedamt))/1024.0)*(1.0-DCL_SPDW_O)/((float)(gdata.curtime-last4sec)*1.0); } tr->lastspeedamt = tr->bytessent; t_checkminspeed(tr); tr = irlist_get_next(tr); } ul = irlist_get_head(&gdata.uploads); while(ul) { if ( ul->con.connecttime+(MIN_TL/2) > gdata.curtime ) /* initial */ { ul->lastspeed = (ul->lastspeed)*DCL_SPDW_I + (((float)(ul->bytesgot-ul->lastspeedamt))/1024.0)*(1.0-DCL_SPDW_I)/((float)(gdata.curtime-last4sec)*1.0); } else /* ongoing */ { ul->lastspeed = (ul->lastspeed)*DCL_SPDW_O + (((float)(ul->bytesgot-ul->lastspeedamt))/1024.0)*(1.0-DCL_SPDW_O)/((float)(gdata.curtime-last4sec)*1.0); } ul->lastspeedamt = ul->bytesgot; ul = irlist_get_next(ul); } last4sec = gdata.curtime; } updatecontext(); /*----- check for size change ----- */ if (changesec) checktermsize(); updatecontext(); for (ss=0; ss<gdata.networks_online; ss++) { gnetwork = &(gdata.networks[ss]); /*----- plist stuff ----- */ if ((gnetwork->serverstatus == SERVERSTATUS_CONNECTED) && changemin && irlist_size(&gdata.xdccs) && !gdata.transferlimits_over && (irlist_size(&(gnetwork->serverq_channel)) < irlist_size(&gdata.xdccs)) && (!gdata.queuesize || irlist_size(&gdata.mainqueue) < gdata.queuesize) && (gdata.nolisting <= gdata.curtime)) { char *tchanf = NULL, *tchanm = NULL, *tchans = NULL; for(ch = irlist_get_head(&(gnetwork->channels)); ch; ch = irlist_get_next(ch)) { if ((ch->flags & CHAN_ONCHAN) && (ch->nextann < gdata.curtime) && ch->plisttime && (((gdata.curtime / 60) % ch->plisttime) == ch->plistoffset)) { ch->nextmsg = gdata.curtime + ch->delay; if (ch->pgroup != NULL) { ioutput(OUT_S|OUT_D, COLOR_NO_COLOR, "Plist sent to %s (pgroup)", ch->name); pubplist = mycalloc(sizeof(userinput)); pubplist->method = method_xdl_channel; pubplist->net = gnetwork->net; pubplist->level = ADMIN_LEVEL_PUBLIC; a_fillwith_plist(pubplist, ch->name, ch); u_parseit(pubplist); mydelete(pubplist); continue; } if (ch->flags & CHAN_MINIMAL) { if (tchanm) { strncat(tchanm,",",maxtextlength-strlen(tchanm)-1); strncat(tchanm,ch->name,maxtextlength-strlen(tchanm)-1); } else { tchanm = mymalloc(maxtextlength); strncpy(tchanm,ch->name,maxtextlength-1); } } else if (ch->flags & CHAN_SUMMARY) { if (tchans) { strncat(tchans,",",maxtextlength-strlen(tchans)-1); strncat(tchans,ch->name,maxtextlength-strlen(tchans)-1); } else { tchans = mymalloc(maxtextlength); strncpy(tchans,ch->name,maxtextlength-1); } } else { if (tchanf) { strncat(tchanf,",",maxtextlength-strlen(tchanf)-1); strncat(tchanf,ch->name,maxtextlength-strlen(tchanf)-1); } else { tchanf = mymalloc(maxtextlength); strncpy(tchanf,ch->name,maxtextlength-1); } } } } if (tchans) { if (gdata.restrictprivlist && !gdata.creditline && !irlist_size(&gdata.headline)) { ioutput(OUT_S|OUT_D, COLOR_NO_COLOR, "Can't send Summary Plist to %s (restrictprivlist is set and no creditline or headline, summary makes no sense!)", tchans); } else { ioutput(OUT_S|OUT_D, COLOR_NO_COLOR, "Plist sent to %s (summary)", tchans); pubplist = mycalloc(sizeof(userinput)); a_fillwith_msg2(pubplist, tchans, "XDL"); pubplist->method = method_xdl_channel_sum; u_parseit(pubplist); mydelete(pubplist); } mydelete(tchans); } if (tchanf) { ioutput(OUT_S|OUT_D, COLOR_NO_COLOR, "Plist sent to %s (full)", tchanf); pubplist = mycalloc(sizeof(userinput)); a_fillwith_plist(pubplist, tchanf, NULL); pubplist->method = method_xdl_channel; u_parseit(pubplist); mydelete(pubplist); mydelete(tchanf); } if (tchanm) { ioutput(OUT_S|OUT_D, COLOR_NO_COLOR, "Plist sent to %s (minimal)", tchanm); pubplist = mycalloc(sizeof(userinput)); a_fillwith_msg2(pubplist, tchanm, "XDL"); pubplist->method = method_xdl_channel_min; u_parseit(pubplist); mydelete(pubplist); mydelete(tchanm); } } } /* networks */ gnetwork = NULL; updatecontext(); /*----- low bandwidth send, save state file ----- */ if (changesec && (gdata.curtime - last3min > 180)) { last3min = gdata.curtime; xdccsent = 0; for (i=0; i<XDCC_SENT_SIZE; i++) xdccsent += (ir_uint64)gdata.xdccsent[i]; xdccsent /= XDCC_SENT_SIZE*1024; if ((xdccsent < (unsigned)gdata.lowbdwth) && !gdata.exiting && irlist_size(&gdata.mainqueue) && (irlist_size(&gdata.trans) < gdata.maxtrans)) { check_idle_queue(0); send_from_queue(1, 0, NULL); } write_files(); } updatecontext(); for (ss=0; ss<gdata.networks_online; ss++) { gnetwork = &(gdata.networks[ss]); /*----- queue notify ----- */ if (changesec && gdata.notifytime && (!gdata.quietmode) && ((unsigned)gdata.curtime > (gnetwork->lastnotify + (gdata.notifytime*60)))) { gnetwork->lastnotify = gdata.curtime; if (gnetwork->serverstatus == SERVERSTATUS_CONNECTED) { if ((irlist_size(&(gnetwork->serverq_fast)) >= 10) || (irlist_size(&(gnetwork->serverq_normal)) >= 10) || (irlist_size(&(gnetwork->serverq_slow)) >= 50)) { ioutput(OUT_S|OUT_D|OUT_L, COLOR_NO_COLOR, "notifications skipped on %s, server queue is rather large", gnetwork->name); } else { notifyqueued(); notifybandwidth(); notifybandwidthtrans(); } } } } /* networks */ gnetwork = NULL; updatecontext(); /*----- log stats / remote admin stats ----- */ if ( changesec && ((unsigned)gdata.curtime >= (last2min + gdata.status_time_dcc_chat))) { last2min = gdata.curtime; if (gdata.logstats) { logstat(); chat_writestatus(); } } updatecontext(); /* look to see if any files changed */ if (changesec) look_for_file_remove(); updatecontext(); /*----- 20 seconds ----- */ if (changesec && (gdata.curtime - last20sec > 19)) { expire_badip(); if (gdata.logfd != FD_UNUSED) { /* cycle */ close(gdata.logfd); gdata.logfd = FD_UNUSED; } updatecontext(); for (ss=0; ss<gdata.networks_online; ss++) { gnetwork = &(gdata.networks[ss]); /* try rejoining channels not on */ ch = irlist_get_head(&(gnetwork->channels)); while(ch) { if ((gnetwork->serverstatus == SERVERSTATUS_CONNECTED) && !(ch->flags & CHAN_ONCHAN)) { joinchannel(ch); } ch = irlist_get_next(ch); } } /* networks */ gnetwork = NULL; last20sec = gdata.curtime; updatecontext(); for (ss=0; ss<gdata.networks_online; ss++) { gnetwork = &(gdata.networks[ss]); /* try to regain nick */ if (!gnetwork->user_nick || strcmp(get_config_nick(), gnetwork->user_nick)) { writeserver(WRITESERVER_NORMAL, "NICK %s", get_config_nick()); } } /* networks */ gnetwork = NULL; updatecontext(); /* update status line */ if (!gdata.background && !gdata.noscreen) { char tempstr[maxtextlength]; char tempstr2[maxtextlengthshort]; if (gdata.attop) gotobot(); tostdout(IRVT_SAVE_CURSOR); getstatusline(tempstr,maxtextlength); tempstr[min2(maxtextlength-2,gdata.termcols-4)] = '\0'; snprintf(tempstr2, maxtextlengthshort, IRVT_CURSOR_HOME1 "[ %%-%us ]", gdata.termlines - 1, gdata.termcols - 4); tostdout(tempstr2,tempstr); tostdout(IRVT_CURSOR_HOME2 IRVT_UNSAVE_CURSOR, gdata.termlines, gdata.termcols); } admin_jobs(); #ifdef USE_RUBY rehash_myruby(1); #endif /* USE_RUBY */ delayed_announce(); } updatecontext(); if (changemin) { reverify_restrictsend(); update_hour_dinoex(lastmin); check_idle_queue(0); clean_uploadhost(); auto_rehash(); } updatecontext(); if ((gdata.md5build.file_fd != FD_UNUSED) && FD_ISSET(gdata.md5build.file_fd, &gdata.readset)) { ssize_t howmuch; #if defined(_OS_CYGWIN) int reads_per_loop = 32; #else /* _OS_CYGWIN */ int reads_per_loop = 64; #endif /* _OS_CYGWIN */ assert(gdata.md5build.xpack); while (reads_per_loop--) { howmuch = read(gdata.md5build.file_fd, gdata.sendbuff, BUFFERSIZE); if (gdata.debug >30) { ioutput(OUT_S, COLOR_YELLOW, "MD5: [Pack %u] read %ld", number_of_pack(gdata.md5build.xpack), (long)howmuch); } if ((howmuch < 0) && (errno != EAGAIN)) { outerror(OUTERROR_TYPE_WARN, "MD5: [Pack %u] Can't read data from file '%s': %s", number_of_pack(gdata.md5build.xpack), gdata.md5build.xpack->file, strerror(errno)); event_close(gdata.md5build.file_fd); gdata.md5build.file_fd = FD_UNUSED; gdata.md5build.xpack = NULL; break; } else if (howmuch < 0) { break; } else if (howmuch == 0) { /* EOF */ outerror(OUTERROR_TYPE_WARN, "MD5: [Pack %u] Can't read data from file '%s': %s", number_of_pack(gdata.md5build.xpack), gdata.md5build.xpack->file, "truncated"); start_md5_hash(gdata.md5build.xpack, number_of_pack(gdata.md5build.xpack)); break; } /* else got data */ MD5Update(&gdata.md5build.md5sum, gdata.sendbuff, howmuch); if (!gdata.nocrc32) crc32_update((char *)gdata.sendbuff, howmuch); gdata.md5build.bytes += howmuch; if (gdata.md5build.bytes == gdata.md5build.xpack->st_size) { complete_md5_hash(); break; } } } if (!gdata.nomd5sum && changesec && (!gdata.md5build.xpack)) { unsigned int packnum = 1; /* see if any pack needs a md5sum calculated */ if (gdata.nomd5_start <= gdata.curtime) for (xd = irlist_get_head(&gdata.xdccs); xd; xd = irlist_get_next(xd), packnum++) { if (!gdata.nocrc32) { if (!xd->has_crc32) xd->has_md5sum = 0; /* force recheck with crc */ } if (!xd->has_md5sum) { if (verifyshell(&gdata.md5sum_exclude, xd->file)) continue; if (!gdata.attop) gototop(); start_md5_hash(xd, packnum); break; } } } updatecontext(); if (gdata.exiting && has_closed_servers()) { for (chat = irlist_get_head(&gdata.dccchats); chat; chat = irlist_delete(&gdata.dccchats,chat)) { writedccchat(chat, 0, "iroffer exited, Closing DCC Chat\n"); shutdowndccchat(chat,1); } mylog("iroffer exited\n\n"); exit_iroffer(0); } updatecontext(); if (gdata.needsrehash) { gdata.needsrehash = 0; urehash = mycalloc(sizeof(userinput)); a_fillwith_msg2(urehash, NULL, "REHASH"); urehash->method = method_out_all; /* just OUT_S|OUT_L|OUT_D it */ urehash->net = 0; urehash->level = ADMIN_LEVEL_FULL; u_parseit(urehash); mydelete(urehash); } updatecontext(); chat = irlist_get_head(&gdata.dccchats); while (chat) { if (chat->status == DCCCHAT_UNUSED) { chat = irlist_delete(&gdata.dccchats,chat); } else { flushdccchat(chat); chat = irlist_get_next(chat); } } if (gdata.autoadd_time > 0) { if (changesec && ((unsigned)gdata.curtime > (lastautoadd + gdata.autoadd_time))) { lastautoadd = gdata.curtime; autoadd_all(); } } /* END */ updatecontext(); if (gdata.needsclear) drawbot(); changehour=changemin=0; }
unsigned int read_statefile(void) { int fd; ir_uint32 *buffer, *buffer_begin; ir_uint32 buffer_len; struct MD5Context md5sum; MD5Digest digest; struct stat st; statefile_hdr_t *hdr; ir_uint32 calluval; unsigned int save = 0; time_t timestamp = 0; updatecontext(); if (gdata.statefile == NULL) { return save; } ioutput(OUT_S|OUT_L|OUT_D, COLOR_NO_COLOR, "Loading State File... "); fd = open(gdata.statefile, O_RDONLY | O_CREAT | ADDED_OPEN_FLAGS, CREAT_PERMISSIONS ); if (fd < 0) { outerror(OUTERROR_TYPE_WARN_LOUD, "Cant Access State File '%s': %s", gdata.statefile, strerror(errno)); return ++save; } if ((fstat(fd, &st) < 0) || (st.st_size < ((off_t)(sizeof(ir_uint32) * 2) + (off_t)(sizeof(MD5Digest))))) { ioutput(OUT_S|OUT_L|OUT_D, COLOR_NO_COLOR, "State File: Too small, Skipping"); close(fd); return ++save; } buffer_len = st.st_size; buffer_begin = buffer = mycalloc(buffer_len); calluval = read(fd, buffer, buffer_len); close(fd); if (calluval != buffer_len) { outerror(OUTERROR_TYPE_WARN_LOUD, "Cant Read State File (%u != %u) %s", calluval, buffer_len, strerror(errno)); goto error_out; } /* verify md5sum */ buffer_len -= sizeof(MD5Digest); MD5Init(&md5sum); MD5Update(&md5sum, (md5byte*)buffer, buffer_len); MD5Final(digest, &md5sum); if (memcmp(digest, buffer+(buffer_len/sizeof(ir_uint32)), sizeof(MD5Digest))) { outerror(OUTERROR_TYPE_CRASH, "\"%s\" Appears corrupt or is not an iroffer state file", gdata.statefile); goto error_out; } /* read */ if (ntohl(*buffer) != STATEFILE_MAGIC) { outerror(OUTERROR_TYPE_CRASH, "\"%s\" Does not appear to be an iroffer state file", gdata.statefile); goto error_out; } buffer++; buffer_len -= sizeof(ir_uint32); if (gdata.debug > 0) { ioutput(OUT_S|OUT_L|OUT_D, COLOR_NO_COLOR, " [Version %u State File]", ntohl(*buffer)); } buffer++; buffer_len -= sizeof(ir_uint32); while ((hdr = read_statefile_item(&buffer, &buffer_len))) { switch (hdr->tag) { case STATEFILE_TAG_TIMESTAMP: read_statefile_time(hdr, "Timestamp", ×tamp, "Written on"); break; case STATEFILE_TAG_XFR_RECORD: read_statefile_float(hdr, "xfr Record", &(gdata.record), "Record"); break; case STATEFILE_TAG_SENT_RECORD: read_statefile_float(hdr, "sent Record", &(gdata.sentrecord), "Bandwidth Record"); break; case STATEFILE_TAG_TOTAL_SENT: read_statefile_llint(hdr, "Total Transferred", &(gdata.totalsent), "Total Transferred"); break; case STATEFILE_TAG_TOTAL_UPTIME: read_statefile_long(hdr, "Total Runtime", &(gdata.totaluptime)); if (gdata.debug > 0) { char *tempstr; tempstr = mymalloc(maxtextlength); getuptime(tempstr, 0, gdata.curtime-gdata.totaluptime, maxtextlength); ioutput(OUT_S|OUT_L|OUT_D, COLOR_NO_COLOR, " [Total Runtime %s]", tempstr); mydelete(tempstr); } break; case STATEFILE_TAG_LAST_LOGROTATE: read_statefile_time(hdr, "Last Log Rotate", &(gdata.last_logrotate), "Last Log Rotate"); break; case STATEFILE_TAG_IROFFER_VERSION: if (hdr->length > sizeof(statefile_hdr_t)) { char *iroffer_version = (char*)(&hdr[1]); char *iroffer_now; iroffer_version[hdr->length-sizeof(statefile_hdr_t)-1] = '\0'; if (gdata.debug > 0) { ioutput(OUT_S|OUT_L|OUT_D, COLOR_NO_COLOR, " [Written by %s]", iroffer_version); } iroffer_now = mycalloc(maxtextlength); snprintf(iroffer_now, maxtextlength, "iroffer-dinoex " VERSIONLONG ", %s", gdata.osstring); if (strcmp(iroffer_version, iroffer_now) != 0) { ++save; backup_statefile(); } mydelete(iroffer_now); } else { read_statefile_bad_tag(hdr, "Iroffer Version"); } break; case STATEFILE_TAG_IGNORE: { igninfo *ignore; statefile_hdr_t *ihdr; ignore = irlist_add(&gdata.ignorelist, sizeof(igninfo)); hdr->length -= sizeof(*hdr); ihdr = &hdr[1]; while (hdr->length >= sizeof(*hdr)) { ihdr->tag = ntohl(ihdr->tag); ihdr->length = ntohl(ihdr->length); switch (ihdr->tag) { case STATEFILE_TAG_IGNORE_FLAGS: read_statefile_int(ihdr, "Ignore Flags", &(ignore->flags)); break; case STATEFILE_TAG_IGNORE_BUCKET: read_statefile_long(ihdr, "Ignore Bucket", &(ignore->bucket)); break; case STATEFILE_TAG_IGNORE_LASTCONTACT: read_statefile_time(ihdr, "Ignore Lastcontact", &(ignore->lastcontact), NULL); break; case STATEFILE_TAG_IGNORE_HOSTMASK: read_statefile_string(ihdr, "Ignore Hostmask", &(ignore->hostmask)); break; default: read_statefile_unknown_tag(ihdr, "Ignore" ); } hdr->length -= ceiling(ihdr->length, 4); ihdr = (statefile_hdr_t*)(((char*)ihdr) + ceiling(ihdr->length, 4)); } if ((!ignore->lastcontact) || (!ignore->hostmask)) { read_statefile_incomplete_tag("Ignore" ); mydelete(ignore->hostmask); irlist_delete(&gdata.ignorelist, ignore); } else { ignore->bucket -= (gdata.curtime - timestamp)/gdata.autoignore_threshold; } } break; case STATEFILE_TAG_MSGLOG: { msglog_t *msglog; statefile_hdr_t *ihdr; msglog = irlist_add(&gdata.msglog, sizeof(msglog_t)); hdr->length -= sizeof(*hdr); ihdr = &hdr[1]; while (hdr->length >= sizeof(*hdr)) { ihdr->tag = ntohl(ihdr->tag); ihdr->length = ntohl(ihdr->length); switch (ihdr->tag) { case STATEFILE_TAG_MSGLOG_WHEN: read_statefile_time(ihdr, "Msglog When", &(msglog->when), NULL); break; case STATEFILE_TAG_MSGLOG_HOSTMASK: read_statefile_string(ihdr, "Msglog Hostmask", &(msglog->hostmask)); break; case STATEFILE_TAG_MSGLOG_MESSAGE: read_statefile_string(ihdr, "Msglog Message", &(msglog->message)); break; default: read_statefile_unknown_tag(ihdr, "Msglog" ); } hdr->length -= ceiling(ihdr->length, 4); ihdr = (statefile_hdr_t*)(((char*)ihdr) + ceiling(ihdr->length, 4)); } if ((!msglog->when) || (!msglog->hostmask) || (!msglog->message)) { read_statefile_incomplete_tag("Msglog" ); mydelete(msglog->hostmask); mydelete(msglog->message); irlist_delete(&gdata.msglog, msglog); } } break; case STATEFILE_TAG_XDCCS: { xdcc *xd; statefile_hdr_t *ihdr; xd = irlist_add(&gdata.xdccs, sizeof(xdcc)); xd->file_fd = FD_UNUSED; xd->minspeed = gdata.transferminspeed; xd->maxspeed = gdata.transfermaxspeed; hdr->length -= sizeof(*hdr); ihdr = &hdr[1]; while (hdr->length >= sizeof(*hdr)) { ihdr->tag = ntohl(ihdr->tag); ihdr->length = ntohl(ihdr->length); switch (ihdr->tag) { case STATEFILE_TAG_XDCCS_FILE: read_statefile_string(ihdr, "XDCC File", &(xd->file)); xd->desc = mystrdup(getfilename(xd->file)); break; case STATEFILE_TAG_XDCCS_DESC: mydelete(xd->desc); read_statefile_string(ihdr, "XDCC Desc", &(xd->desc)); break; case STATEFILE_TAG_XDCCS_NOTE: read_statefile_string(ihdr, "XDCC Note", &(xd->note)); break; case STATEFILE_TAG_XDCCS_GETS: read_statefile_int(ihdr, "XDCC Gets", &(xd->gets)); break; case STATEFILE_TAG_XDCCS_MINSPEED: read_statefile_float_set(ihdr, "XDCC Minspeed", &(xd->minspeed)); break; case STATEFILE_TAG_XDCCS_MAXSPEED: read_statefile_float_set(ihdr, "XDCC Maxspeed", &(xd->maxspeed)); break; case STATEFILE_TAG_XDCCS_MD5SUM_INFO: read_statefile_md5info(ihdr, "XDCC md5sum", xd); break; case STATEFILE_TAG_XDCCS_CRC32: read_statefile_int(ihdr, "XDCC CRC32", &(xd->crc32)); xd->has_crc32 = 1; break; case STATEFILE_TAG_XDCCS_GROUP: read_statefile_string(ihdr, "XDCC Group", &(xd->group)); break; case STATEFILE_TAG_XDCCS_GROUP_DESC: read_statefile_string(ihdr, "XDCC Group Desc", &(xd->group_desc)); break; case STATEFILE_TAG_XDCCS_LOCK: read_statefile_string(ihdr, "XDCC Lock", &(xd->lock)); break; case STATEFILE_TAG_XDCCS_DLIMIT_MAX: read_statefile_int(ihdr, "XDCC Limit Max", &(xd->dlimit_max)); break; case STATEFILE_TAG_XDCCS_DLIMIT_USED: read_statefile_int(ihdr, "XDCC Limit Used", &(xd->dlimit_used)); break; case STATEFILE_TAG_XDCCS_DLIMIT_DESC: read_statefile_string(ihdr, "XDCC Limit Desc", &(xd->dlimit_desc)); break; case STATEFILE_TAG_XDCCS_TRIGGER: read_statefile_string(ihdr, "XDCC Trigger", &(xd->trigger)); break; case STATEFILE_TAG_XDCCS_XTIME: read_statefile_time(ihdr, "XDCC Time", &(xd->xtime), NULL); break; case STATEFILE_TAG_XDCCS_COLOR: read_statefile_int(ihdr, "XDCC Color", &(xd->color)); break; default: read_statefile_unknown_tag(ihdr, "XDCC" ); } hdr->length -= ceiling(ihdr->length, 4); ihdr = (statefile_hdr_t*)(((char*)ihdr) + ceiling(ihdr->length, 4)); } if ((!xd->file) || (!xd->desc)) { read_statefile_incomplete_tag("XDCC" ); mydelete(xd->file); mydelete(xd->desc); mydelete(xd->note); mydelete(xd->group); mydelete(xd->group_desc); mydelete(xd->lock); mydelete(xd->trigger); irlist_delete(&gdata.xdccs, xd); } else { if (stat(xd->file, &st) < 0) { outerror(OUTERROR_TYPE_WARN, "Pack %u: Cant Access Offered File '%s': %s", number_of_pack(xd), xd->file, strerror(errno)); memset(&st, 0, sizeof(st)); break; } if (!xd->has_md5sum || (xd->st_ino != st.st_ino) || (xd->mtime != st.st_mtime) || (xd->st_size != st.st_size)) { xd->st_size = st.st_size; xd->st_dev = st.st_dev; xd->st_ino = st.st_ino; xd->mtime = st.st_mtime; xd->has_md5sum = 0; memset(xd->md5sum, 0, sizeof(MD5Digest)); } if (xd->st_dev != st.st_dev) { /* only mountpoint has changed */ xd->st_dev = st.st_dev; } if (xd->st_size == 0) { outerror(OUTERROR_TYPE_WARN, "Pack %u: The file \"%s\" has size of 0 byte!", number_of_pack(xd), xd->file); } if (xd->st_size > gdata.max_file_size) { outerror(OUTERROR_TYPE_CRASH, "Pack %u: The file \"%s\" is too large!", number_of_pack(xd), xd->file); } } } break; case STATEFILE_TAG_TLIMIT_DAILY_USED: read_statefile_llint(hdr, "Daily Transfer Limit Used", &(gdata.transferlimits[TRANSFERLIMIT_DAILY].used), "Daily Transfer Limit Used"); break; case STATEFILE_TAG_TLIMIT_DAILY_ENDS: read_statefile_time(hdr, "Daily Transfer Limit Ends", &(gdata.transferlimits[TRANSFERLIMIT_DAILY].ends), "Daily Transfer Limit Ends"); break; case STATEFILE_TAG_TLIMIT_WEEKLY_USED: read_statefile_llint(hdr, "Weekly Transfer Limit Used", &(gdata.transferlimits[TRANSFERLIMIT_WEEKLY].used), "Weekly Transfer Limit Used"); break; case STATEFILE_TAG_TLIMIT_WEEKLY_ENDS: read_statefile_time(hdr, "Weekly Transfer Limit Ends", &(gdata.transferlimits[TRANSFERLIMIT_WEEKLY].ends), "Weekly Transfer Limit Ends"); break; case STATEFILE_TAG_TLIMIT_MONTHLY_USED: read_statefile_llint(hdr, "Monthly Transfer Limit Used", &(gdata.transferlimits[TRANSFERLIMIT_MONTHLY].used), "Monthly Transfer Limit Used"); break; case STATEFILE_TAG_TLIMIT_MONTHLY_ENDS: read_statefile_time(hdr, "Monthly Transfer Limit Ends", &(gdata.transferlimits[TRANSFERLIMIT_MONTHLY].ends), "Monthly Transfer Limit Ends"); break; case STATEFILE_TAG_QUEUE: read_statefile_queue(hdr); break; default: read_statefile_unknown_tag(hdr, "Main" ); break; } } if (buffer_len) { outerror(OUTERROR_TYPE_WARN, "Extra data at end of state file!? %u left", buffer_len); } /* end read */ if ((gdata.debug > 0) || irlist_size(&gdata.ignorelist)) { ioutput(OUT_S|OUT_L|OUT_D, COLOR_NO_COLOR, " [Found %u %s]", irlist_size(&gdata.ignorelist), (irlist_size(&gdata.ignorelist) == 1) ? "ignore" : "ignores"); } if ((gdata.debug > 0) || irlist_size(&gdata.msglog)) { ioutput(OUT_S|OUT_L|OUT_D, COLOR_NO_COLOR, " [Found %u %s]", irlist_size(&gdata.msglog), (irlist_size(&gdata.msglog) == 1) ? "message" : "messages"); } if ((gdata.debug > 0) || irlist_size(&gdata.xdccs)) { ioutput(OUT_S|OUT_L|OUT_D, COLOR_NO_COLOR, " [Found %u %s]", irlist_size(&gdata.xdccs), (irlist_size(&gdata.xdccs) == 1) ? "pack" : "packs"); } if ((gdata.debug > 0) || irlist_size(&gdata.mainqueue)) { ioutput(OUT_S|OUT_L|OUT_D, COLOR_NO_COLOR, " [Found %u %s]", irlist_size(&gdata.mainqueue), (irlist_size(&gdata.mainqueue) == 1) ? "queue" : "queues"); } if ((gdata.debug > 0) || irlist_size(&gdata.idlequeue)) { ioutput(OUT_S|OUT_L|OUT_D, COLOR_NO_COLOR, " [Found %u %s]", irlist_size(&gdata.idlequeue), (irlist_size(&gdata.idlequeue) == 1) ? "queue" : "queues"); } ioutput(OUT_S|OUT_L|OUT_D, COLOR_NO_COLOR, " [Done]"); error_out: mydelete(buffer_begin); return save; }