void SLIPFramedDataMessageIOGateway :: AddPendingByte(uint8 b)
{
   if (_pendingBuffer() == NULL) 
   {
      _pendingBuffer = GetByteBufferFromPool(256);  // An arbitrary initial size, since I can't think of any good heuristic
      if (_pendingBuffer()) _pendingBuffer()->Clear(false);  // but make it look empty
                       else return;  // out of memory?
   }
   (void) _pendingBuffer()->AppendByte(b);
}
int32
PlainTextMessageIOGateway ::
DoOutputImplementation(uint32 maxBytes)
{
   if (GetMaximumPacketSize() > 0)
   {
      // For the packet-based implementation, we will send one packet per outgoing Message
      // It'll be up to the user to make sure not to put too much text in one Message
      uint32 totalNumBytesSent = 0;
      MessageRef nextMsg;
      while((totalNumBytesSent < maxBytes)&&(GetOutgoingMessageQueue().RemoveHead(nextMsg) == B_NO_ERROR))
      {
         uint32 outBufLen = 1; // 1 for the one extra NUL byte at the end of all the strings (per String::Flatten(), below)
         const String * nextStr;
         for (uint32 i=0; nextMsg()->FindString(PR_NAME_TEXT_LINE, i, &nextStr) == B_NO_ERROR; i++) outBufLen += (nextStr->Length() + _eolString.Length());

         ByteBufferRef outBuf = GetByteBufferFromPool(outBufLen);
         if (outBuf())
         {
            uint8 * b = outBuf()->GetBuffer();
            for (uint32 i=0; nextMsg()->FindString(PR_NAME_TEXT_LINE, i, &nextStr) == B_NO_ERROR; i++) 
            {
               nextStr->Flatten(b);   b += nextStr->Length();   // Advance by Length() instead of FlattenedSize()
               _eolString.Flatten(b); b += _eolString.Length(); // to avoid NUL bytes inside our outBuf
            }

            const uint8 * outBytes      = outBuf()->GetBuffer();
            const uint32 numBytesToSend = outBuf()->GetNumBytes()-1;  // don't sent the NUL terminator byte; receivers shouldn't rely on it anyway

            PacketDataIO * pdio = GetPacketDataIO();  // guaranteed non-NULL
            IPAddressAndPort packetDest;
            const int32 numBytesSent = (nextMsg()->FindFlat(PR_NAME_PACKET_REMOTE_LOCATION, packetDest) == B_NO_ERROR)
                                     ? pdio->WriteTo(outBytes, numBytesToSend, packetDest)
                                     : pdio->Write(  outBytes, numBytesToSend);
                 if (numBytesSent > 0) totalNumBytesSent += numBytesSent;
            else if (numBytesSent < 0) return (totalNumBytesSent > 0) ? totalNumBytesSent : -1;
            else
            {
               (void) GetOutgoingMessageQueue().AddHead(nextMsg);  // roll back -- we'll try again later to send it, maybe
               break;
            }
         }
         else break;
      }
      return totalNumBytesSent;
   }
   else return DoOutputImplementationAux(maxBytes, 0);  // stream-based implementation is here
}
static status_t ReadZipFileAux(zipFile zf, Message & msg, char * nameBuf, uint32 nameBufLen, bool loadData)
{
   while(unzOpenCurrentFile(zf) == UNZ_OK)
   {
      unz_file_info fileInfo;
      if (unzGetCurrentFileInfo(zf, &fileInfo, nameBuf, nameBufLen, NULL, 0, NULL, 0) != UNZ_OK) return B_ERROR;

      // Add the new entry to the appropriate spot in the tree (demand-allocate sub-Messages as necessary)
      {
         const char * nulByte = strchr(nameBuf, '\0');
         const bool isFolder = ((nulByte > nameBuf)&&(*(nulByte-1) == '/'));
         Message * m = &msg;
         StringTokenizer tok(true, nameBuf, "/");
         const char * nextTok;
         while((nextTok = tok()) != NULL)
         {
            String fn(nextTok);
            if ((isFolder)||(tok.GetRemainderOfString()))
            {
               // Demand-allocate a sub-message
               MessageRef subMsg;
               if (m->FindMessage(fn, subMsg) != B_NO_ERROR) 
               {
                  if ((m->AddMessage(fn, Message()) != B_NO_ERROR)||(m->FindMessage(fn, subMsg) != B_NO_ERROR)) return B_ERROR;
               }
               m = subMsg();
            }
            else
            {
               if (loadData)
               {
                  ByteBufferRef bufRef = GetByteBufferFromPool((uint32) fileInfo.uncompressed_size);
                  if ((bufRef() == NULL)||(unzReadCurrentFile(zf, bufRef()->GetBuffer(), bufRef()->GetNumBytes()) != (int32)bufRef()->GetNumBytes())||(m->AddFlat(fn, bufRef) != B_NO_ERROR)) return B_ERROR;
               }
               else if (m->AddInt64(fn, fileInfo.uncompressed_size) != B_NO_ERROR) return B_ERROR;
            }
         }
      }
      if (unzCloseCurrentFile(zf) != UNZ_OK) return B_ERROR;
      if (unzGoToNextFile(zf) != UNZ_OK) break;
   }
   return B_NO_ERROR;
}
ByteBufferRef ParseHexBytes(const char * buf)
{
   ByteBufferRef bb = GetByteBufferFromPool((uint32)strlen(buf));
   if (bb())
   {
      uint8 * b = bb()->GetBuffer();
      uint32 count = 0;
      StringTokenizer tok(buf, " \t\r\n");
      const char * next;
      while((next = tok()) != NULL)
      {
         if (strlen(next) > 0)
         {
                 if (next[0] == '/') b[count++] = next[1];
            else if (next[0] == '\\')
            {
               // handle standard C escaped-control-chars conventions also (\r, \n, \t, etc)
               char c = 0;
               switch(next[1])
               {
                  case 'a':  c = 0x07; break;
                  case 'b':  c = 0x08; break;
                  case 'f':  c = 0x0C; break;
                  case 'n':  c = 0x0A; break;
                  case 'r':  c = 0x0D; break;
                  case 't':  c = 0x09; break;
                  case 'v':  c = 0x0B; break;
                  case '\\': c = 0x5C; break;
                  case '\'': c = 0x27; break;
                  case '"':  c = 0x22; break;
                  case '?':  c = 0x3F; break;
               }
               b[count++] = c;
            }
            else b[count++] = (uint8) strtol(next, NULL, 16);
         }
      }
      bb()->SetNumBytes(count, true);
   }
   return bb;
}
static ByteBufferRef SLIPEncodeBytes(const uint8 * bytes, uint32 numBytes)
{
   // First, calculate how many bytes the SLIP'd buffer will need to hold
   uint32 numSLIPBytes = 2;  // 1 for the SLIP_END byte at the beginning, and one for the SLIP_END at the end.
   for (uint32 i=0; i<numBytes; i++)
   {
      switch(bytes[i])
      {
         case SLIP_END: case SLIP_ESC: numSLIPBytes += 2; break;  // these get escaped as two characters
         default:                      numSLIPBytes += 1; break;
      }
   }

   ByteBufferRef bufRef = GetByteBufferFromPool(numSLIPBytes);
   if (bufRef())
   {
      uint8 * out = bufRef()->GetBuffer();
      *out++ = SLIP_END;
      for (uint32 i=0; i<numBytes; i++)
      {
         switch(bytes[i])
         {
            case SLIP_END: 
               *out++ = SLIP_ESC;
               *out++ = SLIP_ESCAPE_END;
            break;

            case SLIP_ESC:
               *out++ = SLIP_ESC;
               *out++ = SLIP_ESCAPE_ESC;
            break;

            default:
               *out++ = bytes[i];
            break;
         }
      }
      *out++ = SLIP_END;
   }
   return bufRef;
}
ByteBufferRef ParseHexBytes(const char * buf)
{
   ByteBufferRef bb = GetByteBufferFromPool((uint32)strlen(buf));
   if (bb())
   {
      uint8 * b = bb()->GetBuffer();
      uint32 count = 0;
      StringTokenizer tok(buf, " \t\r\n");
      const char * next;
      while((next = tok()) != NULL) 
      {
         if (strlen(next) > 0) 
         {
            if (next[0] == '/') b[count++] = next[1];
                           else b[count++] = (uint8) strtol(next, NULL, 16);
         }
      }
      bb()->SetNumBytes(count, true);
   }
   return bb;
}
int32 PacketTunnelIOGateway :: DoInputImplementation(AbstractGatewayMessageReceiver & receiver, uint32 maxBytes)
{
   if (_inputPacketBuffer.SetNumBytes(_maxTransferUnit, false) != B_NO_ERROR) return -1;

   bool firstTime = true;
   uint32 totalBytesRead = 0;
   while((totalBytesRead < maxBytes)&&((firstTime)||(IsSuggestedTimeSliceExpired() == false)))
   {
      firstTime = false;

      int32 bytesRead = GetDataIO()()->Read(_inputPacketBuffer.GetBuffer(), _inputPacketBuffer.GetNumBytes());
//printf("   READ " INT32_FORMAT_SPEC "/" UINT32_FORMAT_SPEC " bytes\n", bytesRead, _inputPacketBuffer.GetNumBytes());
      if (bytesRead > 0)
      {
         totalBytesRead += bytesRead;

         IPAddressAndPort fromIAP;
         const PacketDataIO * packetIO = dynamic_cast<PacketDataIO *>(GetDataIO()());
         if (packetIO) fromIAP = packetIO->GetSourceOfLastReadPacket();

         const uint8 * p = (const uint8 *) _inputPacketBuffer.GetBuffer();
         if ((_allowMiscData)&&((bytesRead < (int32)FRAGMENT_HEADER_SIZE)||(((uint32)B_LENDIAN_TO_HOST_INT32(muscleCopyIn<uint32>(p))) != _magic)))
         {
            // If we're allowed to handle miscellaneous data, we'll just pass it on through verbatim
            ByteBuffer temp;
            temp.AdoptBuffer(bytesRead, const_cast<uint8 *>(p));
            HandleIncomingMessage(receiver, ByteBufferRef(&temp, false), fromIAP);
            (void) temp.ReleaseBuffer();
         }
         else
         {
            const uint8 * invalidByte = p+bytesRead;
            while(invalidByte-p >= (int32)FRAGMENT_HEADER_SIZE)
            {
               const uint32 magic     = B_LENDIAN_TO_HOST_INT32(muscleCopyIn<uint32>(&p[0*sizeof(uint32)]));
               const uint32 sexID     = B_LENDIAN_TO_HOST_INT32(muscleCopyIn<uint32>(&p[1*sizeof(uint32)]));
               const uint32 messageID = B_LENDIAN_TO_HOST_INT32(muscleCopyIn<uint32>(&p[2*sizeof(uint32)]));
               const uint32 offset    = B_LENDIAN_TO_HOST_INT32(muscleCopyIn<uint32>(&p[3*sizeof(uint32)]));
               const uint32 chunkSize = B_LENDIAN_TO_HOST_INT32(muscleCopyIn<uint32>(&p[4*sizeof(uint32)]));
               const uint32 totalSize = B_LENDIAN_TO_HOST_INT32(muscleCopyIn<uint32>(&p[5*sizeof(uint32)]));
//printf("   PARSE magic=" UINT32_FORMAT_SPEC "/" UINT32_FORMAT_SPEC " sex=" UINT32_FORMAT_SPEC "/" UINT32_FORMAT_SPEC " messageID=" UINT32_FORMAT_SPEC " offset=" UINT32_FORMAT_SPEC " chunkSize=" UINT32_FORMAT_SPEC " totalSize=" UINT32_FORMAT_SPEC "\n", magic, _magic, sexID, _sexID, messageID, offset, chunkSize, totalSize);

               p += FRAGMENT_HEADER_SIZE;
               if ((magic == _magic)&&((_sexID == 0)||(_sexID != sexID))&&((invalidByte-p >= (int32)chunkSize)&&(totalSize <= _maxIncomingMessageSize)))
               {
                  ReceiveState * rs = _receiveStates.Get(fromIAP);
                  if (rs == NULL)
                  {
                     if (offset == 0) rs = _receiveStates.PutAndGet(fromIAP, ReceiveState(messageID));
                     if (rs)
                     {
                        rs->_buf = GetByteBufferFromPool(totalSize);
                        if (rs->_buf() == NULL)
                        {
                           _receiveStates.Remove(fromIAP);
                           rs = NULL;
                        }
                     }
                  }
                  if (rs)
                  {
                     if ((offset == 0)||(messageID != rs->_messageID))
                     {
                        // A new message... start receiving it (but only if we are starting at the beginning)
                        rs->_messageID = messageID;
                        rs->_offset    = 0;
                        rs->_buf()->SetNumBytes(totalSize, false);
                     }

                     uint32 rsSize = rs->_buf()->GetNumBytes();
//printf("  CHECK:  offset=" UINT32_FORMAT_SPEC "/" UINT32_FORMAT_SPEC " %s\n", offset, rs->_offset, (offset==rs->_offset)?"":"DISCONTINUITY!!!");
                     if ((messageID == rs->_messageID)&&(totalSize == rsSize)&&(offset == rs->_offset)&&(offset+chunkSize <= rsSize))
                     {
                        memcpy(rs->_buf()->GetBuffer()+offset, p, chunkSize);
                        rs->_offset += chunkSize;
                        if (rs->_offset == rsSize) 
                        {
                           HandleIncomingMessage(receiver, rs->_buf, fromIAP);
                           rs->_offset = 0;
                           rs->_buf()->Clear(rsSize > MAX_CACHE_SIZE);
                        }
                     }
                     else 
                     {
                        LogTime(MUSCLE_LOG_DEBUG, "Unknown fragment (" UINT32_FORMAT_SPEC "/" UINT32_FORMAT_SPEC "/" UINT32_FORMAT_SPEC "/" UINT32_FORMAT_SPEC ") received from %s, ignoring it.\n", messageID, offset, chunkSize, totalSize, fromIAP.ToString()());
                        rs->_offset = 0;
                        rs->_buf()->Clear(rsSize > MAX_CACHE_SIZE);
                     }
                  }
                  p += chunkSize;
               }
               else break;
            }
         }
      }
      else if (bytesRead < 0) return -1;
      else break;
   }
   return totalBytesRead;
}
Beispiel #8
0
void
WUploadThread::DoUpload()
{
	PRINT("WUploadThread::DoUpload\n");
	if (fShutdownFlag && *fShutdownFlag)	// Do we need to interrupt?
	{
		ConnectTimer();
		return;
	}

	// Still connected?

	if (!IsInternalThreadRunning())
	{
		ConnectTimer();
		return;
	}

	// Small files get to bypass queue
	if (IsLocallyQueued())
	{
		if (
			(fFile && (fFileSize >= gWin->fSettings->GetMinQueuedSize())) ||
			IsManuallyQueued()
			)
		{
			// not yet
			fForced = false;
			WUploadEvent *lq = new WUploadEvent(WUploadEvent::FileQueued);
			if (lq)
			{
				SendReply(lq);
			}
			return;
		}
		fForced = true;		// Set this here to avoid duplicate call to DoUpload()
	}

	// Recheck if IP is ignored or not
	//

	if (gWin->IsIgnoredIP(fStrRemoteIP) && !IsBlocked())
	{
		SetBlocked(true);
	}

	if (IsBlocked())
	{
		WUploadEvent *wue = new WUploadEvent(WUploadEvent::FileBlocked);
		if (wue)
		{
			if (fTimeLeft != -1)
				wue->SetTime(fTimeLeft);
			SendReply(wue);
		}
		return;
	}

	if (fStartTime == 0)
		fStartTime = GetRunTime64();

	if (fFile)
	{
		MessageRef uref(GetMessageFromPool(WTransfer::TransferFileData));
		if (uref())
		{
			// think about doing this in a dynamic way (depending on connection)
			double dpps = GetPacketSize() * 1024.0;
			uint32 bufferSize = lrint(dpps);
			ByteBufferRef buf = GetByteBufferFromPool(bufferSize);

			uint8 * scratchBuffer = buf()->GetBuffer();
			if (scratchBuffer == NULL)
			{
				_nobuffer();
				return;
			}

			int32 numBytes = 0;
			numBytes = fFile->ReadBlock32(scratchBuffer, bufferSize);
			if (numBytes > 0)
			{
				buf()->SetNumBytes(numBytes, true);

				// munge mode

				switch (fMungeMode)
				{
					case WTransfer::MungeModeNone:
					{
						uref()->AddInt32("mm", WTransfer::MungeModeNone);
						break;
					}

					case WTransfer::MungeModeXOR:
					{
						for (int32 x = 0; x < numBytes; x++)
							scratchBuffer[x] ^= 0xFF;
						uref()->AddInt32("mm", WTransfer::MungeModeXOR);
						break;
					}

					default:
					{
						break;
					}
				}

				if (uref()->AddFlat("data", buf) == B_OK)
				{
					// possibly do checksums here
					uref()->AddInt32("chk", CalculateFileChecksum(buf));  // a little paranoia, due to file-resumes not working.... (TCP should handle this BUT...)

					SendMessageToSessions(uref);

					// NOTE: RequestOutputQueuesDrainedNotification() can recurse, so we need to update the offset before
					//       calling it!
					fCurrentOffset += numBytes;
					if (fTunneled)
					{
						SignalUpload();
					}
					else
					{
						MessageRef drain(GetMessageFromPool());
						if (drain())
							qmtt->RequestOutputQueuesDrainedNotification(drain);
					}

					WUploadEvent *update = new WUploadEvent(WUploadEvent::FileDataSent);
					if (update)
					{
						update->SetOffset(fCurrentOffset);
						update->SetSize(fFileSize);
						update->SetSent(numBytes);

						if (fCurrentOffset >= fFileSize)
						{
							update->SetDone(true);	// file done!
							update->SetFile(SimplifyPath(fFileUl));

							if (gWin->fSettings->GetUploads())
							{
								SystemEvent( gWin, tr("%1 has finished downloading %2.").arg( GetRemoteUser() ).arg( SimplifyPath(fFileUl) ) );
							}
						}
						SendReply(update);
					}

					return;
				}
				else
				{
					_nobuffer();
					return;
				}
			}

			if (numBytes <= 0)
			{
				NextFile();
				SignalUpload();
				return;
			}
		}
	}
	else
	{
		while (!fFile)
		{
			if (fUploads.GetNumItems() != 0)
			{
				// grab the ref and remove it from the list
				fUploads.RemoveHead(fCurrentRef);

				fFileUl = MakeUploadPath(fCurrentRef);

#ifdef _DEBUG
				// <*****@*****.**> 20021023, 20030702 -- Add additional debug message
				WString wul(fFileUl);
				PRINT("WUploadThread::DoUpload: filePath = %S\n", wul.getBuffer());
#endif

				fFile = new WFile();
				Q_CHECK_PTR(fFile);
				if (!fFile->Open(fFileUl, QIODevice::ReadOnly))	// probably doesn't exist
				{
					delete fFile;
					fFile = NULL;
					fCurFile++;
					continue;	// onward
				}
				// got our file!
				fFileSize = fFile->Size();
				fCurrentOffset = 0;	// from the start
                                if (fCurrentRef()->FindInt64("secret:offset", fCurrentOffset) == B_OK)
				{
					if (!fFile->Seek(fCurrentOffset)) // <*****@*****.**> 20021026
					{
						fFile->Seek(0);	// this can't fail :) (I hope)
						fCurrentOffset = 0;
					}
				}
				// copy the message in our current file ref
				MessageRef headRef = fCurrentRef.Clone();
				if (headRef())
				{
					headRef()->what = WTransfer::TransferFileHeader;
					headRef()->AddInt64("beshare:StartOffset", fCurrentOffset);
					SendMessageToSessions(headRef);
				}

				fCurFile++;

				// Reset statistics
				InitTransferRate();
				InitTransferETA();

				WUploadEvent *started = new WUploadEvent(WUploadEvent::FileStarted);
				if (started)
				{
					started->SetFile(SimplifyPath(fFileUl));
					started->SetStart(fCurrentOffset);
					started->SetSize(fFileSize);
#ifdef _DEBUG
					started->SetSession(fRemoteSessionID);
#endif
					SendReply(started);
				}

				if (gWin->fSettings->GetUploads())
				{
					SystemEvent( gWin, tr("%1 is downloading %2.").arg( GetRemoteUser() ).arg( SimplifyPath(fFileUl) ) );
				}

				// nested call
				SignalUpload();
				return;
			}
			else
			{
				PRINT("No more files!\n");
				fWaitingForUploadToFinish = true;
				SetFinished(true);
				if (fTunneled)
				{
					_OutputQueuesDrained();
				}
				else
				{
					MessageRef drain(GetMessageFromPool());
					if (drain())
						qmtt->RequestOutputQueuesDrainedNotification(drain);
				}
				break;
			}
		}
	}
}
Beispiel #9
0
App::App(void)
	:
	BApplication(STR_MUSCLE_DEAMON_NAME)
	, maxBytes(MUSCLE_NO_LIMIT)
	, maxNodesPerSession(MUSCLE_NO_LIMIT)
	, maxReceiveRate(MUSCLE_NO_LIMIT)
	, maxSendRate(MUSCLE_NO_LIMIT)
	, maxCombinedRate(MUSCLE_NO_LIMIT)
	, maxMessageSize(MUSCLE_NO_LIMIT)
	, maxSessions(MUSCLE_NO_LIMIT)
	, maxSessionsPerHost(MUSCLE_NO_LIMIT)
	, fprivateKeyFilePath(NULL)
	, retVal(0)
	, okay(true)
{
	CompleteSetupSystem css;

	TCHECKPOINT;

#ifdef MUSCLE_ENABLE_MEMORY_TRACKING
	printf("MUSCLE_ENABLE_MEMORY_TRACKING\n");
	// Set up memory allocation policies for our server.  These policies will make sure
	// that the server can't allocate more than a specified amount of memory, and if it tries,
	// some emergency callbacks will be called to free up cached info.
	FunctionCallback fcb(AbstractObjectRecycler::GlobalFlushAllCachedObjects);
	MemoryAllocatorRef nullRef;
	AutoCleanupProxyMemoryAllocator cleanupAllocator(nullRef);
	cleanupAllocator.GetCallbacksQueue().AddTail(GenericCallbackRef(&fcb, false));

	UsageLimitProxyMemoryAllocator usageLimitAllocator(MemoryAllocatorRef(&cleanupAllocator, false));

	SetCPlusPlusGlobalMemoryAllocator(MemoryAllocatorRef(&usageLimitAllocator, false));
	SetCPlusPlusGlobalMemoryAllocator(MemoryAllocatorRef());  // unset, so that none of our allocator objects will be used after they are gone
	
	if ((maxBytes != MUSCLE_NO_LIMIT) && (&usageLimitAllocator)) 
		usageLimitAllocator.SetMaxNumBytes(maxBytes);
#endif

	TCHECKPOINT;

	server.GetAddressRemappingTable() = tempRemaps;

	if (maxNodesPerSession != MUSCLE_NO_LIMIT) 
		server.GetCentralState().AddInt32(PR_NAME_MAX_NODES_PER_SESSION, maxNodesPerSession);
	
	for (MessageFieldNameIterator iter = tempPrivs.GetFieldNameIterator(); iter.HasData(); iter++) 
		tempPrivs.CopyName(iter.GetFieldName(), server.GetCentralState());

	// If the user asked for bandwidth limiting, create Policy objects to handle that.
	AbstractSessionIOPolicyRef inputPolicyRef, outputPolicyRef;
	if (maxCombinedRate != MUSCLE_NO_LIMIT) {
		inputPolicyRef.SetRef(newnothrow RateLimitSessionIOPolicy(maxCombinedRate));
		outputPolicyRef = inputPolicyRef;
		
		if (inputPolicyRef()) 
			LogTime(MUSCLE_LOG_INFO, "Limiting aggregate I/O bandwidth to %.02f kilobytes/second.\n", ((float)maxCombinedRate/1024.0f));
		else
		{
			WARN_OUT_OF_MEMORY;
			okay = false;
		}
	} else {
		if (maxReceiveRate != MUSCLE_NO_LIMIT) {
			inputPolicyRef.SetRef(newnothrow RateLimitSessionIOPolicy(maxReceiveRate));
			
			if (inputPolicyRef())
				LogTime(MUSCLE_LOG_INFO, "Limiting aggregate receive bandwidth to %.02f kilobytes/second.\n", ((float)maxReceiveRate/1024.0f));
			else {
				WARN_OUT_OF_MEMORY;
				okay = false;
			}
		}
		
		if (maxSendRate != MUSCLE_NO_LIMIT) {
			outputPolicyRef.SetRef(newnothrow RateLimitSessionIOPolicy(maxSendRate));
			
			if (outputPolicyRef())
				LogTime(MUSCLE_LOG_INFO, "Limiting aggregate send bandwidth to %.02f kilobytes/second.\n", ((float)maxSendRate/1024.0f)); 
			else {
				WARN_OUT_OF_MEMORY;
				okay = false; 
			}
		}
	}

	// Set up the Session Factory.  This factory object creates the new StorageReflectSessions
	// as needed when people connect, and also has a filter to keep out the riff-raff.
	StorageReflectSessionFactory factory; factory.SetMaxIncomingMessageSize(maxMessageSize);
	FilterSessionFactory filter(ReflectSessionFactoryRef(&factory, false), maxSessionsPerHost, maxSessions);
	filter.SetInputPolicy(inputPolicyRef);
	filter.SetOutputPolicy(outputPolicyRef);

	for (int b=bans.GetNumItems()-1; ((okay)&&(b>=0)); b--) 
		if (filter.PutBanPattern(bans[b]()) != B_NO_ERROR) 
			okay = false;
	
	for (int a=requires.GetNumItems()-1; ((okay)&&(a>=0)); a--) 
		if (filter.PutRequirePattern(requires[a]()) != B_NO_ERROR)
			okay = false;

#ifdef MUSCLE_ENABLE_SSL
   ByteBufferRef optCryptoBuf;
   if (fprivateKeyFilePath)
   {
      FileDataIO fdio(muscleFopen(fprivateKeyFilePath->Cstr(), "rb"));
      ByteBufferRef fileData = GetByteBufferFromPool((uint32)fdio.GetLength());
      if ((fdio.GetFile())&&(fileData())&&(fdio.ReadFully(fileData()->GetBuffer(), fileData()->GetNumBytes()) == fileData()->GetNumBytes()))
      { 
         LogTime(MUSCLE_LOG_INFO, "Using private key file [%s] to authenticate with connecting clients\n", fprivateKeyFilePath->Cstr());
         server.SetSSLPrivateKey(fileData);
      }
      else
      {
         LogTime(MUSCLE_LOG_CRITICALERROR, "Couldn't load private key file [%s] (file not found?)\n", fprivateKeyFilePath->Cstr());
         okay = false;
      }
   }
#else
   if (fprivateKeyFilePath)
   {
      LogTime(MUSCLE_LOG_CRITICALERROR, "Can't loadp private key file [%s], SSL support is not compiled in!\n", fprivateKeyFilePath->Cstr());
      okay = false;
   }
#endif

	// Set up ports.  We allow multiple ports, mostly just to show how it can be done;
	// they all get the same set of ban/require patterns (since they all do the same thing anyway).
	if (listenPorts.IsEmpty())
		listenPorts.PutWithDefault(IPAddressAndPort(invalidIP, DEFAULT_MUSCLED_PORT));
	
	for (HashtableIterator<IPAddressAndPort, Void> iter(listenPorts); iter.HasData(); iter++) {
		const IPAddressAndPort & iap = iter.GetKey();
		if (server.PutAcceptFactory(iap.GetPort(), ReflectSessionFactoryRef(&filter, false), iap.GetIPAddress()) != B_NO_ERROR) {
			if (iap.GetIPAddress() == invalidIP)
				LogTime(MUSCLE_LOG_CRITICALERROR, "Error adding port %u, aborting.\n", iap.GetPort());
			else
				LogTime(MUSCLE_LOG_CRITICALERROR, "Error adding port %u to interface %s, aborting.\n", iap.GetPort(), Inet_NtoA(iap.GetIPAddress())());
			
			okay = false;
			break;
		}
	}

	if (okay) {
		retVal = (server.ServerProcessLoop() == B_NO_ERROR) ? 0 : 10;
		
		if (retVal > 0)
			LogTime(MUSCLE_LOG_CRITICALERROR, "Server process aborted!\n");
		else 
			LogTime(MUSCLE_LOG_INFO, "Server process exiting.\n");
	} else
		LogTime(MUSCLE_LOG_CRITICALERROR, "Error occurred during setup, aborting!\n");

	server.Cleanup();
}
int32
PlainTextMessageIOGateway ::
DoInputImplementation(AbstractGatewayMessageReceiver & receiver, uint32 maxBytes)
{
   TCHECKPOINT;

   int32 ret = 0;
   const int tempBufSize = 2048;
   char buf[tempBufSize];

   const uint32 mtuSize = GetMaximumPacketSize();
   if (mtuSize > 0)
   {
      // Packet-IO implementation
      char * pbuf  = buf;
      int pbufSize = tempBufSize;

      ByteBufferRef bigBuf;
      if (mtuSize > tempBufSize)
      {
         // Just in case our MTU size is too big for our on-stack buffer
         bigBuf = GetByteBufferFromPool(mtuSize);
         if (bigBuf())
         {
            pbuf     = (char *) bigBuf()->GetBuffer();
            pbufSize = bigBuf()->GetNumBytes();
         }
      }

      while(true)
      {
         IPAddressAndPort sourceIAP;
         const int32 bytesRead = GetPacketDataIO()->ReadFrom(pbuf, muscleMin(maxBytes, (uint32)(pbufSize-1)), sourceIAP);
              if (bytesRead < 0) return (ret > 0) ? ret : -1;
         else if (bytesRead > 0)
         {
            uint32 filteredBytesRead = bytesRead;
            FilterInputBuffer(pbuf, filteredBytesRead, pbufSize-1);
            ret += filteredBytesRead;
            pbuf[filteredBytesRead] = '\0';

            bool prevCharWasCarriageReturn = false;  // deliberately a local var, since UDP packets should be independent of each other
            MessageRef inMsg;  // demand-allocated
            int32 beginAt = 0;
            for (uint32 i=0; i<filteredBytesRead; i++)
            {
               char nextChar = pbuf[i];
               if ((nextChar == '\r')||(nextChar == '\n'))
               {
                  pbuf[i] = '\0';  // terminate the string here
                  if ((nextChar == '\r')||(prevCharWasCarriageReturn == false)) inMsg = AddIncomingText(inMsg, &pbuf[beginAt]);
                  beginAt = i+1;
               }
               prevCharWasCarriageReturn = (nextChar == '\r');
            }
            if (beginAt < (int32)filteredBytesRead) inMsg = AddIncomingText(inMsg, &pbuf[beginAt]);
            if (inMsg()) 
            {
               (void) inMsg()->AddFlat(PR_NAME_PACKET_REMOTE_LOCATION, sourceIAP);
               receiver.CallMessageReceivedFromGateway(inMsg);
               inMsg.Reset();
            }
            ret += bytesRead;
         }
         else return ret;
      }
   }
   else
   {
      // Stream-IO implementation
      const int32 bytesRead = GetDataIO()()->Read(buf, muscleMin(maxBytes, (uint32)(sizeof(buf)-1)));
      if (bytesRead < 0)
      {
         FlushInput(receiver);
         return -1;
      }
      if (bytesRead > 0)
      {
         uint32 filteredBytesRead = bytesRead;
         FilterInputBuffer(buf, filteredBytesRead, sizeof(buf)-1);
         ret += filteredBytesRead;
         buf[filteredBytesRead] = '\0';

         MessageRef inMsg;  // demand-allocated
         int32 beginAt = 0;
         for (uint32 i=0; i<filteredBytesRead; i++)
         {
            char nextChar = buf[i];
            if ((nextChar == '\r')||(nextChar == '\n'))
            {
               buf[i] = '\0';  // terminate the string here
               if ((nextChar == '\r')||(_prevCharWasCarriageReturn == false)) inMsg = AddIncomingText(inMsg, &buf[beginAt]);
               beginAt = i+1;
            }
            _prevCharWasCarriageReturn = (nextChar == '\r');
         }
         if (beginAt < (int32)filteredBytesRead)
         {
            if (_flushPartialIncomingLines) inMsg = AddIncomingText(inMsg, &buf[beginAt]);
                                       else _incomingText += &buf[beginAt];
         }
         if (inMsg()) receiver.CallMessageReceivedFromGateway(inMsg);
      }
   }
   return ret;
}