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();
  }
}