зеркало из https://github.com/mozilla/pjs.git
Isolate common http functionality
This commit is contained in:
Родитель
ba467da92b
Коммит
502b143b54
|
@ -1,110 +0,0 @@
|
|||
# Makefile for mailstone
|
||||
# This should be run using 'gmake'
|
||||
########################################################################
|
||||
|
||||
topsrcdir = ..
|
||||
|
||||
ifndef INCLUDED_CONFIG_MK
|
||||
include $(topsrcdir)/config/config.mk
|
||||
endif
|
||||
|
||||
# you may want to force debug on the command line (default is release)
|
||||
# BUILD_VARIANT=debug
|
||||
# pass in extra compile arguments in CPPFLAGS
|
||||
|
||||
BINDIR = ../bin
|
||||
|
||||
########################################################################
|
||||
|
||||
# what are we making
|
||||
|
||||
all:: $(OBJDIR) mailclient
|
||||
|
||||
########################################################################
|
||||
|
||||
.SUFFIXES: .c .$(OBJ_SUFFIX)
|
||||
|
||||
.SUFFIXES: .c .$(OBJ_SUFFIX)
|
||||
|
||||
.c.$(OBJ_SUFFIX):
|
||||
ifeq ($(ARCH), WINNT)
|
||||
$(COMPILE) -c -MT $< -Fo$(OBJDIR)/$@
|
||||
else
|
||||
$(COMPILE) -c $< -o $(OBJDIR)/$@
|
||||
endif
|
||||
|
||||
$(OBJDIR)/%.$(OBJ_SUFFIX): %.c
|
||||
ifeq ($(ARCH), WINNT)
|
||||
$(COMPILE) -c -MT $< -Fo$(OBJDIR)/$*.$(OBJ_SUFFIX)
|
||||
else
|
||||
$(COMPILE) -c $< -o $(OBJDIR)/$*.$(OBJ_SUFFIX)
|
||||
endif
|
||||
|
||||
########################################################################
|
||||
# mailclient itself
|
||||
|
||||
STONE = $(OBJDIR)/mailclient$(EXE_SUFFIX)
|
||||
|
||||
STONESRCS = bench.c client.c errexit.c main.c \
|
||||
parse.c sysdep.c timefunc.c \
|
||||
http.c imap4.c pop3.c smtp.c wmap.c
|
||||
|
||||
STONEOBJS = $(addprefix $(OBJDIR)/, $(STONESRCS:.c=.$(OBJ_SUFFIX)) )
|
||||
|
||||
|
||||
mailclient:: $(STONE)
|
||||
|
||||
$(OBJDIR):
|
||||
mkdir -p $(OBJDIR)
|
||||
|
||||
$(STONE): $(STONEOBJS) Makefile
|
||||
@$(ECHO) "\n===== [`date`] making $(STONE)...\n"
|
||||
$(COMPILE) $(STONEOBJS) $(LIBPATH) $(LIBS) $(OS_LINKFLAGS) -o $(STONE)
|
||||
|
||||
$(OBJDIR)/bench.$(OBJ_SUFFIX): bench.c bench.h sysdep.h Makefile
|
||||
|
||||
$(OBJDIR)/client.$(OBJ_SUFFIX): client.c bench.h sysdep.h Makefile
|
||||
|
||||
$(OBJDIR)/errexit.$(OBJ_SUFFIX): errexit.c bench.h sysdep.h Makefile
|
||||
|
||||
$(OBJDIR)/http.$(OBJ_SUFFIX): http.c bench.h pish.h sysdep.h Makefile
|
||||
|
||||
$(OBJDIR)/imap4.$(OBJ_SUFFIX): imap4.c bench.h pish.h sysdep.h Makefile
|
||||
|
||||
$(OBJDIR)/main.$(OBJ_SUFFIX): main.c bench.h sysdep.h Makefile
|
||||
|
||||
$(OBJDIR)/parse.$(OBJ_SUFFIX): parse.c bench.h sysdep.h Makefile
|
||||
|
||||
$(OBJDIR)/pop3.$(OBJ_SUFFIX): pop3.c bench.h pish.h sysdep.h Makefile
|
||||
|
||||
$(OBJDIR)/smtp.$(OBJ_SUFFIX): smtp.c bench.h pish.h sysdep.h Makefile
|
||||
|
||||
$(OBJDIR)/stats.$(OBJ_SUFFIX): stats.c bench.h sysdep.h Makefile
|
||||
|
||||
$(OBJDIR)/sysdep.$(OBJ_SUFFIX): sysdep.c bench.h sysdep.h Makefile
|
||||
|
||||
$(OBJDIR)/timefunc.$(OBJ_SUFFIX): timefunc.c bench.h sysdep.h Makefile
|
||||
|
||||
$(OBJDIR)/wmap.$(OBJ_SUFFIX): wmap.c bench.h sysdep.h Makefile
|
||||
|
||||
# currently broken. See ../Makefile for packaging
|
||||
install: all
|
||||
$(CP) $(STONE) $(BINDIR)
|
||||
|
||||
# clean out everything that we created.
|
||||
distclean:: clean
|
||||
$(RM) -rf $(OBJDIR)
|
||||
|
||||
# clean out the intermediate files, keep the executable
|
||||
clean::
|
||||
$(RM) $(STONEOBJS)
|
||||
|
||||
debug::
|
||||
@$(ECHO) "\n===== [`date`] making debug...\n"
|
||||
$(MAKE) BUILD_VARIANT=debug OBJDIR_TAG=_DBG
|
||||
|
||||
release::
|
||||
@$(ECHO) "\n===== [`date`] making release...\n"
|
||||
$(MAKE) BUILD_VARIANT=release OBJDIR_TAG=_OPT
|
||||
|
||||
########################################################################
|
|
@ -192,6 +192,8 @@ typedef struct stats { /* used for throttling ??? */
|
|||
} stats_t;
|
||||
|
||||
typedef struct resolved_addr {
|
||||
char * hostName; /* name of server */
|
||||
NETPORT portNum; /* port ot use */
|
||||
int resolved;
|
||||
struct hostent host_phe;
|
||||
struct protoent host_ppe;
|
||||
|
@ -465,8 +467,7 @@ extern double compdifftime_double(struct timeval *End, struct timeval *Strt);
|
|||
/* routines in main.c */
|
||||
extern char *safe_inet_ntoa(struct in_addr ina, char *psz);
|
||||
|
||||
extern SOCKET connectsock(ptcx_t ptcx, char *host, resolved_addr_t *, NETPORT portnum,
|
||||
char *protocol);
|
||||
extern SOCKET connectSocket(ptcx_t ptcx, resolved_addr_t *, char *protocol);
|
||||
extern int set_abortive_close(SOCKET sock);
|
||||
|
||||
extern void throttle(ptcx_t ptcx, mail_command_t *comm, cmd_stats_t *timer);
|
||||
|
|
|
@ -0,0 +1,419 @@
|
|||
/* -*- Mode: C; c-file-style: "bsd"; comment-column: 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 the Netscape Mailstone utility,
|
||||
* released March 17, 2000.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1999-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Dan Christian <robodan@netscape.com>
|
||||
* Marcel DePaolis <marcel@netcape.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU Public License Version 2 or later (the "GPL"), in
|
||||
* which case the provisions of the GPL are applicable instead of
|
||||
* those above. If you wish to allow use of your version of this file
|
||||
* only under the terms of the GPL and not to allow others to use your
|
||||
* version of this file under the NPL, indicate your decision by
|
||||
* deleting the provisions above and replace them with the notice and
|
||||
* other provisions required by the GPL. If you do not delete the
|
||||
* provisions above, a recipient may use your version of this file
|
||||
* under either the NPL or the GPL.
|
||||
*/
|
||||
/* http-util.c -- Shared HTTP functions */
|
||||
|
||||
#include "bench.h"
|
||||
#include "http-util.h"
|
||||
|
||||
/*
|
||||
Establish (or re-establish) connection to server.
|
||||
No data is exchanged.
|
||||
*/
|
||||
int
|
||||
HttpConnect (
|
||||
ptcx_t ptcx,
|
||||
resolved_addr_t *hostInfo,
|
||||
event_timer_t *timer)
|
||||
{
|
||||
int rc=0;
|
||||
|
||||
D_PRINTF(stderr, "HttpConnect()\n");
|
||||
|
||||
event_start(ptcx, timer);
|
||||
ptcx->sock = connectSocket(ptcx, hostInfo, "tcp");
|
||||
event_stop(ptcx, timer);
|
||||
if (BADSOCKET(ptcx->sock)) {
|
||||
if (gf_timeexpired < EXIT_FAST) {
|
||||
timer->errs++;
|
||||
returnerr(debugfile,
|
||||
"%s<HttpConnect: HTTP Couldn't connect to %s: %s\n",
|
||||
ptcx->errMsg, hostInfo->hostName, neterrstr());
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (gf_abortive_close) {
|
||||
if (set_abortive_close(ptcx->sock) != 0) {
|
||||
returnerr(debugfile,
|
||||
"%s<HttpConnect: HTTP: WARNING: Could not set abortive close\n",
|
||||
ptcx->errMsg, neterrstr());
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
HttpReadResponse handles the details of reading a HTTP response It
|
||||
takes and interactive parsing function and a response buffer. The
|
||||
response buffer will hold at least the last 1/2 buffer of the data
|
||||
stream. This allows errors to be handled by the calling routine.
|
||||
Long responses should be parsed on the fly by the parsing callback.
|
||||
|
||||
HttpReadResponse handles find the content-length and header break.
|
||||
Once the break is called, it will call the parsing callback so that it can
|
||||
set findStr (which is NULL).
|
||||
|
||||
The findStr search is case insensitive if the first character of findStr
|
||||
has distinct upper and lower cases (see toupper and tolower).
|
||||
|
||||
The callback is called with the buffer, the bytes in the buffer,
|
||||
a pointer just past the findStr match, and a pointer to findStr.
|
||||
The callback should then update findStr and searchStr; and return -2
|
||||
for an error (abort message), 0 for success, and 1 for need more data.
|
||||
|
||||
findStr is expected to be a constant or static storage.
|
||||
Before exit, the parsing callback is called one last time (with NULL
|
||||
findStr and searchStr), so that it can do any cleanup.
|
||||
|
||||
Management of the buffer is done automatically by the movement of searchStr.
|
||||
|
||||
HttpReadResponse returns bytesInBuffer on success, -1 for IO error,
|
||||
-2 for error returned by the parser.
|
||||
*/
|
||||
int
|
||||
HttpReadResponse(
|
||||
ptcx_t ptcx,
|
||||
mail_command_t *cmd, /* command info for msgParse */
|
||||
void *me, /* connection state for msgParse */
|
||||
char *buffer,
|
||||
int buflen,
|
||||
parseMsgPtr_t msgParse
|
||||
)
|
||||
{
|
||||
/* read the server response and do nothing with it */
|
||||
/* Will need to look for HTTP headers and Content-Length/Keep-Alive */
|
||||
int gotheader = 0;
|
||||
int totalbytesread = 0;
|
||||
int bytesread;
|
||||
int bytesInBuffer = 0;
|
||||
const char *findStr; /* string we are watching for */
|
||||
const char *oldFindStr = NULL;
|
||||
char findStrSpn[3]; /* case insensitive search start */
|
||||
int findLen=0; /* length of string */
|
||||
char *foundStr; /* what we found */
|
||||
char *searchStart; /* where next to look for findStr */
|
||||
int contentlength = 0; /* HTTP content length */
|
||||
int bytestoread = buflen-1; /* start by reading lots */
|
||||
int getBytes = 0; /* need more input */
|
||||
|
||||
D_PRINTF(stderr, "HttpReadResponse()\n");
|
||||
|
||||
findStr = HTTP_CONTENT_LENGTH;
|
||||
searchStart = buffer;
|
||||
memset(buffer, 0, buflen); /* DEBUG */
|
||||
while (1)
|
||||
{
|
||||
if (gf_timeexpired >= EXIT_FAST) {
|
||||
D_PRINTF(stderr,"HttpReadResponse() Time expired.\n");
|
||||
break;
|
||||
}
|
||||
if (findStr != oldFindStr) { /* findStr changed */
|
||||
if (NULL == findStr) {
|
||||
findLen = 0;
|
||||
findStrSpn[0] = 0;
|
||||
} else {
|
||||
char upperC, lowerC; /* upper and lower of findStr[0] */
|
||||
findLen = strlen (findStr);
|
||||
upperC = toupper (findStr[0]);
|
||||
lowerC = tolower (findStr[0]);
|
||||
if (lowerC != upperC) {
|
||||
/*D_PRINTF (stderr, "New findStr [%s] upper %c lower %c\n",
|
||||
findStr, upperC, lowerC);*/
|
||||
findStrSpn[0] = upperC;
|
||||
findStrSpn[1] = lowerC;
|
||||
findStrSpn[2] = 0;
|
||||
} else {
|
||||
/*D_PRINTF (stderr, "New findStr [%s] NOT case sensitive\n",
|
||||
findStr);*/
|
||||
findStrSpn[0] = 0;
|
||||
}
|
||||
}
|
||||
oldFindStr = findStr;
|
||||
}
|
||||
/* See if we should read more */
|
||||
if ((getBytes > 0)
|
||||
|| (0 == findLen)
|
||||
|| ((bytesInBuffer - (searchStart - buffer)) < findLen)) {
|
||||
int count;
|
||||
|
||||
if (totalbytesread >= bytestoread) { /* done reading */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Make room for more data */
|
||||
/* need to be careful to save data for response. shift by half */
|
||||
if ((searchStart - buffer) > buflen/2) {
|
||||
/* This is the only place we reduce searchStart or bytesInBuffer */
|
||||
int toSkip = buflen/2;
|
||||
int toSave = bytesInBuffer - toSkip;
|
||||
/*D_PRINTF (stderr, "Shifting %d of %d bytes\n",
|
||||
toSave, bytesInBuffer);*/
|
||||
memcpy (buffer, buffer+toSkip, toSave); /* shift data down */
|
||||
bytesInBuffer = toSave;
|
||||
buffer[bytesInBuffer] = 0; /* re-terminate??? */
|
||||
searchStart -= toSkip;
|
||||
assert (searchStart >= buffer);
|
||||
}
|
||||
count = MIN (bytestoread-totalbytesread,
|
||||
buflen-bytesInBuffer-1);
|
||||
/*D_PRINTF(stderr, "retryRead() size=%d %d/%d inBuffer=%d\n",
|
||||
count, totalbytesread, bytestoread, bytesInBuffer);*/
|
||||
bytesread = retryRead(ptcx, ptcx->sock, buffer+bytesInBuffer, count);
|
||||
|
||||
if (0 == bytesread) { /* most likely an error */
|
||||
strcpy (ptcx->errMsg, "HttpReadResponse:got 0 bytes");
|
||||
break;
|
||||
}
|
||||
if (bytesread < 0) { /* ERROR */
|
||||
strcat (ptcx->errMsg, "<HttpReadResponse");
|
||||
return -1;
|
||||
}
|
||||
T_PRINTF(ptcx->logfile, buffer+bytesInBuffer, bytesread,
|
||||
"%s ReadResponse", cmd->proto->name); /* telemetry log */
|
||||
totalbytesread += bytesread;
|
||||
bytesInBuffer += bytesread;
|
||||
buffer[bytesInBuffer] = 0; /* terminate for string searches */
|
||||
ptcx->bytesread += bytesread; /* log statistics */
|
||||
getBytes = 0;
|
||||
} else {
|
||||
/*D_PRINTF (stderr,
|
||||
"Not reading, have %d only need %d. %d/%d\n",
|
||||
bytesInBuffer- (searchStart - buffer), findLen,
|
||||
bytestoread, totalbytesread);*/
|
||||
}
|
||||
|
||||
if (NULL == findStr) { /* nothing to search for */
|
||||
searchStart = buffer+bytesInBuffer; /* discard buffer */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* otherwise search for findStr */
|
||||
if (findStrSpn[0]) { /* do case insensitive version */
|
||||
char *cp;
|
||||
foundStr = NULL;
|
||||
for (cp = searchStart; (cp - buffer) < bytesInBuffer; ++cp) {
|
||||
cp = strpbrk (cp, findStrSpn); /* look for first char match */
|
||||
if (NULL == cp) {
|
||||
break;
|
||||
}
|
||||
if (!strnicmp(cp, findStr, findLen)) { /* check whole match */
|
||||
foundStr = cp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else { /* non case sensitive version */
|
||||
foundStr = strstr(searchStart, findStr);
|
||||
}
|
||||
|
||||
if (NULL == foundStr) { /* found nothing, shift and continue */
|
||||
/* jump to findLen-1 from end */
|
||||
if (bytesInBuffer < findLen)
|
||||
continue; /* nothing to shift */
|
||||
|
||||
searchStart = buffer + bytesInBuffer - findLen + 1;
|
||||
continue; /* get more input */
|
||||
}
|
||||
|
||||
/* Found search string */
|
||||
/*D_PRINTF (stderr, "Found [%s] after %d bytes\n",
|
||||
findStr, totalbytesread);*/
|
||||
searchStart = foundStr + findLen; /* found this much */
|
||||
|
||||
if (0 == gotheader) { /* found length */
|
||||
contentlength = atoi(searchStart); /* save contentlength */
|
||||
searchStart = strchr (searchStart, '\n'); /* jump to EOL */
|
||||
if (NULL == searchStart) { /* missing line end, get more */
|
||||
searchStart = buffer;
|
||||
} else { /* got complete contentlength line */
|
||||
gotheader++;
|
||||
findStr = HTTP_HEADER_BREAK; /* now look for break */
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else if (1 == gotheader) { /* found header break */
|
||||
gotheader++;
|
||||
/* now compute bytetoread */
|
||||
bytestoread = contentlength
|
||||
+ ((searchStart - buffer) /* position in buffer */
|
||||
+ (totalbytesread - bytesInBuffer)); /* buffer offset */
|
||||
D_PRINTF(stderr, "contentlength=%d, bytestoread=%d\n",
|
||||
contentlength, bytestoread);
|
||||
|
||||
findStr = NULL; /* should chain into extra searches */
|
||||
|
||||
if (msgParse) { /* initialize callback */
|
||||
int rc;
|
||||
/* having findStr == NULL signal initial callback */
|
||||
rc = (*(msgParse)) (ptcx, cmd, me,
|
||||
buffer, bytesInBuffer, &searchStart, &findStr);
|
||||
if (rc < 0) { /* parser signaled error */
|
||||
return rc;
|
||||
}
|
||||
if (NULL == searchStart) {
|
||||
searchStart = buffer+bytesInBuffer; /* discard buffer */
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (msgParse) { /* call extra searches */
|
||||
int rc;
|
||||
rc = (*(msgParse)) (ptcx, cmd, me,
|
||||
buffer, bytesInBuffer, &searchStart, &findStr);
|
||||
if (rc < 0) { /* protocol error */
|
||||
return rc;
|
||||
}
|
||||
if (rc > 0) { /* need more data */
|
||||
getBytes = rc;
|
||||
searchStart = foundStr; /* back up search string */
|
||||
continue;
|
||||
}
|
||||
if (searchStart < buffer) { /* or NULL */
|
||||
searchStart = buffer+bytesInBuffer; /* discard buffer */
|
||||
}
|
||||
} else {
|
||||
searchStart = buffer+bytesInBuffer; /* discard buffer */
|
||||
}
|
||||
}
|
||||
}
|
||||
D_PRINTF(stderr, "HttpReadResponse: Read %d/%d saved %d\n",
|
||||
totalbytesread, bytestoread, bytesInBuffer);
|
||||
if (msgParse) { /* call extra searches */
|
||||
findStr = NULL; /* signal final callback */
|
||||
searchStart = NULL;
|
||||
(void)(*(msgParse)) (ptcx, cmd, me,
|
||||
buffer, bytesInBuffer, &searchStart, &findStr);
|
||||
}
|
||||
|
||||
return bytesInBuffer;
|
||||
}
|
||||
|
||||
/*
|
||||
Handle a command-response transaction. Connects/retries as needed.
|
||||
Expects pointers to buffers of these sizes:
|
||||
char command[MAX_COMMAND_LEN]
|
||||
char response[resplen]
|
||||
*/
|
||||
int
|
||||
HttpCommandResponse (
|
||||
ptcx_t ptcx, /* thread state */
|
||||
mail_command_t *cmd, /* command info [blind] */
|
||||
void *me, /* connection state for msgParse */
|
||||
resolved_addr_t *hostInfo, /* reconnect info */
|
||||
event_timer_t *reconnect, /* timer for reconnects */
|
||||
|
||||
event_timer_t *timer, /* timer for this command */
|
||||
char *command, /* command to send */
|
||||
char *response, /* response buffer */
|
||||
int resplen, /* size of response buffer */
|
||||
parseMsgPtr_t msgParse) /* response handler */
|
||||
{
|
||||
int retries = 0;
|
||||
int ret;
|
||||
|
||||
if (response == NULL)
|
||||
return -1;
|
||||
|
||||
response[0] = 0; /* make sure it makes sense on error */
|
||||
|
||||
D_PRINTF(stderr, "HttpCommandResponse() command=[%.99s]\n", command);
|
||||
|
||||
while (retries++ < HTTP_MAX_RECONNECTS) {
|
||||
if (BADSOCKET(ptcx->sock)) {
|
||||
ret = HttpConnect(ptcx, hostInfo, reconnect);
|
||||
if (ret == -1) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
/* send the command already formatted */
|
||||
T_PRINTF(ptcx->logfile, command, strlen (command),
|
||||
"%s SendCommand", cmd->proto->name);
|
||||
event_start(ptcx, timer);
|
||||
ret = sendCommand(ptcx, ptcx->sock, command);
|
||||
if (ret == -1) {
|
||||
event_stop(ptcx, timer);
|
||||
reconnect->errs++;
|
||||
/* this can only mean an IO error. Probably EPIPE */
|
||||
NETCLOSE(ptcx->sock);
|
||||
ptcx->sock = BADSOCKET_VALUE;
|
||||
strcat (ptcx->errMsg, "<HttpCommandResponse");
|
||||
D_PRINTF (stderr, "%s Aborting connection %s\n",
|
||||
ptcx->errMsg, neterrstr());
|
||||
continue;
|
||||
}
|
||||
|
||||
/* read server response */
|
||||
ret = HttpReadResponse(ptcx, cmd, me, response, resplen, msgParse);
|
||||
event_stop(ptcx, timer);
|
||||
if (ret == 0) { /* got nothing */
|
||||
/* Probably an IO error. It will be definate if re-tried. */
|
||||
MS_usleep (5000); /* time for bytes to show up */
|
||||
continue; /* just re-try it */
|
||||
} else if (ret == -1) { /* IO error */
|
||||
reconnect->errs++;
|
||||
NETCLOSE(ptcx->sock);
|
||||
ptcx->sock = BADSOCKET_VALUE;
|
||||
strcat (ptcx->errMsg, "<HttpCommandResponse");
|
||||
D_PRINTF (stderr, "%s Aborting connection %s\n",
|
||||
ptcx->errMsg, neterrstr());
|
||||
continue;
|
||||
} else if (ret < -1) { /* some other error */
|
||||
timer->errs++;
|
||||
/* this is overkill */
|
||||
NETCLOSE(ptcx->sock);
|
||||
ptcx->sock = BADSOCKET_VALUE;
|
||||
strcat (ptcx->errMsg, "<HttpCommandResponse: protocol ERROR");
|
||||
return -1;
|
||||
}
|
||||
/*D_PRINTF (stderr, "HttpCommandResponse saved %d bytes response=[%s]\n",
|
||||
ret, response);*/
|
||||
/* You get parent.timeoutCB on any kind of error (like bad sid) */
|
||||
if (strstr (response, "parent.timeoutCB()")) {
|
||||
timer->errs++;
|
||||
NETCLOSE(ptcx->sock);
|
||||
ptcx->sock = BADSOCKET_VALUE;
|
||||
strcpy (ptcx->errMsg, "HttpCommandResponse: got HTTP error msg");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
reconnect->errs++;
|
||||
NETCLOSE(ptcx->sock);
|
||||
ptcx->sock = BADSOCKET_VALUE;
|
||||
strcat (ptcx->errMsg, "<HttpCommandResponse: Too many connection retries");
|
||||
return -1;
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
/* -*- Mode: C; c-file-style: "bsd"; comment-column: 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 the Netscape Mailstone utility,
|
||||
* released March 17, 2000.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1999-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Dan Christian <robodan@netscape.com>
|
||||
* Marcel DePaolis <marcel@netcape.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU Public License Version 2 or later (the "GPL"), in
|
||||
* which case the provisions of the GPL are applicable instead of
|
||||
* those above. If you wish to allow use of your version of this file
|
||||
* only under the terms of the GPL and not to allow others to use your
|
||||
* version of this file under the NPL, indicate your decision by
|
||||
* deleting the provisions above and replace them with the notice and
|
||||
* other provisions required by the GPL. If you do not delete the
|
||||
* provisions above, a recipient may use your version of this file
|
||||
* under either the NPL or the GPL.
|
||||
*/
|
||||
/* http-util.h -- Shared HTTP functions */
|
||||
|
||||
#define HTTP_HEADER_BREAK "\r\n\r\n"
|
||||
#define HTTP_CONTENT_TYPE_POST "Content-type: application/x-www-form-urlencoded"
|
||||
#define HTTP_CONTENT_LENGTH "Content-length:"
|
||||
#define HTTP_LOCATION "Location:"
|
||||
#define HTTP_PROTOCOL "http://"
|
||||
|
||||
#define HTTP_MAX_RECONNECTS 5 /* max to reconnect/retry a command */
|
||||
|
||||
/* Callback type for parsing messages on the fly */
|
||||
typedef int (*parseMsgPtr_t)(
|
||||
ptcx_t, pmail_command_t, void *me,
|
||||
char *buffer, int bytesInBuffer, char **searchStr, const char **findStr);
|
||||
|
||||
extern int HttpConnect(ptcx_t ptcx, resolved_addr_t *hostInfo,
|
||||
event_timer_t *timer);
|
||||
|
||||
extern int HttpReadResponse(ptcx_t ptcx, mail_command_t *cmd, void *me,
|
||||
char *responce, int resplen,
|
||||
parseMsgPtr_t msgParse);
|
||||
|
||||
extern int HttpCommandResponse (ptcx_t ptcx, mail_command_t *cmd, void *me,
|
||||
resolved_addr_t *hostInfo, event_timer_t *reconnect,
|
||||
event_timer_t *timer, char *command, char *response, int resplen,
|
||||
parseMsgPtr_t msgParse);
|
|
@ -35,7 +35,7 @@
|
|||
/* http.c: HTTP protocol test */
|
||||
|
||||
#include "bench.h"
|
||||
#include "pish.h"
|
||||
#include "http-util.h"
|
||||
|
||||
#define MAX_HTTP_RESPONSE_LEN (2*1024) /* size of sliding buffer */
|
||||
|
||||
|
@ -44,24 +44,36 @@
|
|||
There is one of these for every command in every thread.
|
||||
*/
|
||||
typedef struct http_stats {
|
||||
event_timer_t connect;
|
||||
event_timer_t connect; /* initial connections */
|
||||
event_timer_t reconnect; /* re-connections */
|
||||
event_timer_t msgread; /* AKA retrieve */
|
||||
event_timer_t logout; /* AKA dis-connect */
|
||||
/* no local storage */
|
||||
} http_stats_t;
|
||||
|
||||
/* These are common to POP, IMAP, SMTP, HTTP */
|
||||
typedef struct http_command {
|
||||
resolved_addr_t hostInfo; /* Host, port, and IP cache */
|
||||
|
||||
char * httpCommand; /* Old: single HTTP command */
|
||||
|
||||
#if 0
|
||||
string_list_t getFirstCmds; /* GET commands after connect */
|
||||
string_list_t getLoopCmds; /* GET commands, each loop */
|
||||
string_list_t getLastCmds; /* GET commands before disconnect */
|
||||
#endif
|
||||
|
||||
} http_command_t;
|
||||
|
||||
/*
|
||||
State during command execution.
|
||||
*/
|
||||
typedef struct _doHTTP_state {
|
||||
int numMsgs; /* messages in folder */
|
||||
int totalMsgLength; /* total msg length */
|
||||
int msgCounter; /* count in download */
|
||||
int nothingHere;
|
||||
} doHTTP_state_t;
|
||||
|
||||
static void doHttpExit (ptcx_t ptcx, doHTTP_state_t *me);
|
||||
static int readHttpResponse(ptcx_t ptcx, SOCKET sock, char *buffer, int buflen);
|
||||
static int doHttpCommandResponse(ptcx_t ptcx, SOCKET sock, char *command, char *response, int resplen);
|
||||
static int HttpParseNameValue (pmail_command_t cmd, char *name, char *tok);
|
||||
|
||||
/*
|
||||
Set defaults in command structure
|
||||
|
@ -72,17 +84,17 @@ HttpParseStart (pmail_command_t cmd,
|
|||
param_list_t *defparm)
|
||||
{
|
||||
param_list_t *pp;
|
||||
pish_command_t *pish = (pish_command_t *)mycalloc
|
||||
(sizeof (pish_command_t));
|
||||
cmd->data = pish;
|
||||
http_command_t *mycmd = (http_command_t *)mycalloc
|
||||
(sizeof (http_command_t));
|
||||
cmd->data = mycmd;
|
||||
|
||||
cmd->numLoops = 1; /* default 1 downloads */
|
||||
pish->portNum = HTTP_PORT; /* get default port */
|
||||
mycmd->hostInfo.portNum = HTTP_PORT; /* get default port */
|
||||
|
||||
D_PRINTF(stderr, "Http Assign defaults\n");
|
||||
/* Fill in defaults first, ignore defaults we dont use */
|
||||
for (pp = defparm; pp; pp = pp->next) {
|
||||
(void)pishParseNameValue (cmd, pp->name, pp->value);
|
||||
(void)HttpParseNameValue (cmd, pp->name, pp->value);
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
@ -96,7 +108,7 @@ HttpParseEnd (pmail_command_t cmd,
|
|||
string_list_t *section,
|
||||
param_list_t *defparm)
|
||||
{
|
||||
pish_command_t *pish = (pish_command_t *)cmd->data;
|
||||
http_command_t *mycmd = (http_command_t *)cmd->data;
|
||||
string_list_t *sp;
|
||||
|
||||
/* Now parse section lines */
|
||||
|
@ -111,7 +123,7 @@ HttpParseEnd (pmail_command_t cmd,
|
|||
string_tolower(name);
|
||||
tok = string_unquote(tok);
|
||||
|
||||
if (pishParseNameValue (cmd, name, tok) < 0) {
|
||||
if (HttpParseNameValue (cmd, name, tok) < 0) {
|
||||
/* not a known attr */
|
||||
D_PRINTF(stderr,"unknown attribute '%s' '%s'\n", name, tok);
|
||||
returnerr(stderr,"unknown attribute '%s' '%s'\n", name, tok);
|
||||
|
@ -119,31 +131,58 @@ HttpParseEnd (pmail_command_t cmd,
|
|||
}
|
||||
|
||||
/* check for some of the required command attrs */
|
||||
if (!pish->mailServer) {
|
||||
if (!mycmd->hostInfo.hostName) {
|
||||
D_PRINTF(stderr,"missing server for command");
|
||||
return returnerr(stderr,"missing server for command\n");
|
||||
}
|
||||
|
||||
if (!pish->httpCommand) {
|
||||
if (!mycmd->httpCommand) {
|
||||
D_PRINTF(stderr,"missing httpcommand for HTTP");
|
||||
return returnerr(stderr,"missing httpcommand for HTTP\n");
|
||||
}
|
||||
|
||||
/* see if we can resolve the mailserver addr */
|
||||
if (resolve_addrs(pish->mailServer, "tcp",
|
||||
&(pish->hostInfo.host_phe),
|
||||
&(pish->hostInfo.host_ppe),
|
||||
&(pish->hostInfo.host_addr),
|
||||
&(pish->hostInfo.host_type))) {
|
||||
if (resolve_addrs(mycmd->hostInfo.hostName, "tcp",
|
||||
&(mycmd->hostInfo.host_phe),
|
||||
&(mycmd->hostInfo.host_ppe),
|
||||
&(mycmd->hostInfo.host_addr),
|
||||
&(mycmd->hostInfo.host_type))) {
|
||||
return returnerr (stderr, "Error resolving hostname '%s'\n",
|
||||
pish->mailServer);
|
||||
mycmd->hostInfo.hostName);
|
||||
} else {
|
||||
pish->hostInfo.resolved = 1; /* mark the hostInfo resolved */
|
||||
mycmd->hostInfo.resolved = 1; /* mark the hostInfo resolved */
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
Parse arguments for http command
|
||||
*/
|
||||
static int
|
||||
HttpParseNameValue (pmail_command_t cmd,
|
||||
char *name,
|
||||
char *tok)
|
||||
{
|
||||
http_command_t *mycmd = (http_command_t *)cmd->data;
|
||||
D_PRINTF (stderr, "HttpParseNameValue(name='%s' value='%s')\n", name, tok);
|
||||
|
||||
/* find a home for the attr/value */
|
||||
if (cmdParseNameValue(cmd, name, tok))
|
||||
; /* done */
|
||||
else if (strcmp(name, "server") == 0)
|
||||
mycmd->hostInfo.hostName = mystrdup (tok);
|
||||
else if (strcmp(name, "portnum") == 0)
|
||||
mycmd->hostInfo.portNum = atoi(tok);
|
||||
else if (strcmp(name, "httpcommand") == 0)
|
||||
mycmd->httpCommand = mystrdup (tok);
|
||||
/*stringListAdd(&mycmd->getFirstCmds, tok);*/
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* PROTOCOL specific */
|
||||
void
|
||||
HttpStatsInit(mail_command_t *cmd, cmd_stats_t *p, int procNum, int threadNum)
|
||||
|
@ -157,7 +196,7 @@ HttpStatsInit(mail_command_t *cmd, cmd_stats_t *p, int procNum, int threadNum)
|
|||
}
|
||||
|
||||
if (cmd) { /* do sub-range calulations */
|
||||
/*pish_command_t *pish = (pish_command_t *)cmd->data;
|
||||
/*http_command_t *mycmd = (http_command_t *)cmd->data;
|
||||
http_stats_t *stats = (http_stats_t *)p->data;*/
|
||||
}
|
||||
}
|
||||
|
@ -258,182 +297,56 @@ HttpStatsFormat (protocol_t *pp,
|
|||
strcat (cp, "</FORMAT>\n");
|
||||
}
|
||||
|
||||
static int
|
||||
readHttpResponse(ptcx_t ptcx, SOCKET sock, char *buffer, int buflen)
|
||||
{
|
||||
/* read the server response and do nothing with it */
|
||||
int totalbytesread = 0;
|
||||
int bytesread;
|
||||
|
||||
memset (buffer, 0, buflen);
|
||||
while (totalbytesread < buflen)
|
||||
{
|
||||
if (gf_timeexpired >= EXIT_FAST) {
|
||||
D_PRINTF(debugfile,"readHttpResponse() Time expired.\n");
|
||||
break;
|
||||
}
|
||||
bytesread = retryRead(ptcx, sock, buffer, buflen-1);
|
||||
if (bytesread == 0) /* just read until we hit emtpy */
|
||||
break;
|
||||
if (bytesread < 0) { /* IO error */
|
||||
strcat (ptcx->errMsg, "<ReadHttpResponse");
|
||||
return -1;
|
||||
}
|
||||
totalbytesread += bytesread;
|
||||
buffer[bytesread] = 0; /* terminate for later searches */
|
||||
ptcx->bytesread += bytesread;
|
||||
T_PRINTF(ptcx->logfile, buffer, bytesread, "HTTP ReadResponse");
|
||||
}
|
||||
D_PRINTF(debugfile, "Read %d from server [%.99s]\n", totalbytesread, buffer);
|
||||
|
||||
if (0 == totalbytesread) {
|
||||
strcpy (ptcx->errMsg, "ReadHttpResponse: Read 0 bytes");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
return totalbytesread;
|
||||
}
|
||||
|
||||
/* expects pointers to buffers of these sizes */
|
||||
/* char command[MAX_COMMAND_LEN] */
|
||||
/* char response[resplen] */
|
||||
|
||||
static int
|
||||
doHttpCommandResponse(ptcx_t ptcx, SOCKET sock, char *command, char *response, int resplen)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (response == NULL)
|
||||
return -1;
|
||||
memset(response, 0, resplen);
|
||||
|
||||
T_PRINTF(ptcx->logfile, command, strlen (command), "HTTP SendCommand");
|
||||
/* send the command already formatted */
|
||||
if ((ret = sendCommand(ptcx, sock, command)) == -1) {
|
||||
if (gf_timeexpired < EXIT_FAST) {
|
||||
returnerr(debugfile, "Error sending [%s] command to server: %s\n",
|
||||
command, neterrstr());
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* read server response */
|
||||
if ((ret = readHttpResponse(ptcx, sock, response, resplen)) <= 0) {
|
||||
if (gf_timeexpired < EXIT_FAST) {
|
||||
trimEndWhite (command);
|
||||
returnerr(debugfile, "Error reading [%s] response: %s\n",
|
||||
command, neterrstr());
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if 0
|
||||
int
|
||||
httpLogin(ptcx_t ptcx, mail_command_t *cmd, SOCKET sock)
|
||||
{
|
||||
char command[MAX_COMMAND_LEN];
|
||||
char respBuffer[MAX_RESPONSE_LEN];
|
||||
char mailUser[MAX_MAILADDR_LEN];
|
||||
char userPasswd[MAX_MAILADDR_LEN];
|
||||
unsigned long loginNum;
|
||||
|
||||
/* generate a random username (with a mailbox on the server) */
|
||||
loginNum = (RANDOM() % pish->numLogins);
|
||||
/* add the the base user */
|
||||
loginNum += pish->firstLogin;
|
||||
|
||||
sprintf(mailUser, pish->loginFormat, loginNum);
|
||||
D_PRINTF(debugfile,"mailUser=%s\n", mailUser);
|
||||
sprintf(command, "USER %s%s", mailUser, CRLF);
|
||||
|
||||
if (doHttpCommandResponse(ptcx, sock, command, respBuffer) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* send Password */
|
||||
sprintf(userPasswd, pish->passwdFormat, loginNum);
|
||||
sprintf(command, "PASS %s%s", userPasswd, CRLF);
|
||||
if (doHttpCommandResponse(ptcx, sock, command, respBuffer) == -1) {
|
||||
if (gf_timeexpired < EXIT_FAST) {
|
||||
returnerr(debugfile,"HTTP cannot login user=%s pass=%s\n",
|
||||
mailUser, userPasswd);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void *
|
||||
doHttpStart(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer)
|
||||
{
|
||||
doHTTP_state_t *me = (doHTTP_state_t *)mycalloc (sizeof (doHTTP_state_t));
|
||||
http_stats_t *stats = (http_stats_t *)ptimer->data;
|
||||
pish_command_t *pish = (pish_command_t *)cmd->data;
|
||||
NETPORT port;
|
||||
http_command_t *mycmd = (http_command_t *)cmd->data;
|
||||
|
||||
if (!me) return NULL;
|
||||
|
||||
me->numMsgs = 0;
|
||||
me->totalMsgLength = 0;
|
||||
me->msgCounter = 0;
|
||||
port = pish->portNum;
|
||||
|
||||
event_start(ptcx, &stats->connect);
|
||||
ptcx->sock = connectsock(ptcx, pish->mailServer, &pish->hostInfo, port, "tcp");
|
||||
event_stop(ptcx, &stats->connect);
|
||||
if (BADSOCKET(ptcx->sock)) {
|
||||
if (gf_timeexpired < EXIT_FAST) {
|
||||
stats->connect.errs++;
|
||||
returnerr(debugfile,
|
||||
"%s<wmapConnect: HTTP Couldn't connect to %s: %s\n",
|
||||
ptcx->errMsg, pish->mailServer, neterrstr());
|
||||
}
|
||||
myfree (me);
|
||||
if (HttpConnect(ptcx, &mycmd->hostInfo, &stats->connect) == -1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (gf_abortive_close) {
|
||||
if (set_abortive_close(ptcx->sock) != 0) {
|
||||
returnerr (debugfile,
|
||||
"HTTP: WARNING: Could not set abortive close\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* there is no banner or login state for HTTP */
|
||||
|
||||
return me;
|
||||
}
|
||||
|
||||
int
|
||||
doHttpLoop(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer, void *mystate)
|
||||
doHttpLoop (
|
||||
ptcx_t ptcx,
|
||||
mail_command_t *cmd,
|
||||
cmd_stats_t *ptimer,
|
||||
void *mystate)
|
||||
{
|
||||
doHTTP_state_t *me = (doHTTP_state_t *)mystate;
|
||||
char command[MAX_COMMAND_LEN];
|
||||
char respBuffer[MAX_HTTP_RESPONSE_LEN];
|
||||
int rc;
|
||||
http_stats_t *stats = (http_stats_t *)ptimer->data;
|
||||
pish_command_t *pish = (pish_command_t *)cmd->data;
|
||||
http_command_t *mycmd = (http_command_t *)cmd->data;
|
||||
|
||||
#if 0
|
||||
if (me->msgCounter >= me->numMsgs)
|
||||
return -1; /* done, close */
|
||||
#endif
|
||||
if (BADSOCKET(ptcx->sock)) { /* re-connect if needed */
|
||||
rc = HttpConnect(ptcx, &mycmd->hostInfo, &stats->connect);
|
||||
if (rc == -1) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* send the HTTP command */
|
||||
|
||||
/* will have to deal with encoding URLs before too long... */
|
||||
sprintf(command, pish->httpCommand, me->msgCounter);
|
||||
strcat(command, " HTTP/1.0\r\n");
|
||||
strcpy (command, mycmd->httpCommand);
|
||||
strcat (command, " HTTP/1.0\r\n");
|
||||
/* other headers go here... */
|
||||
strcat(command, "\r\n");
|
||||
event_start(ptcx, &stats->msgread);
|
||||
rc = doHttpCommandResponse(ptcx, ptcx->sock,
|
||||
command, respBuffer, sizeof(respBuffer));
|
||||
event_stop(ptcx, &stats->msgread);
|
||||
rc = HttpCommandResponse(ptcx, cmd, mystate,
|
||||
&mycmd->hostInfo, &stats->connect,
|
||||
&stats->msgread,
|
||||
command, respBuffer,
|
||||
sizeof(respBuffer), NULL);
|
||||
if (rc == 0) {
|
||||
doHttpExit (ptcx, me);
|
||||
return -1;
|
||||
|
|
|
@ -119,7 +119,7 @@ Imap4ParseStart (pmail_command_t cmd,
|
|||
cmd->data = pish;
|
||||
|
||||
cmd->loopDelay = 10*60; /* default 10 min */
|
||||
pish->portNum = IMAP4_PORT; /* get default port */
|
||||
pish->hostInfo.portNum = IMAP4_PORT; /* get default port */
|
||||
|
||||
D_PRINTF(stderr, "Imap4 Assign defaults\n");
|
||||
/* Fill in defaults first, ignore defaults we dont use */
|
||||
|
@ -161,7 +161,7 @@ Imap4ParseEnd (pmail_command_t cmd,
|
|||
}
|
||||
|
||||
/* check for some of the required command attrs */
|
||||
if (!pish->mailServer) {
|
||||
if (!pish->hostInfo.hostName) {
|
||||
D_PRINTF(stderr,"missing server for command");
|
||||
return returnerr(stderr,"missing server for command\n");
|
||||
}
|
||||
|
@ -177,13 +177,13 @@ Imap4ParseEnd (pmail_command_t cmd,
|
|||
}
|
||||
|
||||
/* see if we can resolve the mailserver addr */
|
||||
if (resolve_addrs(pish->mailServer, "tcp",
|
||||
if (resolve_addrs(pish->hostInfo.hostName, "tcp",
|
||||
&(pish->hostInfo.host_phe),
|
||||
&(pish->hostInfo.host_ppe),
|
||||
&(pish->hostInfo.host_addr),
|
||||
&(pish->hostInfo.host_type))) {
|
||||
return returnerr (stderr, "Error resolving hostname '%s'\n",
|
||||
pish->mailServer);
|
||||
pish->hostInfo.hostName);
|
||||
} else {
|
||||
pish->hostInfo.resolved = 1; /* mark the hostInfo resolved */
|
||||
}
|
||||
|
@ -204,7 +204,6 @@ doImap4Start(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer)
|
|||
{
|
||||
doIMAP4_state_t *me = (doIMAP4_state_t *)mycalloc (sizeof (doIMAP4_state_t));
|
||||
pish_command_t *pish = (pish_command_t *)cmd->data;
|
||||
NETPORT port = pish->portNum;
|
||||
pish_stats_t *stats = (pish_stats_t *)ptimer->data;
|
||||
int rc;
|
||||
|
||||
|
@ -219,13 +218,13 @@ doImap4Start(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer)
|
|||
me->pIMAP->seq_num = 1;
|
||||
|
||||
event_start(ptcx, &stats->connect);
|
||||
ptcx->sock = connectsock(ptcx, pish->mailServer, &pish->hostInfo, port, "tcp");
|
||||
ptcx->sock = connectSocket(ptcx, &pish->hostInfo, "tcp");
|
||||
event_stop(ptcx, &stats->connect);
|
||||
if (BADSOCKET(ptcx->sock)) {
|
||||
if (gf_timeexpired < EXIT_FAST) {
|
||||
stats->connect.errs++;
|
||||
returnerr(debugfile, "IMAP4 Couldn't connect to %s: %s\n",
|
||||
pish->mailServer, neterrstr());
|
||||
pish->hostInfo.hostName, neterrstr());
|
||||
}
|
||||
myfree (me);
|
||||
return NULL;
|
||||
|
|
|
@ -265,7 +265,7 @@ safe_inet_ntoa(struct in_addr ina, char *psz)
|
|||
}
|
||||
|
||||
/* look up the host name and protocol
|
||||
* called from each protocol (via connectsock)
|
||||
* called from each protocol (via connectSocket)
|
||||
*/
|
||||
|
||||
int
|
||||
|
@ -344,10 +344,8 @@ resolve_addrs(char *host,
|
|||
|
||||
/* connect to a socket given the hostname and protocol */
|
||||
SOCKET
|
||||
connectsock(ptcx_t ptcx,
|
||||
char *host,
|
||||
connectSocket(ptcx_t ptcx,
|
||||
resolved_addr_t *hostInfo,
|
||||
NETPORT portnum,
|
||||
char *protocol)
|
||||
{
|
||||
struct sockaddr_in sin; /* an Internet endpoint address */
|
||||
|
@ -357,15 +355,15 @@ connectsock(ptcx_t ptcx,
|
|||
int returnval; /* temporary return value */
|
||||
char ntoa_buf[SIZEOF_NTOABUF];
|
||||
|
||||
D_PRINTF(debugfile, "Beginning connectsock; host=%s port=%d proto=%s\n",
|
||||
host, portnum, protocol );
|
||||
D_PRINTF(debugfile, "Beginning connectSocket; host=%s port=%d proto=%s\n",
|
||||
hostInfo->hostName, hostInfo->portNum, protocol );
|
||||
|
||||
sin.sin_family = AF_INET;
|
||||
memset((char *)&sin, 0, sizeof(sin));
|
||||
D_PRINTF(debugfile, "Zeroed address structure\n" );
|
||||
|
||||
sin.sin_port = htons(portnum);
|
||||
D_PRINTF(debugfile, "Set port number %d\n", portnum );
|
||||
sin.sin_port = htons(hostInfo->portNum);
|
||||
D_PRINTF(debugfile, "Set port number %d\n", hostInfo->portNum);
|
||||
|
||||
/* check if we've resolved this already */
|
||||
if ((hostInfo) && (hostInfo->resolved)) {
|
||||
|
@ -379,10 +377,10 @@ connectsock(ptcx_t ptcx,
|
|||
unsigned long host_addr;
|
||||
short host_type; /* socket type */
|
||||
|
||||
if (resolve_addrs(host, "tcp",
|
||||
if (resolve_addrs(hostInfo->hostName, "tcp",
|
||||
&host_phe, &host_ppe, &host_addr, &host_type)) {
|
||||
return returnerr(debugfile,"Can't resolve hostname %s in get()\n",
|
||||
host);
|
||||
hostInfo->hostName);
|
||||
}
|
||||
sin.sin_addr.S_ADDR = host_addr;
|
||||
sin.sin_family = PF_INET;
|
||||
|
@ -419,10 +417,10 @@ connectsock(ptcx_t ptcx,
|
|||
}
|
||||
|
||||
/* all done, returning socket descriptor */
|
||||
D_PRINTF(debugfile, "Returning %d from connectsock call\n", s );
|
||||
D_PRINTF(debugfile, "Returning %d from connectSocket call\n", s );
|
||||
return(s);
|
||||
|
||||
} /* END connectsock() */
|
||||
} /* END connectSocket() */
|
||||
|
||||
int
|
||||
set_abortive_close(SOCKET sock)
|
||||
|
|
|
@ -55,9 +55,7 @@ typedef struct pish_stats {
|
|||
|
||||
/* These are common to POP, IMAP, SMTP, HTTP */
|
||||
typedef struct pish_command {
|
||||
char * mailServer;
|
||||
resolved_addr_t hostInfo; /* should be a read only cache */
|
||||
NETPORT portNum;
|
||||
|
||||
/* These are common to SMTP, POP, IMAP */
|
||||
char * loginFormat;
|
||||
|
@ -87,12 +85,6 @@ typedef struct pish_command {
|
|||
char * imapSearchFolder;
|
||||
char * imapSearchPattern;
|
||||
int imapSearchRate;
|
||||
|
||||
/* HTTP command */
|
||||
char * httpCommand;
|
||||
|
||||
/* WMAP command */
|
||||
char * wmapCommand;
|
||||
} pish_command_t;
|
||||
|
||||
/* TRANSITION functions */
|
||||
|
|
|
@ -80,7 +80,7 @@ Pop3ParseStart (pmail_command_t cmd,
|
|||
cmd->data = pish;
|
||||
|
||||
cmd->numLoops = 9999; /* default 9999 downloads */
|
||||
pish->portNum = POP3_PORT; /* default port */
|
||||
pish->hostInfo.portNum = POP3_PORT; /* default port */
|
||||
|
||||
D_PRINTF(stderr, "Pop3 Assign defaults\n");
|
||||
/* Fill in defaults first, ignore defaults we dont use */
|
||||
|
@ -122,7 +122,7 @@ Pop3ParseEnd (pmail_command_t cmd,
|
|||
}
|
||||
|
||||
/* check for some of the required command attrs */
|
||||
if (!pish->mailServer) {
|
||||
if (!pish->hostInfo.hostName) {
|
||||
D_PRINTF(stderr,"missing server for command");
|
||||
return returnerr(stderr,"missing server for command\n");
|
||||
}
|
||||
|
@ -138,13 +138,13 @@ Pop3ParseEnd (pmail_command_t cmd,
|
|||
}
|
||||
|
||||
/* see if we can resolve the mailserver addr */
|
||||
if (resolve_addrs(pish->mailServer, "tcp",
|
||||
if (resolve_addrs(pish->hostInfo.hostName, "tcp",
|
||||
&(pish->hostInfo.host_phe),
|
||||
&(pish->hostInfo.host_ppe),
|
||||
&(pish->hostInfo.host_addr),
|
||||
&(pish->hostInfo.host_type))) {
|
||||
return returnerr (stderr, "Error resolving hostname '%s'\n",
|
||||
pish->mailServer);
|
||||
pish->hostInfo.hostName);
|
||||
} else {
|
||||
pish->hostInfo.resolved = 1; /* mark the hostInfo resolved */
|
||||
}
|
||||
|
@ -241,7 +241,6 @@ doPop3Start(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer)
|
|||
int rc;
|
||||
int numBytes;
|
||||
char command[MAX_COMMAND_LEN];
|
||||
NETPORT port;
|
||||
pish_stats_t *stats = (pish_stats_t *)ptimer->data;
|
||||
pish_command_t *pish = (pish_command_t *)cmd->data;
|
||||
|
||||
|
@ -250,16 +249,15 @@ doPop3Start(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer)
|
|||
me->numMsgs = 0;
|
||||
me->totalMsgLength = 0;
|
||||
me->msgCounter = 0;
|
||||
port = pish->portNum;
|
||||
|
||||
event_start(ptcx, &stats->connect);
|
||||
ptcx->sock = connectsock(ptcx, pish->mailServer, &pish->hostInfo, port, "tcp");
|
||||
ptcx->sock = connectSocket(ptcx, &pish->hostInfo, "tcp");
|
||||
event_stop(ptcx, &stats->connect);
|
||||
if (BADSOCKET(ptcx->sock)) {
|
||||
if (gf_timeexpired < EXIT_FAST) {
|
||||
stats->connect.errs++;
|
||||
returnerr(debugfile, "POP3 Couldn't connect to %s: %s\n",
|
||||
pish->mailServer, neterrstr());
|
||||
pish->hostInfo.hostName, neterrstr());
|
||||
}
|
||||
myfree (me);
|
||||
return NULL;
|
||||
|
|
|
@ -60,7 +60,7 @@ SmtpParseStart (pmail_command_t cmd,
|
|||
cmd->data = pish;
|
||||
|
||||
cmd->numLoops = 1; /* default 1 message */
|
||||
pish->portNum = SMTP_PORT; /* get default port */
|
||||
pish->hostInfo.portNum = SMTP_PORT; /* get default port */
|
||||
|
||||
D_PRINTF(stderr, "Smtp Assign defaults\n");
|
||||
/* Fill in defaults first, ignore defaults we dont use */
|
||||
|
@ -105,7 +105,7 @@ SmtpParseEnd (pmail_command_t cmd,
|
|||
}
|
||||
|
||||
/* check for some of the required command attrs */
|
||||
if (!pish->mailServer) {
|
||||
if (!pish->hostInfo.hostName) {
|
||||
D_PRINTF(stderr,"missing server for command");
|
||||
return returnerr(stderr,"missing server for command\n");
|
||||
}
|
||||
|
@ -170,13 +170,13 @@ SmtpParseEnd (pmail_command_t cmd,
|
|||
close(fd);
|
||||
|
||||
/* see if we can resolve the mailserver addr */
|
||||
if (resolve_addrs(pish->mailServer, "tcp",
|
||||
if (resolve_addrs(pish->hostInfo.hostName, "tcp",
|
||||
&(pish->hostInfo.host_phe),
|
||||
&(pish->hostInfo.host_ppe),
|
||||
&(pish->hostInfo.host_addr),
|
||||
&(pish->hostInfo.host_type))) {
|
||||
return returnerr (stderr, "Error resolving hostname '%s'\n",
|
||||
pish->mailServer);
|
||||
pish->hostInfo.hostName);
|
||||
} else {
|
||||
pish->hostInfo.resolved = 1; /* mark the hostInfo resolved */
|
||||
}
|
||||
|
@ -211,7 +211,7 @@ pishParseNameValue (pmail_command_t cmd,
|
|||
if (cmdParseNameValue(cmd, name, tok))
|
||||
; /* done */
|
||||
else if (strcmp(name, "server") == 0)
|
||||
pish->mailServer = mystrdup (tok);
|
||||
pish->hostInfo.hostName = mystrdup (tok);
|
||||
else if (strcmp(name, "smtpmailfrom") == 0)
|
||||
pish->smtpMailFrom = mystrdup (tok);
|
||||
else if (strcmp(name, "loginformat") == 0)
|
||||
|
@ -237,17 +237,13 @@ pishParseNameValue (pmail_command_t cmd,
|
|||
else if (strcmp(name, "sequentialaddresses") == 0)
|
||||
pish->addressRange.sequential = atoi(tok);
|
||||
else if (strcmp(name, "portnum") == 0)
|
||||
pish->portNum = atoi(tok);
|
||||
pish->hostInfo.portNum = atoi(tok);
|
||||
else if (strcmp(name, "numrecips") == 0)
|
||||
pish->numRecipients = atoi(tok);
|
||||
else if (strcmp(name, "numrecipients") == 0)
|
||||
pish->numRecipients = atoi(tok);
|
||||
else if (strcmp(name, "file") == 0)
|
||||
pish->filename= mystrdup (tok);
|
||||
else if (strcmp(name, "httpcommand") == 0)
|
||||
pish->httpCommand = mystrdup (tok);
|
||||
else if (strcmp(name, "wmapcommand") == 0)
|
||||
pish->wmapCommand = mystrdup (tok);
|
||||
else if (strcmp(name, "passwdformat") == 0)
|
||||
pish->passwdFormat = mystrdup (tok);
|
||||
else if (strcmp(name, "searchfolder") == 0)
|
||||
|
@ -689,20 +685,19 @@ sendSMTPStart(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer)
|
|||
int numBytes;
|
||||
int rc;
|
||||
pish_command_t *pish = (pish_command_t *)cmd->data;
|
||||
NETPORT port = pish->portNum;
|
||||
pish_stats_t *stats = (pish_stats_t *)ptimer->data;
|
||||
|
||||
if (!me) return NULL;
|
||||
|
||||
|
||||
event_start(ptcx, &stats->connect);
|
||||
ptcx->sock = connectsock(ptcx, pish->mailServer, &pish->hostInfo, port, "tcp");
|
||||
ptcx->sock = connectSocket(ptcx, &pish->hostInfo, "tcp");
|
||||
event_stop(ptcx, &stats->connect);
|
||||
if (BADSOCKET(ptcx->sock)) {
|
||||
if (gf_timeexpired < EXIT_FAST) {
|
||||
stats->connect.errs++;
|
||||
returnerr(debugfile, "%s SMTP Couldn't connect to %s: %s\n",
|
||||
ptcx->errMsg, pish->mailServer, neterrstr());
|
||||
ptcx->errMsg, pish->hostInfo.hostName, neterrstr());
|
||||
}
|
||||
myfree (me);
|
||||
return NULL;
|
||||
|
|
|
@ -35,14 +35,7 @@
|
|||
/* wmap.c -- Test Netscape Messaging WebMail 4.x (know as Web-IMAP or WMAP) */
|
||||
|
||||
#include "bench.h"
|
||||
|
||||
#define HTTP_HEADER_BREAK "\r\n\r\n"
|
||||
#define HTTP_CONTENT_TYPE_POST "Content-type: application/x-www-form-urlencoded"
|
||||
#define HTTP_CONTENT_LENGTH "Content-length:"
|
||||
#define HTTP_LOCATION "Location:"
|
||||
#define HTTP_PROTOCOL "http://"
|
||||
|
||||
#define HTTP_MAX_RECONNECTS 5 /* max to reconnect/retry a command */
|
||||
#include "http-util.h"
|
||||
|
||||
/*
|
||||
these are protocol dependent timers
|
||||
|
@ -70,9 +63,7 @@ typedef struct wmap_stats {
|
|||
|
||||
/* Command information */
|
||||
typedef struct wmap_command {
|
||||
char * mailServer;
|
||||
resolved_addr_t hostInfo; /* should be a read only cache */
|
||||
NETPORT portNum;
|
||||
|
||||
/* These are common to SMTP, POP, IMAP, WMAP */
|
||||
char * loginFormat;
|
||||
|
@ -135,22 +126,8 @@ typedef struct _doWMAP_state {
|
|||
int * msgList; /* array[numMsgs] of message IDs */
|
||||
char response_buffer[RESPONSE_BUFFER_SIZE];
|
||||
} doWMAP_state_t;
|
||||
|
||||
/* Callback type for parsing messages on the fly */
|
||||
typedef int (*parseMsgPtr_t)(
|
||||
ptcx_t, pmail_command_t, void *me,
|
||||
char *buffer, int bytesInBuffer, char **searchStr, const char **findStr);
|
||||
|
||||
static int readWmapResponse(
|
||||
ptcx_t ptcx, mail_command_t *, void *, char *, int, parseMsgPtr_t );
|
||||
|
||||
static int doWmapCommandResponse(
|
||||
ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer, doWMAP_state_t *me,
|
||||
event_timer_t *timer, char *command, char *response, int buflen, parseMsgPtr_t);
|
||||
static int WmapParseNameValue(pmail_command_t cmd, char *name, char *tok);
|
||||
|
||||
static int wmapConnect(ptcx_t ptcx, mail_command_t *cmd, doWMAP_state_t *me, event_timer_t *timer);
|
||||
|
||||
static int wmapBanner(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer, doWMAP_state_t *me);
|
||||
static int wmapLogin(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer, doWMAP_state_t *me);
|
||||
static int wmapLogout(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer, doWMAP_state_t *me);
|
||||
|
@ -169,7 +146,7 @@ WmapParseStart(pmail_command_t cmd, char *line, param_list_t *defparm)
|
|||
cmd->data = wmap;
|
||||
|
||||
cmd->numLoops = 1; /* default 1 downloads */
|
||||
wmap->portNum = WMAP_PORT; /* get default port */
|
||||
wmap->hostInfo.portNum = WMAP_PORT; /* get default port */
|
||||
|
||||
D_PRINTF(stderr, "Wmap Assign defaults\n");
|
||||
/* Fill in defaults first, ignore defaults we dont use */
|
||||
|
@ -209,7 +186,7 @@ WmapParseEnd(pmail_command_t cmd, string_list_t *section, param_list_t *defparm)
|
|||
}
|
||||
|
||||
/* check for some of the required command attrs */
|
||||
if (!wmap->mailServer) {
|
||||
if (!wmap->hostInfo.hostName) {
|
||||
D_PRINTF(stderr,"missing server for command");
|
||||
return returnerr(stderr,"missing server for command\n");
|
||||
}
|
||||
|
@ -250,13 +227,13 @@ WmapParseEnd(pmail_command_t cmd, string_list_t *section, param_list_t *defparm)
|
|||
}
|
||||
|
||||
/* see if we can resolve the mailserver addr */
|
||||
if (resolve_addrs(wmap->mailServer, "tcp",
|
||||
if (resolve_addrs(wmap->hostInfo.hostName, "tcp",
|
||||
&(wmap->hostInfo.host_phe),
|
||||
&(wmap->hostInfo.host_ppe),
|
||||
&(wmap->hostInfo.host_addr),
|
||||
&(wmap->hostInfo.host_type))) {
|
||||
return returnerr (stderr, "Error resolving hostname '%s'\n",
|
||||
wmap->mailServer);
|
||||
wmap->hostInfo.hostName);
|
||||
} else {
|
||||
wmap->hostInfo.resolved = 1; /* mark the hostInfo resolved */
|
||||
}
|
||||
|
@ -283,7 +260,7 @@ WmapParseNameValue(pmail_command_t cmd, char *name, char *tok)
|
|||
if (cmdParseNameValue(cmd, name, tok))/* generic stuff */
|
||||
; /* done */
|
||||
else if (strcmp(name, "server") == 0)
|
||||
wmap->mailServer = mystrdup(tok);
|
||||
wmap->hostInfo.hostName = mystrdup(tok);
|
||||
else if (strcmp(name, "loginformat") == 0)
|
||||
wmap->loginFormat = mystrdup(tok);
|
||||
else if (strcmp(name, "firstlogin") == 0)
|
||||
|
@ -315,7 +292,7 @@ WmapParseNameValue(pmail_command_t cmd, char *name, char *tok)
|
|||
else if (strcmp(name, "numrecipients") == 0)
|
||||
wmap->numRecipients = atoi(tok);
|
||||
else if (strcmp(name, "portnum") == 0)
|
||||
wmap->portNum = atoi(tok);
|
||||
wmap->hostInfo.portNum = atoi(tok);
|
||||
else if (strcmp(name, "passwdformat") == 0)
|
||||
wmap->passwdFormat = mystrdup(tok);
|
||||
else if (strcmp(name, "leavemailonserver") == 0)
|
||||
|
@ -498,390 +475,6 @@ WmapStatsFormat(protocol_t *pp,
|
|||
strcat(cp, "</FORMAT>\n");
|
||||
}
|
||||
|
||||
/*
|
||||
Establish (or re-establish) connection to server.
|
||||
No data is exchanged.
|
||||
*/
|
||||
static int
|
||||
wmapConnect (
|
||||
ptcx_t ptcx,
|
||||
mail_command_t *cmd,
|
||||
doWMAP_state_t *me,
|
||||
event_timer_t *timer)
|
||||
{
|
||||
wmap_command_t *wmap = (wmap_command_t *)cmd->data;
|
||||
int rc=0;
|
||||
NETPORT port;
|
||||
port = wmap->portNum;
|
||||
|
||||
D_PRINTF(stderr, "wmapConnect()\n");
|
||||
|
||||
event_start(ptcx, timer);
|
||||
ptcx->sock = connectsock(ptcx, wmap->mailServer, &wmap->hostInfo,
|
||||
port, "tcp");
|
||||
event_stop(ptcx, timer);
|
||||
if (BADSOCKET(ptcx->sock)) {
|
||||
if (gf_timeexpired < EXIT_FAST) {
|
||||
timer->errs++;
|
||||
returnerr(debugfile,
|
||||
"%s<wmapConnect: WMAP Couldn't connect to %s: %s\n",
|
||||
ptcx->errMsg, wmap->mailServer, neterrstr());
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (gf_abortive_close) {
|
||||
if (set_abortive_close(ptcx->sock) != 0) {
|
||||
returnerr(debugfile,
|
||||
"%s<wmapConnect: WMAP: WARNING: Could not set abortive close\n",
|
||||
ptcx->errMsg, neterrstr());
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
readWmapResponse handles the details of reading a HTTP response It
|
||||
takes and interactive parsing function and a response buffer. The
|
||||
response buffer will hold at least the last 1/2 buffer of the data
|
||||
stream. This allows errors to be handled by the calling routine.
|
||||
Long responses should be parsed on the fly by the parsing callback.
|
||||
|
||||
readWmapResponse handles find the content-length and header break.
|
||||
Once the break is called, it will call the parsing callback so that it can
|
||||
set findStr (which is NULL).
|
||||
|
||||
The findStr search is case insensitive if the first character of findStr
|
||||
has distinct upper and lower cases (see toupper and tolower).
|
||||
|
||||
The callback is called with the buffer, the bytes in the buffer,
|
||||
a pointer just past the findStr match, and a pointer to findStr.
|
||||
The callback should then update findStr and searchStr; and return -2
|
||||
for an error (abort message), 0 for success, and 1 for need more data.
|
||||
|
||||
findStr is expected to be a constant or static storage.
|
||||
Before exit, the parsing callback is called one last time (with NULL
|
||||
findStr and searchStr), so that it can do any cleanup.
|
||||
|
||||
Management of the buffer is done automatically by the movement of searchStr.
|
||||
|
||||
readWmapResponse returns bytesInBuffer on success, -1 for IO error,
|
||||
-2 for error returned by the parser.
|
||||
*/
|
||||
static int
|
||||
readWmapResponse(
|
||||
ptcx_t ptcx,
|
||||
mail_command_t *cmd, /* command info for msgParse */
|
||||
void *me, /* connection state for msgParse */
|
||||
char *buffer,
|
||||
int buflen,
|
||||
parseMsgPtr_t msgParse
|
||||
)
|
||||
{
|
||||
/* read the server response and do nothing with it */
|
||||
/* Will need to look for HTTP headers and Content-Length/Keep-Alive */
|
||||
int gotheader = 0;
|
||||
int totalbytesread = 0;
|
||||
int bytesread;
|
||||
int bytesInBuffer = 0;
|
||||
const char *findStr; /* string we are watching for */
|
||||
const char *oldFindStr = NULL;
|
||||
char findStrSpn[3]; /* case insensitive search start */
|
||||
int findLen=0; /* length of string */
|
||||
char *foundStr; /* what we found */
|
||||
char *searchStart; /* where next to look for findStr */
|
||||
int contentlength = 0; /* HTTP content length */
|
||||
int bytestoread = buflen-1; /* start by reading lots */
|
||||
int getBytes = 0; /* need more input */
|
||||
|
||||
D_PRINTF(stderr, "readWmapResponse()\n");
|
||||
|
||||
findStr = HTTP_CONTENT_LENGTH;
|
||||
searchStart = buffer;
|
||||
memset(buffer, 0, buflen); /* DEBUG */
|
||||
while (1)
|
||||
{
|
||||
if (gf_timeexpired >= EXIT_FAST) {
|
||||
D_PRINTF(stderr,"readWmapResponse() Time expired.\n");
|
||||
break;
|
||||
}
|
||||
if (findStr != oldFindStr) { /* findStr changed */
|
||||
if (NULL == findStr) {
|
||||
findLen = 0;
|
||||
findStrSpn[0] = 0;
|
||||
} else {
|
||||
char upperC, lowerC; /* upper and lower of findStr[0] */
|
||||
findLen = strlen (findStr);
|
||||
upperC = toupper (findStr[0]);
|
||||
lowerC = tolower (findStr[0]);
|
||||
if (lowerC != upperC) {
|
||||
/*D_PRINTF (stderr, "New findStr [%s] upper %c lower %c\n",
|
||||
findStr, upperC, lowerC);*/
|
||||
findStrSpn[0] = upperC;
|
||||
findStrSpn[1] = lowerC;
|
||||
findStrSpn[2] = 0;
|
||||
} else {
|
||||
/*D_PRINTF (stderr, "New findStr [%s] NOT case sensitive\n",
|
||||
findStr);*/
|
||||
findStrSpn[0] = 0;
|
||||
}
|
||||
}
|
||||
oldFindStr = findStr;
|
||||
}
|
||||
/* See if we should read more */
|
||||
if ((getBytes > 0)
|
||||
|| (0 == findLen)
|
||||
|| ((bytesInBuffer - (searchStart - buffer)) < findLen)) {
|
||||
int count;
|
||||
|
||||
if (totalbytesread >= bytestoread) { /* done reading */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Make room for more data */
|
||||
/* need to be careful to save data for response. shift by half */
|
||||
if ((searchStart - buffer) > buflen/2) {
|
||||
/* This is the only place we reduce searchStart or bytesInBuffer */
|
||||
int toSkip = buflen/2;
|
||||
int toSave = bytesInBuffer - toSkip;
|
||||
/*D_PRINTF (stderr, "Shifting %d of %d bytes\n",
|
||||
toSave, bytesInBuffer);*/
|
||||
memcpy (buffer, buffer+toSkip, toSave); /* shift data down */
|
||||
bytesInBuffer = toSave;
|
||||
buffer[bytesInBuffer] = 0; /* re-terminate??? */
|
||||
searchStart -= toSkip;
|
||||
assert (searchStart >= buffer);
|
||||
}
|
||||
count = MIN (bytestoread-totalbytesread,
|
||||
buflen-bytesInBuffer-1);
|
||||
/*D_PRINTF(stderr, "retryRead() size=%d %d/%d inBuffer=%d\n",
|
||||
count, totalbytesread, bytestoread, bytesInBuffer);*/
|
||||
bytesread = retryRead(ptcx, ptcx->sock, buffer+bytesInBuffer, count);
|
||||
|
||||
if (0 == bytesread) { /* most likely an error */
|
||||
strcpy (ptcx->errMsg, "readWmapResponse:got 0 bytes");
|
||||
break;
|
||||
}
|
||||
if (bytesread < 0) { /* ERROR */
|
||||
strcat (ptcx->errMsg, "<readWmapResponse");
|
||||
return -1;
|
||||
}
|
||||
T_PRINTF(ptcx->logfile, buffer+bytesInBuffer, bytesread,
|
||||
"WMAP ReadResponse"); /* telemetry log */
|
||||
totalbytesread += bytesread;
|
||||
bytesInBuffer += bytesread;
|
||||
buffer[bytesInBuffer] = 0; /* terminate for string searches */
|
||||
ptcx->bytesread += bytesread; /* log statistics */
|
||||
getBytes = 0;
|
||||
} else {
|
||||
/*D_PRINTF (stderr,
|
||||
"Not reading, have %d only need %d. %d/%d\n",
|
||||
bytesInBuffer- (searchStart - buffer), findLen,
|
||||
bytestoread, totalbytesread);*/
|
||||
}
|
||||
|
||||
if (NULL == findStr) { /* nothing to search for */
|
||||
searchStart = buffer+bytesInBuffer; /* discard buffer */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* otherwise search for findStr */
|
||||
if (findStrSpn[0]) { /* do case insensitive version */
|
||||
char *cp;
|
||||
foundStr = NULL;
|
||||
for (cp = searchStart; (cp - buffer) < bytesInBuffer; ++cp) {
|
||||
cp = strpbrk (cp, findStrSpn); /* look for first char match */
|
||||
if (NULL == cp) {
|
||||
break;
|
||||
}
|
||||
if (!strnicmp(cp, findStr, findLen)) { /* check whole match */
|
||||
foundStr = cp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else { /* non case sensitive version */
|
||||
foundStr = strstr(searchStart, findStr);
|
||||
}
|
||||
|
||||
if (NULL == foundStr) { /* found nothing, shift and continue */
|
||||
/* jump to findLen-1 from end */
|
||||
if (bytesInBuffer < findLen)
|
||||
continue; /* nothing to shift */
|
||||
|
||||
searchStart = buffer + bytesInBuffer - findLen + 1;
|
||||
continue; /* get more input */
|
||||
}
|
||||
|
||||
/* Found search string */
|
||||
/*D_PRINTF (stderr, "Found [%s] after %d bytes\n",
|
||||
findStr, totalbytesread);*/
|
||||
searchStart = foundStr + findLen; /* found this much */
|
||||
|
||||
if (0 == gotheader) { /* found length */
|
||||
contentlength = atoi(searchStart); /* save contentlength */
|
||||
searchStart = strchr (searchStart, '\n'); /* jump to EOL */
|
||||
if (NULL == searchStart) { /* missing line end, get more */
|
||||
searchStart = buffer;
|
||||
} else { /* got complete contentlength line */
|
||||
gotheader++;
|
||||
findStr = HTTP_HEADER_BREAK; /* now look for break */
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else if (1 == gotheader) { /* found header break */
|
||||
gotheader++;
|
||||
/* now compute bytetoread */
|
||||
bytestoread = contentlength
|
||||
+ ((searchStart - buffer) /* position in buffer */
|
||||
+ (totalbytesread - bytesInBuffer)); /* buffer offset */
|
||||
D_PRINTF(stderr, "contentlength=%d, bytestoread=%d\n",
|
||||
contentlength, bytestoread);
|
||||
|
||||
findStr = NULL; /* should chain into extra searches */
|
||||
|
||||
if (msgParse) { /* initialize callback */
|
||||
int rc;
|
||||
/* having findStr == NULL signal initial callback */
|
||||
rc = (*(msgParse)) (ptcx, cmd, me,
|
||||
buffer, bytesInBuffer, &searchStart, &findStr);
|
||||
if (rc < 0) { /* parser signaled error */
|
||||
return rc;
|
||||
}
|
||||
if (NULL == searchStart) {
|
||||
searchStart = buffer+bytesInBuffer; /* discard buffer */
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (msgParse) { /* call extra searches */
|
||||
int rc;
|
||||
rc = (*(msgParse)) (ptcx, cmd, me,
|
||||
buffer, bytesInBuffer, &searchStart, &findStr);
|
||||
if (rc < 0) { /* protocol error */
|
||||
return rc;
|
||||
}
|
||||
if (rc > 0) { /* need more data */
|
||||
getBytes = rc;
|
||||
searchStart = foundStr; /* back up search string */
|
||||
continue;
|
||||
}
|
||||
if (searchStart < buffer) { /* or NULL */
|
||||
searchStart = buffer+bytesInBuffer; /* discard buffer */
|
||||
}
|
||||
} else {
|
||||
searchStart = buffer+bytesInBuffer; /* discard buffer */
|
||||
}
|
||||
}
|
||||
}
|
||||
D_PRINTF(stderr, "readWmapResponse: Read %d/%d saved %d\n",
|
||||
totalbytesread, bytestoread, bytesInBuffer);
|
||||
if (msgParse) { /* call extra searches */
|
||||
findStr = NULL; /* signal final callback */
|
||||
searchStart = NULL;
|
||||
(void)(*(msgParse)) (ptcx, cmd, me,
|
||||
buffer, bytesInBuffer, &searchStart, &findStr);
|
||||
}
|
||||
|
||||
return bytesInBuffer;
|
||||
}
|
||||
|
||||
/*
|
||||
Handle a command-response transaction. Connects/retries as needed.
|
||||
Expects pointers to buffers of these sizes:
|
||||
char command[MAX_COMMAND_LEN]
|
||||
char response[resplen]
|
||||
*/
|
||||
static int
|
||||
doWmapCommandResponse (
|
||||
ptcx_t ptcx, /* thread state */
|
||||
mail_command_t *cmd, /* command info for exit,connect */
|
||||
cmd_stats_t *ptimer, /* all timers for connect */
|
||||
doWMAP_state_t *me, /* connection state */
|
||||
event_timer_t *timer, /* timer for this command */
|
||||
char *command, /* command to send */
|
||||
char *response,
|
||||
int resplen,
|
||||
parseMsgPtr_t msgParse) /* response handler */
|
||||
{
|
||||
wmap_stats_t *stats = (wmap_stats_t *)ptimer->data;
|
||||
int retries = 0;
|
||||
int ret;
|
||||
|
||||
if (response == NULL)
|
||||
return -1;
|
||||
|
||||
response[0] = 0; /* make sure it makes sense on error */
|
||||
|
||||
D_PRINTF(stderr, "WmapCommandResponse() command=[%.99s]\n", command);
|
||||
|
||||
while (retries++ < HTTP_MAX_RECONNECTS) {
|
||||
if (BADSOCKET(ptcx->sock)) {
|
||||
ret = wmapConnect(ptcx, cmd, me, &stats->reconnect);
|
||||
if (ret == -1) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
/* send the command already formatted */
|
||||
T_PRINTF(ptcx->logfile, command, strlen (command), "WMAP SendCommand");
|
||||
event_start(ptcx, timer);
|
||||
ret = sendCommand(ptcx, ptcx->sock, command);
|
||||
if (ret == -1) {
|
||||
event_stop(ptcx, timer);
|
||||
stats->reconnect.errs++;
|
||||
/* this can only mean an IO error. Probably EPIPE */
|
||||
NETCLOSE(ptcx->sock);
|
||||
ptcx->sock = BADSOCKET_VALUE;
|
||||
strcat (ptcx->errMsg, "<WmapCommandResponse");
|
||||
D_PRINTF (stderr, "%s Aborting connection %s\n",
|
||||
ptcx->errMsg, neterrstr());
|
||||
continue;
|
||||
}
|
||||
|
||||
/* read server response */
|
||||
ret = readWmapResponse(ptcx, cmd, me, response, resplen, msgParse);
|
||||
event_stop(ptcx, timer);
|
||||
if (ret == 0) { /* got nothing */
|
||||
/* Probably an IO error. It will be definate if re-tried. */
|
||||
MS_usleep (5000); /* time for bytes to show up */
|
||||
continue; /* just re-try it */
|
||||
} else if (ret == -1) { /* IO error */
|
||||
stats->reconnect.errs++;
|
||||
NETCLOSE(ptcx->sock);
|
||||
ptcx->sock = BADSOCKET_VALUE;
|
||||
strcat (ptcx->errMsg, "<WmapCommandResponse");
|
||||
D_PRINTF (stderr, "%s Aborting connection %s\n",
|
||||
ptcx->errMsg, neterrstr());
|
||||
continue;
|
||||
} else if (ret < -1) { /* some other error */
|
||||
timer->errs++;
|
||||
/* this is overkill */
|
||||
NETCLOSE(ptcx->sock);
|
||||
ptcx->sock = BADSOCKET_VALUE;
|
||||
strcat (ptcx->errMsg, "<WmapCommandResponse: protocol ERROR");
|
||||
return -1;
|
||||
}
|
||||
/*D_PRINTF (stderr, "WmapCommandResponse saved %d bytes response=[%s]\n",
|
||||
ret, response);*/
|
||||
/* You get parent.timeoutCB on any kind of error (like bad sid) */
|
||||
if (strstr (response, "parent.timeoutCB()")) {
|
||||
timer->errs++;
|
||||
NETCLOSE(ptcx->sock);
|
||||
ptcx->sock = BADSOCKET_VALUE;
|
||||
strcpy (ptcx->errMsg, "WmapCommandResponse: got WMAP error msg");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
stats->reconnect.errs++;
|
||||
NETCLOSE(ptcx->sock);
|
||||
ptcx->sock = BADSOCKET_VALUE;
|
||||
strcat (ptcx->errMsg, "<WmapCommandResponse: Too many connection retries");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
Get the initial screen
|
||||
*/
|
||||
|
@ -896,7 +489,7 @@ wmapBanner(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer, doWMAP_state_t
|
|||
int rc = 0;
|
||||
|
||||
if (BADSOCKET(ptcx->sock)) { /* should always be true */
|
||||
rc = wmapConnect(ptcx, cmd, me, &stats->connect);
|
||||
rc = HttpConnect(ptcx, &wmap->hostInfo, &stats->connect);
|
||||
if (rc == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
@ -908,11 +501,13 @@ wmapBanner(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer, doWMAP_state_t
|
|||
|
||||
D_PRINTF(stderr, "wmapBanner() cmd=[%s]\n", pl->value);
|
||||
|
||||
sprintf(header, wmap->wmapClientHeader, wmap->mailServer, wmap->mailServer);
|
||||
sprintf(header, wmap->wmapClientHeader, wmap->hostInfo.hostName, wmap->hostInfo.hostName);
|
||||
sprintf(command, "%s\r\n%s\r\n", pl->value, header);
|
||||
assert (strlen(command) < MAX_COMMAND_LEN);
|
||||
|
||||
rc = doWmapCommandResponse(ptcx, cmd, ptimer, me, &stats->banner,
|
||||
rc = HttpCommandResponse(ptcx, cmd, me,
|
||||
&wmap->hostInfo, &stats->reconnect,
|
||||
&stats->banner,
|
||||
command, me->response_buffer,
|
||||
sizeof(me->response_buffer), NULL);
|
||||
if (rc == -1) {
|
||||
|
@ -953,7 +548,7 @@ wmapLogin(
|
|||
char *cp;
|
||||
|
||||
if (BADSOCKET(ptcx->sock)) {
|
||||
rc = wmapConnect(ptcx, cmd, me, &stats->reconnect);
|
||||
rc = HttpConnect(ptcx, &wmap->hostInfo, &stats->reconnect);
|
||||
if (rc == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
@ -974,16 +569,18 @@ wmapLogin(
|
|||
|
||||
/* send wmapLoginCmd, read response into wmapRedirectURL */
|
||||
sprintf(content, wmap->wmapLoginData, mailUser, userPasswd);
|
||||
sprintf(header, wmap->wmapClientHeader, wmap->mailServer, wmap->mailServer);
|
||||
sprintf(header, wmap->wmapClientHeader, wmap->hostInfo.hostName, wmap->hostInfo.hostName);
|
||||
sprintf(command, "%s\r\n%s"
|
||||
HTTP_CONTENT_TYPE_POST "\r\n"
|
||||
HTTP_CONTENT_LENGTH " %d\r\n\r\n%s\r\n",
|
||||
wmap->wmapLoginCmd, header, strlen(content), content);
|
||||
assert (strlen(command) < MAX_COMMAND_LEN);
|
||||
|
||||
rc = doWmapCommandResponse(ptcx, cmd, ptimer, me, &stats->login,
|
||||
rc = HttpCommandResponse(ptcx, cmd, me,
|
||||
&wmap->hostInfo, &stats->reconnect,
|
||||
&stats->banner,
|
||||
command, me->response_buffer,
|
||||
sizeof(me->response_buffer), NULL);
|
||||
sizeof(me->response_buffer), NULL);
|
||||
if (rc == -1) {
|
||||
if (gf_timeexpired < EXIT_FAST) {
|
||||
NETCLOSE(ptcx->sock); ptcx->sock = BADSOCKET_VALUE;
|
||||
|
@ -1067,9 +664,11 @@ wmapInbox(
|
|||
/* First grab the redirect URL */
|
||||
sprintf(command, "GET %s HTTP/1.0\r\n%s" HTTP_CONTENT_LENGTH " 0\r\n\r\n",
|
||||
me->redirectURL, header);
|
||||
rc = doWmapCommandResponse(ptcx, cmd, ptimer, me, &stats->cmd,
|
||||
rc = HttpCommandResponse(ptcx, cmd, me,
|
||||
&wmap->hostInfo, &stats->reconnect,
|
||||
&stats->banner,
|
||||
command, me->response_buffer,
|
||||
sizeof(me->response_buffer), NULL);
|
||||
sizeof(me->response_buffer), NULL);
|
||||
if (rc == -1) { /* most common disconnect point */
|
||||
if (gf_timeexpired < EXIT_FAST) {
|
||||
returnerr(debugfile,"%s WMAP cannot get inbox %s\n",
|
||||
|
@ -1085,14 +684,16 @@ wmapInbox(
|
|||
|
||||
/* send wmapInboxCmd, read response into wmapRedirectURL */
|
||||
sprintf(header, wmap->wmapClientHeader,
|
||||
wmap->mailServer, wmap->mailServer);
|
||||
wmap->hostInfo.hostName, wmap->hostInfo.hostName);
|
||||
sprintf(getcmd, pl->value,
|
||||
me->sessionID);
|
||||
sprintf(command, "%s\r\n%s" HTTP_CONTENT_LENGTH " 0\r\n\r\n",
|
||||
getcmd, header);
|
||||
assert (strlen(command) < MAX_COMMAND_LEN);
|
||||
|
||||
rc = doWmapCommandResponse(ptcx, cmd, ptimer, me, &stats->cmd,
|
||||
rc = HttpCommandResponse(ptcx, cmd, me,
|
||||
&wmap->hostInfo, &stats->reconnect,
|
||||
&stats->banner,
|
||||
command, me->response_buffer,
|
||||
sizeof(me->response_buffer), NULL);
|
||||
if (rc == -1) { /* most common disconnect point */
|
||||
|
@ -1119,7 +720,7 @@ wmapLogout(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer, doWMAP_state_t
|
|||
int rc = 0;
|
||||
|
||||
if (BADSOCKET(ptcx->sock)) {
|
||||
rc = wmapConnect(ptcx, cmd, me, &stats->reconnect);
|
||||
rc = HttpConnect(ptcx, &wmap->hostInfo, &stats->reconnect);
|
||||
if (rc == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
@ -1131,12 +732,14 @@ wmapLogout(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer, doWMAP_state_t
|
|||
|
||||
D_PRINTF(stderr, "wmapLogout() cmd=[%s]\n", pl->value);
|
||||
|
||||
sprintf(header, wmap->wmapClientHeader, wmap->mailServer, wmap->mailServer);
|
||||
sprintf(header, wmap->wmapClientHeader, wmap->hostInfo.hostName, wmap->hostInfo.hostName);
|
||||
sprintf(getcmd, pl->value, me->sessionID);
|
||||
sprintf(command, "%s\r\n%s" HTTP_CONTENT_LENGTH " 0\r\n\r\n", getcmd, header);
|
||||
|
||||
assert (strlen(command) < MAX_COMMAND_LEN);
|
||||
rc = doWmapCommandResponse(ptcx, cmd, ptimer, me, &stats->logout,
|
||||
rc = HttpCommandResponse(ptcx, cmd, me,
|
||||
&wmap->hostInfo, &stats->reconnect,
|
||||
&stats->banner,
|
||||
command, me->response_buffer,
|
||||
sizeof(me->response_buffer), NULL);
|
||||
if (rc == -1) {
|
||||
|
@ -1284,12 +887,14 @@ doWmapLoop(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer, void *mystate)
|
|||
sprintf(getcmd, pl->value,
|
||||
me->sessionID);
|
||||
sprintf(header, wmap->wmapClientHeader,
|
||||
wmap->mailServer, wmap->mailServer);
|
||||
wmap->hostInfo.hostName, wmap->hostInfo.hostName);
|
||||
sprintf(command, "%s\r\n%s" HTTP_CONTENT_LENGTH " 0\r\n\r\n",
|
||||
getcmd, header);
|
||||
assert (strlen(command) < MAX_COMMAND_LEN);
|
||||
|
||||
rc = doWmapCommandResponse(ptcx, cmd, ptimer, me, &stats->headers,
|
||||
rc = HttpCommandResponse(ptcx, cmd, me,
|
||||
&wmap->hostInfo, &stats->reconnect,
|
||||
&stats->banner,
|
||||
command, me->response_buffer,
|
||||
sizeof(me->response_buffer), &GetMessageNumbers);
|
||||
if (rc == -1) { /* un-recoverable error */
|
||||
|
@ -1317,12 +922,14 @@ doWmapLoop(ptcx_t ptcx, mail_command_t *cmd, cmd_stats_t *ptimer, void *mystate)
|
|||
sprintf(getcmd, pl->value, /* fill out command string */
|
||||
me->sessionID, me->msgList[seq]);
|
||||
sprintf(header, wmap->wmapClientHeader, /* fill out header */
|
||||
wmap->mailServer, wmap->mailServer);
|
||||
wmap->hostInfo.hostName, wmap->hostInfo.hostName);
|
||||
sprintf(command, "%s\r\n%s" HTTP_CONTENT_LENGTH " 0\r\n\r\n",
|
||||
getcmd, header);
|
||||
assert (strlen(command) < MAX_COMMAND_LEN);
|
||||
|
||||
rc = doWmapCommandResponse(ptcx, cmd, ptimer, me, &stats->msgread,
|
||||
rc = HttpCommandResponse(ptcx, cmd, me,
|
||||
&wmap->hostInfo, &stats->reconnect,
|
||||
&stats->banner,
|
||||
command, me->response_buffer,
|
||||
sizeof(me->response_buffer), NULL);
|
||||
if (rc == -1) { /* un-recoverable error */
|
||||
|
|
Загрузка…
Ссылка в новой задаче