When attempting to read UDP packets using recvfrom the function returns -1 indicating an error. I of course then call WSAGetLastError to find out what the problem is. The reported error number is 183. I cant seem to find any reference as to what that number means.
Edit:
while (bytesRecv != SOCKET_ERROR)
{
// get data from the server
bytesRecv = recvfrom(m_socket, (char*)&receiveData, sizeof(ReceiveData), 0, (struct sockaddr *) &server_addr, &server_addr_len);
logError("Bytes recieved: ", bytesRecv);
// if data was recieved from the server
if (bytesRecv > 0)
{
//Data packet processing code
}
else
{
if (bytesRecv == SOCKET_ERROR)
{
logError("Error: Reading data: ", WSAGetLastError());
}
}
}
Edit:
void logError(const std::string &text, int errorCode)
{
std::ofstream log_file("error_log_file.txt", std::ios_base::out | std::ios_base::app);
log_file << text << errorCode << "\n";
}
The problem is not with WSAGetLastError() itself. The real problem is that you are calling logError() before calling WSAGetLastError(), and logError() ends up resetting the last error code to 183.
logError() uses a std::ofstream to open a file for appending. On Windows, that operation will ultimately call CreateFile() with the OPEN_ALWAYS flag, for which its documentation states:
Opens a file, always.
If the specified file exists, the function succeeds and the last-error code is set to ERROR_ALREADY_EXISTS (183).
If the specified file does not exist and is a valid path to a writable location, the function creates a file and the last-error code is set to zero.
...
If the function fails, the return value is INVALID_HANDLE_VALUE. To get extended error information, call GetLastError.
Internally, WSAGetLastError() simply maps to GetLastError() (a well-known but undocumented implementation detail). So, no matter whether the CreateFile() succeeds or fails in opening the file, the error code reported by WSAGetLastError() will get reset to the result of the open operation.
Your call to logError() is in the wrong place. It needs to be moved inside of your if (bytesRecv > 0) block (BTW, UDP supports 0-length datagrams, so you should be using >= instead of >):
while (true)
{
// get data from the server
bytesRecv = recvfrom(m_socket, (char*)&receiveData, sizeof(ReceiveData), 0, (struct sockaddr *) &server_addr, &server_addr_len);
// if data was received from the server
if (bytesRecv >= 0)
{
logError("Bytes received: ", bytesRecv); // <-- moved here!!!
//Data packet processing code
}
else // if (bytesRecv == SOCKET_ERROR)
{
logError("Error: Reading data: ", WSAGetLastError());
break;
}
}
Alternatively:
while (true)
{
// get data from the server
bytesRecv = recvfrom(m_socket, (char*)&receiveData, sizeof(ReceiveData), 0, (struct sockaddr *) &server_addr, &server_addr_len);
// if data was received from the server
if (bytesRecv == SOCKET_ERROR)
{
logError("Error: Reading data: ", WSAGetLastError());
break;
}
logError("Bytes received: ", bytesRecv); // <-- moved here!!!
//Data packet processing code
}
Related
Ive been trying to build an SNMP trap receiver using C++ and the winsock2 library, I have a thread set up to receive UDP data across port 161... as you would expect, when using a python socket program that i quickly threw together i was able to receive UTF-8 encoded strings and print them to the console. However, when i tried generating a SNMP Trap test event using iDRAC-9 (Dell server remote management tool), i managed to receive the 400 bytes as expected, but only printed 0é☺î☻☺. Frustratingly, the recvfrom() function can only take a char * parameter to receive the data. Im hoping to be able to decode roughly the same detail of data that Wireshark is capturing. Any help would be amazing!
code sample below:
int bytes_received = 0;
BYTE serverBuf[1025]{}; //1 Kilobyte + Null Terminating Character
int serverBufLen = 1024;
struct sockaddr_in SenderAddr {};
int SenderAddrSize = sizeof(SenderAddr);
do {
//Recieve Data
bytes_received = recvfrom(serverSocket, (char*)serverBuf, serverBufLen, 0, (SOCKADDR*)&SenderAddr, &SenderAddrSize);
if (bytes_received == SOCKET_ERROR) {
printf("recvfrom failed with error %d\n", WSAGetLastError());
bytes_received = 0;
}
//Make The String Null Terminated
serverBuf[bytes_received] = '\0';
std::cout << "Bytes Received: ";
std::cout << bytes_received << std::endl;
std::cout << serverBuf << std::endl;
//Send Data Back
char sendBuf[] = "Received\0";
if (sendto(serverSocket, sendBuf, (sizeof(sendBuf) - 1), 0, (SOCKADDR*)&SenderAddr, SenderAddrSize) == SOCKET_ERROR) {
printf("Sending back response got an error: %d\n", WSAGetLastError());
}
} while (active);
Wireshark Info
I am writing C++ socket code using Visual Studio Express 2013 in a .dll project. I am at the point where I am getting an error at this sendto function:
/* Send data back */
if (sendto(sd, (const char *)sendBuffer,(int)sizeof(sendBuffer), 0,
(struct sockaddr *)&client, sizeof(client)) ==
SOCKET_ERROR)
{
err = WSAGetLastError();
closesocket(sd);
WSACleanup();
throw std::runtime_error("Error sending datagram.");
}
I know that we can get an error code with WSAGetLastError(), but if I initialize it to a variable I just seem to get junk numbers. How do I extract the sendtoerror? I have unit tests written to test this dll, but I'm not sure if there is a way I can just print out the error.
Edit: So after changing the condition to == not != it no longer fails at sendtobut now fails at
bytes_received = recvfrom(sd, readBuffer, NTP_PACKET_MAX, 0, (struct sockaddr *)&client, &len);
if (bytes_received == SOCKET_ERROR)
{
err = WSAGetLastError();
closesocket(sd);
WSACleanup();
throw std::runtime_error("Could not receive datagram.");
}
Like in the original question, i'm unsure of how to get the proper error. When debugging the recvfrom function, I hover over err and it says the value it holds is 114351196. From what I can see, that is not a valid Windows Socket Error Code.
Couple of bad mistakes in your code
/* Send data back */
if (sendto(sd, (const char *)sendBuffer,(int)sizeof(sendBuffer), 0,
(struct sockaddr *)&client, sizeof(client)) !=
SOCKET_ERROR) // SHOULD BE == (1)
{
throw std::runtime_error("Error sending datagram.");
// UNREACHABLE CODE (2)
closesocket(sd);
WSACleanup();
}
Error 1: Your error block is entered when you are successfully sending. This may mean that your error is uninitialised (it will be the last error value from somewhere else if not). According to the MSDN documentation for WSAGetLastError, the function should be called immediately after your WinSocket operation fails, and only in the those circumstances.
If you call it after a successful operation (which you are doing) then there is no guarantee of what value you will receive. If could be the last error from another WinSocket operation on this thread, it may be 0, it may be some other value. The docs do not state what happens if the error is retrieved when no operations have failed, and so you can think of this as undefined behaviour.
Error 2: After you throw your exception the function will exit immediately. You will not call closesocket or WSACleanup
UPDATE:
I'm guessing that you are checking the value of err in the debugger before you have assigned it any value. You should be doing something along the lines of:
bytes_received = recvfrom(sd, readBuffer, NTP_PACKET_MAX, 0, (struct sockaddr *)&client, &len);
if (bytes_received == SOCKET_ERROR)
{
int err = WSAGetLastError();
// In debugger you must be here before err is set
closesocket(sd);
WSACleanup();
std::string what{"Could not receive datagram."};
what+= std::to_string(err);
throw std::runtime_error(what.c_str());
}
A am writing a client-server program in C. It sends a directory name and receives a list of files as answer. The problem I have is that it gets stuck in an infinite loop.
If I send only one directory name it works, but if I send a list of directories it never ends and outputs nothing.
Server
while(recv(sock, name, BUFSIZE, 0) > 0){
if ((fddir=opendir(name)) == NULL){
send(sock, strerror(errno), strlen(strerror(errno)), 0);
close(sock);
return 1;
}
send(sock, name, strlen(name), 0);
send(sock, ":", strlen(":"), 0);
send(sock, "\n", strlen("\n"), 0);
while ((dirbuf = readdir(fddir)) != NULL){
buf[0] = '\0';
strcat(buf, dirbuf->d_name);
strcat(buf, "\t");
send(sock, buf, BUFSIZE, 0);
}
}
Client
for (int i=1;i<3;i++){
send(sock, argv[i], strlen(path), 0);
while(recv(sock, buf, BUFSIZE, 0) > 0)
printf("%s", buf);
}
The server waits until all directory names are received, and then the client wait until server send all files in it. How do I trace where the program gets stuck?
TCP is not message based, so you have no way of knowing where the boundaries between two client send() calls is when you call recv() on the server. Thus when you send multiple names back-to-back it is possible for the server to receive them all in a single recv() (or however many bytes you allocated for BUFSIZE). This is probably mangling your directory names, causing opendir to fail. This would be more obvious to you if you were checking for errors from send and recv and Captain Obvlious describes in another answer.
You need to check the calls to recv for errors. It returns 0 if the connection was disconnected and -1 on an error. You are only checking for values > 0 which will not work. The example below shows how to approach checking the errors.
while(true)
{
const int result = recv(sock, buf, BUFSIZE, 0);l
if(result == -1)
{
std::cout << "Error: " << errno << std::endl;
break;
}
else if(result == 0)
{
std::cout << "Disconnected" << std::endl;
break;
}
// process the data here. No errors
}
You should also be checking the value returned by send as it works in the same way.
I'm trying to send a file from client to server using winsock2 lib.
After converting the file into char array, i'm sending this array using the send() command.
The problem: the data sent separately.
For e.g: I have file of size: 144429.
It does not send it at once, the data is split into many portions, like:
first send: 1460
second send: 21544
third send: 57136
etc..
until to whole data is sent.
so my question is: what causes it to send it by parts and not by once????
Solution I found working but not making any sense:
If i'm adding
cout << "bla bla bla";
before the send() function, it does work and send the whole 144429 by once. (but if the string given to cout is shorter, no change, send by parts)
CODE:
CLIENT SIDE
int Client::sendData(char *sendbuf, int length)
{
int iResult;
// if I remove those next few lines (until and including the cout line)
// the send will split.
char tmp[1];
// sent 1 dummy byte
iResult = send( _connectSocket, tmp, 1, 0 );
if (iResult == SOCKET_ERROR) {
printf("send failed with error: %d\n", WSAGetLastError());
return closeSocket();
}
cout << "SENDING DATA..." << endl;
// THIS IS THE RELEVANT AND ACTUAL DATA I WANT TO SEND
// send the data
iResult = send( _connectSocket, sendbuf, length, 0 );
if (iResult == SOCKET_ERROR) {
printf("send failed with error: %d\n", WSAGetLastError());
return closeSocket();
}
cout << "Data sent (" << iResult << " Bytes)" << endl;
return 0;
}
SERVER SIDE:
char recvbuf[DEFAULT_BUFLEN];
int recvbuflen = DEFAULT_BUFLEN;
int iResult = 0;
int totalBytesRead = 0;
// Receive until the peer shuts down the connection
do {
totalBytesRead += iResult;
iResult = recv(_clientSocket, recvbuf, recvbuflen, 0);
if (iResult > 0) {
printf("RECEIVED DATA\n");
printf("Bytes received: %d\n", iResult);
} else if (iResult == 0)
printf("Connection closing...\n");
else {
printf("recv failed: %d\n", WSAGetLastError());
closesocket(_clientSocket);
WSACleanup();
return 1;
}
} while (iResult > 0);
// store data into file
FileTransfer::binaryToFile(recvbuf, "doch.docx", totalBytesRead-1);
return 0;
}
There is no way to guarantee that send transmits some data as one unit - it just doesn't work that way. You have to add some extra information to tell the system that "Here's this much data to come" and/or "I'm done now". Even if you could convince your sending side to send of everything in one packet, assuming the receiving side isn't connected DIRECTLY with just a simple cable to the sender, you can't guarantee that the packet isn't broken up during it's passing through the network.
You just have to accept that if you are sending more than a single byte in a packet, you may have to call send multiple times. To simplify it, write a function that takes a an arbitrary size "whole packet" and calls send as many times as necessary... If you have a protocol that indicates the size of the data sent [such as in the first few bytes], you could have a receive function that does the same thing.
Depending on the socket type you are using there might be a limitation of data size in the underlying transport protocol.
In case you are using a network socket the size is limited by the maximum transfer unit (see: http://en.wikipedia.org/wiki/Maximum_transmission_unit).
If your data doesn't fit this size you will have to iterate in a loop sending portions of your data until either an error occurs or all data has been sent.
I am using a unix socket. When buffer is send to the socket it gives me unknown error 196.
Please help on this.
BOOL SendData(int iBuffer)
{
//Send data over socket
int nRet = send(m_listenSock, m_cBuffer, iBuffer, 0);
if(SOCKET_ERROR > nRet)
{
//log the error char temp;
int length= sizeof(int);
int rc = getsockopt(m_listenSock,SOL_SOCKET,SO_ERROR,&temp,(socklen_t *)&length);
//if(rc == 0)
{
errno = temp;
perror("\nError is");
}
#ifndef LINUX
WSACleanup();
#else
close(m_listenSock);
#endif
printf("\nSend data failed to");
return FALSE;
}
return TRUE;
}
If errno is set but the call didn't fail (i.e. it didn't return -1), then errno's value isn't related to the last call you did. You can try clearing first:
errno = 0;
To be on the safe side. What I'm trying to say is that you can't know that the value of errno is relevant except right after the call that set it. You must check all calls you do that can fail for success/failure.
To detect an error you SHOULD be checking that send returns -1. I don't know what SOCKET_ERROR is, but if it's -1, then the above code won't work right anyway.
Assuming you do get -1 from send(), then an error code will be in errno. It is not necessary to do a getsockopt to retrieve it.
There is no error code 196, so I'd be deeply suspicious about your error handling.
Also, if send() fails, you should probably not close the socket. You haven't specified either the address family or socket type, but I'm assuming AF_INET and SOCK_DGRAM respectively (i.e. UDP)