Winsock IRC client connects but does not send data - visual-studio-2010

I'm using the code posted on http://social.msdn.microsoft.com/Forums/en/vcgeneral/thread/126639f1-487d-4755-af1b-cfb8bb64bdf8 but it doesn't send data just like it says in the first post. How do I use WSAGetLastError() like it says in the solution to find out what's wrong?
I tried the following:
void IRC::SendBuf(char* sendbuf)
{
int senderror = send(m_socket, sendbuf, sizeof(sendbuf), MSG_OOB);
if(senderror == ERROR_SUCCESS) {
printf("Client: The test string sent: \"%s\"\n", sendbuf);
}
else {
cout << "error is: " << senderror << ", WSAGetLastError: " << WSAGetLastError() << endl;
printf("Client: The test string sent: \"%s\"\n", sendbuf);
}
}
And the output is: error is: 4, WSAGetLastError: 0

You're evaluating the address of WSAGetLastError instead of calling it. You need to add parenthesis in order to actually call that function:
void IRC::SendBuf(char* sendbuf)
{
int senderror = send(m_socket, sendbuf, strlen(sendbuf), 0);
if (senderror != SOCKET_ERROR) {
printf("Client: The test string sent: \"%s\"\n", sendbuf);
} else {
cout << "Error is: " << WSAGetLastError() << endl;
}
}
EDIT: The send() function returns the number of bytes written, not an error code. You need to test the return value against SOCKET_ERROR, as in the updated code above. In your case, send() tells that it successfully sent 4 bytes.
As you noted below, it only sends 4 bytes because that's the size of the sendbuf variable (it's a pointer, not a buffer). If the string in sendbuf is null-terminated, you can use strlen() instead. If it isn't, you probably should add a string length parameter to IRC::SendBuf() itself.

Related

What's the order of use of Win32 APIs for Server-client Pipe comm. in C++ (CreateNamedPipe, WriteFile, CreateFile, ReadFile)

I am trying to write a server/client program in C++, in Visual Studio 2019, using Win32 APIs.
This is the referred documentation: Named Pipe Open Modes
I have used 4 APIs:
On the server side (the one creating the pipe and writing to it): CreateNamedPipe(), WriteFile()
On the client side (the one connecting and reading from the pipe): CreateFile(), ReadFile()
However, I observe the server is NOT able to write to the pipe.
Following is the code I have used.
Servermain.cpp
#include <iostream>
#include <windows.h>
using namespace std;
void namedPipeServer()
{
HANDLE hPipeServer;
char Wbuffer[1024] = "Hello, from the pipe server!";
DWORD dwWrite;
BOOL writeSuccessFlag;
//Create a named pipe
hPipeServer = CreateNamedPipe(
TEXT("\\\\.\\pipe\\Agentpipe"), //lpName
PIPE_ACCESS_OUTBOUND, //dwOpenMode
PIPE_TYPE_BYTE, //dwPipeMode
1, //nMaxInstances
1024 * 16, //nOutBufferSize
1024 * 16, //nInBufferSize
NMPWAIT_USE_DEFAULT_WAIT, //nDefaultTimeOut
NULL); //lpSecurityAttributes
cout << "Inside namedPipeServer()" << endl;
if (hPipeServer != INVALID_HANDLE_VALUE)
{
cout << "Just writing to pipe" << endl;
writeSuccessFlag = WriteFile(
hPipeServer, //HANDLE hFile
Wbuffer, //LPCVOID lpBuffer
30, //DWORD nNumberOfBytesToWrite
&dwWrite,
NULL //LPOVERLAPPED lpOverlapped
);
if (writeSuccessFlag)
{
cout << "Server has written to pipe!" << endl;
}
else
{
cout << "Unsuccessful write to pipe, From Agent" << endl;
}
}
else
{
cout << "Unsuccesful pipe connection. hPipeServer: " << hPipeServer << endl;
}
}
int main()
{
cout << "Inside Agent server. Creating a named pipe.\n" << endl;
namedPipeServer();
while (1);
return 0;
}
Clientmain.cpp:
#include <iostream>
#include <windows.h>
using namespace std;
void readFromPipe()
{
HANDLE hPipeClient;
char rBuffer[1024];
DWORD dwRead;
BOOL readSuccessFlag = 0;
//Connect to the server pipe: \\.\\pipe\\Agentpipe
cout << "Inside readFromPipe()." << endl;
hPipeClient = CreateFile(
TEXT("\\\\.\\pipe\\Agentpipe"), //lpFileName
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
NULL,
NULL
);
while (hPipeClient != INVALID_HANDLE_VALUE)
{
cout << "Just connecting to pipe" << endl;
readSuccessFlag = ReadFile(
hPipeClient, //HANDLE hFile,
rBuffer, //LPVOID lpBuffer,
30, //DWORD nNumberOfBytesToRead,
&dwRead, //LPDWORD lpNumberOfBytesRead,
NULL //LPOVERLAPPED lpOverlapped
);
if (readSuccessFlag)
{
cout << "Client has read from pipe of Agent!" << endl;
cout << "From Agent Pipe: " << rBuffer << endl;
}
else
{
cout << "Unsuccessful Pipe read!" << endl;
}
}
if(hPipeClient == INVALID_HANDLE_VALUE)
{
cout << "Unsuccesful pipe connection at client end. hPipeClient: " << hPipeClient << endl;
}
}
int main()
{
cout << "Inside the client. Calling readFromPipe()" << endl;
readFromPipe();
while (1);
return 0;
}
When the above program is executed, it shows that the server is NOT able to write to the pipe, and the output on the server-side is:
Inside Agent server. Creating a named pipe.
Inside namedPipeServer()
Just writing to pipe
Unsuccessful write to pipe, From Agent
Output on the client console is:
Inside the client. Calling readFromPipe()
Inside readFromPipe().
Just connecting to pipe
Upon looking into the sample program in the Win32 documentation, I have observed that the order of use of these Win32 APIs is different, that looks like below:
Pipe Server program:
main(){
...
namedPipeServer()
...
}
void namedPipeServer()
{
...
CreateFile()
WriteFile()
...
}
Pipe Client program:
main(){
...
readFromPipe()
...
}
void readFromPipe()
{
...
CreateNamedPipe()
ReadFile()
...
}
I would be happy if anyone can provide me with clarity on the use of CreateNamedPipe() & CreateFile() especially.
Does the server have to use CreateFile() first (to create the pipe, before writing to it), or can I use CreateNamedPipe()?
Is the order of use of the APIs in MY program posted incorrect? If it is, please specify why.

C++ empty() and all_of() for checking string is empty or have only digit

I'm creating an IO console application and at the inputs i got an 'while' loop with two condition
empty() and all_of(), the function all_of() seems to work properly but when i press enter the empty() function not working and just let me to input the next thing in the 'struct'. I'm not sure am i doing it correct..There is the part of the code
cout << "Enter age: ";
getline(cin, age_str);
while(!age_str.empty() && !all_of(age_str.begin(), age_str.end(), ::isdigit)){
cout << "--Please Enter an integer-- " << endl;
cin.clear();
getline(cin, age_str);
}
stringstream(age_str) >> person_arr[n].age;
There are a link to the full code : enter link description here
The logic of the conditional of the while is incorrect.
What you need to do is:
If the line is empty, get the next line.
If the line is not empty and the line has anything other than digits, get the next line.
!age_str.empty() && !all_of(age_str.begin(), age_str.end(), ::isdigit) does not do that.
You need to use age_str.empty() || (!all_of(age_str.begin(), age_str.end(), ::isdigit))
I always recommend, when in doubt, simplify.
while ( !is_input_valid(age_str)) )
{
...
}
where
bool is_input_valid(std::string const& input)
{
if ( input.empty() )
{
return false;
}
return std::all_of(input.begin(), input.end(), ::isdigit);
}

Full duplex named pipe lockup when written to

I'm trying to use one NamedPipe for bi-direction IPC. In my mind (and I can't find more information on MSDN), one full-duplex pipe would be sufficient. Here's my code.
//Compiled with these commands during my test:
//g++ -DCLIENT -o client.exe xxx.cpp
//g++ -DSERVER -o server.exe xxx.cpp
#include <iostream>
#include <windows.h>
using namespace std;
DWORD WINAPI ReadingThread(LPVOID a)
{
HANDLE pipe = (HANDLE)a;
BOOL result;
char buffer[256];
DWORD numBytesRead;
while (true)
{
result = ReadFile(pipe, buffer, sizeof(buffer) - 1, &numBytesRead, NULL);
if (result)
{
buffer[numBytesRead] = 0;
cout << "[Thread] Number of bytes read: " << numBytesRead << endl;
cout << "[Thread] Message: " << endl
<< buffer << endl
<< endl;
}
else
{
cout << "[Thread] Failed to read data from the pipe. err=" << GetLastError() << endl;
break;
}
}
return 0;
}
int main(int argc, const char **argv)
{
#ifdef CLIENT
cout << "[Main] Connecting to pipe..." << endl;
HANDLE pipe = CreateFileA("\\\\.\\pipe\\PipeTest", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
#else
cout << "[Main] Creating an instance of a named pipe..." << endl;
HANDLE pipe = CreateNamedPipeA("\\\\.\\pipe\\PipeTest", PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE, 1, 0, 0, 0, NULL);
#endif
if (pipe == NULL || pipe == INVALID_HANDLE_VALUE)
{
cout << "[Main] Failed to acquire pipe handle." << endl;
return 1;
}
#ifdef CLIENT
#else
cout << "[Server] Waiting for a client to connect to the pipe..." << endl;
BOOL result = ConnectNamedPipe(pipe, NULL);
if (!result)
{
cout << "[Server] Failed to make connection on named pipe." << endl;
CloseHandle(pipe);
return 1;
}
cout << "[Server] Client is here!" << endl;
{
const char *buf = "Hello pipe!\n";
WriteFile(pipe, buf, strnlen(buf, 30), 0, 0);
}
#endif
CreateThread(0, 0, ReadingThread, pipe, 0, 0);
cout << "[Main] Ready to send data." << endl;
while (true)
{
char buffer[128];
DWORD numBytesWritten = 0;
BOOL result;
cin >> buffer;
if (!strcmp(buffer, "q"))
{
break;
}
cout << "[Main] Writing data to pipe..." << endl;
result = WriteFile(pipe, buffer, strnlen(buffer, _countof(buffer)), &numBytesWritten, 0);
if (result)
{
cout << "[Main] Written " << numBytesWritten << " bytes to the pipe." << endl;
}
else
{
cout << "[Main] Failed to write data to the pipe. err=" << GetLastError() << endl;
}
}
CloseHandle(pipe);
cout << "[Main] Done." << endl;
return 0;
}
I can get the "Hello pipe!" message from server-side to client-side. And I'm expecting to type some string on either program's terminal and press enter, and see it on the other side.
However after the hello message, both program will stuck on the WriteFile call. Meanwhile the thread is stuck at the ReadFile call. How can I make it work, or did I left something out?
when file created for synchronous I/O (flag FO_SYNCHRONOUS_IO present in FILE_OBJECT ) all I/O operations on file is serialized - new operation will be wait in I/O manager before passed to driver, until current(if exist) not complete. in concurrent can execute only single I/O request. if we do blocked read in dedicated thread - all another I/O request on this file will be blocked until read not complete. this related not only to write. even query file name/attributes will block here. as result render reading in separate not help here - we block on first write attemp. solution here use asynchronous files - this let any count of I/O operation execute in concurrent.
Named Pipes in Windows are HALF DUPLEX. As demonstrated on Windows 10. The MSDN Documentation is Wrong. A request has been submitted to Microsoft to correct their documentation.
While a pipe can be opened on the client to be "Generic Read | Generic Write" you can NOT do both at the same time.
And Overlapped IO submitted after the First Overlapped IO will break the pipe.
You can submit overlapped io. Then Wait for it to finish. Then submit the next overlapped io. You can not simultaneously Submit overlapped Reads AND overlapped Writes.
This is by definition, "Half Duplex".

Constructing an object as part of ostream output

For a class declaration as below:
class A{
public:
A(int);
~A()
private:
int a;
};
And a constructor definition as follows:
A::A(int i){
a = i;
cout << a << endl;
}
I would like to do something like this from main():
int main(){
int i;
//user input for value
//stored inside i
cout << "The value is " << A obj(i);
return 0;
}
I now get the following error for the above code in main():
error: 'A' does not refer to a value
What is the cause of this error?
You cannot declare obj and output it on the same line. If you want obj to remain available after printing, do this:
A obj(i);
cout << "The value is " << obj;
Otherwise, skip obj in favor of a temporary object:
cout << "The value is " << A(i);
You cannot have a declaration in the middle of another line.
What you can do is create an A on the fly with casting (A) i, or simply A(i), this will cast the int i into an A, and then send it to cout. The temporary A object is then directly discarded.
If you want to keep it, you have to declare a name for it, in its own statement.
You need to first output the message "The value is " on first code line. On the second code line you create the object obj of type A which will output the i.
int main()
{
int i;
cout << "The value is ";
A obj(i);
return 0;
}

Accessing return by pointer out of function

I have the following function
std::tuple<int,val*>Socket::recv(val* values ) // const
{
char buf [ MAXRECV + 1 ];
memset ( buf, 0, MAXRECV + 1 );
int status = ::recv ( m_sock, buf, MAXRECV, 0 );
if ( status == -1 )
{
std::cout << "status == -1 errno == " << errno << " in Socket::recv\n";
// return std::make_tuple(0,NULL);//this is not working
}
else if ( status == 0 )
{
//return std::make_tuple(0,NULL); //this is not working
}
else
{
struct val* values=(struct val*) buf;
if(!std::isnan(values->val1) &&
!std::isnan(values->val2) &&
!std::isnan(values->val3) &&
!std::isnan(values->val4),
!std::isnan(values->val5),
!std::isnan(values->val6))
printf("received:%f %f %f %f %f %f\n", values->val1, values->val2,
values->val3, values->val4, values->val5, values->val6);
return std::make_tuple(status,values);
}
}
The received values are printed out in to standard output correctly within the function.
But when I try to access these received values out of the function by calling as follows what I get is all 0's.[after creating Socket rcvd object]
Would you tell me how to access these values outside the function?
1.
std::cout << std::get<1>(rcvd.recv(&values)->val1)
<< std::get<1>(rcvd.recv(&values)->val2)
<< std::get<1>(rcvd.recv(&values)->val3)
<< std::get<1>(rcvd.recv(&values)->val4)
<< std::get<1>(rcvd.recv(&values)->val5)
<< std::get<1>(rcvd.recv(&values)->val6)
<< std::endl;
2.
std::cout << std::get<1>(rcvd.recv(&values).val1)
<< std::get<1>(rcvd.recv(&values).val2)
<< std::get<1>(rcvd.recv(&values).val3)
<< std::get<1>(rcvd.recv(&values).val4)
<< std::get<1>(rcvd.recv(&values).val5)
<< std::get<1>(rcvd.recv(&values).val6)
<< std::endl;
3.
std::cout << std::get<1>(rcvd.recv(&values)[0])
<< std::get<1>(rcvd.recv(&values)[1])
<< std::get<1>(rcvd.recv(&values)[2])
<< std::get<1>(rcvd.recv(&values)[3])
<< std::get<1>(rcvd.recv(&values)[4])
<< std::get<1>(rcvd.recv(&values)[5])
<< std::endl;
where "values" comes from
struct val {
val1;
val2;
val3;
val4;
val5;
val6;} values;
All the three options of calling the function or access the struct val could not work for me.
Would you tell me
how to access these received values externally from any function?
how to return zero to struct pointer [NULL is not working ] when status is 0 or -1
Try
return std::make_tuple<int, val*>(0, nullptr);
The type of tuple is deduced from arguments, so by using 0,NULL you are actually using the null constant wich is evaluted to 0 and hence deduced type is <int,int>.
By the way, I see no reason for using NULL in C++11, if you need that really for some reason then cast NULL to val*
static_cast<val*>(NULL);
EDIT:
Other viable alternatives are
val* nullval = nullptr;
return std::make_tuple(0, nullval);
Or
return std::make_tuple(0, static_cast<val*>(nullptr));
Or (as comment suggest)
return {0, nullptr};
Choose the one that seems more clear to you.
You are lucky that the outside function is printing zeroes. It might have as well just dumped the core on you :)
What you are doing is accessing a buffer, that was created on a stack, after that stack was released (once the function's execution finished). That is HIGHLY UNSAFE and, pretty much, illegal.
Instead what you should do is allocate your data buffer in a 'free memory", using functions like malloc (in C) or operator new/new[] (in C++).
The quick fix is to replace the line
char buf [ MAXRECV + 1 ];
with
char * buf = new char [ MAXRECV + 1 ];
And when you do a type casting on line
struct val* values=(struct val*) buf;
you really ought to be sure that what you do is correct. If the sizeof() of you struct val is more than the sizeof(char[MAXRECV + 1]) you'll get in memory access troubles.
After you are done using the returned data buffer don't forget to release it with a call to free (in C) or delete/delete[] (in C++). Otherwise you'd have what is called a memory leak.

Resources