0

I'm trying to make a simple client-server API to be used for two of my machines. I made this simple program that uses the functions I made to test it. For some reason my client sends a message just fine, but my server can't (however, it receives the message from the client).

Server side output:

 host name: my_host
 Our port number is: 34440
 Client msg: Client msg
 Send failed: Invalid argument
 Message from Server sent to Client

Client side output:

 Connection established with server...
 Message from Client sent to Server

Server side:

#include <sys/socket.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdlib.h>
#include "my_socket.h"

int main() {

    server_init();
    char *msg = "Server msg";
    char buffer[100];

    int n = read_from_client((char *)buffer);
    buffer[n] = '\0';
    printf("Client msg: %s\n", buffer);
    write_to_client((char *)msg);
    printf("Message from Server sent to Client \n");   
    return 0;
}

Client Side:

   #include <sys/socket.h>
   #include <stdio.h>
   #include <unistd.h>
   #include <fcntl.h>
   #include <pthread.h>
   #include <stdlib.h>
   #include "my_socket.h"

   int main() {

   client_init();
   char *msg = "Client msg";
   char buffer[100];

   write_to_server((char*)msg);
   printf("Message from Client sent to Server \n");
   int n = read_from_server((char *)buffer);
   buffer[n] = '\0';
   printf("Server msg: %s\n", buffer);

   close_socket();  
   return 0;
 }

my_socket.c:

#include "my_socket.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h> 
#include <sys/socket.h>

   int sockfd1;
   int sockfd2;
   int MAX_BUFF = 1024;
   struct sockaddr_in server;
   struct sockaddr_in client;
   struct hostent *host;

   ssize_t write_to_server(const void *buffer){
      int bytes_sent, server_size = sizeof(server), buf_len = strlen(buffer);
      if ((bytes_sent = sendto(sockfd2, buffer, buf_len, 0, 
            (const struct sockaddr *)&server, server_size)) < 0){
     perror("Send failed");
      }
      return bytes_sent;
   }

   ssize_t write_to_client(const void *buffer){
      int bytes_sent, client_size = sizeof(client), buf_len = strlen(buffer);
      if ((bytes_sent = sendto(sockfd1, buffer, buf_len, 0, 
            (const struct sockaddr *)&client, client_size)) < 0){
     perror("Send failed");
      }
      return bytes_sent;
   }

   int read_from_server(void *buffer){
      int bytes_rcv, len;
      if ((bytes_rcv = recvfrom(sockfd2, buffer, MAX_BUFF, MSG_WAITALL, 
                   (struct sockaddr *)&server, &len)) < 0){
     perror("Read failed");
      }
      return bytes_rcv;
   }

   int read_from_client(void *buffer){
      int bytes_rcv, len;
      if ((bytes_rcv = recvfrom(sockfd1, buffer, MAX_BUFF, MSG_WAITALL, 
                   (struct sockaddr *)&client, &len)) < 0){
     perror("Read failed");
      }
      return bytes_rcv;
   }


   void close_socket() {
      close(sockfd1);
      close(sockfd2);
   }

   void server_init(){
      if ( (sockfd1 = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
     perror("socket creation failed");
      }
      char name[1024];
      name[1023] = '\0';
      gethostname(name, 1023);
      printf("host name: %s \n", name);

      host = gethostbyname("my_host");
      if(host == NULL){
     perror("Host is null");
     exit(0);
      }

      bzero((char *)&server, sizeof(server));
      bzero((char *)&client, sizeof(client));

      server.sin_family          = AF_INET;
      bcopy((char *)host->h_addr, 
        (char *)&server.sin_addr.s_addr, host->h_length);
      //server.sin_port            = 0; 
      server.sin_port            = htons(34440);

      if ( (bind(sockfd1, (struct sockaddr *)&server, sizeof(server) ) ) < 0 ){
     perror("bind failed");
      } 
      socklen_t len = sizeof(server);
      if (getsockname(sockfd1, (struct sockaddr *)&server, &len) == -1){
     perror("getsockname");
      }else{
     printf("Our port number is: %d\n", ntohs(server.sin_port));
      }
   }

   void client_init(){

      if ( (sockfd2 = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
     perror("socket creation failed");
      }

      host = gethostbyname("my_host");
      if(host == NULL){
     perror("Host is null");
     exit(0);
      }

      bzero((char *)&server, sizeof(server));

      server.sin_family       = AF_INET;
      bcopy((char *)host->h_addr, 
        (char *)&server.sin_addr.s_addr, host->h_length);
      //server.sin_port = 0; 
      server.sin_port = htons(34440);

      if(connect(sockfd2, (struct sockaddr *)&server, sizeof(server)) == 0){
     printf("Connection established with server...\n");
      }

   }

my_socket.h:

#ifndef MY_SOCKET
#define MY_SOCKET
#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <string.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <arpa/inet.h> 
#include <netinet/in.h>
#include <netdb.h>


extern int sockfd1;
extern int sockfd2;
extern int MAX_BUFF;
extern struct sockaddr_in server;
extern struct sockaddr_in client;
extern struct hostent *host;


// Send a message over the socket  
ssize_t write_to_server(const void *buffer);
ssize_t write_to_client(const void *buffer);

// Blocks until told it's ready; receives bytes from socket 
int read_from_server(void *buffer);
int read_from_client(void *buffer);   

// Close the socket
void close_socket();

void server_init();

void client_init();      


#endif

Any advice or criticism is welcome. Thanks in advance.

AsiaRican
  • 75
  • 1
  • 13
  • 1
    Along with the answers below, don't make it a habit of ignoring the type aliases provided by the networking libraries, and specified in the API documentation for each API call. They're important. There are multitude of places where `socklen_t`, `ssize_t`, and `size_t` should be used, where you're just stuffing everything in `int` variables instead. Trust me; that can bite you in the most subtle and hard-to-debug ways. Follow the rules. – WhozCraig Sep 13 '18 at 16:10
  • The changes have been made. Thanks for the warning! – AsiaRican Sep 13 '18 at 16:27

1 Answers1

2

At least one issue is that you are not initializing the len variable in read_from_client. The manual page for recvfrom says, in part (emphasis added):

... addrlen is a value-result argument. Before the call, it should be initialized to the size of the buffer associated with src_addr. Upon return, addrlen is updated to contain the actual size of the source address. The returned address is truncated if the buffer provided is too small; in this case, addrlen will return a value greater than was supplied to the call.

That means that, as an uninitialized stack variable, len has an indeterminate value. Probably zero, but at least something smaller than sizeof(struct sockaddr_in). As a result, client is not getting filled in correctly by the recvfrom.

Just before the recvfrom, you should initialize it with:

len = sizeof(client);

On the client side, write_to_server and read_from_server need not use recvfrom and sendto as you have already done a connect on the socket. They can simply use recv and send since the remote socket endpoint is already established by the connect. I believe the address is simply ignored for a connected socket, but I cannot find where that is documented right now.

(In any case, if you do continue to use recvfrom on the client side, you should make the same len initialization there.)

Gil Hamilton
  • 11,973
  • 28
  • 51