c socket port number as cmd line argument is changed? - c

I'm writing my first C program with sockets. I want my server program to take the TCP port number as the only command line argument. Here's a condensed version of my code (compiled on GCC, running on Linux):
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
int main(int argc, char *argv[])
{
int listenfd = 0;
struct sockaddr_in serv_addr;
listenfd = socket(AF_INET, SOCK_STREAM, 0);
memset(&serv_addr, '0', sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
printf("Server:: About to set %hu as the port...\n", (unsigned short)strtoul(argv[1], NULL, 0));
serv_addr.sin_port = htons((unsigned short)strtoul(argv[1], NULL, 0));
bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
printf("Server:: About to listen on port %hu...\n", serv_addr.sin_port);
listen(listenfd, 10);
}
Output of this program is:
[Linux]$ ./server.exe 12345
Server:: About to set 12345 as the port...
Server:: About to listen on port 14640...
^C
[Linux]$
As you can see, I'm trying to tell the server that I want TCP port 12345, but it is somehow getting garbled into TCP port 14640. Not surprisingly, when I run my client program (./client.exe 127.0.0.1 12345), the client gets a "Connection Refused," meaning no-one is listening on port 12345. Ditto if I run (./client.exe 127.0.0.1 14640).
So I'm scratching me head on this one. I'm assuming this is some kind of casting or data handling issue, because if replace this line:
serv_addr.sin_port = htons((unsigned short)strtoul(argv[1], NULL, 0));
with this:
serv_addr.sin_port = htons(12345);
(aka, hardcode the TCP port), the socket works fine and client & server can communicate all they want.
A little Internet research tells me that the TCP port is stored as a unsigned short in the struct sockaddr_in and that's why my code is bending over backwards to hammer the data into the right format. I've tried a lot of other ways to massage the port number; trying to use atoi(argv[1]) and then casting the returned integer as an unsigned short, for example, gives the exact same result.
Any advice? Is this an htons() issue? A formatting or casting issue?
Thanks, -RAO

printf("Server:: About to listen on port %hu...\n", serv_addr.sin_port);
That doesn't work. The %hu format specifier is for unsigned integers in native format. The sin_port field is not in native format, it's in network format. So you can't print it this way.
You can convert it into native byte order with ntohs and then print it, if you want:
printf("Server:: About to listen on port %hu...\n", ntohs(serv_addr.sin_port));

Try this:
addr.sin_family = AF_INET;
addr.sin_port = htons(atoi(argv[1]));
addr.sin_addr.s_addr = inet_addr(*(argv+2));
It worked for me. atoi() accepts integers and inet_addr() accepts strings as arguments. Make sure you pass a string to inet_addr() failing which also may refuse connection

Related

Why is my server getting stuck on recvfrom()? (UDP socket)

I'm required to make a 'height sensing subsystem' to read the data sent from a moonlander by making a UDP protocol. The client is already set up for me, and is a 64bit executable on linux run by using ./simulator. So I need to make the UDP server in linux to connect with the client.
The client sends readings from many subsystems in the moonlander, but I only need to read one of them, which is the laser altimeter reading that corresponds to the a type specified by 0xaa01, there are other types such as 0xaa##, and 0xff##, but those correspond to different subsystems of the moonlander I assume. The data sent from the ./simulator file is sent through the type, which I then need to decode to find if its the laser altimeter, and then I need to decode the values to convert into distance to find when the moonlander has touched down. I need to read the time first, which has a size of 4 bytes and is an unsigned 32 bit integer, and the laser altimeter reading is 3 unsigned 16-bit integers that correspond to 3 different measurements (as there are 3 different sensors on the altimeter, max height of 1000m, convert by dividing by 65.535 which is UINT16_MAX, and multiplying by 100 to convert to cm). I need to then take those readings, convert them into height, and then acknowledge that we've landed once we've hit 40cm away from the ground.
How do I read the data from the ./simulator file? The problem is that when I run the ./receiver file, it stops working at the recvfrom() function as in my code below. In the instructions, they tell me to connect to port 12778, which works, but I'm not receiving anything.
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
// Create a UDP datagram socket
int main() {
int fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd < 0)
{
perror("Can't connect");
exit(EXIT_FAILURE);
}
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET; // use IPv4
addr.sin_addr.s_addr = INADDR_ANY; // bind to all interfaces
addr.sin_port = htons(12778); // the port we want to bind
// Bind to the port specified above
if (bind(fd, (const struct sockaddr *)&addr, sizeof(addr)) < 0)
{
perror("cant connect");
exit(EXIT_FAILURE);
}
printf("here");
// Listen for data on our port (this is blocking)
char buffer[4096];
int n = recvfrom(fd, buffer, 4096, MSG_WAITALL, NULL, NULL);
printf("Recieved!");
}

Program does not send UDP package on specified port

I'm new to socket programming. I want to send a UDP package to a specific port on another PC in the network. When I analysie my network traffic with Wireshark I see a different port number in the outgoing packages from what I specified in my code.
With port=10000 the actual port it gets send to is 4135. When I changed it to port=15000 (just to try something different) it got send to port 38970.
The port numbers wireshark shows must be true, as a receiving program set to listen on these ports (4135 or 38970) does react to sent packages, although the received data seems like garble (the console shows unknown characters, the debug console shows "1\355I\211\321^H\211...").
Any ideas why?
I'm running this on a Debian VM connected to other VMs in a virtual network. A very similar program using TCP worked just fine.
#include <sys/types.h> //Various types, including ssize_t
#include <sys/socket.h> //Types, macros and functions for sockets
#include <netinet/in.h> //Types, including sockaddr_in, macros
#include <arpa/inet.h> //Types and functions, including inet_aton()
#include <unistd.h> //Types, macros and functions for Unix/Posix
#include <stdlib.h> //GP types, macros and functions
#include <stdio.h> //IO operations (streams)
#include <string.h> //Functions for string operations
#define BC_ADDR "192.168.1.255"
int main(int argc, char** argv) {
int clientSocket;
const int setBroadcast = 1;
in_port_t port = 10000;
struct sockaddr_in broadcastAddr;
int broadcastAddrLen = sizeof(struct sockaddr_in);
const char* msg = "Hello World";
//Create a new UDP socket
clientSocket = socket(AF_INET, SOCK_DGRAM, 0);
if(clientSocket > 0) {
printf("Socket created successfully\n");
}
else {
printf("Failure during socket creation\n");
exit(EXIT_FAILURE);
}
//Set socket options to allow broadcasts
int setSockOptStatus = setsockopt(clientSocket, SOL_SOCKET,
SO_BROADCAST, &setBroadcast, sizeof(setBroadcast));
if(setSockOptStatus != 0) {
printf("Error setting socket options!");
close(clientSocket);
return EXIT_FAILURE;
}
//Form boradcast address structure
broadcastAddr.sin_family = AF_INET;
broadcastAddr.sin_port = port;
broadcastAddr.sin_addr.s_addr = inet_addr(BC_ADDR);
//Send broadcast message
sendto(clientSocket, msg, strlen(msg)+1, 0,
(struct sockaddr*) &broadcastAddr, broadcastAddrLen);
//Close socket and exit program
close(clientSocket);
return EXIT_SUCCESS;
}
The problem is how you're setting the port:
broadcastAddr.sin_port = port;
The IP address and port number stored in a struct sockaddr_in must both be in network byte order which is big-endian byte ordering, i.e. most significant byte first. Your machine apparently uses little-endian byte ordering, i.e. least significant byte first, so by assigning the port number directly to the sin_port member that conversion is not being done.
This is more apparent if you look at the hexadecimal representation of the expected and actual port numbers:
10000d = 2710h, 4135d = 1027h
15000d = 3a98h, 38970 = 983ah
You need to call the htons() function, which converts a 16-bit value from host byte order to network byte order:
broadcastAddr.sin_port = htons(port);

Send Array of Objects to C++ client with Node.Js server

I am trying to send an array of objects to my C++ client using the code below. I originally was trying to do so with just the http library alone in which i further investigated and found this out to be not correct approach.
What i'm not clear with this is how socket.write("hello C++ client") will allow me to send this string and have it appear in my terminal C++ but using socket.emit("arrayTransfer", arrayOfObjects); or a similar variation of what i'm trying below will not allow me to receive anything, I have tried different variations of sending the array of objects but have not succeeded can someone help me understand what exactly may be going on in this code and how Nodejs handles these types of sockets?
thank you.
Here is my questions I asked before to gain a better understanding perhaps.
NodeJs server and C++ client
var server = require("net").createServer();
var io = require("socket.io")(server);
socket.emit("message", myArray[0].name);
};
io.on("connection", handleClient);
server.listen(8080);
C++ CLIENT CODE BELOW
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define LENGTH (512)
#include <errno.h>
#include <sys/stat.h>
#include <arpa/inet.h>
#define PORT_NUMBER (8080) // port number where to port in application
int clientSocket;
char buffer[LENGTH];
struct sockaddr_in serverAddr;
socklen_t addr_size;
int main()
{
/*---- Create the socket. The three arguments are: ----*/
/* 1) Internet domain 2) Stream socket 3) Default protocol (TCP in this case) */
clientSocket = socket(PF_INET, SOCK_STREAM, 0);
/*---- Configure settings of the server address struct ----*/
/* Address family = Internet */
serverAddr.sin_family = AF_INET;
/* Set port number, using htons function to use proper byte order */
serverAddr.sin_port = htons(PORT_NUMBER);
/* Set IP address to localhost */
serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
/* Set all bits of the padding field to 0 */
memset(serverAddr.sin_zero, '\0', sizeof serverAddr.sin_zero);
/*---- Connect the socket to the server using the address struct ----*/
addr_size = sizeof serverAddr;
connect(clientSocket, (struct sockaddr *) &serverAddr, addr_size);
/*---- Read the message from the server into the buffer ----*/
recv(clientSocket, buffer, 1024, 0);
printf("This is your message %s", buffer);
close(clientSocket);
return 0;
}

recv() function doesn't read the input (Socket Programming)

This is a simple program that simulates a credential validation server. Clients should connect using telnet to the server on port 80. The client should enter a username and a matching password. The problem is that the recv() function does not seem to receive the right input (so that further processing can be done on it).
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
int main()
{
char * credentialsList[7][2] = {{"Alice","abcdef"}, {"Bob","1234567"}, {"Cindy","qwerty"}, {"David","abababab"}, {"Eve", "cdefgh"}, {"Frank","7654321"}, {"George", "12341234"}};
int serverSocket=socket(AF_INET, SOCK_STREAM, 0);
int new_socket, i;
char *message, client_message[10];
struct sockaddr_in server, client;
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(80);
bind(serverSocket, (struct sockaddr *)&server, sizeof(server));
listen(serverSocket,2);
int c = sizeof(struct sockaddr_in);
new_socket = accept(serverSocket, (struct sockaddr *)&client, (socklen_t*)&c);
message = "Welcome! You Are Now Connected To The Server.\n\n";
write(new_socket, message, strlen(message));
message = "Please Enter A Valid Username: ";
write(new_socket, message, strlen(message));
memset(client_message,0,sizeof(client_message));
recv(new_socket, client_message, 10, 0);
//int x = strcmp(client_message,credentialsList[0][0]);
//printf("%i", x);
puts(client_message);
return 0;
}
How do you detect the end of the username? Is it detected by the end of the connection, by a newline or perhaps by a '\0' character? It's impossible to answer this since you didn't provide the client code.
Anyway, you're not checking the return value of recv() and the commented-out implicitly assumes that it's a '\0'-terminated string which may not be true. You should always check the return code of system calls and never assume the client data to be formatted according to a certain format.
What you need to do is to read the credentials and nothing else. This may even require reading 1 byte at a time until you reach the newline if it's newline-delimited (a more efficient implementation of this would be the implementation of a buffering layer on top of recv()). Note that reading the credentials may require multiple recv() calls as the credentials may arrive in 1-byte-sized TCP segments.

When is the UDP source port set?

I'm writing a very small C UDP client. I know that a random port is chosen as source port when you send data to the server. I also know that you can use bind to specify yourself the port you want a response.
However, I don't know when is the port randomly chosen? For example, I would like to rely on the sender address to keep track of users. It currently works only if the client does not shutdown, the port is still the same then a simple memcmp is enough to detect the same client.
This small code will use the same source port until it exits:
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <err.h>
int main(void)
{
int s, error, ch;
struct addrinfo hints, *res;
memset(&hints, 0, sizeof (struct addrinfo));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_DGRAM;
if ((error = getaddrinfo("localhost", "9988", &hints, &res)))
errx(1, "%s", gai_strerror(error));
if ((s = socket(res->ai_family, res->ai_socktype, 0)) < 0)
err(1, "socket");
while ((ch = fgetc(stdin)) != EOF)
sendto(s, &ch, 1, 0, res->ai_addr, res->ai_addrlen);
}
And running something like : dmesg | ./client will use the same address until the program exits. However, when you run it again, the port is different.
So is it the socket function that choose a port? Or the system? Is it sure that the port will still be the same during the client lifetime?
If the socket is not explicitly bound, then the OS will bind it (with a random port) when you send the first packet. This binding will be active as long as the socket is open, once it's closed the socket is (of course) unbound.
And due to the connectionless nature of UDP sockets, the "server" (if done correctly) should not keep the address of all "clients" that send to it indefinitely. Instead it should use the source address as received in the recvfrom call, and use that for a reply. The only reason to store the source address for more than just a simple request/response, is if you have a more advanced protocol on top of UDP with your own "connection" handling.

Resources