/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * The contents of this file are subject to the Netscape Public License * Version 1.0 (the "NPL"); you may not use this file except in * compliance with the NPL. You may obtain a copy of the NPL at * http://www.mozilla.org/NPL/ * * Software distributed under the NPL is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL * for the specific language governing rights and limitations under the * NPL. * * The Initial Developer of this code under the NPL is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All Rights * Reserved. */ #include "nsRepository.h" #include "nsNetStream.h" #include "nsSocketTransport.h" #include "nsINetService.h" #include "nsINetlibURL.h" #include "nsIServiceManager.h" #include "nsXPComCIID.h" #include "netutils.h" #include "mktcp.h" #include "sockstub.h" #include "plstr.h" extern nsIStreamListener* ns_NewStreamListenerProxy(nsIStreamListener* aListener, PLEventQueue* aEventQ); static NS_DEFINE_IID(kIOutputStreamIID, NS_IOUTPUTSTREAM_IID); static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); static NS_DEFINE_IID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID); static NS_DEFINE_IID(kIEventQueueServiceIID, NS_IEVENTQUEUESERVICE_IID); //////////////////////////////////////////////////////////////////////////// // from nsISupports static NS_DEFINE_IID(kITransportIID, NS_ITRANSPORT_IID); NS_IMPL_ADDREF(nsSocketTransport) NS_IMPL_RELEASE(nsSocketTransport) NS_IMPL_QUERY_INTERFACE(nsSocketTransport, kITransportIID); //////////////////////////////////////////////////////////////////////////// // from nsITransport: NS_METHOD nsSocketTransport::GetURL(nsIURL* *result) { *result = m_url; return NS_OK; } static NS_DEFINE_IID(kINetlibURLIID, NS_INETLIBURL_IID); NS_METHOD nsSocketTransport::LoadURL(nsIURL *pURL) { nsresult rv = NS_OK; if (nsnull == pURL) { return NS_ERROR_NULL_POINTER; } if (nsnull == m_inputStreamConsumer) { return NS_ERROR_NULL_POINTER; } m_url = pURL; NS_IF_ADDREF(m_url); pURL->SetHostPort(m_port); nsresult ns_result = NS_OpenURL(pURL, m_inputStreamConsumer); if (NS_OK != ns_result) { return ns_result; } return NS_OK; } NS_METHOD nsSocketTransport::SetInputStreamConsumer(nsIStreamListener* aListener) { // generates the thread safe proxy m_inputStreamConsumer = ns_NewStreamListenerProxy(aListener, m_evQueue); return NS_OK; } NS_METHOD nsSocketTransport::GetOutputStreamConsumer(nsIStreamListener ** aConsumer) { // assuming the transport layer is a nsIStreamListener *aConsumer = ns_NewStreamListenerProxy(this, m_evQueue); return NS_OK; } NS_METHOD nsSocketTransport::GetOutputStream(nsIOutputStream ** aOutputStream) { if (aOutputStream) { // a buffered stream supports the nsIOutputStream interface nsBufferedStream * stream = new nsBufferedStream(); if (stream) // return the buffer in the format they want stream->QueryInterface(kIOutputStreamIID, (void **) aOutputStream); else *aOutputStream = NULL; } return NS_OK; } NS_IMETHODIMP nsSocketTransport::OnStartBinding(nsIURL* pURL, const char *aContentType) { return NS_OK; } NS_IMETHODIMP nsSocketTransport::OnProgress(nsIURL* pURL, PRUint32 aProgress, PRUint32 aProgressMax) { return NS_OK; } NS_IMETHODIMP nsSocketTransport::OnStatus(nsIURL* pURL, const PRUnichar* aMsg) { return NS_OK; } NS_IMETHODIMP nsSocketTransport::OnStopBinding(nsIURL* pURL, nsresult aStatus, const PRUnichar* aMsg) { return NS_OK; } NS_IMETHODIMP nsSocketTransport::GetBindInfo(nsIURL* pURL, nsStreamBindingInfo* aInfo) { return NS_OK; } NS_IMETHODIMP nsSocketTransport::OnDataAvailable(nsIURL* pURL, nsIInputStream *aIStream, PRUint32 aLength) { nsresult rv = NS_OK; PRUint32 len, lenRead; URL_Struct* URL_s; m_ready_fd = NULL; /* XXX: HACK The following is a hack. * Get the URL_s structure and pass it to sockstub protocol code to get the * socket FD so that we could write the data back. */ rv = GetURLInfo(pURL, &URL_s); if (NS_SUCCEEDED(rv)) { if (nsnull != URL_s) { /* Find the socket given URL_s pointer */ m_ready_fd = NET_GetSocketToHashTable(URL_s); } } else { return rv; } if (m_ready_fd == NULL) { return NS_ERROR_NULL_POINTER; } aIStream->GetLength(&len); memset(m_buffer, '\0', NET_SOCKSTUB_BUF_SIZE); while (len > 0) { if (len < NET_SOCKSTUB_BUF_SIZE) { lenRead = len; } else { lenRead = NET_SOCKSTUB_BUF_SIZE; } rv = aIStream->Read(m_buffer, 0, lenRead, &lenRead); if (NS_OK != rv) { return rv; } /* XXX: We should check if the write has succeeded or not */ (int) NET_BlockingWrite(m_ready_fd, m_buffer, lenRead); len -= lenRead; } return rv; } //////////////////////////////////////////////////////////////////////////// // from nsSocketTransport: nsSocketTransport::nsSocketTransport(PRUint32 aPortToUse, const char * aHostName) { NS_INIT_REFCNT(); // remember the port and host name NS_PRECONDITION(aPortToUse > 0 && aHostName, "Creating a socket transport with an invalid port or host name."); m_port = aPortToUse; if (aHostName) m_hostName = PL_strdup(aHostName); else m_hostName = PL_strdup(""); m_inputStream = NULL; m_inputStreamConsumer = NULL; m_url = NULL; m_outStream = NULL; m_outStreamSize = 0; /* * Cache the EventQueueService... */ // XXX: What if this fails? mEventQService = nsnull; m_evQueue = nsnull; nsresult rv = nsServiceManager::GetService(kEventQueueServiceCID, kIEventQueueServiceIID, (nsISupports **)&mEventQService); if (nsnull != mEventQService) { mEventQService->GetThreadEventQueue(PR_GetCurrentThread(), &m_evQueue); } } nsSocketTransport::~nsSocketTransport() { nsresult rv = NS_OK; URL_Struct* URL_s; /* XXX: HACK The following is a hack. * Get the URL_s structure and pass it to sockstub protocol code to delete it */ rv = GetURLInfo(m_url, &URL_s); if (NS_SUCCEEDED(rv)) { if (nsnull != URL_s) { /* Release the socket given URL_s pointer */ int32 res = NET_FreeSocket(URL_s); } } if (m_hostName) PR_Free(m_hostName); NS_IF_RELEASE(m_outStream); NS_IF_RELEASE(m_url); } NS_IMETHODIMP nsSocketTransport::GetURLInfo(nsIURL* pURL, URL_Struct_ **aResult) { nsresult rv = NS_OK; nsINetlibURL *pNetlibURL = NULL; NS_PRECONDITION(aResult != nsnull, "invalid input argument"); if (aResult) { *aResult = nsnull; rv = pURL->QueryInterface(kINetlibURLIID, (void**)&pNetlibURL); if (NS_SUCCEEDED(rv) && pNetlibURL) { pNetlibURL->GetURLInfo(aResult); NS_RELEASE(pNetlibURL); } } return rv; }