smsc_cimd2.c
资源名称:gateway-1.2.1 [点击查看]
上传用户:gzpyjq
上传日期:2013-01-31
资源大小:1852k
文件大小:61k
源码类别:
手机WAP编程
开发平台:
WINDOWS
- /* Driver for CIMD 2 SMS centres.
- * Copyright 2000 WapIT Oy Ltd.
- * Author: Richard Braakman
- */
- /* TODO: Check checksums on incoming packets */
- /* TODO: Leading or trailing spaces are not allowed on parameters
- * "user identity" and "password". Check this. */
- /* TODO: Try to use the "More messages to send" flag */
- /* This code is based on the CIMD 2 spec, version 2-0 en.
- * All USSD-specific parts have been left out, since we only want to
- * communicate with SMSC's.
- *
- * I found one contradiction in the spec:
- *
- * - The definition of Integer parameters specifies decimal digits only,
- * but at least one Integer parameter (Validity Period Relative) can
- * be negative. I assume that this means a leading - is valid.
- */
- #include <ctype.h>
- #include <time.h>
- #include <errno.h>
- #include <limits.h>
- #include <string.h>
- #include <unistd.h>
- #include "gwlib/gwlib.h"
- #include "smsc_p.h"
- #include "sms.h"
- #include "dlr.h"
- #ifndef CIMD2_TRACE
- #define CIMD2_TRACE 0
- #endif
- /* Microseconds before giving up on a request */
- #define RESPONSE_TIMEOUT (10 * 1000000)
- /* Textual names for the operation codes defined by the CIMD 2 spec. */
- /* If you make changes here, also change the operation table. */
- enum {
- /* Requests from client */
- LOGIN = 1,
- LOGOUT = 2,
- SUBMIT_MESSAGE = 3,
- ENQUIRE_MESSAGE_STATUS = 4,
- DELIVERY_REQUEST = 5,
- CANCEL_MESSAGE = 6,
- SET_REQ = 8,
- GET_REQ = 9,
- /* Requests from server */
- DELIVER_MESSAGE = 20,
- DELIVER_STATUS_REPORT = 23,
- /* Requests from either */
- ALIVE = 40,
- /* Not a request; add to any request to make it a response */
- RESPONSE = 50,
- /* Responses not related to requests */
- GENERAL_ERROR_RESPONSE = 98,
- NACK = 99
- };
- /* Textual names for the parameters defined by the CIMD 2 spec. */
- /* If you make changes here, also change the parameter table. */
- enum {
- P_USER_IDENTITY = 10,
- P_PASSWORD = 11,
- P_DESTINATION_ADDRESS = 21,
- P_ORIGINATING_ADDRESS = 23,
- P_ORIGINATING_IMSI = 26,
- P_ORIGINATED_VISITED_MSC = 28,
- P_DATA_CODING_SCHEME = 30,
- P_USER_DATA_HEADER = 32,
- P_USER_DATA = 33,
- P_USER_DATA_BINARY = 34,
- P_MORE_MESSAGES_TO_SEND = 44,
- P_VALIDITY_PERIOD_RELATIVE = 50,
- P_VALIDITY_PERIOD_ABSOLUTE = 51,
- P_PROTOCOL_IDENTIFIER = 52,
- P_FIRST_DELIVERY_TIME_RELATIVE = 53,
- P_FIRST_DELIVERY_TIME_ABSOLUTE = 54,
- P_REPLY_PATH = 55,
- P_STATUS_REPORT_REQUEST = 56,
- P_CANCEL_ENABLED = 58,
- P_CANCEL_MODE = 59,
- P_MC_TIMESTAMP = 60,
- P_STATUS_CODE = 61,
- P_STATUS_ERROR_CODE = 62,
- P_DISCHARGE_TIME = 63,
- P_TARIFF_CLASS = 64,
- P_SERVICE_DESCRIPTION = 65,
- P_MESSAGE_COUNT = 66,
- P_PRIORITY = 67,
- P_DELIVERY_REQUEST_MODE = 68,
- P_GET_PARAMETER = 500,
- P_MC_TIME = 501,
- P_ERROR_CODE = 900,
- P_ERROR_TEXT = 901
- };
- /***************************************************************************/
- /* Table of properties of the parameters defined by CIMD 2, and some */
- /* functions to look up fields. */
- /***************************************************************************/
- /* Parameter types, internal. CIMD 2 spec considers P_TIME to be "Integer"
- * and P_SMS to be "User Data". */
- enum { P_INT, P_STRING, P_ADDRESS, P_TIME, P_HEX, P_SMS };
- /* Information about the parameters defined by the CIMD 2 spec.
- * Used for warning about invalid incoming messages, and for validating
- * outgoing messages. */
- static const struct
- {
- unsigned char *name;
- int number;
- int maxlen;
- int type; /* P_ values */
- int minval, maxval; /* For P_INT */
- }
- parameters[] = {
- { "user identity", P_USER_IDENTITY, 32, P_STRING },
- { "password", P_PASSWORD, 32, P_STRING },
- { "destination address", P_DESTINATION_ADDRESS, 20, P_ADDRESS },
- { "originating address", P_ORIGINATING_ADDRESS, 20, P_ADDRESS },
- /* IMSI is International Mobile Subscriber Identity number */
- { "originating IMSI", P_ORIGINATING_IMSI, 20, P_ADDRESS },
- { "originated visited MSC", P_ORIGINATED_VISITED_MSC, 20, P_ADDRESS },
- { "data coding scheme", P_DATA_CODING_SCHEME, 3, P_INT, 0, 255 },
- { "user data header", P_USER_DATA_HEADER, 280, P_HEX },
- { "user data", P_USER_DATA, 480, P_SMS },
- { "user data binary", P_USER_DATA_BINARY, 280, P_HEX },
- { "more messages to send", P_MORE_MESSAGES_TO_SEND, 1, P_INT, 0, 1 },
- { "validity period relative", P_VALIDITY_PERIOD_RELATIVE, 3, P_INT, -1, 255 },
- { "validity period absolute", P_VALIDITY_PERIOD_ABSOLUTE, 12, P_TIME },
- { "protocol identifier", P_PROTOCOL_IDENTIFIER, 3, P_INT, 0, 255 },
- { "first delivery time relative", P_FIRST_DELIVERY_TIME_RELATIVE, 3, P_INT, -1, 255 },
- { "first delivery time absolute", P_FIRST_DELIVERY_TIME_ABSOLUTE, 12, P_TIME },
- { "reply path", P_REPLY_PATH, 1, P_INT, 0, 1 },
- { "status report request", P_STATUS_REPORT_REQUEST, 2, P_INT, 0, 63 },
- { "cancel enabled", P_CANCEL_ENABLED, 1, P_INT, 0, 1 },
- { "cancel mode", P_CANCEL_MODE, 1, P_INT, 0, 2 },
- { "service centre timestamp", P_MC_TIMESTAMP, 12, P_TIME },
- { "status code", P_STATUS_CODE, 2, P_INT, 0, 9 },
- { "status error code", P_STATUS_ERROR_CODE, 3, P_INT, 0, 999 },
- { "discharge time", P_DISCHARGE_TIME, 12, P_TIME },
- { "tariff class", P_TARIFF_CLASS, 2, P_INT, 0, 99 },
- { "service description", P_SERVICE_DESCRIPTION, 1, P_INT, 0, 9 },
- { "message count", P_MESSAGE_COUNT, 3, P_INT, 0, 999 },
- { "priority", P_PRIORITY, 1, P_INT, 1, 9 },
- { "delivery request mode", P_DELIVERY_REQUEST_MODE, 1, P_INT, 0, 2 },
- { "get parameter", P_GET_PARAMETER, 3, P_INT, 501, 999 },
- { "MC time", P_MC_TIME, 12, P_TIME },
- { "error code", P_ERROR_CODE, 3, P_INT, 0, 999 },
- { "error text", P_ERROR_TEXT, 64, P_STRING },
- { NULL }
- };
- /* Return the index in the parameters array for this parameter id.
- * Return -1 if it is not found. */
- static const int parm_index(int parmno)
- {
- int i;
- for (i = 0; parameters[i].name != NULL; i++) {
- if (parameters[i].number == parmno)
- return i;
- }
- return -1;
- }
- #ifndef NO_GWASSERT
- /* Return the type of this parameter id. Return -1 if the id is unknown. */
- static const int parm_type(int parmno)
- {
- int i = parm_index(parmno);
- if (i < 0)
- return -1;
- return parameters[i].type;
- }
- #endif
- /* Return the max length for this parameter id.
- * Return -1 if the id is unknown. */
- static const int parm_maxlen(int parmno)
- {
- int i = parm_index(parmno);
- if (i < 0)
- return -1;
- return parameters[i].maxlen;
- }
- static const char *parm_name(int parmno)
- {
- int i = parm_index(parmno);
- if (i < 0)
- return NULL;
- return parameters[i].name;
- }
- #ifndef NO_GWASSERT
- /* Return 1 if the value for this (Integer) parameter is in range.
- * Return 0 otherwise. Return -1 if the parameter was not found. */
- static const int parm_in_range(int parmno, long value)
- {
- int i;
- i = parm_index(parmno);
- if (i < 0)
- return -1;
- return (value >= parameters[i].minval && value <= parameters[i].maxval);
- }
- #endif
- /* Helper function to check P_ADDRESS type */
- static int isphonedigit(int c)
- {
- return isdigit(c) || c == '+' || c == '-';
- }
- static const int parm_valid_address(Octstr *value)
- {
- return octstr_check_range(value, 0, octstr_len(value), isphonedigit);
- }
- /***************************************************************************/
- /* Some functions to look up information about operation codes */
- /***************************************************************************/
- static int operation_find(int operation);
- static Octstr *operation_name(int operation);
- static const int operation_can_send(int operation);
- static const int operation_can_receive(int operation);
- static const struct
- {
- unsigned char *name;
- int code;
- int can_send;
- int can_receive;
- }
- operations[] = {
- { "Login", LOGIN, 1, 0 },
- { "Logout", LOGOUT, 1, 0 },
- { "Submit message", SUBMIT_MESSAGE, 1, 0 },
- { "Enquire message status", ENQUIRE_MESSAGE_STATUS, 1, 0 },
- { "Delivery request", DELIVERY_REQUEST, 1, 0 },
- { "Cancel message", CANCEL_MESSAGE, 1, 0 },
- { "Set parameter", SET_REQ, 1, 0 },
- { "Get parameter", GET_REQ, 1, 0 },
- { "Deliver message", DELIVER_MESSAGE, 0, 1 },
- { "Deliver status report", DELIVER_STATUS_REPORT, 0, 1 },
- { "Alive", ALIVE, 1, 1 },
- { "NACK", NACK, 1, 1 },
- { "General error response", GENERAL_ERROR_RESPONSE, 0, 1 },
- { NULL, 0, 0, 0 }
- };
- static int operation_find(int operation)
- {
- int i;
- for (i = 0; operations[i].name != NULL; i++) {
- if (operations[i].code == operation)
- return i;
- }
- return -1;
- }
- /* Return a human-readable representation of this operation code */
- static Octstr *operation_name(int operation)
- {
- int i;
- i = operation_find(operation);
- if (i >= 0)
- return octstr_create(operations[i].name);
- if (operation >= RESPONSE) {
- i = operation_find(operation - RESPONSE);
- if (i >= 0) {
- Octstr *name = octstr_create(operations[i].name);
- octstr_append_cstr(name, " response");
- return name;
- }
- }
- /* Put the operation number here when we have octstr_format */
- return octstr_create("(unknown)");
- }
- /* Return true if a CIMD2 client may send this operation */
- static const int operation_can_send(int operation)
- {
- int i = operation_find(operation);
- if (i >= 0)
- return operations[i].can_send;
- /* If we can receive the request, then we can send the response. */
- if (operation >= RESPONSE)
- return operation_can_receive(operation - RESPONSE);
- return 0;
- }
- /* Return true if a CIMD2 server may send this operation */
- static const int operation_can_receive(int operation)
- {
- int i = operation_find(operation);
- if (i >= 0)
- return operations[i].can_receive;
- /* If we can send the request, then we can receive the response. */
- if (operation >= RESPONSE)
- return operation_can_send(operation - RESPONSE);
- return 0;
- }
- /***************************************************************************/
- /* Packet encoding/decoding functions. They handle packets at the octet */
- /* level, and know nothing of the network. */
- /***************************************************************************/
- struct packet
- {
- /* operation and seq are -1 if their value could not be parsed */
- int operation;
- int seq; /* Sequence number */
- Octstr *data; /* Encoded packet */
- /* CIMD 2 packet structure is so simple that packet information is
- * stored as a valid encoded packet, and decoded as necessary.
- * Exceptions: operation code and sequence number are also stored
- * as ints for speed, and the checksum is not added until the packet
- * is about to be sent. Since checksums are optional, the packet
- * is still valid without a checksum.
- *
- * The sequence number is kept at 0 until it's time to actually
- * send the packet, so that the send functions have control over
- * the sequence numbers.
- */
- };
- /* These are the separators defined by the CIMD 2 spec */
- #define STX 2 /* Start of packet */
- #define ETX 3 /* End of packet */
- #define TAB 9 /* End of parameter */
- /* The same separators, in string form */
- #define STX_str "