Hi Mangesh,

On Wed, Feb 20, 2013 at 10:47:16AM +0000, Shukla, Mangesh wrote:
> Hi Ariel, Based on your suggestion below, I have implemented a Socket
> server in my external application dll , and now listen to it on
> a different port than the one that it connects with OOo.  I have been
> able to connect with it from the OOBasic macro function. I am even
> able to send across a string to the external application using the
> socket connection. However  I am facing some issues which I have
> posted on the openoffice forum.  Could you please have a look and let
> me know if you have any suggestions to make it work.
> 
> http://forum.openoffice.org/en/forum/viewtopic.php?f=44&t=59806

Unless there is a typo, there is an error in the macro

nBytesRead =  oConnection.read()(aByteArray, 200) 

read() takes two arguments, you have read()(ByteArray, 200)


You should be aware that read() blocks until it reads the amount you
specify or the connection in closed. If your socket server writes 100,
the macro will wait for other 100.

On the socket code, the logic for reading looks wrong too: 

read(buffer, 256) will return after 256 bytes are read, or the
connection is closed. With the exception thrown due to your Basic code,
the connection gets closed by the clean-up performed by the OOo Basic
engine, that's why it returns; but if the macro writes 200 bytes, read()
will wait for the remaining 6. You better use recv, that tries to read
up to some bytes, and you should read in a loop (if your buffer is 256
and the peer writes 300, the first recv will return 256, the second recv
will return 44, -1 on error, and
0 when the peer closed the connection).

Unfortunately, in AOO API the connector uses internally only read(),
this means that unless you will read/write in a fixed size, you will
need to use another language, and not AOO API, but the tools provided by
that language.
http://opengrok.adfinis-sygroup.org/source/xref/aoo-trunk/main/io/source/connector/ctr_socket.cxx#127
(Side note, flush() does nothing, obviously it does not make sense
when they use read/write)


Another point, your socket server should be accepting on its own thread,
otherwise acceptConnection() will block your application.

Attached is a dummy, untested example. It accepts only one connection at
the time, and after reading the first peer's write, it closes the
connection (for something more realistic, you'll need a multi-threaded
server - I'd use boost::asio instead of AOO C++ language binding).


Regards
-- 
Ariel Constenla-Haile
La Plata, Argentina
/**************************************************************
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 *
 *************************************************************/

#include <sal/main.h>
#include <osl/file.hxx>
#include <osl/thread.hxx>
#include <osl/thread.h>
#include <osl/socket.hxx>
#include <rtl/ustring.hxx>
#include <rtl/ustrbuf.hxx>

#include <iostream>
#include <cstring>

#define DEFAULT_PORT    2042

using rtl::OUString;
using namespace std;
using namespace osl;

class AcceptorThread : public osl::Thread
{
    public:
        AcceptorThread( );
        ~AcceptorThread( );

        void run( );
        void terminate( );

        bool
        isValid( )
        {
            return m_bValid;
        }

        sal_Int32
        getPort( )
        {
            return m_aAddress ? m_aAddress->getPort( ) : -1;
        }

    private:
        void bind( );
        void listen( );

        AcceptorSocket *m_aSocket;
        SocketAddr *m_aAddress;
        bool m_bValid;
        sal_Bool m_bListening;
};


AcceptorThread::AcceptorThread( )
    : m_aSocket( 0 )
    , m_aAddress( 0 )
    , m_bValid( false )
    , m_bListening( sal_False )
{
    OSL_TRACE( "AcceptorThread::AcceptorThread" );
    bind( );
}

AcceptorThread::~AcceptorThread( )
{
    OSL_TRACE( "AcceptorThread::~AcceptorThread" );
    delete m_aSocket;
    delete m_aAddress;
}

void
AcceptorThread::run( )
{
    OSL_TRACE( "AcceptorThread::run" );
    listen( );
}

void
AcceptorThread::terminate( )
{
    OSL_TRACE( "AcceptorThread::terminate" );
    if ( m_aSocket )
    {
        m_bListening = sal_False;
        m_aSocket->close( );
    }
    Thread::terminate( );
}

void
AcceptorThread::bind( )
{
    OSL_TRACE( "AcceptorThread::bind" );
    sal_Int32 port = DEFAULT_PORT;
    m_bValid = false;

    m_aAddress = new SocketAddr(
        OUString( RTL_CONSTASCII_USTRINGPARAM( "localhost" ) ), port );
    if ( !m_aAddress->is( ) )
    {
        cerr << " There was an error in creating the SocketAddr \n";
        return;
    }

    m_aSocket = new AcceptorSocket( );
    if ( m_aSocket == 0 )
    {
        cerr << "error creating  a socket\n";
        return;
    }

    while ( !( m_bValid = m_aSocket->bind( *m_aAddress ) ) )
    {
        m_aAddress->setPort( ++port );
    }
}

void
AcceptorThread::listen( )
{
    OSL_TRACE( "AcceptorThread::listen" );
    if ( !isValid() )
        return;

    StreamSocket aConnection;
    oslSocketResult socketResult;
    sal_Int32 nTotalBytes = 255;
    sal_Char buffer[nTotalBytes];
    sal_Int32 nTotalBytesRead, nRead;

    rtl::OUStringBuffer aBuffer;

    // number of connections at a time
    m_bListening = m_aSocket->listen( 5 );

    while ( isRunning( ) && m_bListening )
    {
        socketResult = m_aSocket->acceptConnection( aConnection );
        if ( socketResult != osl_Socket_Ok )
        {
            if ( !isRunning( ) || !m_bListening )
            {
                cout << "Not running... Stop accepting.\n";
                break;
            }

            cerr << " There was an error in accepting connection: "
                 << rtl::OUStringToOString(
                     aConnection.getErrorAsString( ), 
osl_getThreadTextEncoding() ).getStr( )
                 << '\n';

            continue;
        }

        cout << "Received request from "
             << rtl::OUStringToOString(
                 aConnection.getPeerHost(), osl_getThreadTextEncoding() 
).getStr()
             << ':' << aConnection.getPeerPort() << '\n';

        // request
        do
        {
            memset( buffer, '\0', nTotalBytes );
            nRead = aConnection.recv( buffer, nTotalBytes, osl_Socket_MsgNormal 
);
            if ( nRead > 0 )
            {
                nTotalBytesRead += nRead;
                aBuffer.appendAscii( buffer, nRead );
            }
        }
        while ( nRead == nTotalBytes );

        cout << "Received " << nTotalBytesRead << " bytes\n";
        nTotalBytesRead = 0;

        OUString aString = aBuffer.makeStringAndClear( );
        rtl::OString aStr = rtl::OUStringToOString( aString, 
osl_getThreadTextEncoding() );
        cout << "Content received:\n" << aStr.getStr( );

        // response
        sal_Int32 nWrite = aStr.getLength( );
        sal_Int32 n = aConnection.write( aStr.getStr( ), nWrite );
        if ( n != nWrite )
        {
            cerr << "error writing to socket\n";
        }
        aConnection.close( );
    }
}

SAL_IMPLEMENT_MAIN_WITH_ARGS( argc, argv )
{
    AcceptorThread test;
    if ( !test.isValid( ) || !test.create( ) )
        return 1;

    cout << "Listening on port " << test.getPort( ) << '\n';
    cout << "Press ENTER to terminate listening...";
    cin.get( );

    test.terminate( );

    cout << "Press ENTER to exit...";
    cin.get();

    return 0;
}

Attachment: pgpcPMePrRW70.pgp
Description: PGP signature

Reply via email to