0

I am trying to implement UDP sockets in C in a very simple/basic fashion. My programs are meant to send/receive files between terminals with one program running on each. I am having a problem with the sendto() function in my client code. Here is my code:

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<arpa/inet.h>
#include<sys/socket.h>
#include <errno.h>

#define BUFFER_SIZE 512

int main(int argc, char *argv[])
{
    struct sockaddr_in client;
    int sockfd, bytes, errno, slen = sizeof(client);
    char buffer[BUFFER_SIZE];

    sockfd = socket(AF_INET, SOCK_DGRAM, 0);

    if(sockfd == -1)
    {
        perror("Socket creation failed.");
        return 0;
    }

    client.sin_addr.s_addr = INADDR_ANY;
    client.sin_family = AF_INET;
    client.sin_port = htons( 0 );

    if( bind(sockfd, (struct sockaddr *)&client, sizeof(client)) == -1)
    {
        perror("Bind call failed.");
        return 0;
    }

    while(1)
    {
        printf("Enter message : ");
        fgets(buffer, BUFFER_SIZE, stdin);

        printf("Message: %s\n", buffer);
        bytes = sendto(sockfd, buffer, strlen(buffer), 0, (struct sockaddr *)&client, sizeof(client));

        printf("Bytes: %d\n", bytes);

        if(bytes == -1)
        {
            printf("Error number: %d", errno);
            perror("Send failed.");
            return 0;
        }

        memset(buffer,'\0', BUFFER_SIZE);

        if( recvfrom(sockfd, buffer, BUFFER_SIZE, 0, (struct sockaddr *)&client, &slen) == -1)
        {
            perror("Recieve failed.");
            return 0;
        }

        puts(buffer);
    }

    close(sockfd);

    return 0;   
}

No matter what I enter into the buffer, I always get error number 22 from sendto() for invalid arguments. I have tried every solution or tweak I have come across but nothing seems to work.

user207421
  • 305,947
  • 44
  • 307
  • 483
bibzuda7
  • 64
  • 3
  • 10
  • 1
    You're trying to send to port 0. That's not valid. – Barmar Oct 09 '15 at 20:54
  • Why are you trying to send to the client address? If this is the client code, it should be sending to the server's address. – Barmar Oct 09 '15 at 20:54
  • If the port is invalid wouldn't the bind fail as well? If I try to set the port to the same thing as the server, it cannot run because the server is already using the port and the bind fails. Also since it is just sending on the localhost the two addresses are the same I believe? I could be wrong. I'm new to sockets – bibzuda7 Oct 09 '15 at 20:56
  • 1
    You can bind to port 0, which causes a port to be automatically chosen. But you can't send to port 0. You can use `getsockname` after the bind to find out what port got chosen. –  Oct 09 '15 at 20:57
  • 1
    When you call `bind()`, you're setting the local port. Port 0 means that the OS should find an unused port and bind that. – Barmar Oct 09 '15 at 20:57
  • 2
    Unrelated: there's no point in calling `perror()` after calling `printf()`, because `printf()` can change `errno`. – Barmar Oct 09 '15 at 20:58
  • I was just trying everything I could to find the error with that. I'll take away the printf. Also is binding to port 0 what causes the error? If so how would I change it because like I said if I made it into the same port as the server program it fails to bind as it is already in use – bibzuda7 Oct 09 '15 at 21:01
  • 1
    You need two different `sockaddr_in` structures, one for binding the client address/port, another for specifying the destination address/port. – Barmar Oct 09 '15 at 21:22
  • 1
    You don't have to take away the `printf().` You just have to call `perror()` first, before calling any other system call, or anything that could call a system call, so as not to change `errno.` – user207421 Oct 09 '15 at 22:19

1 Answers1

2

Just add this piece of code after bind()

getsockname(sockfd, (struct sockaddr *)&client, &slen);

man page

 DESCRIPTION
     The getsockname() function returns the current address for the specified
     socket.

     The address_len parameter should be initialized to indicate the amount of
     space pointed to by address.  On return it contains the actual size of
     the address returned (in bytes).

     The address is truncated if the buffer provided is too small.

RETURN VALUES
     The getsockname() function returns the value 0 if successful; otherwise
     the value -1 is returned and the global variable errno is set to indicate
     the error.
WalterM
  • 2,686
  • 1
  • 19
  • 26
  • @EJP from the looks of it he wants to send the packet back to the same port he's listening on. if thats the case this will fix it. He said it's "invalid arguments" not segmentation fault. – WalterM Oct 09 '15 at 22:57