void PDCHL1Downlink::bugFixIdleFrame() { // DEBUG: We are only using this function to fix this problem for now. if (gFixIdleFrame) { // For this debug purpose, the mssage is sent on the next frame // TODO: debug purpose only! This only works for one channel! //Time tnext(gBSNNext.FN()); //gBTS.clock().wait(tnext); } // Did we make it in time? { Time tnow = gBTS.time(); int fn = tnow.FN(); int mfn = (fn / 13); // how many 13-multiframes int rem = (fn - (mfn*13)); // how many blocks within the last multiframe. int tbsn = mfn * 3 + ((rem==12) ? 2 : (rem/4)); GPRSLOG(2) <<"idleframe"<<LOGVAR(fn)<<LOGVAR(tbsn)<<LOGVAR(rem); } /*** if (mchIdleFrame.size() == 0) { RLCMsgPacketDownlinkDummyControlBlock *dummymsg = new RLCMsgPacketDownlinkDummyControlBlock(); mchIdleFrame.set(BitVector(RLCBlockSizeInBits[ChannelCodingCS1])); dummymsg->write(mchIdleFrame); delete dummymsg; } send1Frame(mchIdleFrame,ChannelCodingCS1,true); ***/ }
string SipMessage::text(bool verbose) const { std::ostringstream ss; ss << "SipMessage("; { int code = smGetCode(); ss <<LOGVAR(code); } if (!msmReqMethod.empty()) ss <<LOGVAR2("ReqMethod",msmReqMethod); if (!msmReason.empty()) ss <<LOGVAR2("reason",msmReason); if (!msmCSeqMethod.empty()) ss<<" CSeq="<<msmCSeqNum<< " "<<msmCSeqMethod; if (!msmCallId.empty()) ss <<LOGVAR2("callid",msmCallId); if (!msmReqUri.empty()) ss << LOGVAR2("ReqUri",msmReqUri); { string To = msmTo.value(); if (!To.empty()) ss << LOGVAR(To); } { string From = msmFrom.value(); if (!From.empty()) ss<<LOGVAR(From); } if (!msmVias.empty()) ss <<LOGVAR2("Vias",msmVias); if (!msmRoutes.empty()) ss <<LOGVAR2("Routes",msmRoutes); if (!msmRecordRoutes.empty()) ss <<LOGVAR2("RecordRoutes",msmRecordRoutes); if (!msmContactValue.empty()) ss <<LOGVAR2("Contact",msmContactValue); //list<SipBody> msmBodies; if (!msmContentType.empty()) ss<<LOGVAR2("ContentType",msmContentType); if (!msmBody.empty()) ss<<LOGVAR2("Body",msmBody); //if (!msmAuthenticateValue.empty()) ss<<LOGVARM(msmAuthenticateValue); if (!msmAuthorizationValue.empty()) ss<<LOGVARM(msmAuthorizationValue); for (SipParamList::const_iterator it = msmHeaders.begin(); it != msmHeaders.end(); it++) { ss <<" header "<<it->mName <<"="<<it->mValue; } if (verbose) { ss << LOGVARM(msmContent); } else { ss << LOGVAR2("firstLine",smGetFirstLine()); } ss << ")"; return ss.str(); }
string SipMessage::smGetInviteImsi() { // Get request username (IMSI) from assuming this is the invite message. string username = smUriUsername(); LOG(DEBUG) <<LOGVAR(username) <<LOGVAR(extractIMSI(sipSkipPrefix1(username.c_str()))); return string(extractIMSI(sipSkipPrefix1(username.c_str()))); }
// The result is 3-state (LCH, !LCH and deleteMe==true, !LCH && deleteMe==false.) // If it is a TCH or SDCCH return an allocated channel, or NULL if not possible, // in which case the handset may ultimately be sent an immediate assignment reject. // On return, if deleteMe, the caller will delete the rach. static L2LogicalChannel *preallocateChForRach(RachInfo *rach, bool *deleteMe) { *deleteMe = false; Time now = gBTS.time(); int age = now - rach->mWhen; // The result is number of frames and could be negative. if (age>sMaxAge) { LOG(WARNING) << "ignoring RACH burst with age " << age; *deleteMe = true; return NULL; } L2LogicalChannel *LCH = NULL; ChannelType chtype = decodeChannelNeeded(rach->mRA); if (chtype == PSingleBlock1PhaseType || chtype == PSingleBlock2PhaseType) { return NULL; // this routine does nothing for this. } else if (chtype == TCHFType) { LCH = gBTS.getTCH(); } else if (chtype == SDCCHType) { LCH = gBTS.getSDCCH(); } else { LOG(NOTICE) << "RACH burst for unsupported service RA=" << rach->mRA; // (pat) 4-2014: Stop allocating channels for this. We get a lot of false RACHes so lets ignore those with unrecognized RA. // LCH = gBTS.getSDCCH(); *deleteMe = true; return NULL; } if (!LCH) { LOG(DEBUG) << "No channels availablable, RACH discarded"; *deleteMe = true; return NULL; } int initialTA = rach->initialTA(); assert(initialTA >= 0 && initialTA <= 62); // enforced by AccessGrantResponder. LCH->l1InitPhy(rach->RSSI(),initialTA,gBTS.clock().systime(rach->mWhen.FN())); LCH->lcstart(); rach->mChan = LCH; Time sacchStart = LCH->getSACCH()->getNextWriteTime(); // There is a race whether the thread that runs SACCH can run before sacchStart time, and if not // the SACCH will not be transmitted at this time. // Therefore, if sacchStart time is close, add a whole sacch frame, 104 frames == 480ms. now = gBTS.time(); // Must update this because getTCH blocked. int diff = sacchStart - now; // Returns number of 4.8ms frames. if (diff < 26) { // very conservative. sacchStart += 104; } if (sacchStart - now < 0) { // Should never happen. sacchStart = now + 104; } rach->mReadyTime = sacchStart; LOG(DEBUG) <<LOGVAR(sacchStart)<<LOGVAR(now)<<LOGVAR(diff); return LCH; }
string SipMessage::smUriUsername() { string result = SipUri(msmReqUri).uriUsername(); LOG(DEBUG) <<LOGVAR(msmReqUri) <<LOGVAR(msmTo.value()) <<LOGVAR(result); return result; //SipUri uri; uri.uriParse(msmReqUri); //string username = uri.username(); //LOG(DEBUG) << LOGVAR(msmReqUri) <<LOGVAR(username); //return username; }
void startRegister(TranEntryId tid, const FullMobileId &msid, const string rand, const string sres, L3LogicalChannel *chan) // msid is imsi and/or tmsi { LOG(DEBUG) <<LOGVAR(msid)<<LOGVAR(rand)<<LOGVAR(sres); // Kinda dumb to fish out the branch from the request, but its ok. SipDialog *registrar = getRegistrar(); SipMessage *request = registrar->makeRegisterMsg(SIPDTRegister,chan,rand,msid,sres.c_str()); SipRegisterTU *reg = new SipRegisterTU(SipRegisterTU::KindRegister,registrar,tid,request); delete request; // sctInitRegisterTransaction made a copy. Kind of wasteful. reg->sctStart(); }
void SipTransaction::sendAuthOKMessage(SipMessage *sipmsg) { devassert(mstTranId); // The tran id is 0 for unregister messages. If one of those gets this far it is a bug. if (! mstTranId) { return; } string imsi = sipmsg->msmTo.uriUsername(); // The To: and From: have the same value for a REGISTER message. // Validate the imsi: if (imsi.empty()) { LOG(ERR) << "can't find imsi to store kc"; sendAuthFailMessage(400,"",""); return; } if (0 == strncasecmp(imsi.c_str(),"imsi",4)) { // happiness } else if (0 == strncasecmp(imsi.c_str(),"tmsi",4)) { // TODO: In future the user name could be a TMSI. LOG(ERR) << "SIP REGISTER message with TMSI not supported, userid="<<imsi; sendAuthFailMessage(400,"",""); return; } else { LOG(ERR) << "SIP REGISTER message with invalid IMSI:"<<imsi<<" Message:"<<sipmsg->msmContent; sendAuthFailMessage(400,"",""); return; } DialogAuthMessage *dmsg = new DialogAuthMessage(mstTranId, DialogState::dialogActive,200); dmsg->dmPAssociatedUri = sipmsg->msmHeaders.paramFind("P-Associated-URI"); // case doesnt matter dmsg->dmPAssertedIdentity = sipmsg->msmHeaders.paramFind("P-Asserted-Identity"); string authinfo = sipmsg->msmHeaders.paramFind("Authentication-Info"); if (! authinfo.empty()) { SipParamList params; parseToParams(authinfo, params); dmsg->dmKc = params.paramFind("cnonce"); // This is the way SR passes the Kc. } else { // There will not be a cnonce if the Registrar does not know it. Dont worry about it. //LOG(INFO) << "No Authenticate-Info header in SIP REGISTER response:"<<sipmsg->msmContent; } if (dmsg->dmKc.empty()) { dmsg->dmKc = sipmsg->msmHeaders.paramFind("P-GSM-Kc"); // This is the way Yate passes the Kc. } WATCHF("CNONCE: imsi=%s Kc=%s\n",imsi.c_str(),dmsg->dmKc.c_str()); if (! dmsg->dmKc.empty()) { LOG(DEBUG) << "Storing Kc:"<<LOGVAR(imsi)<<LOGVAR(dmsg->dmKc.size()); // We dont put Kc itself in the log. //gTMSITable.putKc(imsi.c_str()+4, kc, pAssociatedUri, pAssertedIdentity); } else { LOG(NOTICE) << "No Kc in SIP REGISTER response:"<<sipmsg->msmContent; } //NewTransactionTable_ttAddMessage(mstTranId,dmsg); SipCallbacks::ttAddMessage(mstTranId,dmsg); }
void L3SupServFacilityIE::text(ostream& os) const { char rawdata[2*255+1+1]; // Add 1 extra for luck. unsigned len = lengthV(); const unsigned char *components = peData(); for (unsigned i = 0; i < len; i++) { sprintf(&rawdata[2*i],"%02x",components[i]); } string ussd = Control::ssMap2Ussd(components,len); os <<"SupServFacilityIE(size=" <<len <<" components:" <<LOGVAR(rawdata) <<LOGVAR(ussd)<<")"; }
// (pat) This is started when SACCH is opened, and runs forever. // The SACCHLogicalChannel are created by the SDCCHLogicalChannel and TCHFACCHLogicalChannel constructors. void *SACCHLogicalChannel::SACCHServiceLoop(SACCHLogicalChannel* sacch) { WATCHINFO("Starting SACCHServiceLoop for "<<sacch); unsigned count = 0; while (!gBTS.btsShutdown()) { //if (gBTS.time().FN() % 104 == 0) { OBJLOG(DEBUG) <<LOGVAR(l1active()) <<LOGVAR(recyclable()); } // Throttle back if not active. // This is equivalent to testing if the L2LAPDm is in 'null' state as defined in GSM 4.06. // In null state we send dummy frames; in L2LAPDm idle state we send L2 idle frames. // The dummy frame is sent down to the transceiver when L2LAPDm is closed. if (! sacch->l1active()) { // pat 5-2013: Vastly reducing the delays here and in L2LAPDm to try to reduce // random failures of handover and channel reassignment from SDCCH to TCHF. // Update: The further this sleep is reduced, the more reliable handover becomes. // I left it at 4 for a while but handover still failed sometimes. //sleepFrames(51); #if USE_SEMAPHORE sleepFrames(51); // In case the semaphore does not work. // (pat) Update: Getting rid of the sleep entirely. We will use a semaphore instead. // Note that the semaphore call may return on signal, which is ok here. int sval, semstat= sem_getvalue(&mOpenSignal,&sval); //cout << descriptiveString() << " WAIT " <<sem_getvalue(&mOpenSignal,&sval) <<LOGVAR(sval) <<endl; LOG(DEBUG) << descriptiveString() << " SEM_WAIT " <<LOGVAR(semstat) <<LOGVAR(sval); sem_wait(&mOpenSignal); // sem_post sem_overview semstat= sem_getvalue(&mOpenSignal,&sval); //cout << descriptiveString() << " AFTER " <<LOGVAR(semstat) <<LOGVAR(sval) <<endl; LOG(DEBUG) << descriptiveString() << " SEM_AFTER " <<sem_getvalue(&mOpenSignal,&sval) <<LOGVAR(sval); #else // (pat 3-2014) Changing this sleepFrames(51) to sleepFrames(2) had an enormous impact // on idle cpu utilization, from 11.2% to 8.5% with a C-5 beacon, ie, with only 4 SACCH running. // TODO: Can use fewer CPU cycles by using something like waitToSend to sleep until the next SACCH transmission time. sleepFrames(1); #endif // A clever way to avoid the sleep above would be to wait for ESTABLISH primitive. // (But which do you wait on - the tx or the rx queue? continue; // paranoid, check again. } // (pat 4-2014) Added to detect RR failure. This is needed because a Layer3 MMContext is not allocated // until the first L3 message arrives. If the channel fails without sending an L3 message we would never // notice unless we are watching these RR level timers. // Close the host channel, which will also close this SACCH. sacch->serviceSACCH(count); } //sacch->mSacchRunning = false; dont think we would restart this one; would alloc a new one. return NULL; }
void PDCHL1Downlink::mchResync() { // If the encoder's clock is far from the current BTS clock, // get it caught up to something reasonable. Time now = gBTS.time(); int32_t delta = mchNextWriteTime-now; GPRSLOG(8) << "PDCHL1Downlink" <<LOGVAR(mchNextWriteTime) <<LOGVAR(now)<< LOGVAR(delta); if ((delta<0) || (delta>(51*26))) { mchNextWriteTime = now; //mchNextWriteTime.TN(now.TN()); // unneeded? mchNextWriteTime.rollForward(mchMapping.frameMapping(mchTotalBursts),mchMapping.repeatLength()); GPRSLOG(2) <<"PDCHL1Downlink RESYNC" << LOGVAR(mchNextWriteTime) << LOGVAR(now); } }
void PDCHL1FEC::mchStart() { getRadio()->setSlot(TN(),Transceiver::IGPRS); // Load up the GPRS filler idle burst tables in the transceiver. // We could use any consecutive bsn, but lets use ones around the current time // just to make sure they get through in case someone is triaging somewhere. // Sending all 12 blocks is 2x overkill because the modulus in Transceiver::setModulus // for type IGPRS is set the same as type I which is only 26, not 52. RLCBSN_t bsn = FrameNumber2BSN(gBTS.time().FN()) + 1; for (int i = 0; i < 12; i++, bsn = bsn + 1) { GPRSLOG(1) <<"sendIdleFrame"<<LOGVAR2("TN",TN())<<LOGVAR(bsn)<<LOGVAR(i); mchDownlink->sendIdleFrame(bsn); } mchOldFec->setGPRS(true,this); debug_test(); }
// (pat 9-2014) Print out peering messages. We triage the messages depending on the log level. // INFO level - Handover messages only. // DEBUG level - all messages. static void logMessage(const char*sendOrRecv, const struct sockaddr_in* peer, const char *message) { const char *arg1 = getPeeringMsgArg1(message); if (0 == strncmp(arg1,"HANDOVER",8)) { LOG(INFO) << "Peering "<<sendOrRecv <<LOGVAR2("peer",sockaddr2string(peer,true)) <<LOGVAR(message); // We used to watch everything except REQ NEI messages: if (strncmp(message,"REQ NEI",7)) const char *eol = strchr(message,'\n'); WATCHLEVEL(INFO," Peering "<<sendOrRecv <<LOGVAR2("peer",sockaddr2string(peer,true)) <<LOGVAR2("message",string(message,eol?eol-message:strlen(message)))); // first line of message; they used to be long. } else { // At DEBUG level log all messages. LOG(DEBUG) << "Peering "<<sendOrRecv<<LOGVAR2("peer",sockaddr2string(peer,true)) <<LOGVAR(message); } }
// Return true on success. bool MTSMSMachine::createRPData(RPData &rp_data) { // TODO: Read MIME Type from smqueue!! const char *contentType = tran()->mContentType.c_str(); PROCLOG(DEBUG)<<LOGVAR(contentType)<<LOGVAR(tran()->mMessage); if (strncmp(contentType,"text/plain",10)==0) { TLAddress tlcalling = TLAddress(tran()->calling().digits()); TLUserData tlmessage = TLUserData(tran()->mMessage.c_str()); PROCLOG(DEBUG)<<LOGVAR(tlcalling)<<LOGVAR(tlmessage); rp_data = RPData(this->mRpduRef, RPAddress(gConfig.getStr("SMS.FakeSrcSMSC").c_str()), TLDeliver(tlcalling,tlmessage,0)); } else if (strncmp(contentType,"application/vnd.3gpp.sms",24)==0) { BitVector2 RPDUbits(strlen(tran()->mMessage.c_str())*4); if (!RPDUbits.unhex(tran()->mMessage.c_str())) { LOG(WARNING) << "Message is zero length which is valid"; // This is valid continue return true; } try { // I suspect this is here to catch the above FIXED crash when string is zero length RLFrame RPDU(RPDUbits); LOG(DEBUG) << "SMS RPDU: " << RPDU; rp_data.parse(RPDU); LOG(DEBUG) << "SMS RP-DATA " << rp_data; } catch (SMSReadError) { LOG(WARNING) << "SMS parsing failed (above L3)"; // Cause 95, "semantically incorrect message". //LCH->l2sendf(CPData(L3TI,RPError(95,this->mRpduRef)),3); if you ever use this, it should call l3sendSms return false; } catch (GSM::L3ReadError) { LOG(WARNING) << "SMS parsing failed (in L3)"; // TODO:: send error back to the phone return false; } catch (...) { LOG(ERR) << "Unexpected throw"; // cryptic, but should never happen. return false; } } else { LOG(WARNING) << "Unsupported content type (in incoming SIP MESSAGE) -- type: " << contentType; return false; } return true; }
L3Frame * L2LogicalChannel::l2recv(unsigned timeout_ms) { LOG(DEBUG); L3Frame *result = mL3Out.read(timeout_ms); if (result) WATCHINFO("l2recv " << this <<LOGVAR2("sap",result->getSAPI()) <<LOGVAR(result)); return result; }
void PeerInterface::process(const struct sockaddr_in* peer, const char* message) { logMessage("receive",peer,message); // neighbor message? if (strncmp(message+3," NEIGHBOR_PARAMS",16)==0) return processNeighborParams(peer,message); // must be handover related string peerString = sockaddr2string(peer, true); LOG(INFO) << "received from"<<LOGVAR2("peer",peerString) <<LOGVAR(message); // Initial inbound handover request? if (strncmp(message,"REQ HANDOVER ",13)==0) return processHandoverRequest(peer,message); // Handover response? ("Handover Accept" in the ladder.) if (strncmp(message,"RSP HANDOVER ",13)==0) return processHandoverResponse(peer,message); // IND HANDOVER_COMPLETE if (strncmp(message,"IND HANDOVER_COMPLETE ", 22)==0) return processHandoverComplete(peer,message); // IND HANDOVER_FAILURE if (strncmp(message,"IND HANDOVER_FAILURE ", 21)==0) return processHandoverFailure(peer,message); // Other handover messages go into the FIFO map. // (pat) It is an ACK message, and we need to queue it because the 'senduntilack' is running in a different thread. // FIXME -- We need something here to spot malformed messages. unsigned transactionID; sscanf(message, "%*s %*s %u", &transactionID); mFIFOMap.writeFIFO(transactionID,message); }
void L2SAPMux::sapWriteFromL1(const L2Frame& frame) { OBJLOG(DEBUG) << frame; unsigned sap; // (pat) Add switch to validate upstream primitives. The upstream only generates a few primitives; // the rest are created in L2LAPDm. switch (frame.primitive()) { case L2_DATA: sap = frame.SAPI(); assert(sap == SAPI0 || sap == SAPI3); if (mL2[sap]) { mL2[sap]->l2dlWriteLowSide(frame); } else { LOG(WARNING) << "received DATA for unsupported"<<LOGVAR(sap); } return; case PH_CONNECT: // All this does is fully reset LAPDm; copy it out to every SAP. for (int s = 0; s <= 3; s++) { if (mL2[s]) mL2[s]->l2dlWriteLowSide(frame); // Note: the frame may have the wrong SAP in it, but LAPDm doesnt care. } return; default: // If you get this assertion, make SURE you know what will happen upstream to that primitive. devassert(0); return; // make g++ happy. } }
// It is hardly worth the effort to make a transaction for REGISTER, which occurs outside a dialog // and has only one reply, but we need to know when to destroy it. // Note: The registrar may return messages, which we must ignore for the Unregister case since there is no transaction to receive them. void SipRegisterTU::TUWriteHighSideV(SipMessage *sipmsg) { int code = sipmsg->msmCode; static const char *pRejectCauseHeader = "P-GSM-Reject-Cause"; static const char *whatami = stKind == KindRegister ? "SIP Register " : "SIP UnRegister "; LOG(DEBUG) <<LOGVAR(code); if (code == 0) { // A register transaction does not receive any requests. LOG(ERR) << whatami <<"received unexpected message:"<<sipmsg; stDestroyV(); } else if (code == 401) { //setDialogState(Fail,sipmsg); LOG(INFO) <<whatami <<"received:"<<sipmsg; if (stKind == KindRegister) { sendAuthFailMessage(code,sipmsg->smGetRand401(),sipmsg->msmHeaders.paramFind(pRejectCauseHeader)); } setTransactionState(stCompleted); } else if (code == 200) { // (pat) We can no longer stash Kc directly in the TMSI table because the entry is not created until the MS is validated. if (stKind == KindRegister) { sendAuthOKMessage(sipmsg); } } else switch ((code/100) * 100) { case 100: return; // we dont care. case 200: LOG(ERR) <<whatami<<"received invalid code:"<<code <<" in message:"<<sipmsg; // Code in the range 201-299 is allegedly impossible. default: if (stKind == KindRegister) { sendAuthFailMessage(code,"",sipmsg->msmHeaders.paramFind(pRejectCauseHeader)); } return; } }
// Simplified version for public release bool CCCHLogicalChannel::processPages() { while (NewPagingEntry *npe1 = gPagingQ.mPageQ.readNoBlock()) { LOG(DEBUG)<<LOGVAR(npe1); if (npe1->mGprsClient) { // Is it a GPRS page? // Add 51 to the frame time because the message because the MS may be on the other 51-multiframe. Time future(mCcchNextWriteTime + 52); if (! sendGprsCcchMessage(npe1,future)) { delete npe1; // In the incredibly unlikely event that the above failed, just give up. continue; } } else { const L3MobileIdentity& id1 = npe1->getMobileId(); ChannelType type1 = npe1->getGsmChanType(); L3PagingRequestType1 page1(id1,type1); L2LogicalChannelBase::l2sendm(page1,L3_UNIT_DATA); } if (++npe1->mSendCount < 2) { // Send each page twice. gPagingQ.mPageQ.write_front(npe1); // Put it back for resend in the next multiframe. } else { delete npe1; } return true; } return false; // CCCH unused. }
bool SipClientTrLayer::TLWriteHighSideV(SipMessage *sipmsg) { int code = sipmsg->smGetCode(); LOG(DEBUG) <<LOGVAR(mstState) <<LOGVAR(code); // This is overly verbose to exactly match the state machine described in RFC3261. switch (mstState) { case stInitializing: // Someone sent us a reply before we sent the outgoing message? LOG(ERR) << "SIP Message received on uninitialized client transaction."<<LOGVAR(sipmsg) <<this; return false; case stCallingOrTrying: case stProceeding: switch ((code / 100) * 100) { case 100: mstState = stProceeding; TUWriteHighSideV(sipmsg); return true; default: mstState = stCompleted; TUWriteHighSideV(sipmsg); if (stIsInvite()) { mstState = stTerminated; if (code >= 300) { mstDialog->MOCSendACK(); } else { stDestroyV(); return true; } // The TU is responssible for sending the ACK, after connection setup. } if (stIsReliableTransport()) { stDestroyV(); return true; } else { mTimerDK.set(32*1000); } return true; } case stCompleted: switch ((code / 100) * 100) { case 100: case 200: return false; // suppress duplicate messages. default: if (stIsInvite()) { mstDialog->MOCSendACK(); } return false; // suppress duplicate messages. } case stTerminated: // Now what? LOG(ERR) << "SIP Message received on terminated client transaction."<<LOGVAR(sipmsg) <<this; return false; } assert(0); TUWriteHighSideV(sipmsg); return true; // For outbound transactions, TransactionLayer sends all inbound replies to the TU. }
void startUnregister(const FullMobileId &msid, L3LogicalChannel *chan) { LOG(DEBUG) <<LOGVAR(msid); SipDialog *registrar = getRegistrar(); SipMessage *request = registrar->makeRegisterMsg(SIPDTUnregister,chan,"",msid,NULL); SipRegisterTU *reg = new SipRegisterTU(SipRegisterTU::KindUnRegister,registrar,(TranEntryId)0,request); delete request; // sctInitRegisterTransaction made a copy. Kind of wasteful. reg->sctStart(); }
// Return TRUE to delete it. bool SipClientTrLayer::TLPeriodicServiceV() { LOG(DEBUG) << LOGVAR(mTimerDK) <<LOGVAR(mTimerBF) <<LOGVAR(mTimerAE); ScopedLock lock(mstLock); if (mstState == stInitializing) { return false; } if (mstState == stTerminated) { return true; } // The timerDK is the time in the Completed state, and used just to suck up additional incoming replies. if (mTimerDK.expired()) { stDestroyV(); return true; } // The transaction completed, a message was sent to layer3, so we just exit. if (mTimerBF.expired()) { if (mstState == stCallingOrTrying || mstState == stProceeding) { stFail(408); // 408 - SIP Timeout. Must send a fail message to layer3. } TUTimeoutV(); stDestroyV(); return true; } if (mstState == stCallingOrTrying && mTimerAE.expired()) { stWrite(&mstOutRequest); mTimerAE.setDouble(); } return false; }
void SACCHLogicalChannel::l2sendf(const L3Frame& frame) { SAPI_t sap = frame.getSAPI(); devassert(SAPIsSacch(sap)); if (sap != SAPI3Sacch) { LOG(NOTICE) << "unexpected"<<LOGVAR(sap)<<" in "<<LOGVAR(frame); } LOG(INFO) <<channelDescription() <<LOGVAR(sap) <<LOGVAR(chtype()) <<" " <<frame; switch (frame.primitive()) { case L3_ESTABLISH_REQUEST: // Fall through. case L3_DATA: case L3_UNIT_DATA: case L3_RELEASE_REQUEST: case L3_HARDRELEASE_REQUEST: mL3In.write(new L3Frame(frame)); return; default: assert(0); } }
// Return true if the current CCCH was used. bool CCCHLogicalChannel::ccchServiceQueue() { // Update the time when the next CCCH frame will be sent. // All the l2sendm/l2sendp calls below block using waitToSend() // on the mPrevWriteTime set by the getNextWriteTime call. mCcchNextWriteTime = getNextWriteTime(); if (gBTS.btsHold()) { return false; } // Is this CCCH used for pages? We determine this by looking at the frame number within the 51-multiframe. int paging_block_index = mRevPCH[mCcchNextWriteTime.FN() % 51]; if (paging_block_index >= 0 && processPages()) { return true; } // We did not use this CCCH for a page, so lets look for something else to send. if (processRaches()) { return true; // We used this CCCH. } // GPRS messages may be in DRX mode or not. // If they are in DRX mode, move them to a paging queue and set foundSomeNewPages. bool foundSomeNewPages = false; for (NewPagingEntry *gprsIt = gGprsCcchMessageQ.itBegin(); gprsIt; ) { NewPagingEntry *gprsMsg = gprsIt; // This is redundant; the items are not currently modified by iteration. LOG(DEBUG) << "processing"<<LOGVAR(gprsMsg); GSM::Time drxBeginTime(gprsMsg->mDrxBegin); if (mCcchNextWriteTime >= drxBeginTime) { // This MS is now in DRX mode. Move the message to the paging queue. gprsIt = gGprsCcchMessageQ.itRemove(gprsIt); gPagingQ.addPage(gprsMsg); foundSomeNewPages = true; continue; } // Woo hoo! Send out the message. if (sendGprsCcchMessage(gprsMsg,mCcchNextWriteTime)) { gprsIt = gGprsCcchMessageQ.itRemove(gprsIt); delete gprsMsg; return true; // We used this CCCH. } else { // Failed. That means we were unable to make a reservation for some reason. // While unlikely, it is possible that a reservation on one channel failed while reservations on other // channels would succeed, so dont block the entire queue due to this one failure, keep going. gprsIt = gGprsCcchMessageQ.itSkip(gprsIt); } } if (foundSomeNewPages); // shut up gcc return false; // We have not used this CCCH. }
static int opensock(uint32_t sgsnIp, int sgsnPort /*,int bssgPort*/ ) { //int fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); int sockfd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); if (sockfd < 0) { LOG(ERR) << "Could not create socket for BSSGP"; return -1; } /****** { // We dont want to bind here. connect will pick a port for us. int32_t bssgIp = INADDR_ANY; struct sockaddr_in myAddr; memset(&myAddr,0,sizeof(myAddr)); // be safe. myAddr.sin_family = AF_INET; myAddr.sin_addr.s_addr = htonl(bssgIp); myAddr.sin_port = htons(bssgPort); if (0 != bind(sockfd,(sockaddr*)&myAddr,sizeof(myAddr))) { LOG(ERR) << "Could not bind NS socket to" << LOGVAR(bssgIp) << LOGVAR(bssgPort) << LOGVAR(errno); close(sockfd); return -1; } } ****/ struct sockaddr_in sgsnAddr; memset(&sgsnAddr,0,sizeof(sgsnAddr)); sgsnAddr.sin_family = AF_INET; sgsnAddr.sin_addr.s_addr = sgsnIp; // This is already in network order. sgsnAddr.sin_port = htons(sgsnPort); if (0 != connect(sockfd,(sockaddr*)&sgsnAddr,sizeof(sgsnAddr))) { LOG(ERR) << "Could not connect NS socket to" << LOGVAR(sgsnIp) << LOGVAR(sgsnPort) << LOGVAR(errno); close(sockfd); return -1; } else { GPRSLOG(1) << "connected to SGSN at "<< inet_ntoa(sgsnAddr.sin_addr) <<" port "<<sgsnPort; } return sockfd; }
static int BSTLVParse(ByteType *data, int &rp, IEIType::type expected_ieitype, int expected_length) { int received_ieitype = data[rp++]; int received_length = data[rp++]; if (received_ieitype != expected_ieitype || received_length != expected_length) { int bstype = data[NSMsg::UnitDataHeaderLen]; LOG(ERR) << "Error in BSSG msg type="<<bstype <<LOGVAR(expected_ieitype) <<LOGVAR(expected_length) <<LOGVAR(received_ieitype) <<LOGVAR(received_length); return 0; } int result; switch (received_length) { case 1: result = data[rp++]; break; case 2: result = getntohs(&data[rp]); rp+=2; break; case 4: result = getntohl(&data[rp]); rp+=4; break; default: assert(0); } return result; }
void L2LogicalChannel::l2sendf(const L3Frame& frame) { SAPI_t sap = frame.getSAPI(); assert(sap == SAPI0 || sap == SAPI3 || sap == SAPI0Sacch || sap == SAPI3Sacch); WATCHINFO("l2sendf "<<channelDescription() <<LOGVAR(sap) <<LOGVAR(chtype()) <<" " <<frame); if (SAPIsSacch(sap)) { getSACCH()->l2sendf(frame); return; } switch (frame.primitive()) { case L3_ESTABLISH_REQUEST: if (sap != SAPI3) { LOG(NOTICE) << "unexpected"<<LOGVAR(sap)<<" in "<<LOGVAR(frame); } break; case L3_DATA: case L3_UNIT_DATA: break; case L3_RELEASE_REQUEST: // Normal release initiated by layer3. if (sap == SAPI0) { // Total deactivation requested. startNormalRelease(); return; } break; case L3_HARDRELEASE_REQUEST: // This is a full immediate release. if (sap == SAPI0) { immediateRelease(); return; } LOG(NOTICE) << "unexpected"<<LOGVAR(sap)<<" in "<<LOGVAR(frame); break; default: assert(0); return; } mL3In.write(new L3Frame(frame)); }
void L2LogicalChannel::writeToL3(L3Frame*frame) { LOG(DEBUG) <<this <<LOGVAR(*frame); switch (frame->primitive()) { case L3_ESTABLISH_INDICATION: case L3_ESTABLISH_CONFIRM: case HANDOVER_ACCESS: case L3_DATA: case L3_UNIT_DATA: break; case MDL_ERROR_INDICATION: // Normal release procedure initiated by handset, or due to error at LAPDm level. // An error is handled identically to a normal release, because the handset may still be listening to us // even though we lost contact with it, and we want to tell it to release as gracefully as possible // even though the channel condition may suck. if (frame->getSAPI() == SAPI0) { // Release on host chan sap 0 is a total release. We will start the release now. // FIXME: Are we supposed to wait for any pending SMS requests on SACCH to clear first? startNormalRelease(); } else { // We dont kill the whole link for SAP3 release. // Pass the message on to layer3 to abort whatever transaction is running on SAP3 } break; case L3_DATA_CONFIRM: // Sent from LAPDm when data delivered, but we dont care. WATCHINFO(this <<LOGVAR2("sap",frame->getSAPI()) <<LOGVAR(frame)); delete frame; return; case L3_RELEASE_INDICATION: case L3_RELEASE_CONFIRM: // Sent from LAPDm when link release is confirmed, but we dont care. if (frame->getSAPI() == SAPI0) { mT3109.reset(); mT3111.set(); } break; default: assert(0); } mL3Out.write(frame); }
// OLD: Send this loop an NS_BLOCK message to kill this thread off; // and we dont normally use that NS message. // There is a BSSG-level BVC_BLOCK message that we would use to do a temporary data block. void *sendServiceLoop(void *arg) { BSSGMain *bssgp = (BSSGMain*)arg; NSPDUType::type nstype = NSPDUType::NS_RESET; // init to anything. do { NSMsg *ulmsg = bssgp->mbsTxQ.read(); // It is already wrapped up in an NS protocol. int msgsize = ulmsg->size(); ssize_t result = send(bssgp->mbsSGSockfd,ulmsg->begin(),msgsize,0); nstype = ulmsg->getNSPDUType(); int debug_level = 1; //(nstype == NSPDUType::NS_UNITDATA) ? 1 : 4; if (GPRS::GPRSDebug & debug_level) { GPRSLOG(debug_level) << "BSSG ===> sendServiceLoop sent " <<nstype<<LOGVAR(msgsize)<<ulmsg->str()<<timestr(); } if (result != msgsize) { LOG(ERR) << "BSSGP invalid send result" << LOGVAR(result) << LOGVAR(msgsize); } delete ulmsg; } while (bssgp->mbsIsOpen /*&& nstype != NSPDUType::NS_BLOCK*/); return NULL; }
void SACCHLogicalChannel::sacchInit() { LOG(DEBUG) <<this; if (mL1) mL1->l1init(); // (pat) L1FEC::l1init() neighborClearMeasurements(); //mAverageRXLEV_SUB_SERVICING_CELL = 0; // Just make sure any stray messages are flushed when we reactivate the channel. while (L3Message *straymsg = mTxQueue.readNoBlock()) { delete straymsg; } mMeasurementResults = L3MeasurementResults(); // clear it #if USE_SEMAPHORE //cout << descriptiveString() << " POST " <<sem_getvalue(&mOpenSignal,&sval) <<LOGVAR(sval) <<endl; int sval, semstat= sem_getvalue(&mOpenSignal,&sval); LOG(DEBUG) << descriptiveString() << " SEM_POST " <<LOGVAR(semstat) <<LOGVAR(sval); sem_post(&mOpenSignal); // Note: you must open the L2LogicalChannel before starting the SACCH service loop. #endif if (!mSacchRunning) { mSacchRunning=true; // This thread pushes data through lapdm and all the way to L1Encoder. mSacchServiceThread.start2((void*(*)(void*))SACCHServiceLoop,this,12000*sizeof(void*)); } LOG(DEBUG); }
SACCHLogicalChannel::SACCHLogicalChannel( unsigned wCN, unsigned wTN, const MappingPair& wMapping, /*const*/ L2LogicalChannel *wHost) : mHost(wHost) { mSACCHL1 = new SACCHL1FEC(wCN,wTN,wMapping); mL1 = mSACCHL1; // SAP0 is RR, SAP3 is SMS // SAP1 and SAP2 are not used. L2LAPDm *sap0 = new SACCHL2(1,SAPI0); // derived from L2LAPDm L2LAPDm *sap3 = new SACCHL2(1,SAPI3); sapInit(sap0,sap3); connect(mL1); //assert(mSACCH==NULL); #if USE_SEMAPHORE int sval, semstat= sem_getvalue(&mOpenSignal,&sval); LOG(DEBUG) << descriptiveString() << " SEM_INIT " <<LOGVAR(semstat) <<LOGVAR(sval); sem_init(&mOpenSignal,0,0); #endif }