From 2bda2ee4fc336f698de5f729ad33f73b1c7822a5 Mon Sep 17 00:00:00 2001 From: "sgehani%netscape.com" Date: Thu, 28 Dec 2000 00:27:10 +0000 Subject: [PATCH] Initial checkin of libxpnet developed on Linux and ported to Windows. (Not part of build. Awaiting sr.) b = 63835 r = ssu,dbragg --- xpinstall/wizard/libxpnet/Makefile.in | 34 + xpinstall/wizard/libxpnet/makefile.win | 30 + xpinstall/wizard/libxpnet/src/Makefile.in | 44 ++ xpinstall/wizard/libxpnet/src/makefile.win | 48 ++ xpinstall/wizard/libxpnet/src/nsFTPConn.cpp | 496 +++++++++++++++ xpinstall/wizard/libxpnet/src/nsFTPConn.h | 126 ++++ xpinstall/wizard/libxpnet/src/nsHTTPConn.cpp | 598 ++++++++++++++++++ xpinstall/wizard/libxpnet/src/nsHTTPConn.h | 102 +++ xpinstall/wizard/libxpnet/src/nsSocket.cpp | 450 +++++++++++++ xpinstall/wizard/libxpnet/src/nsSocket.h | 112 ++++ xpinstall/wizard/libxpnet/test/Makefile.in | 40 ++ .../wizard/libxpnet/test/TestLibxpnet.cpp | 158 +++++ xpinstall/wizard/libxpnet/test/makefile.win | 49 ++ 13 files changed, 2287 insertions(+) create mode 100644 xpinstall/wizard/libxpnet/Makefile.in create mode 100644 xpinstall/wizard/libxpnet/makefile.win create mode 100644 xpinstall/wizard/libxpnet/src/Makefile.in create mode 100644 xpinstall/wizard/libxpnet/src/makefile.win create mode 100644 xpinstall/wizard/libxpnet/src/nsFTPConn.cpp create mode 100644 xpinstall/wizard/libxpnet/src/nsFTPConn.h create mode 100644 xpinstall/wizard/libxpnet/src/nsHTTPConn.cpp create mode 100644 xpinstall/wizard/libxpnet/src/nsHTTPConn.h create mode 100644 xpinstall/wizard/libxpnet/src/nsSocket.cpp create mode 100644 xpinstall/wizard/libxpnet/src/nsSocket.h create mode 100644 xpinstall/wizard/libxpnet/test/Makefile.in create mode 100644 xpinstall/wizard/libxpnet/test/TestLibxpnet.cpp create mode 100644 xpinstall/wizard/libxpnet/test/makefile.win diff --git a/xpinstall/wizard/libxpnet/Makefile.in b/xpinstall/wizard/libxpnet/Makefile.in new file mode 100644 index 000000000000..dcef95dd4968 --- /dev/null +++ b/xpinstall/wizard/libxpnet/Makefile.in @@ -0,0 +1,34 @@ +# +# The contents of this file are subject to the Netscape Public +# License Version 1.1 (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.mozilla.org/NPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under the License. +# +# The Original Code is Mozilla Communicator client code, +# released March 31, 1998. +# +# The Initial Developer of the Original Code is Netscape Communications +# Corporation. Portions created by Netscape are +# Copyright (C) 1998 Netscape Communications Corporation. All +# Rights Reserved. +# +# Contributor(s): +# Samir Gehani +# + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +DIRS = src test + +include $(topsrcdir)/config/rules.mk + diff --git a/xpinstall/wizard/libxpnet/makefile.win b/xpinstall/wizard/libxpnet/makefile.win new file mode 100644 index 000000000000..6f765b96b7c9 --- /dev/null +++ b/xpinstall/wizard/libxpnet/makefile.win @@ -0,0 +1,30 @@ +#!gmake +# +# The contents of this file are subject to the Netscape Public +# License Version 1.1 (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.mozilla.org/NPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under the License. +# +# The Original Code is Mozilla Communicator client code, +# released March 31, 1998. +# +# The Initial Developer of the Original Code is Netscape Communications +# Corporation. Portions created by Netscape are +# Copyright (C) 1998 Netscape Communications Corporation. All +# Rights Reserved. +# +# Contributor(s): +# Samir Gehani +# + +DEPTH=..\..\.. + +DIRS=src test + +include <$(DEPTH)\config\rules.mak> + diff --git a/xpinstall/wizard/libxpnet/src/Makefile.in b/xpinstall/wizard/libxpnet/src/Makefile.in new file mode 100644 index 000000000000..8810cd40a7e3 --- /dev/null +++ b/xpinstall/wizard/libxpnet/src/Makefile.in @@ -0,0 +1,44 @@ +# +# The contents of this file are subject to the Netscape Public +# License Version 1.1 (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.mozilla.org/NPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under the License. +# +# The Original Code is Mozilla Communicator client code, +# released March 31, 1998. +# +# The Initial Developer of the Original Code is Netscape Communications +# Corporation. Portions created by Netscape are +# Copyright (C) 1998 Netscape Communications Corporation. All +# Rights Reserved. +# +# Contributor(s): +# Samir Gehani +# + +DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VAPTH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpnet +LIBRARY_NAME = xpnet_s + +CPPSRCS = \ + nsSocket.cpp \ + nsFTPConn.cpp \ + nsHTTPConn.cpp \ + $(NULL) + +override NO_SHARED_LIB=1 +override NO_STATIC_LIB= + +include $(topsrcdir)/config/rules.mk + diff --git a/xpinstall/wizard/libxpnet/src/makefile.win b/xpinstall/wizard/libxpnet/src/makefile.win new file mode 100644 index 000000000000..bf02bd7796f1 --- /dev/null +++ b/xpinstall/wizard/libxpnet/src/makefile.win @@ -0,0 +1,48 @@ +#!gmake +# +# The contents of this file are subject to the Netscape Public +# License Version 1.1 (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.mozilla.org/NPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under the License. +# +# The Original Code is Mozilla Communicator client code, +# released March 31, 1998. +# +# The Initial Developer of the Original Code is Netscape Communications +# Corporation. Portions created by Netscape are +# Copyright (C) 1998 Netscape Communications Corporation. All +# Rights Reserved. +# +# Contributor(s): +# Samir Gehani +# + +MODULE=xpnet +LIBNAME=$(MODULE) +DEPTH=..\..\..\.. + +MAKE_OBJ_TYPE=DLL + +LIBRARY=$(OBJDIR)\$(LIBNAME)_s.lib + +OBJS= \ + .\$(OBJDIR)\nsSocket.obj \ + .\$(OBJDIR)\nsFTPConn.obj \ + .\$(OBJDIR)\nsHTTPConn.obj \ + $(NULL) + +include <$(DEPTH)/config/rules.mak> + +install:: + $(MAKE_INSTALL) $(LIBRARY) $(DIST)\lib + +clobber:: + $(RM) $(DIST)\lib\$(LIBNAME)_s.lib + +clobber_all:: clobber + diff --git a/xpinstall/wizard/libxpnet/src/nsFTPConn.cpp b/xpinstall/wizard/libxpnet/src/nsFTPConn.cpp new file mode 100644 index 000000000000..ba165398356c --- /dev/null +++ b/xpinstall/wizard/libxpnet/src/nsFTPConn.cpp @@ -0,0 +1,496 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (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.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla Communicator client code, + * released March 31, 1998. + * + * The Initial Developer of the Original Code is Netscape Communications + * Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * Samir Gehani + */ + +#include +#include +#include +#include +#include + +#ifdef __unix +#include +#elif defined(_WINDOWS) +#include +#define MAXPATHLEN MAX_PATH +#endif + +#include "nsSocket.h" +#include "nsFTPConn.h" + +const int kCntlPort = 21; +const int kDataPort = 20; +const int kCmdBufSize = 64 + MAXPATHLEN; +const int kRespBufSize = 1024; +const int kKilobyte = 1024; +const int kUsecsPerSec = 1000000; +const int kDlBufSize = 1024; + +nsFTPConn::nsFTPConn(char *aHost) : + mHost(aHost), + mState(CLOSED), + mPassive(FALSE), + mCntlSock(NULL), + mDataSock(NULL) +{ +} + +nsFTPConn::~nsFTPConn() +{ + // don't release mHost cause we don't own it +} + +int +nsFTPConn::Open() +{ + int err = OK; + char cmd[kCmdBufSize], resp[kRespBufSize]; + int respBufSize = kRespBufSize; + + if (!mHost) + return E_PARAM; + if (mState != CLOSED) + return E_ALREADY_OPEN; + + /* open control connection on port 21 */ + mCntlSock = new nsSocket(mHost, kCntlPort); + if (!mCntlSock) + return E_MEM; + ERR_CHECK(mCntlSock->Open()); + ERR_CHECK(mCntlSock->Recv((unsigned char *)resp, &respBufSize)); + DUMP(resp); + + /* issue USER command on control connection */ + sprintf(cmd, "USER anonymous\r\n"); + err = IssueCmd(cmd, resp, kRespBufSize, mCntlSock); + + /* issue PASS command on control connection */ + sprintf(cmd, "PASS -linux@installer.sbg\r\n"); + ERR_CHECK(IssueCmd(cmd, resp, kRespBufSize, mCntlSock)); + + mState = OPEN; + + return err; + +BAIL: + if (mCntlSock) + { + mCntlSock->Close(); + delete mCntlSock; + mCntlSock = NULL; + } + if (mDataSock) + { + mDataSock->Close(); + delete mDataSock; + mDataSock = NULL; + } + return err; +} + +int +nsFTPConn::Open(char *aHost) +{ + if (!aHost) + return E_PARAM; + + mHost = aHost; + return Open(); +} + +int +nsFTPConn::Get(char *aSrvPath, char *aLoclPath, int aType, int aOvWrite, + FTPGetCB aCBFunc) +{ + struct stat dummy; + int err = OK, wrote = 0, totBytesRd = 0; + char cmd[kCmdBufSize], resp[kRespBufSize]; + int fileSize = 0, respBufSize = kRespBufSize; + FILE *loclfd = NULL; + + if (!aSrvPath || !aLoclPath) + return E_PARAM; + if (mState != OPEN || !mCntlSock) + return E_NOT_OPEN; + + /* stat local path and verify aOvWrite is set if file already exists */ + err = stat(aLoclPath, &dummy); + if (err != -1 && aOvWrite == FALSE) + return E_CANT_OVWRITE; + + mState = GETTING; + + /* initialize data connection */ + ERR_CHECK(DataInit(mHost, kDataPort, &mDataSock)); + + /* issue SIZE command on control connection */ + sprintf(cmd, "SIZE %s\r\n", aSrvPath); + err = IssueCmd(cmd, resp, kRespBufSize, mCntlSock); /* non-fatal */ + if (err == OK && (resp[0] == '2')) + fileSize = atoi(&resp[4]); + + /* issue TYPE command on control connection */ + sprintf(cmd, "TYPE %s\r\n", aType==BINARY ? "I" : "A"); + ERR_CHECK(IssueCmd(cmd, resp, kRespBufSize, mCntlSock)); + + /* issue RETR command on control connection */ + sprintf(cmd, "RETR %s\r\n", aSrvPath); + ERR_CHECK(IssueCmd(cmd, resp, kRespBufSize, mCntlSock)); + + /* get file contents on data connection */ + if (!mPassive) + ERR_CHECK(mDataSock->SrvAccept()); + + /* initialize locl file */ + if (!(loclfd = fopen(aLoclPath, aType==BINARY ? "wb" : "w")) || + (fseek(loclfd, 0, SEEK_SET) != 0)) + { + err = E_LOCL_INIT; + goto BAIL; + } + + totBytesRd = 0; + do + { + respBufSize = kDlBufSize; + err = mDataSock->Recv((unsigned char *)resp, &respBufSize); + if (err != nsSocket::E_READ_MORE && + err != nsSocket::E_EOF_FOUND && + err != nsSocket::OK) + goto BAIL; + totBytesRd += respBufSize; + if (err == nsSocket::E_READ_MORE && aCBFunc) + aCBFunc(totBytesRd, fileSize); + + /* append to local file */ + wrote = fwrite((void *)resp, 1, respBufSize, loclfd); + if (wrote != respBufSize) + { + err = E_WRITE; + goto BAIL; + } + } + while (err == nsSocket::E_READ_MORE || err == nsSocket::OK); + if (err == nsSocket::E_EOF_FOUND) + err = OK; + +BAIL: + /* close locl file if open */ + if (loclfd) + fclose(loclfd); + + /* kill data connection if it exists */ + if (mDataSock) + { + mDataSock->Close(); + delete mDataSock; + mDataSock = NULL; + } + + mState = OPEN; + mPassive = FALSE; + + return err; +} + +int +nsFTPConn::Close() +{ + int err = OK; + + if (mState != OPEN) + return E_NOT_OPEN; + + /* close sockets */ + if (mCntlSock) + { + ERR_CHECK(mCntlSock->Close()); + delete mCntlSock; + mCntlSock = NULL; + } + if (mDataSock) + { + ERR_CHECK(mDataSock->Close()); + delete mDataSock; + mDataSock = NULL; + } + +BAIL: + return err; +} + +int +nsFTPConn::IssueCmd(char *aCmd, char *aResp, int aRespSize, nsSocket *aSock) +{ + int err = OK; + int len; + + /* param check */ + if (!aSock || !aCmd || !aResp || aRespSize <= 0) + return E_PARAM; + + /* send command */ + len = strlen(aCmd); + ERR_CHECK(aSock->Send((unsigned char *)aCmd, &len)); + DUMP(aCmd); + + /* receive response */ + do + { + err = aSock->Recv((unsigned char *)aResp, &aRespSize); + if (err != nsSocket::OK && + err != nsSocket::E_READ_MORE && + err != nsSocket::E_EOF_FOUND) + goto BAIL; + DUMP(aResp); + } + while (err == nsSocket::E_READ_MORE); + + /* alternate interpretation of err codes */ + if ( (strncmp(aCmd, "APPE", 4) == 0) || + (strncmp(aCmd, "LIST", 4) == 0) || + (strncmp(aCmd, "NLST", 4) == 0) || + (strncmp(aCmd, "REIN", 4) == 0) || + (strncmp(aCmd, "RETR", 4) == 0) || + (strncmp(aCmd, "STOR", 4) == 0) || + (strncmp(aCmd, "STOU", 4) == 0) ) + { + switch (*aResp) + { + case '1': /* exception: 100 series is OK */ + case '2': + break; + case '3': + err = E_CMD_ERR; + break; + case '4': + case '5': + err = E_CMD_FAIL; + break; + default: + err = E_CMD_UNEXPECTED; + break; + } + } + + /* regular interpretation of err codes */ + else + { + switch (*aResp) + { + case '2': + break; + case '1': + case '3': + err = E_CMD_ERR; + break; + case '4': + case '5': + err = E_CMD_FAIL; + break; + default: + err = E_CMD_UNEXPECTED; + break; + } + } + +BAIL: + return err; +} + +int +nsFTPConn::ParseAddr(char *aBuf, char **aHost, int *aPort) +{ + int err = OK; + char *c; + int addr[6]; + + /* param check */ + if (!aBuf || !aHost || !aPort) + return E_PARAM; + + c = aBuf + strlen("227 "); /* pass by return code */ + while (!isdigit((int)(*c))) + { + if (*c == '\0') + return E_INVALID_ADDR; + c++; + } + + if (sscanf(c, "%d,%d,%d,%d,%d,%d", + &addr[0], &addr[1], &addr[2], &addr[3], &addr[4], &addr[5]) != 6) + return E_INVALID_ADDR; + + *aHost = (char *)malloc(strlen("XXX.XXX.XXX.XXX")); + sprintf(*aHost, "%d.%d.%d.%d", addr[0], addr[1], addr[2], addr[3]); + + *aPort = ((addr[4] & 0xFF) << 8) | (addr[5] & 0xFF); + +#ifdef DEBUG + printf("%s %d: PASV response: %d,%d,%d,%d,%d,%d\n", __FILE__, __LINE__, + addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); + printf("%s %d: Host = %s\tPort = %d\n", __FILE__, __LINE__, *aHost, *aPort); +#endif + + return err; +} + +int +nsFTPConn::DataInit(char *aHost, int aPort, nsSocket **aSock) +{ + int err = OK; + char cmd[kCmdBufSize], resp[kRespBufSize]; + char *srvHost = NULL; + int srvPort = 0; + char *hostPort = NULL; + + /* param check */ + if (!aHost || !aSock) + return E_PARAM; + + /* issue PASV command */ + sprintf(cmd, "PASV\r\n"); + err = IssueCmd(cmd, resp, kRespBufSize, mCntlSock); + if (err != OK) + { + err = OK; + goto ACTIVE; /* failover to active mode */ + } + + mPassive = TRUE; + + ERR_CHECK(ParseAddr(resp, &srvHost, &srvPort)); + *aSock = new nsSocket(srvHost, srvPort); + if (!*aSock) + { + err = E_MEM; + goto BAIL; + } + + ERR_CHECK((*aSock)->Open()); + + if (srvHost) + { + free(srvHost); + srvHost = NULL; + } + + return err; + +ACTIVE: + + *aSock = new nsSocket(aHost, aPort); + if (!*aSock) + { + err = E_MEM; + goto BAIL; + } + + /* init data socket making it listen */ + ERR_CHECK((*aSock)->SrvOpen()); + + ERR_CHECK((*aSock)->GetHostPortString(&hostPort)); // allocates + if (!hostPort) + { + err = E_MEM; + goto BAIL; + } + + sprintf(cmd, "PORT %s\r\n", hostPort); + ERR_CHECK(IssueCmd(cmd, resp, kRespBufSize, mCntlSock)); + +BAIL: + if (mPassive && err != OK) + mPassive = FALSE; + + if (err != OK && (*aSock)) + { + delete *aSock; + *aSock = NULL; + } + + if (srvHost) + { + free(srvHost); + srvHost = NULL; + } + + if (hostPort) + { + free(hostPort); + hostPort = NULL; + } + + return err; +} + +#ifdef TEST_NSFTPCONN +static struct timeval init; +int +TestFTPGetCB(int aBytesRd, int aTotal) +{ + struct timeval now; + float rate; + + gettimeofday(&now, NULL); + rate = nsSocket::CalcRate(&init, &now, aBytesRd); + printf("br=%d\ttot=%d\trt=%f\tirt=%d\n",aBytesRd, aTotal, rate, (int)rate); + return 0; +} + +int +main(int argc, char **argv) +{ + int err = nsFTPConn::OK; + nsFTPConn *conn = 0; + char *leaf = NULL; + + if (argc < 2) + { + printf("usage: %s \n", argv[0]); + exit(0); + } + + if ((leaf = strrchr(argv[2], '/'))) leaf++; + else leaf = argv[2]; + + conn = new nsFTPConn(argv[1]); + + printf("Opening connection to %s...\n", argv[1]); + err = conn->Open(); + if (err != nsFTPConn::OK) { printf("error: %d\n", err); exit(err); } + + printf("Getting binary file %s...\n", argv[2]); + gettimeofday(&init, NULL); + err = conn->Get(argv[2], leaf, nsFTPConn::BINARY, TRUE, TestFTPGetCB); + if (err != nsFTPConn::OK) { printf("error: %d\n", err); exit(err); } + + printf("Closing connection to %s...\n", argv[1]); + err = conn->Close(); + if (err != nsFTPConn::OK) { printf("error: %d\n", err); exit(err); } + + printf("Test successful!\n"); + exit(err); +} +#endif /* TEST_NSFTPCONN */ + diff --git a/xpinstall/wizard/libxpnet/src/nsFTPConn.h b/xpinstall/wizard/libxpnet/src/nsFTPConn.h new file mode 100644 index 000000000000..cb55ad5d5402 --- /dev/null +++ b/xpinstall/wizard/libxpnet/src/nsFTPConn.h @@ -0,0 +1,126 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (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.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla Communicator client code, + * released March 31, 1998. + * + * The Initial Developer of the Original Code is Netscape Communications + * Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * Samir Gehani + */ + +#ifndef _NS_FTPCONN_H_ +#define _NS_FTPCONN_H_ + +class nsSocket; + +typedef int (*FTPGetCB)(int aBytesRd, int aTotal); + +class nsFTPConn +{ +public: + nsFTPConn(char *aHost); + ~nsFTPConn(); + + /* ftp type */ + enum + { + ASCII = 0, + BINARY + }; + + /* connection state */ + enum + { + OPEN = 0, + GETTING, + CLOSED + }; + + int Open(); + int Open(char *aHost); + int Get(char *aSrvPath, char *aLoclPath, int aType, int aOvWrite, + FTPGetCB aCBFunc); + int Close(); + +/*--------------------------------------------------------------------* + * Errors + *--------------------------------------------------------------------*/ + enum + { + OK = 0, + E_MEM = -801, /* out of memory */ + E_PARAM = -802, /* parameter null or incorrect */ + E_ALREADY_OPEN = -803, /* connection already established */ + E_NOT_OPEN = -804, /* connection not established, can't use */ + E_CMD_ERR = -805, /* ftp command error */ + E_CMD_FAIL = -806, /* ftp command failed */ + E_CMD_UNEXPECTED = -807, /* ftp command unexpected response */ + E_WRITE = -808, /* write to socket/fd failed */ + E_READ = -809, /* read on socket/fd failed */ + E_SMALL_BUF = -810, /* buffer too small, provide bigger one */ + E_CANT_OVWRITE = -811, /* cannot overwrite existing file */ + E_LOCL_INIT = -812, /* local file open/init failed */ + E_INVALID_ADDR = -814 /* couldn't parse address/port */ + }; + +private: + int IssueCmd(char *aCmd, char *aResp, int aRespSize, + nsSocket *aSock); + int ParseAddr(char *aBuf, char **aHost, int *aPort); + int DataInit(char *aHost, int aPort, nsSocket **aSock); + + char *mHost; + int mState; + int mPassive; + nsSocket *mCntlSock; + nsSocket *mDataSock; +}; + +#ifndef NULL +#define NULL (void*)0L +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifdef DUMP +#undef DUMP +#endif + +#if defined(DEBUG) || defined(DEBUG_sgehani) +#define DUMP(_msg) printf("%s %d: %s\n", __FILE__, __LINE__, _msg); +#else +#define DUMP(_msg) +#endif /* DEBUG */ + +#ifndef ERR_CHECK +#define ERR_CHECK(_func) \ +do { \ + err = _func; \ + if (err != OK) \ + goto BAIL; \ +} while(0); + +#endif + +#endif /* _NS_FTPCONN_H_ */ + diff --git a/xpinstall/wizard/libxpnet/src/nsHTTPConn.cpp b/xpinstall/wizard/libxpnet/src/nsHTTPConn.cpp new file mode 100644 index 000000000000..bd4557c10d8d --- /dev/null +++ b/xpinstall/wizard/libxpnet/src/nsHTTPConn.cpp @@ -0,0 +1,598 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (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.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla Communicator client code, + * released March 31, 1998. + * + * The Initial Developer of the Original Code is Netscape Communications + * Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * Samir Gehani + */ + +#include +#include +#include +#include +#include +#include "nsHTTPConn.h" +#include "nsSocket.h" + +const char kHTTPProto[8] = "http://"; +const char kFTPProto[8] = "ftp://"; +const int kHTTPPort = 80; +const int kFTPPort = 21; +const int kRespBufSize = 1024; +const int kReqBufSize = 1024; +const int kHdrBufSize = 256; +const char kCRLF[3] = "\r\n"; +const char kHdrBodyDelim[5] = "\r\n\r\n"; +const char kDefaultDestFile[11] = "index.html"; + +nsHTTPConn::nsHTTPConn(char *aHost, int aPort, char *aPath) : + mHost(aHost), + mPath(aPath), + mProxiedURL(NULL), + mProxyUser(NULL), + mProxyPswd(NULL), + mDestFile(NULL), + mHostPathAllocd(FALSE), + mSocket(NULL) +{ + if (aPort <= 0) + mPort = kHTTPPort; + else + mPort = aPort; + + DUMP(("mHost = %s\n", mHost)); + DUMP(("mPort = %d\n", mPort)); + DUMP(("mPath = %s\n", mPath)); +} + +nsHTTPConn::nsHTTPConn(char *aURL) : + mPort(kHTTPPort), + mProxiedURL(NULL), + mProxyUser(NULL), + mProxyPswd(NULL), + mDestFile(NULL), + mHostPathAllocd(FALSE), + mSocket(NULL) +{ + // parse URL + if (ParseURL(kHTTPProto, aURL, &mHost, &mPort, &mPath) == OK) + mHostPathAllocd = TRUE; + else + { + mHost = NULL; + mPath = NULL; + } + + DUMP(("mHost = %s\n", mHost)); + DUMP(("mPort = %d\n", mPort)); + DUMP(("mPath = %s\n", mPath)); +} + +nsHTTPConn::~nsHTTPConn() +{ + if (mHostPathAllocd) + { + if (mHost) + free(mHost); + if (mPath) + free(mPath); + } +} + +int +nsHTTPConn::Open() +{ + // verify host && path + if (!mHost || !mPath) + return E_MALFORMED_URL; + + // create socket + mSocket = new nsSocket(mHost, mPort); + if (!mSocket) + return E_MEM; + + // open socket + return mSocket->Open(); +} + +int +nsHTTPConn::Get(HTTPGetCB aCallback, char *aDestFile) +{ + int rv; + char *pathToUse; + + // verify host && path + if (!mHost || !mPath) + return E_MALFORMED_URL; + + if (!aDestFile) + { + if (mProxiedURL) + pathToUse = mProxiedURL; + else + pathToUse = mPath; + + // no leaf: assume default file 'index.html' + if (*(pathToUse + strlen(pathToUse) - 1) == '/') + aDestFile = (char *) kDefaultDestFile; + else + aDestFile = strrchr(pathToUse, '/') + 1; + } + + // issue request + rv = Request(); + + // recv response + if (rv == OK) + rv = Response(aCallback, aDestFile); + + return rv; +} + +int +nsHTTPConn::Close() +{ + int rv; + + // close socket + rv = mSocket->Close(); + + // destroy socket + delete mSocket; + + return rv; +} + +void +nsHTTPConn::SetProxyInfo(char *aProxiedURL, char *aProxyUser, + char *aProxyPswd) +{ + mProxiedURL = aProxiedURL; + mProxyUser = aProxyUser; + mProxyPswd = aProxyPswd; +} + +int +nsHTTPConn::Request() +{ + char req[kReqBufSize]; + char hdr[kHdrBufSize]; + int rv; + + memset(req, 0, kReqBufSize); + + // format header buf: + + // request line + memset(hdr, 0, kHdrBufSize); + if (mProxiedURL) + { + sprintf(hdr, "GET %s HTTP/1.1%s", mProxiedURL, kCRLF); + strcpy(req, hdr); + + memset(hdr, 0, kHdrBufSize); + if (strncmp(mProxiedURL, kFTPProto, strlen(kFTPProto)) == 0) + { + char *ftpHost, *ftpPath; + int ftpPort = kFTPPort; + rv = ParseURL(kFTPProto, mProxiedURL, + &ftpHost, &ftpPort, &ftpPath); + + if (rv == OK) + sprintf(hdr, "Host: %s:%d%s", ftpHost, ftpPort, kCRLF); + + if (ftpHost) + free(ftpHost); + if (ftpPath) + free(ftpPath); + } + else + sprintf(hdr, "Host: %s%s", mHost, kCRLF); + strcat(req, hdr); + } + else + { + sprintf(hdr, "GET %s HTTP/1.1%s", mPath, kCRLF); + strcpy(req, hdr); + + memset(hdr, 0, kHdrBufSize); + sprintf(hdr, "Host: %s%s", mHost, kCRLF); + strcat(req, hdr); + } + + // if proxy set and proxy user/pswd set + if (mProxyUser && mProxyPswd) + { + char *usrPsd = (char *) malloc(strlen(mProxyUser) + + strlen(":") + + strlen(mProxyPswd)); + if (!usrPsd) + return E_MEM; + sprintf(usrPsd, "%s:%s", mProxyUser, mProxyPswd); + + // base 64 encode proxy header + char usrPsdEncoded[128]; // pray that 128 is long enough + memset(usrPsdEncoded, 0, 128); + + DUMP(("Unencoded string: %s\n", usrPsd)); + rv = Base64Encode((const unsigned char *)usrPsd, strlen(usrPsd), + usrPsdEncoded, 128); + DUMP(("Encoded string: %s\n", usrPsdEncoded)); + DUMP(("Base64Encode returned: %d\n", rv)); + if (rv <= 0) + { + return E_B64_ENCODE; + } + + // append proxy header to header buf + memset(hdr, 0, kHdrBufSize); + sprintf(hdr, "Proxy-authorization: Basic %s%s", usrPsdEncoded, kCRLF); + strcat(req, hdr); + + // XXX append host with port 21 if ftp + + } + + // headers all done so indicate + strcat(req, kCRLF); + + // send header buf over socket + int bufSize = strlen(req); + rv = mSocket->Send((unsigned char *) req, &bufSize); + DUMP(("\n\n%s", req)); + + if (bufSize != (int) strlen(req)) + rv = E_REQ_INCOMPLETE; + + return rv; +} + +int +nsHTTPConn::Response(HTTPGetCB aCallback, char *aDestFile) +{ + // NOTE: overwrites dest file if it already exists + + int rv = OK; + char resp[kRespBufSize]; + int bufSize, fwriteLen, fwrote, bytesWritten = 0, expectedSize = 0; + FILE *destFd; + char *fwritePos; + int bFirstIter = TRUE; + + if (!aDestFile) + return E_PARAM; + + // open dest file + destFd = fopen(aDestFile, "w+"); + if (!destFd) + return E_OPEN_FILE; + + // iteratively recv response + do + { + memset(resp, 0, kRespBufSize); + bufSize = kRespBufSize; + + rv = mSocket->Recv((unsigned char *) resp, &bufSize); + DUMP((resp)); + DUMP(("nsSocket::Recv returned: %d\t and recd: %d\n", rv, bufSize)); + + if (bFirstIter) + { + fwritePos = strstr(resp, kHdrBodyDelim); + if (fwritePos == NULL) + { + // XXX no header! should we handle? + fwritePos = resp; + fwriteLen = bufSize; + } + else + { + ParseContentLength((const char *)resp, &expectedSize); + + // move past hdr-body delimiter + fwritePos += strlen(kHdrBodyDelim); + fwriteLen = bufSize - (fwritePos - resp); + } + + bFirstIter = FALSE; + } + else + { + fwritePos = resp; + fwriteLen = bufSize; + } + + fwrote = fwrite(fwritePos, sizeof(char), fwriteLen, destFd); + assert(fwrote == fwriteLen); + + if (fwriteLen > 0) + bytesWritten += fwriteLen; + if (aCallback) + aCallback(bytesWritten, expectedSize); + + } while (rv == nsSocket::E_READ_MORE || rv == nsSocket::OK); + + if (rv == nsSocket::E_EOF_FOUND) + { + DUMP(("EOF detected\n")); + rv = OK; + } + + fclose(destFd); + + return rv; +} + +int +nsHTTPConn::ParseURL(const char *aProto, char *aURL, char **aHost, + int *aPort, char **aPath) +{ + char *pos, *nextSlash, *nextColon, *end, *hostEnd; + int protoLen = strlen(aProto); + + if (!aURL || !aHost || !aPort || !aPath || !aProto) + return E_PARAM; + + if ((strncmp(aURL, aProto, protoLen) != 0) || + (strlen(aURL) < 9)) + return E_MALFORMED_URL; + + pos = aURL + protoLen; + nextColon = strchr(pos, ':'); + nextSlash = strchr(pos, '/'); + + // optional port specification + if (nextColon && ((nextSlash && nextColon < nextSlash) || + !nextSlash)) + { + int portStrLen; + if (nextSlash) + portStrLen = nextSlash - nextColon; + else + portStrLen = strlen(nextColon); + + char *portStr = (char *) malloc(portStrLen); + if (!portStr) + return E_MEM; + memset(portStr, 0, portStrLen); + strncpy(portStr, nextColon+1, portStrLen); + *aPort = atoi(portStr); + free(portStr); + } + if ( (!nextColon || (nextSlash && (nextColon > nextSlash))) + && *aPort <= 0) // don't override port if already set + *aPort = -1; + + // only host in URL, assume '/' for path + if (!nextSlash) + { + int copyLen; + if (nextColon) + copyLen = nextColon - pos; + else + copyLen = strlen(pos); + + *aHost = (char *) malloc(copyLen + 1); // to NULL terminate + strncpy(*aHost, pos, copyLen); + + *aPath = (char *) malloc(2); + *aPath = "/\0"; + + return OK; + } + + // normal parsing: both host and path exist + if (nextColon) + hostEnd = nextColon; + else + hostEnd = nextSlash; + *aHost = (char *) malloc(hostEnd - pos + 1); // to NULL terminate + if (!*aHost) + return E_MEM; + memset(*aHost, 0, hostEnd - pos + 1); + strncpy(*aHost, pos, hostEnd - pos); + *(*aHost + (hostEnd - pos)) = 0; // NULL terminate + + pos = nextSlash; + end = aURL + strlen(aURL); + + *aPath = (char *) malloc(end - pos + 1); + if (!*aPath) + { + if (*aHost) + free(*aHost); + return E_MEM; + } + memset(*aPath, 0, end - pos + 1); + strncpy(*aPath, pos, end - pos); + + return OK; +} + +void +nsHTTPConn::ParseContentLength(const char *aBuf, int *aLength) +{ + char *clHdr; // Content-length header line start + char *eol, *pos; + char clNameStr1[16] = "Content-length:"; + char clNameStr2[16] = "Content-Length:"; + char *clNameStr = clNameStr1; + + if (!aBuf || !aLength) + return; // non fatal so no error codes returned + *aLength = 0; + + // XXX strcasestr() needs to be ported for Solaris (and Win32 and Mac?) + clHdr = strstr(aBuf, (char *)clNameStr1); + if (!clHdr) + { + clHdr = strstr(aBuf, (char *)clNameStr2); + clNameStr = clNameStr2; + } + if (clHdr) + { + eol = strstr(clHdr, kCRLF); // end of line + pos = clHdr + strlen(clNameStr); + while ((pos < eol) && (*pos == ' ' || *pos == '\t')) + pos++; + if (pos < eol) + { + int clValStrLen = eol - pos + 1; // extra byte to NULL terminate + char *clValStr = (char *) malloc(clValStrLen); + if (!clValStr) + return; // imminent doom! + + memset(clValStr, 0, clValStrLen); + strncpy(clValStr, pos, eol - pos); + *aLength = atoi(clValStr); + } + } +} + +int +nsHTTPConn::Base64Encode(const unsigned char *in_str, int in_len, + char *out_str, int out_len) +{ + // NOTE: shamelessly copied from nsAbSyncPostEngine.cpp + + static unsigned char base64[] = + { + /* 0 1 2 3 4 5 6 7 */ + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', /* 0 */ + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', /* 1 */ + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', /* 2 */ + 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', /* 3 */ + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', /* 4 */ + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', /* 5 */ + 'w', 'x', 'y', 'z', '0', '1', '2', '3', /* 6 */ + '4', '5', '6', '7', '8', '9', '+', '/' /* 7 */ + }; + + int curr_out_len = 0; + + int i = 0; + unsigned char a, b, c; + + out_str[0] = '\0'; + + if (in_len > 0) + { + + while (i < in_len) + { + a = in_str[i]; + b = (i + 1 >= in_len) ? 0 : in_str[i + 1]; + c = (i + 2 >= in_len) ? 0 : in_str[i + 2]; + + if (i + 2 < in_len) + { + out_str[curr_out_len++] = (base64[(a >> 2) & 0x3F]); + out_str[curr_out_len++] = (base64[((a << 4) & 0x30) + + ((b >> 4) & 0xf)]); + out_str[curr_out_len++] = (base64[((b << 2) & 0x3c) + + ((c >> 6) & 0x3)]); + out_str[curr_out_len++] = (base64[c & 0x3F]); + } + else if (i + 1 < in_len) + { + out_str[curr_out_len++] = (base64[(a >> 2) & 0x3F]); + out_str[curr_out_len++] = (base64[((a << 4) & 0x30) + + ((b >> 4) & 0xf)]); + out_str[curr_out_len++] = (base64[((b << 2) & 0x3c) + + ((c >> 6) & 0x3)]); + out_str[curr_out_len++] = '='; + } + else + { + out_str[curr_out_len++] = (base64[(a >> 2) & 0x3F]); + out_str[curr_out_len++] = (base64[((a << 4) & 0x30) + + ((b >> 4) & 0xf)]); + out_str[curr_out_len++] = '='; + out_str[curr_out_len++] = '='; + } + + i += 3; + + if((curr_out_len + 4) > out_len) + { + return(-1); + } + + } + out_str[curr_out_len] = '\0'; + } + + return curr_out_len; +} + +#ifdef TEST_NSHTTPCONN + +int +TestHTTPCB(int aBytesRd, int aTotal) +{ + DUMP(("Bytes rd: %d\tTotal: %d\n", aBytesRd, aTotal)); + return 0; +} + +int +main(int argc, char **argv) +{ + nsHTTPConn *conn; + int rv = nsHTTPConn::OK; + char *proxiedURL = NULL; + char *proxyUser = NULL; + char *proxyPswd = NULL; + + DUMP(("*** %s: A self-test for the nsHTTPConn class.\n", argv[0])); + + if (argc < 2) + { + printf("usage: %s [ [ ", argv[0]); + printf("]]\n"); + exit(1); + } + + conn = new nsHTTPConn(argv[1]); + + if (argc >= 3) + { + proxiedURL = argv[2]; + } + if (argc >= 5) + { + proxyUser = argv[3]; + proxyPswd = argv[4]; + } + + conn->SetProxyInfo(proxiedURL, proxyUser, proxyPswd); + + rv = conn->Open(); + DUMP(("nsHTTPConn::Open returned: %d\n", rv)); + + rv = conn->Get(TestHTTPCB, NULL); // NULL: local file name = URL leaf + DUMP(("nsHTTPConn::Get returned: %d\n", rv)); + + rv = conn->Close(); + DUMP(("nsHTTPConn::Close returned: %d\n", rv)); + + return 0; +} + +#endif /* TEST_NSHTTPCONN */ diff --git a/xpinstall/wizard/libxpnet/src/nsHTTPConn.h b/xpinstall/wizard/libxpnet/src/nsHTTPConn.h new file mode 100644 index 000000000000..c7eeaed499d4 --- /dev/null +++ b/xpinstall/wizard/libxpnet/src/nsHTTPConn.h @@ -0,0 +1,102 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (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.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla Communicator client code, + * released March 31, 1998. + * + * The Initial Developer of the Original Code is Netscape Communications + * Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * Samir Gehani + */ + +#ifndef _NS_HTTPCONN_H_ +#define _NS_HTTPCONN_H_ + +class nsSocket; + +typedef int (*HTTPGetCB)(int aBytesRd, int aTotal); + +class nsHTTPConn +{ +public: + nsHTTPConn(char *aHost, int aPort, char *aPath); + nsHTTPConn(char *aURL); + ~nsHTTPConn(); + + int Open(); + int Get(HTTPGetCB aCallback, char *aDestFile); + int Close(); + + void SetProxyInfo(char *aProxiedURL, char *aProxyUser, + char *aProxyPswd); + static int ParseURL(const char *aProto, char *aURL, char **aHost, + int *aPort, char **aPath); + + enum + { + OK = 0, + E_MEM = -801, + E_PARAM = -802, + E_MALFORMED_URL = -803, + E_REQ_INCOMPLETE = -804, + E_B64_ENCODE = -805, + E_OPEN_FILE = -806 + }; + +private: + int Request(); + int Response(HTTPGetCB aCallback, char *aDestFile); + void ParseContentLength(const char *aBuf, int *aLength); + int Base64Encode(const unsigned char *in_str, int in_len, + char *out_str, int out_len); + + char *mHost; + char *mPath; + int mPort; + char *mProxiedURL; + char *mProxyUser; + char *mProxyPswd; + char *mDestFile; + int mHostPathAllocd; + nsSocket *mSocket; +}; + +#ifndef NULL +#define NULL ((void*) 0L); +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifdef DUMP +#undef DUMP +#endif +#if defined(DEBUG_sgehani) || defined(DEBUG) +#define DUMP(_vargs) \ +do { \ + printf("%s %d: ", __FILE__, __LINE__); \ + printf _vargs; \ +} while(0); +#else +#define DUMP(_vargs) +#endif + +#endif /* _NS_HTTPCONN_H_ */ diff --git a/xpinstall/wizard/libxpnet/src/nsSocket.cpp b/xpinstall/wizard/libxpnet/src/nsSocket.cpp new file mode 100644 index 000000000000..a0d42d6de6e7 --- /dev/null +++ b/xpinstall/wizard/libxpnet/src/nsSocket.cpp @@ -0,0 +1,450 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (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.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla Communicator client code, + * released March 31, 1998. + * + * The Initial Developer of the Original Code is Netscape Communications + * Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * Samir Gehani + */ + +#include +#include +#include +#include + +/* Platform-specific headers for socket functionality */ +#ifdef __unix +#include +#include +#include +#include +#elif defined(_WINDOWS) +#define read(_socket, _buf, _len) \ + recv(_socket, (char *) _buf, _len, 0); +#define write(_socket, _buf, _len) \ + send(_socket, (char *) _buf, _len, 0); +#include +#endif + +#include "nsSocket.h" + +#define MAXSOCKADDR 128 + +#include "platform.h" // for SOLARIS define +#if defined(SOLARIS) || defined(_WINDOWS) +#define socklen_t int +#endif + +#ifndef SHUT_RDWR +#define SHUT_RDWR 2 +#endif + +const int kUsecsPerSec = 1000000; +const int kTimeoutThresholdUsecs = 120 * kUsecsPerSec; +const int kTimeoutSelectUsecs = 100000; +const int kKilobyte = 1024; +const int kReadBufSize = 1024; + +nsSocket::nsSocket(char *aHost, int aPort) : + mHost(aHost), + mPort(aPort), + mFd(-1), + mListenFd(-1) +{ +} + +nsSocket::~nsSocket() +{ + // don't release mHost cause we don't own it +} + +int +nsSocket::Open() +{ +#ifdef _WINDOWS + /* funky windows initialization of winsock */ + + int err; + WSADATA wsaData; + WORD wVersionRequested = MAKEWORD(4, 0); + err = WSAStartup(wVersionRequested, &wsaData); + if (err != 0) + { + return E_WINSOCK; + } +#endif + + int rv = OK; + struct sockaddr_in servaddr; + struct hostent *hptr = NULL; + + mFd = socket(AF_INET, SOCK_STREAM, 0); +#ifdef _WINDOWS + if (mFd == INVALID_SOCKET) + { + printf("Last error: %d\n", WSAGetLastError()); + } +#endif + + memset(&servaddr, 0, sizeof(servaddr)); + servaddr.sin_family = AF_INET; + servaddr.sin_port = htons(mPort); + + if ( (hptr = gethostbyname(mHost)) == NULL ) + return E_INVALID_HOST; + + memcpy(&servaddr.sin_addr, (struct in_addr **) hptr->h_addr_list[0], + sizeof(struct in_addr)); + + rv = connect(mFd, (struct sockaddr *) &servaddr, sizeof(servaddr)); + if (rv < 0) + { +#if defined(DEBUG) && defined(__unix) + printf("ETIMEDOUT: %d\n", ETIMEDOUT); + printf("ECONNREFUSED: %d\n", ECONNREFUSED); + printf("EHOSTUNREACH: %d\n", EHOSTUNREACH); + printf("ENETUNREACH: %d\n", ENETUNREACH); + + printf("connect error: %d\n", errno); +#endif /* DEBUG && __unix */ + mFd = -1; + rv = E_SOCK_OPEN; + } + else + rv = OK; + + return rv; +} + +int +nsSocket::SrvOpen() +{ + int rv = OK; + struct sockaddr_in servaddr; + + /* init data socket making it listen */ + mListenFd = socket(AF_INET, SOCK_STREAM, 0); + + memset(&servaddr, 0, sizeof(servaddr)); + servaddr.sin_addr.s_addr = htonl(INADDR_ANY); /* wildcard */ + servaddr.sin_port = 0; /* let kernel bind an ephemeral port */ + + if ((bind(mListenFd, (struct sockaddr *) &servaddr, sizeof(servaddr))) != 0) + return E_BIND; + + if ((listen(mListenFd, SOMAXCONN)) != 0) + return E_LISTEN; + return rv; +} + +int +nsSocket::SrvAccept() +{ + int rv = OK; + struct sockaddr cliaddr; + socklen_t clilen; + + if (mListenFd < 0) + return E_PARAM; + + clilen = sizeof(cliaddr); + mFd = accept(mListenFd, (struct sockaddr *) &cliaddr, &clilen); + if (mFd < 0) + rv = E_ACCEPT; + + return rv; +} + +int +nsSocket::Send(unsigned char *aBuf, int *aBufSize) +{ + int rv = OK; + struct timeval seltime; + int timeout = 0; + fd_set selset; + + if (!aBuf || aBufSize <= 0 || mFd < 0) + return E_PARAM; + + while (timeout < kTimeoutThresholdUsecs) + { + FD_ZERO(&selset); + FD_SET(mFd, &selset); + seltime.tv_sec = 0; + seltime.tv_usec = kTimeoutSelectUsecs; + + rv = select(mFd+1, NULL, &selset, NULL, &seltime); + switch (rv) + { + case -1: /* error occured! */ + return errno; + case 0: /* timeout; retry */ + timeout += kTimeoutSelectUsecs; + continue; + default: /* ready to write */ + break; + } + + if (!FD_ISSET(mFd, &selset)) + { + timeout += kTimeoutSelectUsecs; + continue; /* not ready to write; retry */ + } + else + break; + } + if (rv == 0) + return E_TIMEOUT; + + rv = write(mFd, aBuf, *aBufSize); + if (rv <= 0) + rv = E_WRITE; + else + { + *aBufSize = rv; + rv = OK; + } + + return rv; +} + +int +nsSocket::Recv(unsigned char *aBuf, int *aBufSize) +{ + int rv = OK; + unsigned char lbuf[kReadBufSize]; /* function local buffer */ + int bytesrd = 0; + struct timeval seltime; + fd_set selset; + int bufsize; + + if (!aBuf || *aBufSize <= 0 || mFd < 0) + return E_PARAM; + memset(aBuf, 0, *aBufSize); + + for ( ; ; ) + { + /* return if we anticipate overflowing caller's buffer */ + if (bytesrd >= *aBufSize) + return E_READ_MORE; + + memset(&lbuf, 0, kReadBufSize); + + FD_ZERO(&selset); + FD_SET(mFd, &selset); + seltime.tv_sec = 0; + seltime.tv_usec = kTimeoutSelectUsecs; + + rv = select(mFd+1, &selset, NULL, NULL, &seltime); + switch (rv) + { + case -1: /* error occured! */ + return errno; + case 0: /* timeout; retry */ + continue; + default: /* ready to read */ + break; + } + + // XXX TODO: prevent inf loop returning at kTimeoutThresholdUsecs + if (!FD_ISSET(mFd, &selset)) + continue; /* not ready to read; retry */ + + bufsize = *aBufSize - bytesrd; + rv = read(mFd, lbuf, bufsize); + if (rv == 0) /* EOF encountered */ + { + rv = E_EOF_FOUND; + break; + } + if (rv < 0) + { + rv = E_READ; + break; + } + + if (*aBufSize >= bytesrd + rv) + { + memcpy(aBuf + bytesrd, lbuf, rv); + bytesrd += rv; + if (rv <= bufsize) + { + FD_ZERO(&selset); + FD_SET(mFd, &selset); + seltime.tv_sec = 0; + seltime.tv_usec = kTimeoutSelectUsecs; + + /* check if we still need to read from this socket */ + rv = select(mFd+1, &selset, NULL, NULL, &seltime); + if (rv == 1) + rv = E_READ_MORE; + else + rv = OK; + break; + } + } + else + { + rv = E_SMALL_BUF; + break; + } + } + *aBufSize = bytesrd; + return rv; +} + +int +nsSocket::Close() +{ + int rv = OK, rv1 = OK, rv2 = OK; + + rv1 = shutdown(mFd, SHUT_RDWR); + if (mListenFd > 0) + rv2 = shutdown(mListenFd, SHUT_RDWR); + + if (rv1 != 0 || rv2 != 0) + rv = E_SOCK_CLOSE; + +/* funky windows shutdown of winsock */ +#ifdef _WINDOWS + int wsaErr = WSACleanup(); + if (wsaErr != 0) + rv = wsaErr; +#endif + + return rv; +} + +int +nsSocket::GetHostPortString(char **aHostPort) +{ + int rv = OK; + socklen_t salen; + struct sockaddr_in servaddr; + int hpsLen; // host-port string length + + if (!aHostPort) + return E_PARAM; + + salen = MAXSOCKADDR; + if ((getsockname(mListenFd, (struct sockaddr *) &servaddr, &salen)) < 0) + { + *aHostPort = NULL; + return E_GETSOCKNAME; + } + + hpsLen = strlen("AA1,AA2,AA3,AA4,PP1,PP2"); + *aHostPort = (char *) malloc(hpsLen); + if (!*aHostPort) + return E_MEM; + + memset(*aHostPort, 0, hpsLen); + sprintf(*aHostPort, "%d,%d,%d,%d,%d,%d", + (int)((char*)&servaddr.sin_addr)[0] & 0xFF, + (int)((char*)&servaddr.sin_addr)[1] & 0xFF, + (int)((char*)&servaddr.sin_addr)[2] & 0xFF, + (int)((char*)&servaddr.sin_addr)[3] & 0xFF, + (int)((char*)&servaddr.sin_port)[0] & 0xFF, + (int)((char*)&servaddr.sin_port)[1] & 0xFF); + + return rv; +} + +float +nsSocket::CalcRate(struct timeval *aPre, struct timeval *aPost, int aBytes) +{ + float diffUsecs, rate; + + /* param check */ + if (!aPre || !aPost || aBytes <= 0) + return 0; + + diffUsecs = (float)(aPost->tv_sec - aPre->tv_sec) * kUsecsPerSec; + diffUsecs += (float)aPost->tv_usec - (float)aPre->tv_usec; + rate = ((float)(aBytes/kKilobyte))/ + ((float)(diffUsecs/kUsecsPerSec)); + + return rate; +} + +#ifdef TEST_NSSOCKET + +void +my_nprintf(char *buf, int len) +{ + printf("buf size = %d\n", len); + for (int i = 0; i < len; ++i) + { + printf("%c", *(buf+i)); + } + printf("\n"); +} + +const int kTestBufSize = 1024; + +int +main(int argc, char **argv) +{ + DUMP(("*** %s: A self-test for nsSocket.\n", argv[0])); + + if (argc < 4) + { + fprintf(stderr, "usage: %s \n", + argv[0]); + exit(1); + } + + int rv = nsSocket::OK; + nsSocket *sock = new nsSocket(argv[1], atoi(argv[2])); + char buf[kTestBufSize]; + int bufSize; + memset(buf, 0, kTestBufSize); + + // open socket + rv = sock->Open(); + DUMP(("nsSocket::Open returned: %d\n", rv)); + + // prepare http request str + sprintf(buf, "GET %s HTTP/1.1\r\n\r\n", argv[3]); + bufSize = strlen(buf) + 1; // add 1 for NULL termination + + // make request + rv = sock->Send((unsigned char *)buf, &bufSize); + DUMP(("nsSocket::Send returned: %d\t and sent: %d bytes\n", rv, bufSize)); + + // get response + do { + // prepare response buf + memset(buf, 0, kTestBufSize); + bufSize = kTestBufSize; + + rv = sock->Recv((unsigned char *)buf, &bufSize); + + DUMP(("nsSocket::Recv returned: %d\t and recd: %d bytes\n", + rv, bufSize)); + // DUMP(("%s\n", buf)); + my_nprintf(buf, bufSize); + } while (rv == nsSocket::E_READ_MORE); + + // close socket + rv = sock->Close(); + DUMP(("nsSocket::Close returned: %d\n", rv)); + + return 0; +} +#endif /* TEST_NSSOCKET */ diff --git a/xpinstall/wizard/libxpnet/src/nsSocket.h b/xpinstall/wizard/libxpnet/src/nsSocket.h new file mode 100644 index 000000000000..b96372c8defd --- /dev/null +++ b/xpinstall/wizard/libxpnet/src/nsSocket.h @@ -0,0 +1,112 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (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.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla Communicator client code, + * released March 31, 1998. + * + * The Initial Developer of the Original Code is Netscape Communications + * Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * Samir Gehani + */ + +#ifndef _NS_SOCKET_H_ +#define _NS_SOCKET_H_ + +#ifndef _WINDOWS +#include +#endif + +class nsSocket +{ +public: + nsSocket(char *aHost, int aPort); + ~nsSocket(); + +//---------------------------------------------------------------------- +// Errors +//---------------------------------------------------------------------- + enum + { + OK = 0, + E_PARAM = -1001, + E_MEM = -1002, + E_INVALID_HOST = -1003, + E_SOCK_OPEN = -1004, + E_SOCK_CLOSE = -1005, + E_TIMEOUT = -1006, + E_WRITE = -1007, + E_READ_MORE = -1008, + E_READ = -1009, + E_SMALL_BUF = -1010, + E_EOF_FOUND = -1011, + E_BIND = -1012, + E_LISTEN = -1014, + E_ACCEPT = -1015, + E_GETSOCKNAME = -1016, + E_WINSOCK = -1017 + }; + +//---------------------------------------------------------------------- +// Public interface +//---------------------------------------------------------------------- + int Open(); + int SrvOpen(); // server alternate to client Open() + int SrvAccept(); // must be called after SrvOpen() + int Send(unsigned char *aBuf, int *aBufSize); + int Recv(unsigned char *aBuf, int *aBufSize); + int Close(); + + int GetHostPortString(char **aHostPort); + + static + float CalcRate(struct timeval *aPre, struct timeval *aPost, int aBytes); + +private: + char *mHost; + int mPort; + int mFd; // connected socket + int mListenFd; // listening socket (only if SrvOpen() was called) +}; + +//---------------------------------------------------------------------- +// Macro definitions +//---------------------------------------------------------------------- +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef NULL +#define NULL ((void *) 0L) +#endif + +#ifdef DUMP +#undef DUMP +#endif +#if defined(DEBUG) || defined(DEBUG_sgehani) +#define DUMP(_vargs) \ +do { \ + printf("%s %d: ", __FILE__, __LINE__); \ + printf _vargs; \ +} while (0); +#else +#define DUMP(_vargs) +#endif + +#endif /* _NS_SOCKET_H_ */ diff --git a/xpinstall/wizard/libxpnet/test/Makefile.in b/xpinstall/wizard/libxpnet/test/Makefile.in new file mode 100644 index 000000000000..f97432a70f91 --- /dev/null +++ b/xpinstall/wizard/libxpnet/test/Makefile.in @@ -0,0 +1,40 @@ +# +# The contents of this file are subject to the Netscape Public +# License Version 1.1 (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.mozilla.org/NPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under the License. +# +# The Original Code is Mozilla Communicator client code, +# released March 31, 1998. +# +# The Initial Developer of the Original Code is Netscape Communications +# Corporation. Portions created by Netscape are +# Copyright (C) 1998 Netscape Communications Corporation. All +# Rights Reserved. +# +# Contributor(s): +# Samir Gehani +# + +DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VAPTH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +CPPSRCS = TestLibxpnet.cpp + +SIMPLE_PROGRAMS = $(CPPSRCS:.cpp=$(BIN_SUFFIX)) + +LIBS = -lxpnet_s + +include $(topsrcdir)/config/rules.mk + +INCLUDES += -I$(srcdir)/../src + diff --git a/xpinstall/wizard/libxpnet/test/TestLibxpnet.cpp b/xpinstall/wizard/libxpnet/test/TestLibxpnet.cpp new file mode 100644 index 000000000000..900285d14fc6 --- /dev/null +++ b/xpinstall/wizard/libxpnet/test/TestLibxpnet.cpp @@ -0,0 +1,158 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (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.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla Communicator client code, + * released March 31, 1998. + * + * The Initial Developer of the Original Code is Netscape Communications + * Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * Samir Gehani + */ + +#include +#include +#include + +#include "nsFTPConn.h" +#include "nsHTTPConn.h" + +const int kProxySrvrLen = 1024; +const char kHTTP[8] = "http://"; +const char kFTP[7] = "ftp://"; +const char kLoclFile[7] = "zzzFTP"; + +int +ProgressCB(int aBytesSoFar, int aTotalFinalSize) +{ + printf("."); + return 0; +} + +void +spew(char *funcName, int rv) +{ + printf("%s returned %d\n", funcName, rv); +} + +void +usage(char *prog) +{ + fprintf(stderr, "usage: %s [ProxyServer ", prog); + fprintf(stderr, "ProxyPort [ProxyUserName ProxyPassword]\n"); +} + +int +main(int argc, char **argv) +{ + char *proxyUser = 0, *proxyPswd = 0; + char proxyURL[kProxySrvrLen]; + int rv = 0; + + if (argc < 2) + { + usage(argv[0]); + exit(1); + } + + /* has a proxy server been specified? */ + if (argc >= 4) + { + memset(proxyURL, 0, kProxySrvrLen); + sprintf(proxyURL, "http://%s:%s", argv[2], argv[3]); + + if (argc >=6) + { + proxyUser = argv[4]; + proxyPswd = argv[5]; + } + + nsHTTPConn *conn = new nsHTTPConn(proxyURL); + conn->SetProxyInfo(argv[1], proxyUser, proxyPswd); + printf("Proxy URL: %s\n", argv[1]); + if (proxyUser && proxyPswd) + { + printf("Proxy User: %s\n", proxyUser); + printf("Proxy Pswd: %s\n", proxyPswd); + } + + rv = conn->Open(); + spew("nsHTTPConn::Open", rv); + + rv = conn->Get(ProgressCB, NULL); // use leaf from URL + printf("\n"); // newline after progress completes + spew("nsHTTPConn::Get", rv); + + rv = conn->Close(); + spew("nsHTTPConn::Close", rv); + } + else + { + /* is this an HTTP URL? */ + if (strncmp(argv[1], kHTTP, strlen(kHTTP)) == 0) + { + nsHTTPConn *conn = new nsHTTPConn(argv[1]); + + rv = conn->Open(); + spew("nsHTTPConn::Open", rv); + + rv = conn->Get(ProgressCB, NULL); + printf("\n"); // newline after progress completes + spew("nsHTTPConn::Get", rv); + + rv = conn->Close(); + spew("nsHTTPConn::Close", rv); + } + + /* or is this an FTP URL? */ + else if (strncmp(argv[1], kFTP, strlen(kFTP)) == 0) + { + char *host = 0, *path = 0, *file = (char*) kLoclFile; + int port = 21; + + rv = nsHTTPConn::ParseURL(kFTP, argv[1], &host, &port, &path); + spew("nsHTTPConn::ParseURL", rv); + + nsFTPConn *conn = new nsFTPConn(host); + + rv = conn->Open(); + spew("nsFTPConn::Open", rv); + + if (strrchr(path, '/') != (path + strlen(path))) + file = strrchr(path, '/') + 1; // set to leaf name + rv = conn->Get(path, file, nsFTPConn::BINARY, 1, ProgressCB); + printf("\n"); // newline after progress completes + spew("nsFTPConn::Get", rv); + + rv = conn->Close(); + spew("nsFTPConn::Close", rv); + + if (host) + free(host); + if (path) + free(path); + } + + /* or we don't understand the args */ + else + { + fprintf(stderr, "Like, uhm, dude! I don't get you. "); + fprintf(stderr, "See usage...\n"); + usage(argv[0]); + } + } + + return 0; +} diff --git a/xpinstall/wizard/libxpnet/test/makefile.win b/xpinstall/wizard/libxpnet/test/makefile.win new file mode 100644 index 000000000000..38950a1dbf00 --- /dev/null +++ b/xpinstall/wizard/libxpnet/test/makefile.win @@ -0,0 +1,49 @@ +#!gmake +# +# The contents of this file are subject to the Netscape Public +# License Version 1.1 (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.mozilla.org/NPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under the License. +# +# The Original Code is Mozilla Communicator client code, +# released March 31, 1998. +# +# The Initial Developer of the Original Code is Netscape Communications +# Corporation. Portions created by Netscape are +# Copyright (C) 1998 Netscape Communications Corporation. All +# Rights Reserved. +# +# Contributor(s): +# Samir Gehani +# + +MODULE=xpnet +DEPTH=..\..\..\.. + +MAKE_OBJ_TYPE=EXE + +EXENAME=TestLibxpnet +PDBFILE=TestLibxpnet +MAPFILE=TestLibxpnet.map + +PROGRAM=.\$(OBJDIR)\$(EXENAME).exe + +OBJS=.\$(OBJDIR)\TestLibxpnet.obj + +LINCS=-I..\src + +LLIBS=$(DIST)\lib\$(MODULE)_s.lib + +include <$(DEPTH)/config/rules.mak> + +install:: $(PROGRAM) + $(MAKE_INSTALL) $(PROGRAM) $(DIST)\bin + +clobber:: + $(RM) $(DIST)\bin\$(EXENAME).exe +