C# send or receive data was disallowed because the socket had already been shut down

125 Views Asked by At

I am developing an SMS Sender Application using SMPP and I have used EasySMPP which is an open source project. While sending SMS to the SMS Gateway I get below error, although the socket is open but still it is not able to send SMS and is yelling from socket shutdown.

System.Net.Sockets.SocketException (0x80004005): A request to send or receive data was disallowed because the socket had already been shut down in that direction with a previous shutdown call

Here is my code which is used for sending SMS to mobile device:

  public bool SendSms(string from, string to, string text)
        {
            bool result = false;
            if (smppClient.CanSend)
            {
                AutoResetEvent sentEvent;
                int sequence;
                lock (events)
                {
                    sequence = smppClient.SendSms(from, to, text);
                    sentEvent = new AutoResetEvent(false);
                    events[sequence] = sentEvent;
                }
                if (sentEvent.WaitOne(waitForResponse, true))
                {
                    lock (events)
                    {
                        events.Remove(sequence);
                    }
                    int statusCode;
                    bool exist;
                    lock (statusCodes)
                    {
                        exist = statusCodes.TryGetValue(sequence, out statusCode);
                    }
                    if (exist)
                    {
                        lock (statusCodes)
                        {
                            statusCodes.Remove(sequence);
                        }
                        if (statusCode == StatusCodes.ESME_ROK)
                            result = true;
                    }
                }
            }

            Trace.WriteLine(string.Format("SendSMS bool: "+result));

            return result;
        }

private void connectToSMSC()
            {
                try
                {
                    if (!smscArray.HasItems)
                    {
                        logMessage(LogLevels.LogErrors, "Connect | ERROR #1011 : No SMSC defined. Please add SMSC definition first.");
                    return;
                    }
                    initClientParameters();

                    IPAddress ipAddress = IPAddress.Parse(smscArray.currentSMSC.Host);
                    IPEndPoint remoteEP = new IPEndPoint(ipAddress, smscArray.currentSMSC.Port);
                    //  Create a TCP/IP  socket.
                    //Try to disconnect if connected
                    tryToDisconnect();
                    clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

                    logMessage(LogLevels.LogSteps, "Trying to connect to " + smscArray.currentSMSC.Description + "[" + smscArray.currentSMSC.Host + ":" + smscArray.currentSMSC.Port + "]");
            
                    clientSocket.BeginConnect(remoteEP, new AsyncCallback(connectCallback), clientSocket);
                    connectionState= ConnectionStates.SMPP_SOCKET_CONNECT_SENT;

            }
            catch (Exception ex)
                {
                    Trace.WriteLine( "connectToSMSC Error | " + ex.Message.ToString());
                }

            }//connectToSMSC

The error is thrown in below receiveCallBack() method client.BeginReceive ...

private void receiveCallback(IAsyncResult ar)
            {
                try
                {
                    int _command_length;
                    uint _command_id;
                    int _command_status;
                    int _sequence_number;
                    int _body_length;
                    byte[] _PDU_body = new byte[0];
                    byte[] _RESPONSE_PDU = new byte[KernelParameters.MaxPduSize];
                    int i, x;
                    bool _exit_flag;

                    // Retrieve the state object and the client socket 
                    // from the async state object.
                    StateObject state = (StateObject)ar.AsyncState;
                    Socket client = state.workSocket;
                    // Read data from the remote device.
                    int bytesRead = client.EndReceive(ar);
                    logMessage(LogLevels.LogSteps, "Received " + Tools.ConvertIntToHexString(bytesRead) + " bytes");

                if (bytesRead > 0)
                    {
                        // There might be more data, so store the data received so far.
                        if ((LogLevel & LogLevels.LogPdu) > 0)
                            logMessage(LogLevels.LogPdu, "Received Binary Data " + Tools.ConvertArrayToHexString(state.buffer, bytesRead));

                    //////////////////////////////
                    /// Begin processing SMPP messages
                    /// 
                    mLen = mPos + bytesRead;
                        if (mLen > KernelParameters.MaxBufferSize)
                        {
                            mPos = 0;
                            mLen = 0;
                            mbResponse = new byte[KernelParameters.MaxBufferSize];
                        }
                        else
                        {
                            Array.Copy(state.buffer, 0, mbResponse, mPos, bytesRead);
                            mPos = mLen;
                            _exit_flag = false;
                            x = 0;
                            while (((mLen - x) >= 16) && (_exit_flag == false))
                            {
                                _command_length = mbResponse[x + 0];
                                for (i = x + 1; i < x + 4; i++)
                                {
                                    _command_length <<= 8;
                                    _command_length = _command_length | mbResponse[i];
                                }

                                _command_id = mbResponse[x + 4];
                                for (i = x + 5; i < x + 8; i++)
                                {
                                    _command_id <<= 8;
                                    _command_id = _command_id | mbResponse[i];
                                }

                                _command_status = mbResponse[x + 8];
                                for (i = x + 9; i < x + 12; i++)
                                {
                                    _command_status <<= 8;
                                    _command_status = _command_status | mbResponse[i];
                                }

                                _sequence_number = mbResponse[x + 12];
                                for (i = x + 13; i < x + 16; i++)
                                {
                                    _sequence_number <<= 8;
                                    _sequence_number = _sequence_number | mbResponse[i];
                                }
                                if ((_command_length <= (mLen - x)) && (_command_length >= 16))
                                {
                                    if (_command_length == 16)
                                        _body_length = 0;
                                    else
                                    {
                                        _body_length = _command_length - 16;
                                        _PDU_body = new byte[_body_length];
                                        Array.Copy(mbResponse, x + 16, _PDU_body, 0, _body_length);
                                    }
                                    //////////////////////////////////////////////////////////////////////////////////////////
                                    ///SMPP Command parsing

                                    switch (_command_id)
                                    {
                                        case 0x80000009:
                                            logMessage(LogLevels.LogSteps, "Bind_Transiver_Resp");

                                            if (connectionState== ConnectionStates.SMPP_BIND_SENT)
                                            {
                                                if (_command_status == 0)
                                                {
                                                    connectionState= ConnectionStates.SMPP_BINDED;
                                                    logMessage(LogLevels.LogSteps, "SMPP Binded");

                                            }
                                            else
                                                {
                                                    logMessage(LogLevels.LogSteps | LogLevels.LogErrors, "SMPP BIND ERROR : " + Tools.ConvertIntToHexString(_command_status));

                                                disconnect(client);
                                                    tryToReconnect();
                                                    return;
                                                }
                                            }
                                            else
                                            {
                                                logMessage(LogLevels.LogSteps | LogLevels.LogWarnings, "ERROR #3011 : Unexpected Bind_Transiver_Resp");
                                            }
                                            break;
                                        case 0x80000004:
                                            logMessage(LogLevels.LogSteps, "Submit_Sm_Resp");
                                            SubmitSmRespEventArgs evArg = new SubmitSmRespEventArgs(_sequence_number, _command_status, Tools.ConvertArrayToString(_PDU_body, _body_length - 1));
                                            processSubmitSmResp(evArg);
                                            break;
                                        case 0x80000103:
                                            logMessage(LogLevels.LogSteps, "Data_Sm_Resp");
                                            evArg = new SubmitSmRespEventArgs(_sequence_number, _command_status, Tools.ConvertArrayToString(_PDU_body, _body_length - 1));
                                            processSubmitSmResp(evArg);
                                            break;
                                        case 0x80000015:
                                            logMessage(LogLevels.LogSteps, "Enquire_Link_Resp");
                                            enquireLinkResponseTime = DateTime.Now;
                                            break;
                                        case 0x00000015:
                                            logMessage(LogLevels.LogSteps, "Enquire_Link");
                                            sendEnquireLinkResp(_sequence_number);
                                            break;
                                        case 0x80000006:
                                            logMessage(LogLevels.LogSteps, "Unbind_Resp");
                                            connectionState= ConnectionStates.SMPP_UNBINDED;
                                            disconnect(client);
                                            break;
                                        case 0x00000005:
                                            logMessage(LogLevels.LogSteps, "Deliver_Sm");
                                            decodeAndProcessDeliverSm(_sequence_number, _PDU_body, _body_length);
                                            break;
                                        case 0x00000103:
                                            logMessage(LogLevels.LogSteps, "Data_Sm");
                                            decodeAndProcessDataSm(_sequence_number, _PDU_body, _body_length);
                                            break;
                                        default:
                                            sendGenericNack(_sequence_number, StatusCodes.ESME_RINVCMDID);
                                            logMessage(LogLevels.LogSteps | LogLevels.LogWarnings, "Unknown SMPP PDU type" + Tools.ConvertUIntToHexString(_command_id));
                                            break;
                                    }
                                    ///////////////////////////////////////////////////////////////////////////////////////////
                                    ///END SMPP Command parsing
                                    ///////////////////////////////////////////////////////////////////////////////////////////

                                    if (_command_length == (mLen - x))
                                    {
                                        mLen = 0;
                                        mPos = 0;
                                        x = 0;
                                        _exit_flag = true;
                                    }
                                    else
                                    {
                                        x += _command_length;
                                    }
                                }
                                else
                                {
                                    sendGenericNack(_sequence_number, StatusCodes.ESME_RINVMSGLEN);
                                    mLen -= x;
                                    mPos = mLen;
                                    Array.Copy(mbResponse, x, mbResponse, 0, mLen);
                                    _exit_flag = true;
                                    logMessage(LogLevels.LogSteps | LogLevels.LogWarnings, "Invalid PDU Length");
                                }
                                if (x < mLen)
                                    logMessage(LogLevels.LogPdu, "NEXT PDU STEP IN POS " + Convert.ToString(x) + " FROM " + Convert.ToString(mLen));
                                    Trace.WriteLine(string.Format("Response: "+x.ToString()));

                        }
                    }
                    //////////////////////////////
                    /// End processing SMPP messages
                    //  Get the rest of the data.
                    //### The socket error is thrown here ###
                    client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,new AsyncCallback(receiveCallback), state);
                   
                }
                else
                    {
                        logMessage(LogLevels.LogSteps | LogLevels.LogWarnings, "Incoming network buffer from SMSC is empty.");
                        /*                  if (client.Poll(0,SelectMode.SelectError)&&client.Poll(0,SelectMode.SelectRead)&&client.Poll(0,SelectMode.SelectWrite))
                                            {
                                                logMessage(LogLevels.LogSteps|LogLevels.LogExceptions, "Socket Error");
                                                unBind();
                                            }
                        */
                        tryToReconnect();
                    }
                }

                catch (Exception ex)
                {
                    Trace.WriteLine( "receiveCallback | " + ex.ToString());
                    unBind();
                }

            }//receiveCallback
1

There are 1 best solutions below

0
Hizbullah Watandost On

The issue is resolved after sending CLI as the source address. The CLI is mapped to mobile number in SMS gateway side (SMPP service provider). Some SMPP service providers which are mostly MNOs they do the mapping of CLI and source mobile number at their end and the system handles both if you send CLI or mobile number as sender source. in our case our SMS gateway was accepting CLI only not mobile number as sender address.

The following four parameters are required to bind or send SMS via SMPP protocol.

You need contact/contract with an SMS gateway or SMPP service provider which are mostly Mobile Network Operators (MNOs) to get the following details.

  1. HOST --> which is an IP from SMS gateway
  2. username/account: test
  3. password: test
  4. source mobile number/CLI: ABC or 937895565

The following two parameters are also sent, but you need to contact SMS gateway what values they expect. In our case we are sending both as 0.

  1. TON
  2. NPI

I hope the provided information could help anyone who is using EasySMPP library in their project.