0

currently I am writing a program which shall receive a message from another pc via UDP and send another message back to this pc. Receiving messages is working, but when I want to send messages back, I get an (Socket) error while creating a socket. So, why do I get the error, and is my code wrong on some other parts, too?

SOCKET recv, trans;
WORD wVersionRequested;
WSADATA wsaData;
int err;

wVersionRequested = MAKEWORD( 2, 2 );

err = WSAStartup( wVersionRequested, &wsaData );
if ( err != 0 ) {
  /* Tell the user that we could not find a usable */
   /* WinSock DLL.                                  */
   return 1;
}

char   myname[256], yourname[256];
struct sockaddr_in sa_recv, sa_trans;
struct hostent *hp_recv, *hp_trans;

memset(&sa_recv, 0, sizeof(struct sockaddr_in)); /* clear our address */
memset(&sa_trans, 0, sizeof(struct sockaddr_in));
gethostname(myname, sizeof(myname));        /* who are we? */
hp_recv = gethostbyname("localhost");                 /* get our address info */
//std::cout << hp_recv->h_addrtype << ' ' << hp_recv->h_addr_list << ' ' << hp_recv->h_aliases << ' ' << hp_recv->h_length << ' ' << hp_recv->h_name << ' \n';
if (hp_recv == NULL)                             /* we don't exist !? */
    return(INVALID_SOCKET);
sa_recv.sin_family = hp_recv->h_addrtype;             /* this is our host address */
sa_recv.sin_port = htons(PORTNUM);               /* this is our port number */
recv = socket(AF_INET, SOCK_DGRAM, 0);        /* create the socket */
if (recv == INVALID_SOCKET)
    return INVALID_SOCKET;

/* bind the socket to the internet address */
if (bind(recv, (struct sockaddr *)&sa_recv, sizeof(struct sockaddr_in)) ==
  SOCKET_ERROR) 
{
    closesocket(recv);
    return(INVALID_SOCKET);
}

struct sockaddr from;
int fromlen = sizeof(from);
char inStr[100];
int ret = recvfrom(recv, inStr, sizeof(inStr), 0, &from, &fromlen); 
in_addr * addr = (in_addr * )get_in_addr(&from);
std::cout << "Received " << inStr << " from " << inet_ntoa(*addr);
std::cout << '\n';
closesocket(recv);
std::cout << "Sending Data to " << inet_ntoa(*addr) << '\n'; 
char *ip = NULL;
ip = (char *) get_in_addr(&from);
/*if (from.sa_family == AF_INET)
{
    struct sockaddr_in *sin = (struct sockaddr_in *) from;
    ip = inet_ntoa(sin->sin_addr);
};*/
gethostname(yourname, sizeof(yourname));
/*hp_trans = gethostbyname(ip);
if(hp_trans == NULL)
{
    std::cerr << "hp_trans is zero " << hp_trans << " from " << hp_recv << " and " << &from << '\n';
    getchar();
    return(INVALID_SOCKET);
};*/
memset(&sa_trans,0,sizeof(sa_trans));
memcpy((char *)&sa_trans.sin_addr, ip, hp_recv->h_length);   /* set address */
sa_trans.sin_family = AF_INET;
sa_trans.sin_port = htons(50001);
trans = socket(AF_INET, SOCK_DGRAM, 0);
if(trans == INVALID_SOCKET)
{
    std::cerr << "Trans is an invalid socket " << '\n';
    getchar();
    return INVALID_SOCKET;
};
if(bind(trans, (struct sockaddr *)&sa_trans, sizeof(struct sockaddr_in)) == SOCKET_ERROR)
{
    closesocket(trans);
    std::cout << "bind has failed with error " << WSAGetLastError() << '\n';
    getchar();
    return(INVALID_SOCKET);
};
char str[100] = "Message transmitted. Transmission finished.";
int transmit = sendto(trans, str, sizeof(str), 0, (struct sockaddr *)&sa_trans, sizeof(sa_trans));
std::cout << "Transmission finished. Program will exit. " << '\n';
std::getchar();
return 1;

Thank you very much in advance!

alk
  • 69,737
  • 10
  • 105
  • 255
arc_lupus
  • 3,942
  • 5
  • 45
  • 81
  • can you paste program output from console? – 4pie0 Sep 07 '13 at 11:33
  • Output is: Received Data from \n, Sending Data to \n, bind has failed with error 0 – arc_lupus Sep 07 '13 at 11:40
  • 2
    Try printing the error message *before* closing the socket. At present you're destroying the error code so you don't know what is is. Neither do we. Of course you don't need to bind the sending socket at all. You don't even need the sending socket, actually. Just use the receiving socket. – user207421 Sep 07 '13 at 11:55
  • Ok, now I'm getting errcode 10049 (Cannot assign requested address). – arc_lupus Sep 07 '13 at 15:43
  • @EJP: How can I set the new ip address for the socket without binding? I have tried to use the recv-Socket for the sendto-command, and then I am getting errcode 10022 (Invalid argument). – arc_lupus Sep 07 '13 at 15:52
  • OT: `recv` is a bad name for variable, especially when dealing with socket, as there is a function to read form a socket with **exactly** this name: `int recv( _In_ SOCKET s, _Out_ char *buf, _In_ int len, _In_ int flags );` A variable having this name would cover and hide this function. – alk Sep 07 '13 at 17:02
  • You don't need to set an IP address for the second socket at all. That's what 'bind' means. You're presently closing the recv-socket after the send: did you remove that? – user207421 Sep 07 '13 at 20:57

3 Answers3

1

I think the problem is in the way you initialize struct sockaddr_in, sin_addr field actually. The problem is you can't initialize this field with char* but with binary data.

Try this:

trans_addr.sin_addr.s_addr = inet_addr(DEST_IP);

The inet_addr() function converts the Internet host address cp from IPv4 numbers-and-dots notation into binary data in network byte order.

or even better:

inet_aton("192.168.0.1", &trans_addr.sin_addr); // store IP in trans_addr

or inet_pton in the world of windows.

It will be helpful to put a brakepoint before bind and check what is the value of sa_trans.sin_addr.

Example on windows: http://msdn.microsoft.com/en-us/library/windows/desktop/ms740148(v=vs.85).aspx

Example on linux:

    char *secret_message = "The Cheese is in The Toaster";

    int stream_socket, dgram_socket;
    struct sockaddr_in dest_addr;
    int temp;

    dest_addr.sin_family = AF_INET;
    /* short, network byte order */
    dest_addr.sin_port = htons(DEST_PORT);
    dest_addr.sin_addr.s_addr = inet_addr(DEST_IP);

    /* zero the rest of the struct */
    memset(&(dest_addr.sin_zero), 0, 8);

    dgram_socket = socket(dest_addr.sin_family, SOCK_DGRAM, 0);


    // send secret message
    sendto(dgram_socket, secret_message, strlen(secret_message) + 1, 0,
            (struct sockaddr*) &dest_addr, sizeof dest_addr);
Community
  • 1
  • 1
4pie0
  • 29,204
  • 9
  • 82
  • 118
0

You use sin_addr incorrectly. It must have 4-bytes size each byte must contain a value of the number of IP-address. For example for IP address 192.168.1.1 it may be initialized following way:

unsigned char addr[4] = { 192, 168, 1, 1 }
memcpy(&sa_trans.sin_addr, addr, sizeof(sa_trans.sin_addr));
Dmitry Poroh
  • 3,705
  • 20
  • 34
0

When sending the reply, you are creating a new socket, initializing it wrong, and telling it to send the reply to itself instead of to the other party.

You should instead use the same socket that received the request, and use the sockaddr_in that recvfrom() gives you (which you have incorrectly declared as sockaddr instead of sockaddr_in) to know where to send the reply back to, eg:

struct sockaddr_in from;
int fromlen = sizeof(from);
int ret = recvfrom(recv, ..., (struct sockaddr *)&from, &fromlen); 
...
int transmit = sendto(recv, ..., (struct sockaddr *)&sfrom, fromlen);
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • Ok, now it is working, but the PORTNUM value I get from (int) ntohs(from.sin_port) is always changing, and not constant as it should be. Why? – arc_lupus Sep 07 '13 at 16:49
  • Ok, problem solved, I just have to set the portnum manually again. – arc_lupus Sep 07 '13 at 17:29
  • `recvfrom()` reports the other party's IP/Port that the data was sent from. So it very well could be using a different outbound port each time. That is not unheard of. And a good reason why you should send your data back to the same IP/Port that `recvfrom()` reports to you. – Remy Lebeau Sep 08 '13 at 15:50