Catching unhanded exceptions in a DLL - c++

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());
}

Related

Getting undocumented error code from recvfrom

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
}

Execute a command on the server and send the result to the client in Windows

I'm writing a simple server program that executes a command and sends the result to the client. I read countless examples that involve using popen(), pipe(), dup2(), fork(), etc., but none of them worked for me and they didn't explain the code very well. I also tried to do it myself, but without success. Could you please provide me with a well documented example?
Here's the code that receives commands/messages from the client:
void server_receive() {
struct sockaddr_in from;
int from_len, recv_len;
char buf[BUFLEN], path[256]; // BUFLEN = 1024
// Getting the path for the command to execute
strcpy(path, getenv("SYSTEMDRIVE"));
strcat(path, "\\WINDOWS\\System32\\tasklist.exe");
from_len = sizeof(from);
memset(buf, '\0', BUFLEN);
// Receiving the command
// I'll add some if-else statements to handle various commands, but for
// now I just need to see if I can even get one to work.
if((recv_len = recvfrom(sockt, buf, BUFLEN, 0, (struct sockaddr*) &from, &from_len)) == SOCKET_ERROR) {
printf("[ERROR] recvfrom() failed: %d.\n\n", WSAGetLastError());
} else {
printf("Packet received from %s:%d\n", inet_ntoa(from.sin_addr), ntohs(from.sin_port));
printf("Data: %s\n\n", buf);
// Code to execute tasklist (I used _popen())
// and send everything back to the client (I used TransmitFile())
}
}
And here's the code that sends commands/messages to the server:
void client_send(char server[], unsigned short port) {
struct sockaddr_in to;
int s, to_len = sizeof(to);
char buf[BUFLEN]; // BUFLEN = 1024
char message[BUFLEN];
memset((char*) &to, 0, sizeof(to));
to.sin_family = AF_INET;
to.sin_port = htons(port);
to.sin_addr.S_un.S_addr = inet_addr(server);
while(true) {
printf("Enter message: ");
gets(message);
if (sendto(sockt, message, strlen(message), 0, (struct sockaddr*) &to, to_len) == SOCKET_ERROR) {
printf("[ERROR] sendto() failed: %d.\n\n" , WSAGetLastError());
}
memset(buf, '\0', BUFLEN);
if (recvfrom(sockt, buf, BUFLEN, 0, (struct sockaddr*) &to, &to_len) == SOCKET_ERROR) {
printf("[ERROR] recvfrom() failed: %d.\n\n", WSAGetLastError());
} else {
printf("Server's response: %s\n\n", buf); /* The result of tasklist
should be outputted by this line of code, however I'm concerned about the
relatively small receive length (BUFLEN = 1024).*/
}
}
}
Needless to say that these two functions are just a part of my code.
That you mention _popen (with the leading underscore) and TransmitFile indicates that you are on Windows, which doesn't have fork or pipe or related functions.
There are many alternatives to executing commands in Windows. One is through _popen as you already mentioned (but you don't say what's wrong with that method). Others include the "classic" system CRT function. And of course the Windows native CreateProcess function. If you want to open a "document" there's the ShellExecute function.
Knowing which functions are available will help you in your search for examples. Adding the term windows to your searches will help finding Windows-specific examples and tutorials. And adding the term msdn will help finding topics on the Microsoft Developer Network.

Sendto function return error - UDP socket on windows

I have problem with sendto function. I want to get time from UDP server. My code like this:
unsigned char msg[48]={010,0,0,0,0,0,0,0,0};
char* hostname=(char *)"tick.usno.navy.mil";
sockaddr_in server_addr;
WSAData data;
int result=WSAStartup( MAKEWORD( 2, 2 ), &data );
if (result != NO_ERROR) {
printf("WSAStartup failed with error: %d\n", result);
return 1;
}
int client_s = socket(AF_INET, SOCK_DGRAM,IPPROTO_UDP);
if (client_s == INVALID_SOCKET) {
printf("socket failed with error: %ld\n", WSAGetLastError());
WSACleanup();
return 1;
}
unsigned short Port = 123;
server_addr.sin_family = AF_INET; // Address family to use
server_addr.sin_port = htons(Port); // Port num to use
server_addr.sin_addr.s_addr = inet_addr(hostname); // IP address to use
char out_buf[BUFFER_SIZE];
int retcode = sendto(client_s, reinterpret_cast<const char*>(msg), sizeof(msg), 0,(struct sockaddr *)&server_addr, sizeof(server_addr));
perror("sendto:");
if (retcode == SOCKET_ERROR) {
printf("sendto failed with error: %d\n", WSAGetLastError());
closesocket(client_s);
WSACleanup();
return 1;
}
My output is like:
sendto:: No error
sendto failed with error: 10013
When I try recive data with recv, I got something wrong. I want get time from UDP server on windows with c++. Where is problem here? Why one error say no error and one error 10013 and how can I fix that?
The old answer (kept below) is informational but not correct for this case.
The problem is most likely these two lines
char* hostname=(char *)"tick.usno.navy.mil";
...
server_addr.sin_addr.s_addr = inet_addr(hostname); // IP address to use
The inet_addr function expects a dotted-decimal IPv4 address. Not an unresolved host-name. If not a valid IPv4 dotted-decimal address is provided, the function will return INADDR_NONE which is not a valid address and will lead to problems when using the address in e.g. sendto. Will it cause the error reported in the question? I honestly don't know, but it will definitely not work as expected.
To resolve a host-name into an IP address you should use getaddrinfo. The linked reference also contains an example on how to use it.
The error 10013 is, if you look at e.g. this Windows socket error reference WSAEACCESS, that there is some permission problems. If you then search a little you will see that ports under 1024 are reserved for the system, and you need elevated privileges to use them.
If you want to create an NTP server or client you need to run your program using elevated access rights, like e.g. using "Run as administrator".
As for the message
sendto:: No error
it comes from the perror call you unconditionally call after sendto. First of all on Windows the socket functions doesn't set errno which perror uses. Secondly, the state of errno is undefined if the previous call to didn't actually fail.
So don't use it unconditionally, and don't use it for the Windows socket functions.

Why isn't AF_INET working with SOCK_STREAM?

I'm just starting out on gaining a better understanding of socket programming, and I'm trying to build a simple program that can send and receive messages. I've run into an issue with binding a socket to an address to use it. Here is what I have-
#include "stdafx.h"
using namespace std;
int main()
{
bool devbuild = true;
WSADATA mainSdata;
SOCKET sock = INVALID_SOCKET;
sockaddr tobind;
tobind.sa_family = AF_INET;
char stringaddr[] = "192.168.1.1";
inet_pton(AF_INET,stringaddr,&tobind);
//initiating Windows Socket API (WSA)
if (WSAStartup(2.2, &mainSdata) == 0)
{
if (devbuild == true)
{
printf("WSA successfully started...\n");
}
}
else
{
printf("WSA failed to set up, press [ENTER] to exit...\n");
pause();
return 1;
}
//instantiating the socket
sock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, NULL);
if (sock != INVALID_SOCKET)
{
if (devbuild == true)
{
printf("Socket successfully created...\n");
}
}
else
{
printf("Socket failed to set up, press [ENTER] to exit...\n");
pause();
return 2;
}
//binding the socket
if (bind(sock, &tobind, sizeof(tobind)) == 0)
{
if (devbuild == true)
{
printf("Socket successfully bound...\n");
}
}
else
{
printf("Socket failed to bind, press [ENTER] to exit...\n");
printf("Last WSA error was: %d", WSAGetLastError());
pause();
return 3;
}
pause();
return 0;
}
I'm getting a return of 3, with WSA error code 10047
10047 - WSAEAFNOSUPPORT
Address family not supported by protocol family.
An address incompatible with the requested protocol was used. All sockets are created with an associated address family (that is, AF_INET for Internet Protocols) and a generic protocol type (that is, SOCK_STREAM). This error is returned if an incorrect protocol is explicitly requested in the socket call, or if an address of the wrong family is used for a socket, for example, in sendto.
This doesn't make sense, because I am only using SOCK_STREAM and AF_INET, which support one another.
I believe one problem (possibly not the only problem, but this is what jumps out at me) is in this line:
inet_pton(AF_INET,stringaddr,&tobind);
The problem is that you are passing &tobind as the final argument, and tobind is a sockaddr, but inet_pton() expects its third argument to point to a struct in_addr instead when using AF_INET (the fact that inet_pton() takes a void-pointer rather than a typed pointer for its third argument makes this kind of mistake really easy to make).
So what you should be doing instead is (note added error checking also):
if (inet_pton(AF_INET,stringaddr,&tobind.sin_addr) != 1)
printf("inet_pton() failed!\n");
Also, you need to make tobind be of type struct sockaddr_in rather than just a sockaddr, and also you need to zero out the struct before using it:
struct sockaddr_in tobind;
memset(&tobind, 0, sizeof(tobind)); // make sure the uninitialized fields are all zero
tobind.sa_family = AF_INET;
[...]

Socket Send error

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)