Printable Version of Topic

Click here to view this topic in its original format

AMIP Community _ SDK Support _ Access AMIP socket server from *nix

Posted by: uplate Oct 10 2007, 02:03 AM

Hi, I am interested in trying to access AMIP from *nix. It appears that AMIP server creates a TCP socket connection that should be able to be accessed remotely. Can you give some indication on how this could be done?

I've tried with socket and telnet, but both indicate that the AMIP hosting machine refuses the connection.

My setup:

[WIN]
AMIP Server:40581

[NIX]
Client access:
`telnet WIN 40581`
`socket WIN 40581`

Thanks

Posted by: Serge Oct 10 2007, 09:01 AM

AMIP uses specific protocol, application which connects must be created using the http://www.codeproject.com/threads/Rcf_Ipc_For_Cpp.asp.

In AMIP API/Server settings set the correct bind address (0.0.0.0 for all interfaces, otherwise, AMIP will listen only on 127.0.0.1, thus making it impossible to connect from another machines).

AMIP's RCF interface IDL:

CODE

RCF_BEGIN(MyService, "MyService");

RCF_METHOD_V3(void, exec, std::string, std::string, std::string);
RCF_METHOD_R2(std::string, eval, std::string, std::string);
RCF_METHOD_R0(std::string, ping);
RCF_METHOD_V5(void, add_event_listener, std::string, int, int, UINT, UINT);
RCF_METHOD_V2(void, remove_event_listener, std::string, int);
RCF_METHOD_R0(std::vector<std::string>, get_pltitles);

RCF_END(MyService);


Current AMIP version is built with RCF 0.4 and will not work with 0.9, the next version will be build with RCF 0.9c.

Posted by: uplate Oct 15 2007, 12:40 PM

::phew::..finally got boost/asio/rcf compiled and working on FreeBSD, can't wait to start writing clients for amip/server.

thank so much for your help so far!


max

Posted by: uplate Oct 15 2007, 11:39 PM

OK, so I've tried writing a basic program to ping AMIP:

CODE

#include <iostream>
#include <string>

#include <RCF/Idl.hpp>
#include <RCF/TcpEndpoint.hpp>
#include <RCF/Exception.hpp>

RCF_BEGIN(Amip, "Amip");
        RCF_METHOD_R0(std::string, ping);
RCF_END(Amip);

int main()
{
        try
        {
          RcfClient<Amip> amipClient( RCF::TcpEndpoint( "192.168.0.203", 60333 ) );
          std::cout << amipClient.ping() << std::endl;
        }
        catch( RCF::Exception ex )
        {
          std::cout << ex.what() << std::endl;
        }
        return 0;
}


When I run the program, I get the following error:
CODE

[uplate@~/devel/src/amip-client]> ./amipclient
Marshal.cpp(67): void RCF::IDL::doInReturnValue(RCF::ClientStub&, RCF::SerializationProtocolIn&, RCF::SerializationProtocolOut&, bool): : Thread-id=134774784 : Timestamp(ms)=63383011: THROW : ClientTransportException: server response timed out: totalTimeoutMs=10000, typeid(connection)=N3RCF22TcpAsioClientTransportE,


I'm sure that the amip server is up and running on 192.168.0.203:60333 because I can telnet to it..is my code bad or is this a problem with my installation of RCF/asio do you think?

Thanks,
Max

Posted by: Serge Oct 15 2007, 11:43 PM

AMIP on Windows is not using ASIO for RCF, but the native sockets, so it could be a problem. I'll try contacting RCF developer with this question.

What kind of client do you want to write and what for?

Posted by: uplate Oct 16 2007, 12:18 AM

Thank you for looking into this for me. I could help you with anything you'd like if you want help using asio on windows, although I'm not much of a programmer.

This is kind of a fun little project for me to do, so the program I write could be as simple as an executable which pulls the song information from AMIP, or an irssi plugin which implements greater functionality. Myself, and a certain percentage of the populace, use Windows as a desktop, but PuTTY+irssi for chat. This would be great for us, as AMIP appears to be quite powerful. Other solutions I've tried were having another Winamp plugin FTP a file with song information to my server, but this is very ugly in comparison with the solution I have in mind.

I guess you are the person who responded to my post on codeproject :-)

I will try to write a simple server program on windows using RCF/ASIO, and see if this will allow cross-platform TCP/socket connection if that would help you diagnose...

Posted by: Serge Oct 16 2007, 10:22 AM

Here is AMIP compiled with RCF 0.9: http://amip.tools-for.net/files/test/gen_irc.dll.
Replace the original in Winamp/Plugins or if using another player, rename to amip.dll.

Compile your client with RCF 0.9 and see if it helps. Don't use BOOST serialization (use RCF_USE_SF_SERIALIZATION).

Here is http://amip.tools-for.net/files/test/amip_sdk.zip compiled with RCF 0.9. You can try the samples on the Windows machine to see if it works.

Posted by: uplate Oct 16 2007, 11:53 PM

IT WORKED!

CODE

[uplate@~/devel/src/amip-client]> ./amipclient
!!! - Bend Over Beethoven
[uplate@~/devel/src/amip-client]> ./amipclient
Karate Kid - You're the Best
[uplate@~/devel/src/amip-client]>


Thanks for you time and effort, this is so great :-)
Max

Posted by: uplate Oct 20 2007, 02:20 AM

ive been working on an irssi module, and it's been kinda successful =-). see the attached screenshot.


if it's ok with you, i'd like to begin public development, on sourceforge or something, so people can help me by contributing/testing. i'd like to call the project NARC, for Nix-Amip Remote Control.


Attached thumbnail(s)
Attached Image

Posted by: Serge Oct 20 2007, 11:27 AM

Looks nice, thanks for your efforts.

Posted by: uplate Oct 21 2007, 02:22 AM

Here's another picture.

Looking at the IDL, I realize I don't really know how a few of the functions work.

CODE

RCF_METHOD_V3(void, exec, std::string, std::string, std::string);
RCF_METHOD_V5(void, add_event_listener, std::string, int, int, UINT, UINT);
RCF_METHOD_V2(void, remove_event_listener, std::string, int);


What three arguments does `exec` accept? 'command',..? ac.h doesn't make it clear to me what ought to be provided to client.exec( ... ), beyond the actual command.

I understand how the event listeners are supposed to work from the perspective of setting up callbacks, but I don't have any idea what arguments are to provided to the IDL functions.

Thanks,
Max


Attached thumbnail(s)
Attached Image

Posted by: Serge Oct 21 2007, 11:35 AM

Using listeners is a bit complicated and requires a server on your side to accept connections with different IDL. It's not needed if you just want to use exec/eval commands.

Exec command executes AMIP API command (see the manual for the list of the commands). 3 parameters is a legacy thing from the DDE API used before.

Actually you need to split the API command into 3 strings by spaces and pass them to this function. If there are less than 3 words in the string, pass empty string.

Like for "control pause"

client->exec("control", "pause", "");

If you need more information, I can provide you sources of ac.dll so that you see how it works (contact me by mail). Note that ac.dll also includes mIRC API, so the code is not very clean.

Posted by: uplate Oct 24 2007, 01:51 AM

thanks for the information, and the source has been quite helpful :-). ac_exec( one, two, three) is now working for this program.

Posted by: uplate Nov 2 2007, 01:36 AM

Hey again,

so i'm a little stuck trying to implement any kind of ClientService. I know that AMIP on my windows machine is properly transmitting commands and events, because when i run a socket tool, i get output:

CODE

[uplate@~/devel/src/narc/src]> socket -sl 60334
ClientServiceC//describe $active np: !!! - Heart Of Hearts [06:02m/320kbps/44kHz]

if i run a program to set up an event listener, i also see stuff appear when i hit play or pause in winamp, or send a play/pause command from my *nix box using MyService IDL.

however, when i try to run the following code i always get a core dump. it starts up fine, but then segfaults when i take any action in amip (play/pause/change song/etc...):

CODE

/*
* C++ headers
*/
#include <RCF/Idl.hpp>
#include <RCF/RcfServer.hpp>
#include <RCF/TcpEndpoint.hpp>
#include <iostream>

/* AMIP IDLs */
#include "amip/ClientService.hpp"

class NarcService
{
  public:
  void exec( std::string cmd )
  {
    std::cout << "Got exec" << std::endl;
  }
  void event( unsigned int code )
  {
    std::cout << "Got event" << std::endl;
  }
};

int main()
{
  NarcService narcService;
  RCF::RcfServer server(RCF::TcpEndpoint(60334));
  server.bind<ClientService>(narcService);
  server.startInThisThread();
  return 0;
}


then this occurs when i create an event from winamp or a MyService program:
CODE

[uplate@~/devel/src/narc/src]> ./narcserver
zsh: segmentation fault (core dumped)  ./narcserver


here is the gdb backtrace:
CODE

Starting program: /usr/home/uplate/devel/src/narc/src/narcserver
warning: Unable to get location for thread creation breakpoint: generic error
[New LWP 100040]
[New Thread 0x8093000 (LWP 100086)]

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x8093000 (LWP 100086)]
0x2825cee9 in RCF::MethodInvocationRequest::decodeFiltered ()
   from /usr/local/lib/librcf.so
(gdb) bt
#0  0x2825cee9 in RCF::MethodInvocationRequest::decodeFiltered ()
   from /usr/local/lib/librcf.so
#1  0x28258c22 in RCF::MethodInvocationRequest::decodeRequest ()
   from /usr/local/lib/librcf.so
#2  0x28274164 in RCF::RcfServer::onReadCompleted () from /usr/local/lib/librcf.so
#3  0x2828eed8 in RCF::TcpServerTransport::cycleRead ()
   from /usr/local/lib/librcf.so
#4  0x2828f96e in RCF::TcpServerTransport::cycle () from /usr/local/lib/librcf.so
#5  0x2828fdc8 in RCF::TcpServerTransport::cycleTransportAndServer ()
   from /usr/local/lib/librcf.so
#6  0x28303f06 in boost::_mfi::mf3<bool, RCF::TcpServerTransport, RCF::RcfServer&, int, bool const volatile&>::operator() () from /usr/local/lib/librcf.so
#7  0x28302eb6 in boost::_bi::list4<boost::_bi::value<RCF::TcpServerTransport*>, boost::reference_wrapper<RCF::RcfServer>, boost::arg<1> (*)(), boost::arg<2> (*)()>::operator()<bool, boost::_mfi::mf3<bool, RCF::TcpServerTransport, RCF::RcfServer&, int, bool const volatile&>, boost::_bi::list3<int&, bool const volatile&, bool&> > ()
   from /usr/local/lib/librcf.so
#8  0x283003b5 in boost::_bi::bind_t<bool, boost::_mfi::mf3<bool, RCF::TcpServerTransport, RCF::RcfServer&, int, bool const volatile&>, boost::_bi::list4<boost::_bi::value<RCF::TcpServerTransport*>, boost::reference_wrapper<RCF::RcfServer>, boost::arg<1> (*)(), boost::arg<2> (*)()> >::operator()<int, bool const volatile, bool> ()
   from /usr/local/lib/librcf.so
---Type <return> to continue, or q <return> to quit---
#9  0x282fdf67 in boost::detail::function::function_obj_invoker3<boost::_bi::bind_t<bool, boost::_mfi::mf3<bool, RCF::TcpServerTransport, RCF::RcfServer&, int, bool const volatile&>, boost::_bi::list4<boost::_bi::value<RCF::TcpServerTransport*>, boost::reference_wrapper<RCF::RcfServer>, boost::arg<1> (*)(), boost::arg<2> (*)()> >, bool, int, bool const volatile&, bool>::invoke () from /usr/local/lib/librcf.so
#10 0x282bf412 in boost::function3<bool, int, bool const volatile&, bool, std::allocator<boost::function_base> >::operator() () from /usr/local/lib/librcf.so
#11 0x28272602 in RCF::RcfServer::cycle () from /usr/local/lib/librcf.so
#12 0x2826ae0a in RCF::repeatCycleServer () from /usr/local/lib/librcf.so
#13 0x28272204 in RCF::RcfServer::startInThisThread () from /usr/local/lib/librcf.so
#14 0x28271fad in RCF::RcfServer::startInThisThread () from /usr/local/lib/librcf.so
#15 0x0805ba50 in main () at narc_server.cpp:30
(gdb)


i realize you do things a little differently in your code, with templating, threads, queues and stuff. that is a little advanced for me right now, so i'm trying to build my way up using the examples on the RCF website.


thanks,
max

Posted by: uplate Nov 3 2007, 02:56 AM

Hey Serge,

Ignore the last email, it was a problem of needing to have the libs and source built with BOOST_ASIO. I got that solved, and now I have a 95% working server program. Using the code I listed above, I now get the following when I run the following test program:

CODE

/*
* C++ headers
*/
#include <RCF/ClientStub.hpp>
#include <RCF/Idl.hpp>
#include <RCF/RcfServer.hpp>
#include <RCF/TcpEndpoint.hpp>
#include <SF/vector.hpp>
#include <iostream>

/* AMIP IDLs */
#include "amip/MyService.hpp"
#include "amip/ClientService.hpp"

/*
* C headers
*/
#ifdef __cplusplus
extern "C" {
#include <unistd.h>
}
#endif

int main()
{
   RcfClient<ClientService> server_test(RCF::TcpEndpoint("localhost", 60334));
   server_test.exec("hello");
   return 0;
}


Run server program, followed by above test.
CODE

[uplate@~/devel/src/narc/src]> ./narcserver
Got exec


However, when I try change a song in AMIP, the server program does not respond. This confuses me, because before, when I had a server program built without ASIO, the server program would segfault when I changed a song in AMIP. Now it seems as if the server program does not even get a connection from AMIP.

It is clear to me that, in the case where the server program runs without ASIO, it binds to *:60334, whereas when I compile with ASIO, it binds to 127.0.0.1:60334, regardless of what I set "host" to in RCF::TcpEndpoint. I have verified this by running `sockstat -l4` in either case. I realize that this appears to be an RCF issue, but I thought I'd post it here for the benefit of anyone else trying this stuff out, or in case you'd encountered anything like this.

Max

Posted by: uplate Nov 3 2007, 05:28 AM

Was a bug in RCF, author gave me a fix. Now I have totally functional amip client on *NIX :-).

CODE

[uplate@~/devel/src/narc/src]> ./narcserver
Got exec: //describe $active np: Black Dice - Bottom Feeder [02:50m/320kbps/44kHz]
Got event: 2
Got event: 1
Got event: 4
Got event: 1
Got event: 128
Got exec: //describe $active np: Black Dice - Scavenger [05:16m/320kbps/44kHz]
Got event: 128
Got exec: //describe $active np: Black Dice - Drool [05:51m/320kbps/44kHz]
Got event: 128
Got exec: //describe $active np: Black Dice - Scavenger [05:16m/320kbps/44kHz]
Got event: 16

Posted by: uplate Nov 4 2007, 05:24 PM

Implemented ClientService mechanism as an irssi plugin. BOOST_THREADS don't seem to play nicely in irssi, I get failure to allocate thread resources. So I'm forced to use POSIX threads (pthreads), which, while probably not as safe, is definitely doable since I'm only using a single thread for the service. I basically copied your GenericServer word for word, replacing the windows thread stuff with unix thread stuff. I think I basically have it down, although I don't really understand a few things.

(1) Mutexes. No idea what these are, I'll have to read up.
(2) The mechanism through which a C++ member function is passed as a function pointer argument to a C function.

Regarding (2), I was pulling my hair out trying to figure out how to do this, when I decided to try it like you did. I figured your method wouldn't work on *nix, thinking it was MS specific, but it worked great. You are a genius sir tongue.gif.

Here are the salient features of my implementation.

CODE

extern "C" {
#include <pthread.h>
void *thread_start(void *);
}

template<typename InterfaceT, typename ImplementationT>
class NarcService {
public:
  NarcService() { ... }
  void start() { pthread_create( &serverThread, NULL, thread_start, this ); }
private:
  void joinServerThread() { pthread_join(serverThread,NULL); }
  virtual void run() { server->startInThisThread(boost::bind(
                                    &NarcService::joinServerThread,this)); }
  static void *thread_start( void *obj )
  { (static_cast<NarcService *>(obj))->run(); }
};




Attached thumbnail(s)
Attached Image

Posted by: uplate Nov 27 2007, 03:06 AM

Now have most of the major functionality of the AMIP socket server available to my Irssi plugin.
+ ping, eval, exec, add/remove_event_listener
+ receive output from AMIP through service

I'm getting ready to release a "demo" version to sourceforge.net.
I was planning on releasing as GPL, but since I'm using two pieces of code from the SDK (MyService.hpp and ClientService.hpp), I thought I'd ask your opinion on that first.


Attached thumbnail(s)
Attached Image

Posted by: Serge Nov 27 2007, 08:12 AM

I don't mind, please feel free to release it.

Posted by: uplate Dec 22 2007, 05:46 PM

Is it OK if I include the gen_irc.dll *compiled with RCF 0.9c that you provided) in the project distribution? If not, can I instruct users to download it from the link?

Thanks
Max

Posted by: Serge Dec 22 2007, 07:34 PM

You'd better give a link, since AMIP should be properly installed for other players and gen_irc.dll is enough only for Winamp.

Posted by: uplate Dec 22 2007, 07:49 PM

Good point, thanks.

Posted by: uplate Dec 23 2007, 01:10 AM

OK, first version is released. I won't use this forum to post any further updates about my project (will keep bugging you for help probably rolleyes.gif ), but I just want to let any people that might have been tracking this project know that it is out there now.

The screen shot shows three of the plugin's features:
* Now playing command to inform IRC channel.
* Statusbar with dynamically updated song information.
* Ability to control AMIP-compatible media player from Irssi command-line.

http://sourceforge.net/projects/libnarc/

Thanks for all your help Serge,
Max





Attached thumbnail(s)
Attached Image

Posted by: uplate Dec 31 2007, 09:42 PM

Hey Serge, I noticed the link to the specially compiled gen_irc.dll is gone. Do you not plan on hosting it anymore?

Thanks,
Max

Posted by: Serge Jan 1 2008, 09:12 PM

2.63 test is available at http://amip.tools-for.net/files/test/ .

Posted by: uplate Jan 1 2008, 11:49 PM

Ah, nice, works great!

Thanks,
Max

Powered by Invision Power Board
© Invision Power Services