static status_t WriteOutgoingData(const String & desc, DataIO & writeIO, const SocketMultiplexer & multiplexer, Queue<ByteBufferRef> & outQ, uint32 & writeIdx) { if (multiplexer.IsSocketReadyForWrite(writeIO.GetWriteSelectSocket().GetFileDescriptor())) { while(outQ.HasItems()) { ByteBufferRef & firstBuf = outQ.Head(); uint32 bufSize = firstBuf()->GetNumBytes(); if (writeIdx >= bufSize) { outQ.RemoveHead(); writeIdx = 0; } else { int32 ret = writeIO.Write(firstBuf()->GetBuffer()+writeIdx, firstBuf()->GetNumBytes()-writeIdx); if (ret > 0) { writeIO.FlushOutput(); LogTime(MUSCLE_LOG_TRACE, "Wrote " INT32_FORMAT_SPEC " bytes to %s:\n", ret, desc()); LogHexBytes(MUSCLE_LOG_TRACE, firstBuf()->GetBuffer()+writeIdx, ret); writeIdx += ret; } else if (ret < 0) LogTime(MUSCLE_LOG_ERROR, "Error, writeIO.Write() returned %i\n", ret); } } } return B_NO_ERROR; }
// This program is equivalent to the portableplaintext client, except // that we communicate with a child process instead of a socket. int main(int argc, char ** argv) { CompleteSetupSystem css; if (argc < 3) PrintUsageAndExit(); const uint32 numProcesses = atol(argv[1]); if (numProcesses == 0) PrintUsageAndExit(); const char * cmd = argv[2]; Hashtable<String,String> testEnvVars; (void) testEnvVars.Put("Peanut Butter", "Jelly"); (void) testEnvVars.Put("Jelly", "Peanut Butter"); (void) testEnvVars.Put("Oranges", "Grapes"); Queue<DataIORef> refs; for (uint32 i=0; i<numProcesses; i++) { ChildProcessDataIO * dio = new ChildProcessDataIO(false); refs.AddTail(DataIORef(dio)); printf("About To Launch child process #" UINT32_FORMAT_SPEC ": [%s]\n", i+1, cmd); fflush(stdout); ConstSocketRef s = (dio->LaunchChildProcess(argc-2, ((const char **) argv)+2, ChildProcessLaunchFlags(MUSCLE_DEFAULT_CHILD_PROCESS_LAUNCH_FLAGS), NULL, &testEnvVars) == B_NO_ERROR) ? dio->GetReadSelectSocket() : ConstSocketRef(); printf("Finished Launching child process #" UINT32_FORMAT_SPEC ": [%s]\n", i+1, cmd); fflush(stdout); if (s() == NULL) { LogTime(MUSCLE_LOG_CRITICALERROR, "Error launching child process #" UINT32_FORMAT_SPEC " [%s]!\n", i+1, cmd); return 10; } } StdinDataIO stdinIO(false); PlainTextMessageIOGateway stdinGateway; QueueGatewayMessageReceiver stdinInputQueue; stdinGateway.SetDataIO(DataIORef(&stdinIO, false)); SocketMultiplexer multiplexer; for (uint32 i=0; i<refs.GetNumItems(); i++) { printf("------------ CHILD PROCESS #" UINT32_FORMAT_SPEC " ------------------\n", i+1); PlainTextMessageIOGateway ioGateway; ioGateway.SetDataIO(refs[i]); ConstSocketRef readSock = refs[i]()->GetReadSelectSocket(); QueueGatewayMessageReceiver ioInputQueue; while(1) { int readFD = readSock.GetFileDescriptor(); multiplexer.RegisterSocketForReadReady(readFD); const int writeFD = ioGateway.HasBytesToOutput() ? refs[i]()->GetWriteSelectSocket().GetFileDescriptor() : -1; if (writeFD >= 0) multiplexer.RegisterSocketForWriteReady(writeFD); const int stdinFD = stdinIO.GetReadSelectSocket().GetFileDescriptor(); multiplexer.RegisterSocketForReadReady(stdinFD); if (multiplexer.WaitForEvents() < 0) printf("testchildprocess: WaitForEvents() failed!\n"); // First, deliver any lines of text from stdin to the child process if ((multiplexer.IsSocketReadyForRead(stdinFD))&&(stdinGateway.DoInput(ioGateway) < 0)) { printf("Error reading from stdin, aborting!\n"); break; } const bool reading = multiplexer.IsSocketReadyForRead(readFD); const bool writing = ((writeFD >= 0)&&(multiplexer.IsSocketReadyForWrite(writeFD))); const bool writeError = ((writing)&&(ioGateway.DoOutput() < 0)); const bool readError = ((reading)&&(ioGateway.DoInput(ioInputQueue) < 0)); if ((readError)||(writeError)) { printf("Connection closed, exiting.\n"); break; } MessageRef incoming; while(ioInputQueue.RemoveHead(incoming) == B_NO_ERROR) { printf("Heard message from server:-----------------------------------\n"); const char * inStr; for (int i=0; (incoming()->FindString(PR_NAME_TEXT_LINE, i, &inStr) == B_NO_ERROR); i++) printf("Line %i: [%s]\n", i, inStr); printf("-------------------------------------------------------------\n"); } if ((reading == false)&&(writing == false)) break; multiplexer.RegisterSocketForReadReady(readFD); if (ioGateway.HasBytesToOutput()) multiplexer.RegisterSocketForWriteReady(writeFD); } if (ioGateway.HasBytesToOutput()) { printf("Waiting for all pending messages to be sent...\n"); while((ioGateway.HasBytesToOutput())&&(ioGateway.DoOutput() >= 0)) {printf ("."); fflush(stdout);} } } printf("\n\nBye!\n"); return 0; }
// This is a text based test client for the muscled server. It is useful for testing // the server, and could possibly be useful for other things, I don't know. int main(int argc, char ** argv) { CompleteSetupSystem css; String hostName; uint16 port = 2960; if (argc > 1) ParseConnectArg(argv[1], hostName, port, false); ConstSocketRef sock = Connect(hostName(), port, "portablereflectclient", false); if (sock() == NULL) return 10; // We'll receive plain text over stdin StdinDataIO stdinIO(false); PlainTextMessageIOGateway stdinGateway; stdinGateway.SetDataIO(DataIORef(&stdinIO, false)); // And send and receive flattened Message objects over our TCP socket TCPSocketDataIO tcpIO(sock, false); MessageIOGateway tcpGateway; tcpGateway.SetDataIO(DataIORef(&tcpIO, false)); DataIORef networkIORef(&tcpIO, false); AbstractMessageIOGatewayRef gatewayRef(&tcpGateway, false); #ifdef MUSCLE_ENABLE_SSL for (int i=1; i<argc; i++) { const char * a = argv[i]; if (strncmp(a, "publickey=", 10) == 0) { a += 10; // skip past the 'publickey=' part SSLSocketDataIO * sslIO = new SSLSocketDataIO(sock, false, false); DataIORef sslIORef(sslIO); if (sslIO->SetPublicKeyCertificate(a) == B_NO_ERROR) { LogTime(MUSCLE_LOG_INFO, "Using public key certificate file [%s] to connect to server\n", a); networkIORef = sslIORef; gatewayRef.SetRef(new SSLSocketAdapterGateway(gatewayRef)); gatewayRef()->SetDataIO(networkIORef); } else { LogTime(MUSCLE_LOG_CRITICALERROR, "Couldn't load public key certificate file [%s] (file not found?)\n", a); return 10; } } } #endif SocketMultiplexer multiplexer; QueueGatewayMessageReceiver stdinInQueue, tcpInQueue; bool keepGoing = true; uint64 nextTimeoutTime = MUSCLE_TIME_NEVER; while(keepGoing) { const int stdinFD = stdinIO.GetReadSelectSocket().GetFileDescriptor(); const int socketReadFD = networkIORef()->GetReadSelectSocket().GetFileDescriptor(); const int socketWriteFD = networkIORef()->GetWriteSelectSocket().GetFileDescriptor(); multiplexer.RegisterSocketForReadReady(stdinFD); multiplexer.RegisterSocketForReadReady(socketReadFD); if (gatewayRef()->HasBytesToOutput()) multiplexer.RegisterSocketForWriteReady(socketWriteFD); if (multiplexer.WaitForEvents(nextTimeoutTime) < 0) printf("portablereflectclient: WaitForEvents() failed!\n"); const uint64 now = GetRunTime64(); if (now >= nextTimeoutTime) { // For OpenSSL testing: Generate some traffic to the server every 50mS printf("Uploading timed OpenSSL-tester update at time " UINT64_FORMAT_SPEC "\n", now); MessageRef stateMsg = GetMessageFromPool(); stateMsg()->AddString("username", "portablereflectclient"); stateMsg()->AddPoint("position", Point((rand()%100)/100.0f, (rand()%100)/100.0f)); stateMsg()->AddInt32("color", -1); MessageRef uploadMsg = GetMessageFromPool(PR_COMMAND_SETDATA); uploadMsg()->AddMessage("qt_example/state", stateMsg); gatewayRef()->AddOutgoingMessage(uploadMsg); nextTimeoutTime = now + MillisToMicros(50); } // Receive data from stdin if (multiplexer.IsSocketReadyForRead(stdinFD)) { while(1) { const int32 bytesRead = stdinGateway.DoInput(stdinInQueue); if (bytesRead < 0) { printf("Stdin closed, exiting!\n"); keepGoing = false; break; } else if (bytesRead == 0) break; // no more to read } } // Handle any input lines that were received from stdin MessageRef msgFromStdin; while(stdinInQueue.RemoveHead(msgFromStdin) == B_NO_ERROR) { const String * st; for (int32 i=0; msgFromStdin()->FindString(PR_NAME_TEXT_LINE, i, &st) == B_NO_ERROR; i++) { const char * text = st->Cstr(); printf("You typed: [%s]\n", text); bool send = true; MessageRef ref = GetMessageFromPool(); const char * arg1 = (st->Length()>2) ? &text[2] : NULL; switch(text[0]) { case 'm': ref()->what = MAKETYPE("umsg"); if (arg1) ref()->AddString(PR_NAME_KEYS, arg1); ref()->AddString("info", "This is a user message"); break; case 'i': ref()->what = PR_COMMAND_PING; ref()->AddString("Test ping", "yeah"); break; case 's': { ref()->what = PR_COMMAND_SETDATA; MessageRef uploadMsg = GetMessageFromPool(MAKETYPE("HELO")); uploadMsg()->AddString("This node was posted at: ", GetHumanReadableTimeString(GetRunTime64())); if (arg1) ref()->AddMessage(arg1, uploadMsg); } break; case 'k': ref()->what = PR_COMMAND_KICK; if (arg1) ref()->AddString(PR_NAME_KEYS, arg1); break; case 'b': ref()->what = PR_COMMAND_ADDBANS; if (arg1) ref()->AddString(PR_NAME_KEYS, arg1); break; case 'B': ref()->what = PR_COMMAND_REMOVEBANS; if (arg1) ref()->AddString(PR_NAME_KEYS, arg1); break; case 'g': ref()->what = PR_COMMAND_GETDATA; if (arg1) ref()->AddString(PR_NAME_KEYS, arg1); break; case 'G': ref()->what = PR_COMMAND_GETDATATREES; if (arg1) ref()->AddString(PR_NAME_KEYS, arg1); ref()->AddString(PR_NAME_TREE_REQUEST_ID, "Tree ID!"); break; case 'q': keepGoing = send = false; break; case 'p': ref()->what = PR_COMMAND_SETPARAMETERS; if (arg1) ref()->AddString(arg1, ""); break; case 'P': ref()->what = PR_COMMAND_GETPARAMETERS; break; case 'L': { // simulate the behavior of qt_example, for testing OpenSSL problem ref()->what = PR_COMMAND_SETPARAMETERS; ref()->AddBool("SUBSCRIBE:qt_example/state", true); printf("Starting OpenSSL problem test...\n"); nextTimeoutTime = 0; } break; case 'x': { ref()->what = PR_COMMAND_SETPARAMETERS; StringQueryFilter sqf("sc_tstr", StringQueryFilter::OP_SIMPLE_WILDCARD_MATCH, "*Output*"); ref()->AddArchiveMessage("SUBSCRIBE:/*/*/csproj/default/subcues/*", sqf); } break; case 'd': ref()->what = PR_COMMAND_REMOVEDATA; if (arg1) ref()->AddString(PR_NAME_KEYS, arg1); break; case 'D': ref()->what = PR_COMMAND_REMOVEPARAMETERS; if (arg1) ref()->AddString(PR_NAME_KEYS, arg1); break; case 't': { // test all data types ref()->what = 1234; ref()->AddString("String", "this is a string"); ref()->AddInt8("Int8", 123); ref()->AddInt8("-Int8", -123); ref()->AddInt16("Int16", 1234); ref()->AddInt16("-Int16", -1234); ref()->AddInt32("Int32", 12345); ref()->AddInt32("-Int32", -12345); ref()->AddInt64("Int64", 123456789); ref()->AddInt64("-Int64", -123456789); ref()->AddBool("Bool", true); ref()->AddBool("-Bool", false); ref()->AddFloat("Float", 1234.56789f); ref()->AddFloat("-Float", -1234.56789f); ref()->AddDouble("Double", 1234.56789); ref()->AddDouble("-Double", -1234.56789); ref()->AddPointer("Pointer", ref()); ref()->AddFlat("Flat", *ref()); char data[] = "This is some data"; ref()->AddData("Flat", B_RAW_TYPE, data, sizeof(data)); } break; default: printf("Sorry, wot?\n"); send = false; break; } if (send) { printf("Sending message...\n"); ref()->PrintToStream(); gatewayRef()->AddOutgoingMessage(ref); } } } // Handle input and output on the TCP socket const bool reading = multiplexer.IsSocketReadyForRead(socketReadFD); const bool writing = multiplexer.IsSocketReadyForWrite(socketWriteFD); const bool writeError = ((writing)&&(gatewayRef()->DoOutput() < 0)); const bool readError = ((reading)&&(gatewayRef()->DoInput(tcpInQueue) < 0)); if ((readError)||(writeError)) { printf("Connection closed (%s), exiting.\n", writeError?"Write Error":"Read Error"); keepGoing = false; } MessageRef msgFromTCP; while(tcpInQueue.RemoveHead(msgFromTCP) == B_NO_ERROR) { printf("Heard message from server:-----------------------------------\n"); msgFromTCP()->PrintToStream(); printf("-------------------------------------------------------------\n"); } } if (gatewayRef()->HasBytesToOutput()) { printf("Waiting for all pending messages to be sent...\n"); while((gatewayRef()->HasBytesToOutput())&&(gatewayRef()->DoOutput() >= 0)) {printf ("."); fflush(stdout);} } printf("\n\nBye!\n"); return 0; }
void HandleSession(const ConstSocketRef & sock, bool myTurnToThrow, bool doFlush) { LogTime(MUSCLE_LOG_ERROR, "Beginning catch session (%s)\n", doFlush?"flush enabled":"flush disabled"); TCPSocketDataIO sockIO(sock, false); uint64 lastThrowTime = 0; uint8 ball = 'B'; // this is what we throw back and forth over the TCP socket! uint64 min=((uint64)-1), max=0; uint64 lastPrintTime = 0; uint64 count = 0; uint64 total = 0; SocketMultiplexer multiplexer; while(1) { int fd = sock.GetFileDescriptor(); multiplexer.RegisterSocketForReadReady(fd); if (myTurnToThrow) multiplexer.RegisterSocketForWriteReady(fd); if (multiplexer.WaitForEvents() < 0) { LogTime(MUSCLE_LOG_ERROR, "WaitForEvents() failed, aborting!\n"); break; } if ((myTurnToThrow)&&(multiplexer.IsSocketReadyForWrite(fd))) { int32 bytesWritten = sockIO.Write(&ball, sizeof(ball)); if (bytesWritten == sizeof(ball)) { if (doFlush) sockIO.FlushOutput(); // nagle's algorithm gets toggled here! lastThrowTime = GetRunTime64(); myTurnToThrow = false; // we thew the ball, now wait to catch it again! } else if (bytesWritten < 0) { LogTime(MUSCLE_LOG_ERROR, "Error sending ball, aborting!\n"); break; } } if (multiplexer.IsSocketReadyForRead(fd)) { int32 bytesRead = sockIO.Read(&ball, sizeof(ball)); if (bytesRead == sizeof(ball)) { if (myTurnToThrow == false) { if (lastThrowTime > 0) { uint64 elapsedTime = GetRunTime64() - lastThrowTime; count++; total += elapsedTime; min = muscleMin(min, elapsedTime); max = muscleMax(max, elapsedTime); if (OnceEvery(MICROS_PER_SECOND, lastPrintTime)) LogTime(MUSCLE_LOG_INFO, "count=" UINT64_FORMAT_SPEC" min=" UINT64_FORMAT_SPEC "us max=" UINT64_FORMAT_SPEC "us avg=" UINT64_FORMAT_SPEC "us\n", count, min, max, total/count); } myTurnToThrow = true; // we caught the ball, now throw it back! } } else if (bytesRead < 0) { LogTime(MUSCLE_LOG_ERROR, "Error reading ball, aborting!\n"); break; } } } }