void CppScanner::GetNext() { SetEmpty(); SkipWhitespace(); if (f.Get() == '/') { SkipComment(); SkipWhitespace(); } char ch = f.Get(); if (IsNumber(ch) || (ch == '+') || (ch == '-')) GetNumber(); else if (IsAlpha(ch)) GetName(); else if (ch == '(' || ch == ')' || ch == '<' || ch == '>' || ch == '=' || ch == ',' || ch == ';' || ch == '&') { type = CToken::DELIMITER; delimiter = ch; f.GetNext(); } else throw CPError(CPError::UNKNOWN_CHARACTER); }
void CppScanner::GetNumber() { long x; bool negative = false; if (f.Get() == '+') f.GetNext(); else if (f.Get() == '-') { negative = true; f.GetNext(); } if (IsNumber(f.Get())) { x = f.Get() - '0'; f.GetNext(); } else throw CPError(CPError::WRONG_NUMBER_FORMAT); while (IsNumber(f.Get())) { x = x*10 + f.Get() - '0'; f.GetNext(); } if (f.Get() == 'u') f.GetNext(); if (f.Get() == 'l') f.GetNext(); if (f.Get() == 'l') f.GetNext(); type = CToken::VALUE; value = x; }
void CppScanner::GetName() { char s[512]; int i = 0; do { s[i++] = f.Get(); if (i > 511) throw CPError(CPError::NAME_TOO_LONG); f.GetNext(); } while (IsAlphaNum(f.Get())); s[i] = 0; type = CToken::SYMBOL; if (!strcmp(s, "void")) symbol = CToken::SYMB_VOID; else if (!strcmp(s, "bool")) symbol = CToken::SYMB_BOOL; else if (!strcmp(s, "int8_t")) symbol = CToken::SYMB_CHAR; else if (!strcmp(s, "int16_t")) symbol = CToken::SYMB_SHORT; else if (!strcmp(s, "int32_t")) symbol = CToken::SYMB_INT; else if (!strcmp(s, "int64_t")) symbol = CToken::SYMB_LONG; else if (!strcmp(s, "uint8_t")) symbol = CToken::SYMB_UCHAR; else if (!strcmp(s, "uint16_t")) symbol = CToken::SYMB_USHORT; else if (!strcmp(s, "uint32_t")) symbol = CToken::SYMB_UINT; else if (!strcmp(s, "uint64_t")) symbol = CToken::SYMB_ULONG; else if (!strcmp(s, "vector")) symbol = CToken::SYMB_VECTOR; else if (!strcmp(s, "vectorR")) symbol = CToken::SYMB_VECTORR; else if (!strcmp(s, "HWvectorR")) symbol = CToken::SYMB_HWVECTORR; else if (!strcmp(s, "string")) symbol = CToken::SYMB_STRING; else if (!strcmp(s, "stringR")) symbol = CToken::SYMB_STRINGR; else if (!strcmp(s, "stringR")) symbol = CToken::SYMB_STRINGR; else if (!strcmp(s, "false")) symbol = CToken::SYMB_FALSE; else if (!strcmp(s, "true")) symbol = CToken::SYMB_TRUE; else if (!strcmp(s, "static")) symbol = CToken::SYMB_STATIC; else { type = CToken::NAME; name = new char[i+1]; strcpy(name, s); } }
// see: Control::MOSMSController MachineStatus MOSMSMachine::machineRunState(int state, const GSM::L3Message *l3msg, const SIP::DialogMessage *sipmsg) { // See GSM 04.11 Arrow Diagram A5 for the transaction (pat) NO, A5 is for GPRS. Closest diagram is F1. // SIP->Network message. // Step 1 MS->Network CP-DATA containing RP-DATA with message // Step 2 Network->MS CP-ACK // 4.11 6.2.2 State wait-for-RP-ACK, timer TR1M // Step 3 Network->MS CP-DATA containing RP-ACK or RP-Error // Step 4 MS->Network CP-ACK // LAPDm operation, from GSM 04.11, Annex F: // """ // Case A: Mobile originating short message transfer, no parallel call: // The mobile station side will initiate SAPI 3 establishment by a SABM command // on the DCCH after the cipher mode has been set. If no hand over occurs, the // SAPI 3 link will stay up until the last CP-ACK is received by the MSC, and // the clearing procedure is invoked. // """ WATCHF("MOSMS state=%x\n",state); PROCLOG2(DEBUG,state)<<LOGVAR(l3msg)<<LOGVAR(sipmsg)<<LOGVAR2("imsi",tran()->subscriber()); switch (state) { case L3CASE_MM(CMServiceRequest): { timerStart(TCancel,30*1000,TimerAbortTran); // Just in case. // This is both the start state and a request to start a new MO SMS when one is already in progress, as per GSM 4.11 5.4 const L3CMServiceRequest *req = dynamic_cast<typeof(req)>(l3msg); const GSM::L3MobileIdentity &mobileID = req->mobileID(); // Reference ok - the SM is going to copy it. // FIXME: We only identify this the FIRST time. // The L3IdentifySM can check the MM state and just return. // FIXME: check provisioning return machPush(new L3IdentifyMachine(tran(),mobileID, &mIdentifyResult), stateIdentResult); } case stateIdentResult: { if (! mIdentifyResult) { //const L3CMServiceReject reject = L3CMServiceReject(L3RejectCause::Invalid_Mandatory_Information); // (pat 6-2014) I think this is wrong, based on comment below, so changing it to the main channel: // l3sendSms(L3CMServiceReject(L3RejectCause::Invalid_Mandatory_Information),SAPI0); MMRejectCause rejectCause = L3RejectCause::Invalid_Mandatory_Information; channel()->l3sendm(L3CMServiceReject(rejectCause),L3_DATA,SAPI0); return MachineStatus::QuitTran(TermCause::Local(rejectCause)); } // Let the phone know we're going ahead with the transaction. // The CMServiceReject is on SAPI 0, not SAPI 3. PROCLOG(DEBUG) << "sending CMServiceAccept"; // Update 8-6-2013: The nokia does not accept this message on SACCH SAPI 0 for in-call SMS; // so I am trying moving it to the main channel. //l3sendSms(GSM::L3CMServiceAccept(),SAPI0); channel()->l3sendm(GSM::L3CMServiceAccept(),L3_DATA,SAPI0); gReports.incr("OpenBTS.GSM.SMS.MOSMS.Start"); return MachineStatusOK; } #if FIXME case L3CASE_ERROR: { // (pat) TODO: Call this on parsel3 error... // TODO: Also send an error code to the sip side, if any. l3sendSms(CPError(getL3TI())); return MachineStatusQuitTran; } #endif case L3CASE_SMS(DATA): { timerStop(TCancel); timerStart(TR1M,TR1Mms,TimerAbortTran); // Step 0: Wait for SAP3 to connect. // The first read on SAP3 is the ESTABLISH primitive. // That was done by our caller. //delete getFrameSMS(LCH,GSM::ESTABLISH); // Step 1: This is the first message: CP-DATA, containing RP-DATA. unsigned L3TI = l3msg->TI() | 0x08; tran()->setL3TI(L3TI); const CPData *cpdata = dynamic_cast<typeof(cpdata)>(l3msg); if (cpdata == NULL) { // Currently this is impossible, but maybe someone will change the code later. l3sendSms(CPError(L3TI)); return MachineStatus::QuitTran(TermCause::Local(L3Cause::SMS_Error)); } // Step 2: Respond with CP-ACK. // This just means that we got the message and could parse it. PROCLOG(DEBUG) << "sending CPAck"; l3sendSms(CPAck(L3TI)); // (pat) The SMS message has already been through L3Message:parseL3, which called SMS::parseSMS(source), which manufactured // a CPMessage::CPData and called L3Message::parse() which called CPData::parseBody which called L3Message::parseLV, // which called CPUserData::parseV to leave the result in L3Message::CPMessage::CPData::mData. // As the mathemetician said after filling 3 blackboards with formulas: It is obvious! // FIXME -- We need to set the message ref correctly, even if the parsing fails. // The compiler gives a warning here. Let it. It will remind someone to fix it. // (pat) Update: If we cant parse far enough to get the ref we send a CPError that does not need the ref. #if 0 unsigned ref; bool success = false; try { // (pat) hierarchy is L3Message::CPMessage::CPData; L3Message::parse calls CPData::parseBody. CPData data; data.parse(*CM); LOG(INFO) << "CPData " << data; // Transfer out the RPDU -> TPDU -> delivery. ref = data.RPDU().reference(); // This handler invokes higher-layer parsers, too. success = handleRPDU(transaction,data.RPDU()); } catch (SMSReadError) { LOG(WARNING) << "SMS parsing failed (above L3)"; // Cause 95, "semantically incorrect message". LCH->l3sendf(CPData(L3TI,RPError(95,ref)),3); if you ever use this, it should call l3sendSms delete CM; throw UnexpectedMessage(); } catch (GSM::L3ReadError) { LOG(WARNING) << "SMS parsing failed (in L3)"; delete CM; throw UnsupportedMessage(); } delete CM; #endif // Step 3 // Send CP-DATA containing message ref and either RP-ACK or RP-Error. // If we cant parse the message, we send RP-Error immeidately, otherwise we wait for the dialog to finish one way or the other. const RLFrame &rpdu = cpdata->data().RPDU(); this->mRpduRef = rpdu.reference(); bool success = false; try { // This creates the outgoing SipDialog to send the message. success = handleRPDU(rpdu); } catch (...) { LOG(WARNING) << "SMS parsing failed (above L3)"; } if (! success) { PROCLOG(INFO) << "sending RPError in CPData"; // Cause 95 is "semantically incorrect message" l3sendSms(CPData(L3TI,RPError(95,mRpduRef))); } mSmsState = MoSmsWaitForAck; LOG(DEBUG) << "case DATA returning"; return MachineStatusOK; } case L3CASE_SIP(dialogBye): { // SIPDialog sends this when the MESSAGE clears. PROCLOG(INFO) << "SMS peer did not respond properly to dialog message; sending RPAck in CPData"; l3sendSms(CPData(getL3TI(),RPAck(mRpduRef))); LOG(DEBUG) << "case dialogBye returning"; } case L3CASE_SIP(dialogFail): { PROCLOG(INFO) << "sending RPError in CPData"; // TODO: Map the dialog failure state to an RPError state. // Cause 127 is "internetworking error, unspecified". // See GSM 04.11 8.2.5.4 Table 8.4. l3sendSms(CPData(getL3TI(),RPError(127,mRpduRef))); LOG(DEBUG) << "case dialogFail returning"; } case L3CASE_SMS(ACK): { timerStop(TR1M); // Step 4: Get CP-ACK from the MS. const CPAck *cpack = dynamic_cast<typeof(cpack)>(l3msg); PROCLOG(INFO) << "CPAck " << cpack; gReports.incr("OpenBTS.GSM.SMS.MOSMS.Complete"); /* MOSMS RLLP request */ //if (gConfig.getBool("Control.SMS.QueryRRLP")) { // Query for RRLP //if (!sendRRLP(mobileID, LCH)) { // LOG(INFO) << "RRLP request failed"; //} //} // Done. mSmsState = MoSmsMMConnection; // TODO: if (set) set->mmCallFinished(); LOG(DEBUG) << "case ACK returning"; // This attach causes any pending MT transactions to start now. gMMLayer.mmAttachByImsi(channel(),tran()->subscriberIMSI()); return MachineStatus::QuitTran(TermCause::Local(L3Cause::SMS_Success)); } default: LOG(DEBUG) << "unexpected state"; return unexpectedState(state,l3msg); } }