# Lesen und Senden von Daten

Beispiel in C für das Lesen von Daten

    /*!\brief Read answer from RRI server
    *
    * Use this function to read an answer from the RRI-Server
    *
    * @param ssl SSL context
    * @return Pointer to a c-string, which contains the answer. The memory used for this
    * string is allocated with malloc and must be freed by the application with free().
    * If an error occured, the function returns NULL.
    */
    char *rriRead(SSL *ssl)
    {
        char *buf;
        int s,nl,size,rest;
        nl=0;
        size=0;
        rest=4;
        while (rest) {
            s=SSL_read(ssl,(char*)&nl+(4-rest),rest);
            if (s<=0) return (NULL);                  // Fehler aufgetreten
            rest-=s;
        }
        size=ntohl(nl);
        buf=(char*)malloc(size+2);
        if (!buf) {
            // Not enough memory
            return (NULL);
        }
        rest=size;
        while (rest) {
            s=SSL_read(ssl,(char*)buf+(size-rest),rest);
            if (s<=0) {
               free(buf);
               return (0);                            // Fehler aufgetreten
            }
           rest-=s;
        }
        buf[size]=0;
        return (buf);
    }

Beispiel in C für das Senden von Daten

    /*!\brief Send order to RRI server
    *
    * Use this function to send an order to the RRI server
    *
    * @param ssl SSL context
    * @param order C-String, which contains the UTF-8 encoded order
    * @return Returns the length of the order, if it was successful send to the
    * RRI server or 0, if an error occured.
    */
    int rriSend(SSL *ssl, const char *order)
    {
      int size,nl,s;
      size=(int)strlen(order);
      nl=htonl(size);
      // Send 4-Byte perfix with length of order in bytes
      s  =SSL_write(ssl,(char*)&nl,4);
      if (s!=4) {
          // Error
          return (0);
      }
      // Send order
      s=SSL_write(ssl,order,size);
      if (s!=size) {
          // Error
          return (0);
      }
      return (s);
    }

Beispiel in PHP für das Lesen von Daten

    /*!\brief Read answer from RRI-Server
    *
    * \param $socket Socket handle
    * \return Returns string with answer from RRI server or false, if an error
    * occured.
    */
    function rriReadData($socket)
    {
        // Step 1: read 4-Byte RRI-Header
        $nlen="";
        $rest=4;
        while ($rest) {
            $a=fread($socket,$rest);               // read answer
            $bytesread=strlen($a);
            $nlen.=$a;
            $rest-=$bytesread;
            if (feof($socket)) return false;
        }

        $len=rriUnpack($nlen);                // convert bytes to local order

        // Step 2: read payload
        $rest=$len;
        $answer="";
        while ($rest) {
            $a=fread($socket,$rest);               // read answer
            $bytesread=strlen($a);
            $answer.=$a;
            $rest-=$bytesread;
            if (feof($socket)) return false;
        }
        return $answer;
    }

Innerhalb der Funktion "rriReadData" wird die Funktion "rriUnpack" aufgerufen. Sie lautet wie folgt:

    /*!\brief Converts network byte order to local byte order
    *
    * \param $value Integer in network byte order
    * \return Returns the converted $value in local byte order
    */
    function rriUnpack($value)
    {
        $a[0]=ord($value[0]);
        $a[1]=ord($value[1]);
        $a[2]=ord($value[2]);
        $a[3]=ord($value[3]);
        return $a[3]+($a[2]<<8) + ($a[1]<<16) + ($a[0]<<24);
    }

Beispiel in PHP für das Senden von Daten

    /*!\brief Sends order to RRI-Server
    *
    * \param $socket Socket handle
    * \param $order String, which should be send to the RRI-server
    * \return Returns 1 on success, 0 on failure
    */
    function rriSendData($socket, $order)
    {
        $len=strlen($order);
        $nlen=pack("N",$len);           // Convert Bytes of len to network order
        if (fwrite($socket,$nlen,4)<4) return 0;  // send length of order to server
        if (fwrite($socket,$order,$len)<$len) return 0;  // send order
        return 1;
    }

Beispiel in Perl für das Lesen von Daten

    # Read answer from RRI-Server
    #
    # Syntax: rriReadData(object socket)
    # Parameter:
    #    - socket: SSL connection established with rriConnect
    #
    # Returnvalue:
    #    Returns string with answer from RRI server on success or "undef", if an error
    #    occured.
    sub rriReadData {
            my $sock=shift;
            my ($head, $head2);
            my ($data, $data2);
            my $ret;
            $head="";
            $data="";

            # Step 1: read 4-byte RRI-header
            my $rest=4;
            while ( $rest ) {
                $ret=read $sock,$head2,$rest;
                if (! defined($ret)) {
                       return (undef);
                }
                $head.=$head2;
                $rest-=$ret;
            }
            my $len=unpack "N",$head;
            if ($len > 65535) {        # Should not happen, something went wrong
                       return (undef);
            }

            # Step 2: read payload
            $rest=$len;
            while ( $rest ) {
                $ret=read $sock,$data2,$rest;
                if (! defined($ret)) {
                       return (undef);
                }
                $data.=$data2;
                $rest-=$ret;
            }
            return $data;
    }

Beispiel in Perl für das Senden von Daten

    # Sends order to RRI-Server
    #
    #
    # Syntax: rriSendData(object socket, string order)
    # Parameter:
    #    - socket: SSL connection established with rriConnect
    #    - order: String, which should be send to the RRI-server
    #
    # Returnvalue:
    #    Returns 1 on success, 0 on failure
    sub rriSendData {
            my ($sock,$data)=@_;
            my $len=length($data);                # Length of data
            my $head=pack "N",$len;               # convert to 4 byte value in network byteorder
            return 0 if (!print $sock $head);     # send 4 byte header
            return 0 if (!print $sock $data);     # send payload
            return 1;
    }

Beispiel in Java für das Lesen und Senden von Daten

    package de.denic.rri.common;

    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.io.Serializable;
    import java.io.UnsupportedEncodingException;
    import java.net.InetSocketAddress;
    import java.net.Socket;
    import java.nio.ByteBuffer;
    import java.nio.CharBuffer;
    import java.nio.charset.CharacterCodingException;
    import java.nio.charset.Charset;
    import java.nio.charset.CharsetDecoder;

    import org.apache.commons.lang.Validate;
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;

    public final class TcpProtocolFramingHandler implements RriConstants {

      private static final Log log = LogFactory.getLog(TcpProtocolFramingHandler.class);
      // Immutable and thread-safe instance:
      private static final Charset PROTOCOL_CHARACTER_SET = Charset.forName(NAME_OF_PROTOCOLS_CHARACTER_SET);

      // Instance is NOT thread-safe!
      private final CharsetDecoder protocolsCharsetDecoder = PROTOCOL_CHARACTER_SET.newDecoder();
      private final Socket socket;

      public TcpProtocolFramingHandler(final Socket socket) throws IllegalArgumentException {
        super();
        Validate.notNull(socket, "Missing socket");
        this.socket = socket;
      }

      public MessageDataWithOptionalExceptionValue nextFrame() throws IOException {
        return nextFrame(-1); // Keine Prüfung der erlaubten Länge des Frames
      }

      public MessageDataWithOptionalExceptionValue nextFrame(final int maxAllowedPayloadSize) throws IOException {
        return doNextFrame(maxAllowedPayloadSize, socket.getInputStream());
      }

      protected final MessageDataWithOptionalExceptionValue doNextFrame(final int maxAllowedPayloadSize, final InputStream inputStream) throws IOException, IllegalArgumentException {
        final long lengthOfFrameInBytes = evaluateLengthOfFrameInBytes(inputStream);
        if (lengthOfFrameInBytes == 0) {
          return new MessageDataWithOptionalExceptionValue("", null);
        }

        if ((maxAllowedPayloadSize > 0) && (lengthOfFrameInBytes > maxAllowedPayloadSize)) {
          return new MessageDataWithOptionalExceptionValue("[Message to long]", new RriException(RriExceptionType.MESSAGE_TOO_LONG, new Serializable[] {Long.toString(lengthOfFrameInBytes) }), true);
        }

        final int lengthOfFrameInBytesAsInt = (int) lengthOfFrameInBytes;
        final byte[] messageAsByteArray = new byte[lengthOfFrameInBytesAsInt];
        if (log.isInfoEnabled()) {
          log.info("Reading frame of " + lengthOfFrameInBytes + " bytes");
        }
        int bytesReadForMessage = 0;
        while (bytesReadForMessage < lengthOfFrameInBytes) {
            bytesReadForMessage += inputStream.read(messageAsByteArray, bytesReadForMessage, lengthOfFrameInBytesAsInt
    								- bytesReadForMessage);
        }
        if (bytesReadForMessage != lengthOfFrameInBytes) {
          throw new IOException("Expecting frame containing minimum of "
    								+ lengthOfFrameInBytes + " bytes, but received only " + bytesReadForMessage + " bytes");
        }

        return decodeMessagesBytes(messageAsByteArray);
      }

      private MessageDataWithOptionalExceptionValue decodeMessagesBytes(final byte[] messageAsByteArray)
    	throws IllegalArgumentException {
          try {
            final CharBuffer message = protocolsCharsetDecoder.decode(ByteBuffer.wrap(messageAsByteArray));
            return new MessageDataWithOptionalExceptionValue(message.toString(), null);
          }	catch (final CharacterCodingException e) {
            log.warn("Decoding received message failed", e);
            return new MessageDataWithOptionalExceptionValue("[Decoding message data failed]", new RriException(RriExceptionType.MESSAGE_ENCODING_ILLEGAL));
          }
      }

      private long evaluateLengthOfFrameInBytes(final InputStream inputStream) throws IOException {
        long lengthOfFrameInBytes = 0;
        for (int i = 3; i >= 0; i--) {
          final int byteRead = inputStream.read();
          if (byteRead < 0) {
            if (i == 3) {
              // No single byte reaches us
              throw new IOException("Input stream of connection is empty: Connection seems to be closed");
            }

            throw new IOException("Missing four bytes representing frame's length");
          }

          lengthOfFrameInBytes += byteRead << (8 * i);
        }
        if ((lengthOfFrameInBytes > Integer.MAX_VALUE) || (lengthOfFrameInBytes < 0)) {
          throw new IOException("The four bytes representing frame's length denotes a number that cannot be handled: "
            + lengthOfFrameInBytes);
        }

        return lengthOfFrameInBytes;
      }

      public void putFrame(final String frame) throws IOException {
        doPutFrame(frame, socket.getOutputStream());
      }

      /**
      * Access modifier protected for testing purposes
      */
      protected final void doPutFrame(final String frame, final OutputStream outputStream)
      throws UnsupportedEncodingException, IOException {
       final byte[] frameAsUtf8Bytes = frame.getBytes(NAME_OF_PROTOCOLS_CHARACTER_SET);
       final int lengthOfFrameInBytes = frameAsUtf8Bytes.length;
       final byte[] lengthEncodedAsBytes = new byte[] {(byte) (lengthOfFrameInBytes >> 24),
          (byte) (lengthOfFrameInBytes >> 16), (byte) (lengthOfFrameInBytes >> 8), (byte) lengthOfFrameInBytes };
       if (log.isInfoEnabled()) {
         log.info("Writing frame of " + lengthOfFrameInBytes + " bytes");
       }
       synchronized (socket) {
         outputStream.write(lengthEncodedAsBytes);
         outputStream.write(frameAsUtf8Bytes);
         outputStream.flush();
       }
      }

      public void close() {
        if (socket.isClosed()) {
          return;
        }

        try {
          synchronized (socket) {
            try {
               socket.getOutputStream().flush();
            } finally {
              socket.close();
              }
          }
        } catch (final IOException e) {
          log.warn("Closing socket failed", e);
          }
        }

        public InetSocketAddress getSocketAddress() {
        return (InetSocketAddress) socket.getRemoteSocketAddress();
      }

      @Override
      public String toString() {
        return socket.toString();
      }
    }