Click to See Complete Forum and Search --> : send() and recv() go into limbo state, i.e. freeze up


jalway
December 24th, 2004, 11:11 PM
I have a program that freezes up, or goes into a limbo state ocassionally on the calling of one of those two functions. Sometimes one, other times the other one. I'm hoping someone here can help me with this Winsock stuff!

The set up I have is as follows. I have an email client connected to a mid point server, which then connects to the main POP3 server. I'm going to use the mid point server to do some data processing when I get it running, but right now I'm having this problem.

The set up is, pictorially:

[Email Client]<------->[MidPoint Server]<------->[POP3 Server]

Note, I wrote a simple email client to test things, and if I hook my email client up to the POP3 Server, everything works fine, but not when using the midpoint server:

[My Email Client]<------->[POP3 Server]


All I'm doing with the midpoint server right now is simply passing commands from the Email Client to the POP3 server, and passing responses from the POP3 server to the Email Client. Just in the development stages.

Anyway, POP3 servers have single line responses and multi line responses. When I send a command which has a single line response everything works smoothly. Yet, when I send a command which has a multiline response, such as LIST and RETR 1, it fails. But it doesn't fail on that command, only on the next command after the multiline response.

The program suddenly freezes, sometimes at recv(), when receiving data from the Email Client, and other times at send(), when sending to the POP3 server.

There must be a more robust way to deal with such things, so that programs don't just halt this way.

I have provided some of the code below. I tried to compact the code so that it's easier to analyze, but present enough of the picture to get the point across. Here is the code:


void server() {
char buf1[120], buf2[120];
char message[120], message[120];
bool bMultiLine = false, bQuit=false;

//Start mid point Server Up Here
// Wait for email client to call up.
// socket pCS->m_oConnectSocket is created as a connetion between
// the email client and this server

//THEN, after the above connection is established, create a client
// connection to the POP3 server, with the socket ClientSocket

//The process loop:
while(bGood) {
//Receive From POP3 Server, Send To Email Client
pCS->recvSD1sendSD2(message,ClientSocket,pCS->m_oConnectSocket,bMultiLine);
if(bQuit) break;
//Receive From Email Client, Send To POP3 Server
pCS->recvSD1sendSD2(message,pCS->m_oConnectSocket,ClientSocket,bMultiLine);

buf1[0] = buf1[0] ='\0';
strToUpper(message,message2);
sscanf(message2,"%s%s",&buf1,&buf2);

bMultiLine = false;
//Process commands to POP3 to see if they will require multiline responses
if( strcmp(buf1,"RETR") == 0)
bMultiLine = true;
else if(strcmp(buf1, "LIST") == 0 && buf2[0] == '\0')
bMultiLine true;
else if(strcmp(buf1, "QUIT") == 0)
bQuit = true;
}
}



bool CClientServer::recvSD1sendSD2(char *buf,SOCKET sd1,SOCKET sd2,bool bMultiLine)
{
LONG32 nXfer;
LPBYTE pBuffer;
LONG32 msgSize=0;
int nRet, nResult=0, endCount=0;
bool bGood=true;

pBuffer = (LPBYTE)buf;

while(!bGood) {
nRet = WSAGetLastError();

//It Freezes Here at times.
nXfer = recv(sd1, (char *)pBuffer, 1, 0);
if(nXfer == SOCKET_ERROR) throw "Client header recv() failed";

//And it Freezes Here at times
nResult = send(sd2, (char *)pBuffer, 1, 0);
if(nResult == SOCKET_ERROR) throw "Client send () failed";

//Returned "-ERR", thus response will not be multiline
if(*pBuffer == '-' && bFirstPass==true) bMultiLine = false;

if(bMultiLine){
switch(*pBuffer){ //Looking for end sequence "\r\n.\r\n"

case '\r':
if(endCount == 0) endCount++;
else if(endCount == 3) endCount++;
else endCount = 1;
break;
case '\n':
if(endCount == 1) endCount++;
else if(endCount == 4) endCount++; //Found last end character
else endCount = 0;
break;
case '.':
if(endCount == 2) endCount++;
else endCount = 0;
break;
default:
endCount = 0;
break;
}
if(endCount == 5){
pBuffer -= 3;
*pBuffer = '\0';
break;
}

}else {
switch(*pBuffer){ // Looking for end sequence "\r\n"
case '\r':
if(endCount == 0) endCount++;
else endCount = 1;
break;
case '\n':
if(endCount == 1) endCount++;
else endCount = 0;
break;
default:
endCount = 0;
break;
}
if(endCount == 2){
pBuffer--;
*pBuffer = '\0';
break;
}
}
pBuffer += nXfer;
}
return bGood;
}

j0nas
December 26th, 2004, 05:49 AM
It looks complicated... I'm sure you could do it better and esieser to understand. The buffer size is hardcoded to 120 bytes--this may cause the problem. You can verify if this is the problem by counting the bytes transferred when a multiline message is handled--just to veriy if this is causing the problem. Or, just increase the buffer (to 8kb or something).

POP3 is a CRLF terminated, text-based protocol. You can implement a queue based on "lines". Add an abstraction layer, like for instance recvline() and sendline(). Those should operate on the queue. If the queue is empty, do recv() (inside recvline()), and so on... Is quite easy actually.


Hope it helps.

jalway
December 26th, 2004, 10:56 PM
Thanks for your reply.

Yes, I do know that POP3 ends its single line responses with CRLF, and multi line responses with CRLF.CRLF.

I did get it working by using select() with a 15 sec delay, and making it none blocking, although I'm not sure why the other wasn't working.

You can't see it in the code I provided, but that buffer cycles around before it gets to 120, so that wasn't the problem. That buffer is only really there to grab commands, which are going to be less than 120.

Thanks for the advice on using a queue. I'll probably do that.