blob: 72992ebb333b0db176f8bedf0a0d9782616e87d6 [file]
/* -*- C++ -*- */
/*
* The Apache Software License, Version 1.1
*
*
* Copyright (c) 2002 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Axis" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
/*
*
*
* @author Lilantha Darshana (lilantha@virtusa.com)
*
*/
#include <axis/client/transport/axis/Platform.hpp>
#include <axis/client/transport/axis/Channel.hpp>
#include <iostream>
#include <axis/client/transport/axis/Transport.hpp>
using namespace std;
/**
* Create a Channel & initialize
*
*/
Channel::Channel() : m_Sock(INVALID_SOCKET)
{
}
Channel::~Channel()
{
CloseChannel();
}
/**
* This channel open INET channel for the time being using primitive sockets
* Do we need any other type of channel; like shared memory, pipes etc. ????
*
* @param p_RemoteNode End point address as hostname/IP
* @param p_RemoteEnd Port #
*
* @return true if successfuly open a soket to the endpoint. o/w exception is thrown
*/
bool Channel::Open(std::string& p_RemoteNode, unsigned short p_RemoteEnd) throw (ChannelException)
{
m_RemoteNode = p_RemoteNode;
m_RemoteEnd = p_RemoteEnd;
if(!Init())
throw ChannelException("Cannot initialize a channel to the remote end");
sockaddr_in clAddr, svAddr;
if ((m_Sock = socket(PF_INET, SOCK_STREAM, 0)) != INVALID_SOCKET)
{
clAddr.sin_family = AF_INET; // AF_INET (address family Internet).
clAddr.sin_port = 0; // No Specify Port required
clAddr.sin_addr.s_addr = INADDR_ANY;
if (bind(m_Sock, (struct sockaddr*) &clAddr, sizeof(clAddr)) == SOCKET_ERROR)
{
Error("Error - Binding");
CloseChannel();
throw ChannelException("Cannot open a channel to the remote end, shutting down the channel");
}
// Although the above fragment makes use of the bind() API, it would be
// just as effective to skip over this call as there are no specific
// local port ID requirements for this client. The only advantage that
// bind() offers is the accessibility of the port which the system chose
// via the .sin_port member of the cli_addr structure which will be set
// upon success of the bind() call.
svAddr.sin_family = AF_INET;
svAddr.sin_port = htons(m_RemoteEnd);
struct hostent* pHostEntry = NULL;
// probably this is the host-name of the server we are connecting to
if((pHostEntry = gethostbyname(m_RemoteNode.c_str())))
{
svAddr.sin_addr.s_addr = ((struct in_addr *)pHostEntry->h_addr)->s_addr;
}
else
{
// no this is the IP address
svAddr.sin_addr.s_addr = inet_addr(m_RemoteNode.c_str());
}
// connect to the remote server.
if (connect(m_Sock,(struct sockaddr*)&svAddr, sizeof(svAddr)) == SOCKET_ERROR)
{
Error("Sockets error Couldn't connect socket.");
CloseChannel();
throw ChannelException("Cannot open a channel to the remote end, shutting down the channel");
}
}
else
{
Error("Sockets error Couldn't create socket.");
CloseChannel();
throw ChannelException("Cannot open a channel");
}
return true;
}
/**
* OS specific initialization should do here
*
* @return true if successfuly initilaize OS specific stuffs. false o/w
*/
bool Channel::Init()
{
#ifdef WIN32
WSADATA wsaData; // contains vendor-specific information, such as the
// maximum number of sockets available and the maximum
// datagram size.
if(WSAStartup(WS_VERSION_REQD, &wsaData)) //Filled by Windows Sockets DLLs
{
m_LastErr = "WinSock DLL not responding.";
Error((char *)m_LastErr.c_str());
return false;
}
else
{
// Query to see whether the available version matches what we need
if (( LOBYTE (wsaData.wVersion) < WS_VERSION_MAJOR()) ||
(LOBYTE (wsaData.wVersion) == WS_VERSION_MAJOR() &&
HIBYTE (wsaData.wVersion) < WS_VERSION_MINOR()))
{
char buf[100];
sprintf(buf,"Windows Sockets version %d.%d not supported by winsock2.dll",
LOBYTE (wsaData.wVersion), HIBYTE (wsaData.wVersion));
Error(buf);
CloseChannel();
return false;
}
}
#else
//cout << "no need for linux" << endl;
// other OS specific Intitialization goes here
#endif
return true;
}
/**
* Write/send a message to the remote server; sending blocks the app.
* we may need to do this asynchronizely; preferably either non-blocking
* send or pthread.
*
* @param Message to be written to the open channel
*/
const Channel& Channel::operator << (const char* msg)
{
if(INVALID_SOCKET == m_Sock)
{
Error("Writing cannot be done without having a open socket to remote end.");
throw ChannelException("Output streaming error on undefined channel; please open the channel first");
}
int size = strlen(msg), nByteSent;
if((nByteSent = send(m_Sock, msg, size, MSG_DONTROUTE )) == SOCKET_ERROR)
{
Error("Output streaming error while writing data.");
CloseChannel();
throw ChannelException("Output streaming error on Channel while writing data");
}
return *this;
}
/**
* Read/receive a message from the remote server; reading may be done in chunks.
*
* @param string to hold the read Message
*/
const Channel& Channel::operator >> (std::string& msg)
{
msg = "";
if(INVALID_SOCKET == m_Sock)
{
Error("Reading cannot be done without having a open socket.");
throw ChannelException("Input streaming error on undefined channel; please open the channel first");
}
int nByteRecv = 0;
const int BUF_SIZE = 4096;
char buf[BUF_SIZE];
do // Manage multiple chuncks of the message
{
if ((nByteRecv = recv(m_Sock, (char *) &buf, BUF_SIZE - 1, 0)) == SOCKET_ERROR)
{
Error("Channel error while getting data.");
CloseChannel();
throw ChannelException("Input streaming error on Channel while getting data");
}
if(nByteRecv)
{
buf[nByteRecv + 1] = '\0'; // got a part of the message, so add it to form
msg += buf; // the whole message
//Validate according to the transport; check whether we are in a position to return.
if (!m_pTransportHandler->GetStatus(msg))
break;
}
else
break; // we have the whole message or an error has occured
}
while (true);
return *this;
}
/**
* Close, and clean-up any OS specific stuff
*
*/
void Channel::CloseChannel()
{
#ifdef WIN32
if(INVALID_SOCKET != m_Sock)
closesocket(m_Sock);
// Check for any possible error conditions from WSACleanup() and report
// them before exiting, as this information might indicate a network
// layer problem in the system.
WSACleanup();
#else
if(INVALID_SOCKET != m_Sock)
close(m_Sock);
#endif
}
/**
* Log any errors that cause on channel usage/initilaization
*
*/
void Channel::Error(const char * err)
{
#ifdef _DEBUG
std::cerr << err << std::endl;
#endif
}