sms_runtime.go 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723
  1. package ims
  2. import (
  3. "bufio"
  4. "context"
  5. "encoding/hex"
  6. "errors"
  7. "fmt"
  8. "net"
  9. "strconv"
  10. "strings"
  11. "time"
  12. "vocat/internal/device"
  13. "vocat/internal/vowifi"
  14. )
  15. const smsContentType = "application/vnd.3gpp.sms"
  16. var (
  17. ErrSMSCUnavailable = errors.New("ims: SMS service-centre address is unavailable")
  18. ErrSMSRejected = errors.New("ims: SMS MESSAGE was rejected")
  19. )
  20. type smsCenterReader interface {
  21. ReadSMSCenter(context.Context, string) (string, error)
  22. }
  23. // ReceivedSMS is a decoded mobile-terminated SMS delivered over IMS.
  24. type ReceivedSMS struct {
  25. MessageID string
  26. DeviceID string
  27. IMSI string
  28. From string
  29. Text string
  30. Timestamp time.Time
  31. ServiceCenterTimestamp *time.Time
  32. Encoding device.SMSEncoding
  33. Concat *device.SMSConcatInfo
  34. RPReference int
  35. CallID string
  36. RawRPDU string
  37. RawTPDU string
  38. }
  39. // ReceivedSMSStatus is network delivery evidence for one submitted SMS part.
  40. type ReceivedSMSStatus struct {
  41. DeviceID string
  42. IMSI string
  43. To string
  44. MessageReference int
  45. StatusCode int
  46. DeliveryStatus string
  47. ServiceCenterTimestamp *time.Time
  48. DischargeTimestamp *time.Time
  49. Timestamp time.Time
  50. RPReference int
  51. CallID string
  52. RawRPDU string
  53. RawTPDU string
  54. }
  55. type sipTransactionKey struct {
  56. callID string
  57. cseq uint32
  58. method string
  59. }
  60. func (session *Session) startRuntimeReceivers() error {
  61. if session.runtimeStarted {
  62. return nil
  63. }
  64. if err := session.conn.SetDeadline(time.Time{}); err != nil {
  65. return fmt.Errorf("ims: clear SIP connection deadline: %w", err)
  66. }
  67. if session.protectedUDP != nil {
  68. _ = session.protectedUDP.SetReadDeadline(time.Time{})
  69. }
  70. session.runtimeStarted = true
  71. session.receiveDone.Add(1)
  72. go session.readMainConnection()
  73. if session.securityActive && session.transport == "tcp" && session.protectedTCP != nil {
  74. session.receiveDone.Add(1)
  75. go session.acceptProtectedTCP()
  76. }
  77. if session.securityActive && session.transport == "udp" && session.protectedUDP != nil {
  78. session.receiveDone.Add(1)
  79. go session.readProtectedUDP()
  80. }
  81. return nil
  82. }
  83. func (session *Session) readMainConnection() {
  84. defer session.receiveDone.Done()
  85. for {
  86. var packet sipPacket
  87. var err error
  88. if session.transport == "tcp" {
  89. packet, err = readSIPPacket(session.reader)
  90. } else {
  91. buffer := make([]byte, 65535)
  92. var count int
  93. count, err = session.conn.Read(buffer)
  94. if err == nil {
  95. packet, err = parseSIPPacket(buffer[:count])
  96. }
  97. }
  98. if err != nil {
  99. if !session.isClosed() {
  100. session.publishFailure(fmt.Errorf("ims: SIP receive loop: %w", err))
  101. }
  102. return
  103. }
  104. session.dispatchPacket(packet, func(response []byte) error {
  105. session.writeMu.Lock()
  106. defer session.writeMu.Unlock()
  107. _, err := session.conn.Write(response)
  108. return err
  109. })
  110. }
  111. }
  112. func (session *Session) acceptProtectedTCP() {
  113. defer session.receiveDone.Done()
  114. for {
  115. connection, err := session.protectedTCP.AcceptTCP()
  116. if err != nil {
  117. return
  118. }
  119. if !session.validProtectedTCPSource(connection.RemoteAddr()) {
  120. _ = connection.Close()
  121. continue
  122. }
  123. session.inboundMu.Lock()
  124. session.inboundConnections[connection] = struct{}{}
  125. session.inboundMu.Unlock()
  126. session.receiveDone.Add(1)
  127. go session.readInboundTCP(connection)
  128. }
  129. }
  130. func (session *Session) readInboundTCP(connection net.Conn) {
  131. defer session.receiveDone.Done()
  132. defer func() {
  133. session.inboundMu.Lock()
  134. delete(session.inboundConnections, connection)
  135. session.inboundMu.Unlock()
  136. _ = connection.Close()
  137. }()
  138. reader := bufio.NewReader(connection)
  139. for {
  140. packet, err := readSIPPacket(reader)
  141. if err != nil {
  142. return
  143. }
  144. session.dispatchPacket(packet, func(response []byte) error {
  145. _, err := connection.Write(response)
  146. return err
  147. })
  148. }
  149. }
  150. func (session *Session) readProtectedUDP() {
  151. defer session.receiveDone.Done()
  152. buffer := make([]byte, 65535)
  153. for {
  154. count, remote, err := session.protectedUDP.ReadFromUDP(buffer)
  155. if err != nil {
  156. return
  157. }
  158. if !session.validProtectedUDPSource(remote) {
  159. continue
  160. }
  161. packet, err := parseSIPPacket(buffer[:count])
  162. if err != nil {
  163. continue
  164. }
  165. session.dispatchPacket(packet, func(response []byte) error {
  166. _, err := session.protectedUDP.WriteToUDP(response, remote)
  167. return err
  168. })
  169. }
  170. }
  171. func (session *Session) validProtectedTCPSource(address net.Addr) bool {
  172. remote, ok := address.(*net.TCPAddr)
  173. if !ok || !session.securityActive {
  174. return false
  175. }
  176. expected := addressIP(session.conn.RemoteAddr())
  177. return expected != nil && expected.Equal(remote.IP) &&
  178. remote.Port == session.securityAgreement.selected.portClient
  179. }
  180. func (session *Session) dispatchPacket(packet sipPacket, respond func([]byte) error) {
  181. if packet.Response != nil {
  182. response := packet.Response
  183. cseq, method, err := cseqNumber(response.value("CSeq"))
  184. if err != nil {
  185. return
  186. }
  187. key := sipTransactionKey{
  188. callID: strings.TrimSpace(response.value("Call-ID")),
  189. cseq: cseq,
  190. method: method,
  191. }
  192. session.transactionsMu.Lock()
  193. channel := session.transactions[key]
  194. session.transactionsMu.Unlock()
  195. if channel != nil {
  196. select {
  197. case channel <- response:
  198. default:
  199. }
  200. }
  201. return
  202. }
  203. if packet.Request != nil {
  204. session.handleSIPRequest(packet.Request, respond)
  205. }
  206. }
  207. func (session *Session) exchangeRuntime(
  208. ctx context.Context,
  209. request []byte,
  210. key sipTransactionKey,
  211. ) (*sipResponse, error) {
  212. responses := make(chan *sipResponse, 4)
  213. session.transactionsMu.Lock()
  214. if _, duplicate := session.transactions[key]; duplicate {
  215. session.transactionsMu.Unlock()
  216. return nil, errors.New("ims: duplicate SIP transaction")
  217. }
  218. session.transactions[key] = responses
  219. session.transactionsMu.Unlock()
  220. defer func() {
  221. session.transactionsMu.Lock()
  222. delete(session.transactions, key)
  223. session.transactionsMu.Unlock()
  224. }()
  225. session.writeMu.Lock()
  226. _, err := session.conn.Write(request)
  227. session.writeMu.Unlock()
  228. if err != nil {
  229. return nil, fmt.Errorf("ims: send SIP %s: %w", key.method, err)
  230. }
  231. timer := time.NewTimer(session.provider.config.TransactionTimeout)
  232. defer timer.Stop()
  233. for {
  234. select {
  235. case <-ctx.Done():
  236. return nil, ctx.Err()
  237. case <-timer.C:
  238. return nil, fmt.Errorf("ims: SIP %s transaction timed out", key.method)
  239. case response := <-responses:
  240. if response.StatusCode >= 100 && response.StatusCode < 200 {
  241. continue
  242. }
  243. return response, nil
  244. }
  245. }
  246. }
  247. func (session *Session) handleSIPRequest(request *sipRequest, respond func([]byte) error) {
  248. status := 200
  249. switch request.Method {
  250. case "OPTIONS":
  251. case "MESSAGE":
  252. contentType := strings.ToLower(strings.TrimSpace(strings.SplitN(request.value("Content-Type"), ";", 2)[0]))
  253. if contentType != smsContentType {
  254. status = 415
  255. }
  256. default:
  257. status = 405
  258. }
  259. response, err := buildSIPResponse(request, status, session.fromTag)
  260. if err == nil {
  261. _ = respond(response)
  262. }
  263. if status != 200 || request.Method != "MESSAGE" {
  264. return
  265. }
  266. go session.processSMSMessage(request)
  267. }
  268. func buildSIPResponse(request *sipRequest, status int, tag string) ([]byte, error) {
  269. reason := map[int]string{200: "OK", 405: "Method Not Allowed", 415: "Unsupported Media Type", 488: "Not Acceptable Here"}[status]
  270. if reason == "" {
  271. return nil, errors.New("ims: unsupported SIP response status")
  272. }
  273. via := request.values("Via")
  274. from := request.value("From")
  275. to := request.value("To")
  276. callID := request.value("Call-ID")
  277. cseq := request.value("CSeq")
  278. if len(via) == 0 || from == "" || to == "" || callID == "" || cseq == "" {
  279. return nil, errors.New("ims: request omitted a mandatory response header")
  280. }
  281. if !strings.Contains(strings.ToLower(to), ";tag=") {
  282. to += ";tag=" + tag
  283. }
  284. lines := []string{fmt.Sprintf("SIP/2.0 %d %s", status, reason)}
  285. for _, value := range via {
  286. lines = append(lines, "Via: "+value)
  287. }
  288. lines = append(lines,
  289. "From: "+from,
  290. "To: "+to,
  291. "Call-ID: "+callID,
  292. "CSeq: "+cseq,
  293. )
  294. if status == 405 {
  295. lines = append(lines, "Allow: REGISTER, MESSAGE, OPTIONS")
  296. }
  297. if status == 415 {
  298. lines = append(lines, "Accept: "+smsContentType)
  299. }
  300. lines = append(lines, "Content-Length: 0", "", "")
  301. return []byte(strings.Join(lines, "\r\n")), nil
  302. }
  303. func (session *Session) processSMSMessage(request *sipRequest) {
  304. rpdu, err := parseRPDU(request.Body)
  305. if err != nil {
  306. session.sendDeliveryReport(request, buildRPError(0, 95))
  307. return
  308. }
  309. if rpdu.messageType != 1 { // RP-DATA, network to MS.
  310. return
  311. }
  312. message, err := device.DecodeSMSDeliverTPDU(rpdu.tpdu)
  313. if err != nil {
  314. session.sendDeliveryReport(request, buildRPError(rpdu.reference, 95))
  315. return
  316. }
  317. receivedAt := time.Now().UTC()
  318. callID := strings.TrimSpace(request.value("Call-ID"))
  319. if message.Direction == device.SMSDirectionStatusReport {
  320. if message.MessageReference == nil || message.StatusCode == nil {
  321. session.sendDeliveryReport(request, buildRPError(rpdu.reference, 95))
  322. return
  323. }
  324. status := ReceivedSMSStatus{
  325. DeviceID: session.request.DeviceID,
  326. IMSI: session.request.Identity.IMSI,
  327. To: message.To,
  328. MessageReference: *message.MessageReference,
  329. StatusCode: *message.StatusCode,
  330. DeliveryStatus: message.DeliveryStatus,
  331. ServiceCenterTimestamp: message.ServiceCenterTimestamp,
  332. DischargeTimestamp: message.DischargeTimestamp,
  333. Timestamp: receivedAt,
  334. RPReference: int(rpdu.reference),
  335. CallID: callID,
  336. RawRPDU: strings.ToUpper(hex.EncodeToString(request.Body)),
  337. RawTPDU: strings.ToUpper(hex.EncodeToString(rpdu.tpdu)),
  338. }
  339. if session.provider.config.OnSMSStatus != nil {
  340. ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
  341. err = session.provider.config.OnSMSStatus(ctx, status)
  342. cancel()
  343. }
  344. if err != nil {
  345. session.sendDeliveryReport(request, buildRPError(rpdu.reference, 22))
  346. return
  347. }
  348. session.sendDeliveryReport(request, []byte{0x02, rpdu.reference})
  349. return
  350. }
  351. if message.Direction != device.SMSDirectionReceived {
  352. session.sendDeliveryReport(request, buildRPError(rpdu.reference, 95))
  353. return
  354. }
  355. var serviceCenterTimestamp *time.Time
  356. if message.ServiceCenterTimestamp != nil {
  357. value := message.ServiceCenterTimestamp.UTC()
  358. serviceCenterTimestamp = &value
  359. }
  360. received := ReceivedSMS{
  361. // A retransmission inside the same SIP transaction is idempotent, but a
  362. // fresh Call-ID/RP reference is a distinct network delivery and must stay
  363. // visible even when its TPDU and text happen to be identical.
  364. MessageID: fmt.Sprintf("ims:%s:%d", callID, rpdu.reference),
  365. DeviceID: session.request.DeviceID,
  366. IMSI: session.request.Identity.IMSI,
  367. From: message.From,
  368. Text: message.Text,
  369. Timestamp: receivedAt,
  370. ServiceCenterTimestamp: serviceCenterTimestamp,
  371. Encoding: message.Encoding,
  372. Concat: message.Concat,
  373. RPReference: int(rpdu.reference),
  374. CallID: callID,
  375. RawRPDU: strings.ToUpper(hex.EncodeToString(request.Body)),
  376. RawTPDU: strings.ToUpper(hex.EncodeToString(rpdu.tpdu)),
  377. }
  378. if session.provider.config.OnSMS != nil {
  379. ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
  380. err = session.provider.config.OnSMS(ctx, received)
  381. cancel()
  382. }
  383. if err != nil {
  384. session.sendDeliveryReport(request, buildRPError(rpdu.reference, 22))
  385. return
  386. }
  387. session.sendDeliveryReport(request, []byte{0x02, rpdu.reference})
  388. }
  389. func (session *Session) sendDeliveryReport(request *sipRequest, report []byte) {
  390. target := firstURI(request.value("P-Asserted-Identity"))
  391. if target == "" {
  392. target = firstURI(request.value("From"))
  393. }
  394. if target == "" {
  395. return
  396. }
  397. _, _ = session.sendSIPMessage(
  398. context.Background(),
  399. target,
  400. report,
  401. strings.TrimSpace(request.value("Call-ID")),
  402. )
  403. }
  404. func (session *Session) SendSMS(ctx context.Context, request vowifi.SMSSubmitRequest) (vowifi.SMSSubmitResult, error) {
  405. if ctx == nil {
  406. ctx = context.Background()
  407. }
  408. session.smsMu.Lock()
  409. defer session.smsMu.Unlock()
  410. session.mu.Lock()
  411. if session.closed || !session.evidence.Registered || !session.smsContactConfirmed {
  412. session.mu.Unlock()
  413. return vowifi.SMSSubmitResult{}, vowifi.ErrSMSNotReady
  414. }
  415. smsc := strings.TrimSpace(session.request.Identity.SMSC)
  416. session.mu.Unlock()
  417. if smsc == "" {
  418. reader, ok := session.provider.aka.(smsCenterReader)
  419. var readErr error
  420. if ok {
  421. smsc, readErr = reader.ReadSMSCenter(ctx, session.request.DeviceID)
  422. }
  423. if strings.TrimSpace(smsc) == "" {
  424. smsc = session.provider.config.SMSCenter
  425. }
  426. if strings.TrimSpace(smsc) == "" {
  427. return vowifi.SMSSubmitResult{}, errors.Join(ErrSMSCUnavailable, readErr)
  428. }
  429. session.mu.Lock()
  430. session.request.Identity.SMSC = smsc
  431. session.mu.Unlock()
  432. }
  433. parts, err := device.PrepareSMSSubmitTPDUs(request.Recipient, request.Text)
  434. if err != nil {
  435. return vowifi.SMSSubmitResult{}, err
  436. }
  437. now := time.Now().UTC()
  438. result := vowifi.SMSSubmitResult{
  439. To: parts[0].To,
  440. Encoding: string(parts[0].Encoding),
  441. SubmittedAt: now,
  442. PartsTotal: len(parts),
  443. ConcatReference: parts[0].ConcatReference,
  444. SubmissionStatus: "pending",
  445. PartResults: make([]vowifi.SMSSubmitPart, 0, len(parts)),
  446. }
  447. psi := "tel:" + normalizeE164(smsc)
  448. for _, part := range parts {
  449. reference := session.allocateRPReference()
  450. if len(part.TPDU) < 2 {
  451. return result, errors.New("ims: SMS-SUBMIT TPDU is truncated")
  452. }
  453. // Use the same value for TP-MR and RP-Message-Reference so an
  454. // SMS-STATUS-REPORT can be mapped back to this submitted part.
  455. part.TPDU[1] = reference
  456. rpdu, buildErr := buildRPData(reference, smsc, part.TPDU)
  457. if buildErr != nil {
  458. return result, buildErr
  459. }
  460. result.PartsAttempted++
  461. response, sendErr := session.sendSIPMessage(ctx, psi, rpdu, "")
  462. partResult := vowifi.SMSSubmitPart{
  463. Part: part.Part, Total: part.Total, Reference: int(reference), SubmittedAt: time.Now().UTC(),
  464. }
  465. if response != nil {
  466. partResult.SIPCode = response.StatusCode
  467. }
  468. if sendErr == nil && response.StatusCode >= 200 && response.StatusCode < 300 {
  469. partResult.Accepted = true
  470. partResult.SubmissionStatus = "accepted_by_ims"
  471. result.PartsAccepted++
  472. } else {
  473. partResult.SubmissionStatus = "rejected_by_ims"
  474. }
  475. result.PartResults = append(result.PartResults, partResult)
  476. if sendErr != nil {
  477. result.SubmissionStatus = "failed"
  478. return result, sendErr
  479. }
  480. if !partResult.Accepted {
  481. result.SubmissionStatus = "rejected"
  482. return result, fmt.Errorf("%w: SIP %d", ErrSMSRejected, response.StatusCode)
  483. }
  484. }
  485. result.AllPartsAccepted = true
  486. result.SubmissionStatus = "accepted_by_ims"
  487. return result, nil
  488. }
  489. func (session *Session) allocateRPReference() byte {
  490. session.mu.Lock()
  491. defer session.mu.Unlock()
  492. value := session.nextRPReference
  493. session.nextRPReference++
  494. return value
  495. }
  496. func (session *Session) sendSIPMessage(
  497. ctx context.Context,
  498. target string,
  499. body []byte,
  500. inReplyTo string,
  501. ) (*sipResponse, error) {
  502. callToken, err := randomHex(18)
  503. if err != nil {
  504. return nil, err
  505. }
  506. branch, err := randomHex(12)
  507. if err != nil {
  508. return nil, err
  509. }
  510. callID := callToken + "@" + addressHost(session.conn.LocalAddr())
  511. session.mu.Lock()
  512. cseq := session.cseq
  513. session.cseq++
  514. serviceRoutes := append([]string(nil), session.evidence.ServiceRoute...)
  515. securityHeaders := runtimeSecurityHeaders(
  516. session.securityActive,
  517. session.securityAgreement.verifyValue,
  518. )
  519. session.mu.Unlock()
  520. transportUpper := strings.ToUpper(session.transport)
  521. lines := []string{
  522. "MESSAGE " + target + " SIP/2.0",
  523. fmt.Sprintf("Via: SIP/2.0/%s %s;branch=z9hG4bK%s;rport", transportUpper, session.conn.LocalAddr().String(), branch),
  524. "Max-Forwards: 70",
  525. }
  526. lines = append(lines, securityHeaders...)
  527. if len(serviceRoutes) == 0 {
  528. lines = append(lines, "Route: <sip:"+session.endpoint.address()+";transport="+session.transport+";lr>")
  529. } else {
  530. for _, route := range serviceRoutes {
  531. lines = append(lines, "Route: "+route)
  532. }
  533. }
  534. lines = append(lines,
  535. "From: <"+session.identity.public+">;tag="+session.fromTag,
  536. "To: <"+target+">",
  537. "Call-ID: "+callID,
  538. fmt.Sprintf("CSeq: %d MESSAGE", cseq),
  539. "P-Preferred-Identity: <"+session.identity.public+">",
  540. "Accept-Contact: *;+g.3gpp.smsip",
  541. )
  542. if inReplyTo != "" {
  543. lines = append(lines, "In-Reply-To: "+inReplyTo)
  544. }
  545. lines = append(lines,
  546. "Content-Type: "+smsContentType,
  547. "Content-Transfer-Encoding: binary",
  548. "Content-Length: "+strconv.Itoa(len(body)),
  549. "", "",
  550. )
  551. request := append([]byte(strings.Join(lines, "\r\n")), body...)
  552. return session.exchangeRuntime(ctx, request, sipTransactionKey{callID: callID, cseq: cseq, method: "MESSAGE"})
  553. }
  554. func runtimeSecurityHeaders(active bool, verifyValue string) []string {
  555. verifyValue = strings.TrimSpace(verifyValue)
  556. if !active || verifyValue == "" {
  557. return nil
  558. }
  559. // RFC 3329 requires every request following a security agreement to
  560. // mirror Security-Server and repeat both sec-agree option tags. Omitting
  561. // these fields causes Vodafone's P-CSCF to reject MESSAGE with SIP 494.
  562. return []string{
  563. "Security-Verify: " + verifyValue,
  564. "Require: sec-agree",
  565. "Proxy-Require: sec-agree",
  566. }
  567. }
  568. type rpMessage struct {
  569. messageType byte
  570. reference byte
  571. tpdu []byte
  572. }
  573. func parseRPDU(data []byte) (rpMessage, error) {
  574. if len(data) < 2 {
  575. return rpMessage{}, errors.New("ims: RPDU is truncated")
  576. }
  577. result := rpMessage{messageType: data[0] & 0x07, reference: data[1]}
  578. if result.messageType != 1 {
  579. return result, nil
  580. }
  581. index := 2
  582. for count := 0; count < 2; count++ {
  583. if index >= len(data) {
  584. return rpMessage{}, errors.New("ims: RP-DATA address is truncated")
  585. }
  586. length := int(data[index])
  587. index++
  588. if length > len(data)-index {
  589. return rpMessage{}, errors.New("ims: RP-DATA address length is invalid")
  590. }
  591. index += length
  592. }
  593. if index >= len(data) {
  594. return rpMessage{}, errors.New("ims: RP-DATA omitted user data")
  595. }
  596. length := int(data[index])
  597. index++
  598. if length == 0 || length > len(data)-index {
  599. return rpMessage{}, errors.New("ims: RP-DATA user-data length is invalid")
  600. }
  601. result.tpdu = append([]byte(nil), data[index:index+length]...)
  602. return result, nil
  603. }
  604. func buildRPData(reference byte, smsc string, tpdu []byte) ([]byte, error) {
  605. address, err := encodeRPAddress(smsc)
  606. if err != nil {
  607. return nil, err
  608. }
  609. if len(tpdu) == 0 || len(tpdu) > 232 {
  610. return nil, errors.New("ims: SMS TPDU length is invalid")
  611. }
  612. result := []byte{0x00, reference, 0x00, byte(len(address))}
  613. result = append(result, address...)
  614. result = append(result, byte(len(tpdu)))
  615. result = append(result, tpdu...)
  616. return result, nil
  617. }
  618. func buildRPError(reference byte, cause byte) []byte {
  619. return []byte{0x04, reference, 0x01, cause & 0x7f}
  620. }
  621. func encodeRPAddress(value string) ([]byte, error) {
  622. value = normalizeE164(value)
  623. digits := strings.TrimPrefix(value, "+")
  624. if len(digits) < 3 || len(digits) > 20 {
  625. return nil, ErrSMSCUnavailable
  626. }
  627. toa := byte(0x81)
  628. if strings.HasPrefix(value, "+") {
  629. toa = 0x91
  630. }
  631. encoded := make([]byte, (len(digits)+1)/2)
  632. for index := 0; index < len(digits); index += 2 {
  633. if digits[index] < '0' || digits[index] > '9' {
  634. return nil, ErrSMSCUnavailable
  635. }
  636. low := digits[index] - '0'
  637. high := byte(0x0f)
  638. if index+1 < len(digits) {
  639. if digits[index+1] < '0' || digits[index+1] > '9' {
  640. return nil, ErrSMSCUnavailable
  641. }
  642. high = digits[index+1] - '0'
  643. }
  644. encoded[index/2] = high<<4 | low
  645. }
  646. return append([]byte{toa}, encoded...), nil
  647. }
  648. func normalizeE164(value string) string {
  649. value = strings.TrimSpace(value)
  650. var result strings.Builder
  651. for index, character := range value {
  652. if character >= '0' && character <= '9' || (index == 0 && character == '+') {
  653. result.WriteRune(character)
  654. }
  655. }
  656. return result.String()
  657. }
  658. func firstURI(value string) string {
  659. value = strings.TrimSpace(strings.SplitN(value, ",", 2)[0])
  660. if start := strings.IndexByte(value, '<'); start >= 0 {
  661. if end := strings.IndexByte(value[start+1:], '>'); end >= 0 {
  662. return strings.TrimSpace(value[start+1 : start+1+end])
  663. }
  664. }
  665. if semicolon := strings.IndexByte(value, ';'); semicolon >= 0 {
  666. value = value[:semicolon]
  667. }
  668. return strings.TrimSpace(value)
  669. }
  670. func (session *Session) isClosed() bool {
  671. session.mu.Lock()
  672. defer session.mu.Unlock()
  673. return session.closed
  674. }
  675. func (session *Session) closeInboundConnections() {
  676. session.inboundMu.Lock()
  677. connections := make([]net.Conn, 0, len(session.inboundConnections))
  678. for connection := range session.inboundConnections {
  679. connections = append(connections, connection)
  680. }
  681. session.inboundMu.Unlock()
  682. for _, connection := range connections {
  683. _ = connection.Close()
  684. }
  685. }
  686. var _ vowifi.SMSSender = (*Session)(nil)