| 
div.main {margin-left: 20pt; margin-right: 20pt} С.Кадаков 
       sgerr@hotmail.com 
      SMS-приложение. Часть 2.
      Глава 1 Процедура авторизации.
       Мы начинаем обсуждать команды протокола. В нашем, самом 
      первом, приложении нам их понадобится совсем немного. Начнем с процедуры 
      авторизации, выполняемой одной из команд семейства BIND.  
      Команды BIND.
      Как уже говорилось, это семейство включает три команды: 
      
        bind_receiver -- сообщает SMSC, что ESME подключается для 
        приема сообщений. Такой режим (только прием) характерен, например, для 
        пэйджинговых шлюзов. 
        bind_transmitter -- сообщает SMSC, что ESME подключается для 
        передачи сообщений. Данный режим используется, в частности, при 
        организации рассылок (в том числе, к сожалению, и спама). 
        bind_transceiver -- сообщает SMSC, что ESME подключается для 
        приема и передачи (т. е. в полнодуплексной моде). Этот режим удобен для 
        создания полнофункциональных шлюзов. 
       
      Ниже мы рассмотрим каждую из команд в отдельности и 
      приведем формат пакетов. Как уже отмечалось, все команды (пакеты) SMPP 
      должны предваряться заголовком. В заголовке команды поле command_id должно 
      содержать соответствующее значение.  
      bind_receiver. command_id = 0x01
      Тело пакета bind_receiver состоит из следующих 
      полей: 
      
       
        
        
          Field name 
          Size (octets) 
          Type 
          Description 
         
          | system_id  | 
          Var. max 16 | 
          C-Octet String | 
          Идентифицирует ESME. Можно рассматривать это поле, как 
            "username".  |  
        
          | password  | 
          Var. max 9 | 
          C-Octet String | 
          Пароль для аутентификации. |  
        
          | system_type  | 
          Var. max 13 | 
          C-Octet String | 
          Необязательное. Используется для указания категории 
            ESME, например "WWW", "E-MAIL" и т. д. Если не используется, должно 
            содержать один октет NULL (0x0) |  
        
          | interface_version  | 
          1 | 
          Integer | 
          Идентифицирует версию протокола SMPP, поддерживаемую 
            ESME. 0x00-0x33 указывают, что поддерживается версия 3.3 или более 
            ранняя. 0x34 указывает, что поддерживается версия 3.4 |  
        
          | addr_ton  | 
          1 | 
          Integer | 
          Указывает тип адреса (TON - Type Of Number) ESME. (см. 
            ниже). Если неизвестен, выставляется в NULL |  
        
          | addr_npi  | 
          1 | 
          Integer | 
          Указывает индикатор плана номеров (NPI -- Numbering 
            Plan Indicator). (см. ниже). Если неизвестен, выставляется в 
        NULL |  
        
          | address_range  | 
          Var. max 41 | 
          C-Octet String | 
          Адрес или диапазон адресов, обслуживаемых ESME. Если 
            неизвестен, выставляется в NULL |   
      
      
      bind_receiver_resp. command_id = 0x80000001
      Тело пакета bind_receiver_resp состоит из 
      следующих полей (*): 
      
       
        
        
          Field name 
          Size (octets) 
          Type 
          Description 
         
          | system_id  | 
          Var. max 16 | 
          C-Octet String | 
          Подтвержденный идентификатор ESME. |  
        
          | sc_interface_version  | 
          -  | 
          TLV | 
          Необязательное поле в формате TLV. Информирует о 
            версии протокола SMPP, поддерживаемой SMSC |   
      
      (*) -- В том случае, если поле command_status заголовка содержит 
      ненулевое значение (т. е. информирует об ошибке) тело пакета не 
      передается. 
      
      bind_transmitter. command_id = 0x02
      Формат и назначение полей тела пакета 
      bind_transmitter совпадает с форматом и назначением полей тела 
      пакета bind_receiver.  
      bind_transmitter_resp. command_id = 0x80000002
      Формат и назначение полей тела пакета 
      bind_transmitter_resp совпадает с форматом и назначением полей тела 
      пакета bind_receiver_resp.  
      bind_tranceiver. command_id = 0x03
      Формат и назначение полей тела пакета 
      bind_transceiver совпадает с форматом и назначением полей тела 
      пакета bind_receiver.  
      bind_tranceiver_resp. command_id = 0x80000003
      Формат и назначение полей тела пакета 
      bind_transceiver_resp совпадает с форматом и назначением полей тела 
      пакета bind_receiver_resp.  
      Параметры TON и NPI.
      Параметры TON и NPI не являются специфичными для 
      протокола SMPP, поэтому мы здесь не будем останавливаться на них подробно, 
      а просто приведем их возможные значения (подробнее об этих параметрах 
      можно прочитать в документации GSM): 
      
       
      
        
        
          TON 
          Value (bin) 
         
          | Unknown | 
          00000000 |  
        
          | International | 
          00000001 |  
        
          | National | 
          00000010 |  
        
          | Network Specific | 
          00000011 |  
        
          | Subscriber Number | 
          00000100 |  
        
          | Alphanumeric | 
          00000101 |  
        
          | Abbreviated | 
          00000110 |  
        
          | Reserved | 
          All others |    
      
        
        
          NPI 
          Value (bin)  
        
          | Unknown | 
          00000000 |  
        
          | ISDN (E163/E164) | 
          00000001 |  
        
          | Data (X.121) | 
          00000011 |  
        
          | Telex (F.69) | 
          00000100 |  
        
          | Land Mobile (E.212) | 
          00000110 |  
        
          | National | 
          00001000 |  
        
          | Private | 
          00001001 |  
        
          | ERMES | 
          00001010 |  
        
          | Internet (IP) | 
          00001100 |  
        
          WAP Client Id (to be defined by WAP Forum) | 
          00010010 |  
        
          | Reserved | 
          All others |   
      
      
      Generic Negative Result (generic_nack)
      Как уже отмечалось, любая из команд, испущенная той или 
      иной из сторон должна квитироваться ACK'ом (за единственным, упомянутым в 
      прошлой статье исключением). При этом поле command_id заголовка ACK'а 
      должно содержать соответствующее значение (равное command_id оригинальной 
      команды с выставленным 31-м битом), а поле sequence_number заголовка 
      должно указывать номер транзакции оригинальной команды. Однако в некоторых 
      случаях, в частности, когда принимающая сторона не может распознать 
      заголовок оригинальной команды -- например, при возникновении "мусора" в 
      TCP/IP канале -- информация, необходимая для формирования корректного 
      ACK'а может оказаться недоступной. В таких случаях принимающая сторона 
      отвечает специальным пакетом, называемым generic_nack (command_id = 
      0x80000000). Данный пакет состоит из одного заголовка с указанным 
      command_id. Поле command_status содержит соответствующий код ошибки, а 
      поле sequence_number может содержать NULL (0x0), если не удалось 
      распознать номер транзакции оригинальной команды.  
      Замечания.
      Несколько слов по поводу направления передачи данных по 
      соединениям, т. к. могут возникать недоразумения, связанные с названиями 
      сессий. Например, если ESME авторизовалось с помощью команды 
      bind_transmitter и сессия перешла в состояние BOUND_TX, не 
      следует думать, что SMSC не может передавать данные в такое 
      соединение (т. е., что программист избавлен от вызова recv(2) с 
      этим сокетом). Напротив, еще раз подчеркнем, что ACK'и передаются в 
      рамках того же соединения (т. е. в тот же сокет), что и оригинальные 
      команды. С другой стороны, разумеется, входящие сообщения (т. е. от SMSC к 
      ESME) не могут быть переданы по соединению, находящемуся в 
      BOUND_TX. Это важный момент и вот почему: как мы договорились, мы 
      будем работать в т. н. Store And Forward Mode, при этом сообщения 
      сначала помещаются в базу данных SMSC, а потом предпринимаются попытки их 
      доведения. Таким образом, факт помещения в базу данных (подтверждаемый 
      ACK'ом) еще не означает, что конечный пользователь получил данное 
      сообщение, кроме того, оно вообще может быть не доведено до истечения 
      срока годности в том случае, например, если аппарат пользователя остается 
      отключенным не протяжении нескольких дней. SMSC сигнализирует о переходе 
      сообщения в финальное состояние (доставлено/не может быть доставлено) с 
      помощью (специального вида) команды deliver_sm, т. е. той же 
      команды с помощью которой передаются входящие сообщения, и которая 
      ... не может быть передана в соединение находящееся в 
      BOUND_TX! В действительности, такие сообщения, называемые 
      delivery receipts некоторое время хранятся на SMSC и передаются в 
      первое же, авторизовавшееся с помощью bind_receiver, соединение 
      с тем же system_id. Таким образом, достаточно время от времени 
      открывать сессию с помощью bind_receiver и "снимать" delivery 
      receipt'ы и входящие сообщения, буде таковые найдутся, или просто сразу же 
      открывать две сессии. Понятно, что для сессий в состоянии BOUND_TRX 
      таких проблем не существует. Однако, в случаях больших загрузок 
      предпочтительней иметь отдельные сессии на прием и передачу (возможно, в 
      разных потоках исполнения -- threads) чтобы распараллелить эти операции. 
       
      Глава 2. Промежуточный итог 2
      В данной главе мы обсудили процедуру авторизации поверх 
      сокетного соединения. Как мы видим, она не слишком сложна, хотя здесь есть 
      некоторые интересные моменты. Нам осталось обсудить команды передачи и 
      приема сообщений и мы вплотную приблизимся к кодированию. Оставайтесь с нами!   P. S. 
      Кстати, еще раз напомним, что возникшие вопросы вы можете задать в форуме. 
 |