I need some serious help here. I have to make a TCP Server Client. When the Client connects to server using a three stage handshake. Afterwards, while the Client is running in the terminal, the user enters Linux shell commands like xinput list, ls -1, etc — something that uses standard output. The server accepts the commands and uses system() (in a fork() in an infinite loop) to run the commands and the standard output is redirected to the client, where the client prints out each line.
Afterward the server sends a completion signal of "\377\n". In which the client goes back to the command prompt asking for a new command and closes its connection and exit()'s when inputting "quit".
I know that you have to dup2() both the STDOUT_FILENO and STDERR_FILENO to the client's file descriptor {dup2(client_FD, STDOUT_FILENO). Everything works except when it comes for the client to retrieve system()'s stdout and printing it out... all I get is a blank line with a blinking cursor (client waiting on stdin). I tried all kinds of different routes to no avail... If anyone can help out I would greatly appreciate it
TCP SERVER CODE
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <netinet/in.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
//Prototype
void handle_client(int connect_fd);
int main()
{
int server_sockfd, client_sockfd;
socklen_t server_len, client_len;
struct sockaddr_in server_address;
struct sockaddr_in client_address;
server_sockfd = socket(AF_INET, SOCK_STREAM, 0);
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = htonl(INADDR_ANY);
server_address.sin_port = htons(9734);
server_len = sizeof(server_address);
bind(server_sockfd, (struct sockaddr *)&server_address, server_len);
/* Create a connection queue, ignore child exit details and wait for clients. */
listen(server_sockfd, 10);
signal(SIGCHLD, SIG_IGN);
while(1) {
printf("server waiting\n");
client_len = sizeof(client_address);
client_sockfd = accept(server_sockfd,
(struct sockaddr *)&client_address, &client_len);
if(fork() == 0)
handle_client(client_sockfd);
else
close(client_sockfd);
}
}
void handle_client(int connect_fd) {
const char* remsh = "<remsh>\n";
const char* ready = "<ready>\n";
const char* ok = "<ok>\n";
const char* command = "<command>\n";
const char* complete = "<\377\n";
const char* shared_secret = "<shapoopi>\n";
static char server_msg[201];
static char client_msg[201];
static char commands[201];
int sys_return;
//memset client_msg, server_msg, commands
memset(&client_msg, 0, sizeof(client_msg));
memset(&server_msg, 0, sizeof(client_msg));
memset(&commands, 0, sizeof(commands));
//read remsh from client
read(connect_fd, &client_msg, 200);
//check remsh validity from client
if(strcmp(client_msg, remsh) != 0) {
errno++;
perror("Error Establishing Handshake");
close(connect_fd);
exit(1);
}
//memset client_msg
memset(&client_msg, 0, sizeof(client_msg));
//write remsh to client
write(connect_fd, remsh, strlen(remsh));
//read shared_secret from client
read(connect_fd, &client_msg, 200);
//check shared_secret validity from client
if(strcmp(client_msg, shared_secret) != 0) {
errno++;
perror("Invalid Security Passphrase");
write(connect_fd, "no", 2);
close(connect_fd);
exit(1);
}
//memset client_msg
memset(&client_msg, 0, sizeof(client_msg));
//write ok to client
write(connect_fd, ok, strlen(ok));
// dup2 STDOUT_FILENO <= client fd, STDERR_FILENO <= client fd
dup2(connect_fd, STDOUT_FILENO);
dup2(connect_fd, STDERR_FILENO);
//begin while... while read (client_msg) from server and >0
while(read(connect_fd, &client_msg, 200) > 0) {
//check command validity from client
if(strcmp(client_msg, command) != 0) {
errno++;
perror("Error, unable to retrieve data");
close(connect_fd);
exit(1);
}
//memset client_msg
memset(&client_msg, 0, sizeof(client_msg));
//write ready to client
write(connect_fd, ready, strlen(ready));
//read commands from client
read(connect_fd, &commands, 200);
//run commands using system( )
sys_return = system(commands);
//check success of system( )
if(sys_return < 0) {
perror("Invalid Commands");
errno++;
}
//memset commands
memset(commands, 0, sizeof(commands));
//write complete to client
write(connect_fd, complete, sizeof(complete));
}
}
TCP CLIENT CODE
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include "readline.c"
int main(int argc, char *argv[])
{
int sockfd;
int len;
struct sockaddr_in address;
int result;
const char* remsh = "<remsh>\n";
const char* ready = "<ready>\n";
const char* ok = "<ok>\n";
const char* command = "<command>\n";
const char* complete = "<\377\n";
const char* shared_secret = "<shapoopi>\n";
static char server_msg[201];
static char client_msg[201];
memset(&client_msg, 0, sizeof(client_msg));
memset(&server_msg, 0, sizeof(server_msg));
/* Create a socket for the client. */
sockfd = socket(AF_INET, SOCK_STREAM, 0);
/* Name the socket, as agreed with the server. */
memset(&address, 0, sizeof(address));
address.sin_family = AF_INET;
address.sin_addr.s_addr = inet_addr(argv[1]);
address.sin_port = htons(9734);
len = sizeof(address);
/* Now connect our socket to the server's socket. */
result = connect(sockfd, (struct sockaddr *)&address, len);
if(result == -1) {
perror("ACCESS DENIED");
exit(1);
}
//write remsh to server
write(sockfd, remsh, strlen(remsh));
//read remsh from server
read(sockfd, &server_msg, 200);
//check remsh validity from server
if(strcmp(server_msg, remsh) != 0) {
errno++;
perror("Error Establishing Initial Handshake");
close(sockfd);
exit(1);
}
//memset server_msg
memset(&server_msg, 0, sizeof(server_msg));
//write shared secret text to server
write(sockfd, shared_secret, strlen(shared_secret));
//read ok from server
read(sockfd, &server_msg, 200);
//check ok velidity from server
if(strcmp(server_msg, ok) != 0 ) {
errno++;
perror("Incorrect security phrase");
close(sockfd);
exit(1);
}
//? dup2 STDIN_FILENO = server socket fd?
//dup2(sockfd, STDIN_FILENO);
//begin while(1)///////////////////////////////////////
while(1){
//memset both msg arrays
memset(&client_msg, 0, sizeof(client_msg));
memset(&server_msg, 0, sizeof(server_msg));
//print Enter Command, scan input, fflush to stdout
printf("<<Enter Command>> ");
scanf("%s", client_msg);
fflush(stdout);
//check quit input, if true close and exit successfully
if(strcmp(client_msg, "quit") == 0) {
printf("Exiting\n");
close(sockfd);
exit(EXIT_SUCCESS);
}
//write command to server
write(sockfd, command, strlen(command));
//read ready from server
read(sockfd, &server_msg, 200);
//check ready validity from server
if(strcmp(server_msg, ready) != 0) {
errno++;
perror("Failed Server Communications");
close(sockfd);
exit(1);
}
//memset server_msg
memset(&server_msg, 0, sizeof(server_msg));
//begin looping and retrieving from stdin,
//break loop at EOF or complete
while((read(sockfd, server_msg, 200) != 0) && (strcmp(server_msg, complete) != 0)) {
//while((fgets(server_msg, 4096, stdin) != EOF) || (strcmp(server_msg, complete) == 0)) {
printf("%s", server_msg);
memset(&server_msg, 0, sizeof(server_msg));
}
}
}
The output of subprocess, spawned by system(), is not connected to the calling parent process.
Try popen().
In the server, the error exits from handle_client() carefully call close(connect_fd); but the ordinary exit does not. This means that the server does not close the connection to the client, so the client waits for the server to disconnect. This is why you see the code hanging.
Related
I created a simple TCP server listening on 8080 port that sends a message to the client once a connection is established. Here's the code.
#include <iostream>
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")
#pragma warning(disable:4996)
int main(int argc, char* argv[]) {
WSADATA wsa;
SOCKET s, new_socket;
int c;
int ret;
struct sockaddr_in server, client;
char* message = "Thank you for connecting to us but i got to go\n";
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0) {
printf("Failed to initialize Winsock : %d", WSAGetLastError());
return 1;
}
s = socket(AF_INET, SOCK_STREAM, 0);
if (s == INVALID_SOCKET) {
printf("Error creating socket : %d", WSAGetLastError());
}
server.sin_family = AF_INET;
server.sin_port = htons(8080);
server.sin_addr.s_addr = INADDR_ANY;
if (bind(s, (struct sockaddr*)&server, sizeof(server)) == SOCKET_ERROR) {
printf("Error binding socket : %d\n", WSAGetLastError());
exit(EXIT_FAILURE);
}
listen(s, 3);
puts("Listening for incoming connection\n");
c = sizeof(struct sockaddr_in);
while (new_socket = accept(s, (struct sockaddr*)&client, &c) != INVALID_SOCKET) {
puts("Connection established\n");
send(new_socket, message, strlen(message), 0);
}
if (new_socket == INVALID_SOCKET) {
printf("Connection failed : %d", WSAGetLastError());
return 1;
}
closesocket(s);
WSACleanup();
return 0;
}
When I'm running this, the server runs just fine. I open another terminal and open telnet and try to connect to the server on 8080 port. This is the client side terminal.
Welcome to Microsoft Telnet Client
Escape Character is 'CTRL+]'
Microsoft Telnet> open localhost 8080
Connecting To localhost...
And this is the server side.
Listening for incoming connection
Connection established
But even after server says that a connection is established, the client side stays at "Connecting to localhost". I send the message "Thank you for connecting to us but i got to go\n" but it doesn't show on the client side. what can possibly be wrong?
As it appears, it was a silly mistake.
while (new_socket = accept(s, (struct sockaddr*)&client, &c) != INVALID_SOCKET)
Since I didn't put another bracket over the new_socket = accept(s, (struct sockaddr*)&client, &c after initializing new_socket, the inequality was being applied on the accept function return.
The correct syntax would be
while ((new_socket = accept(s, (struct sockaddr*)&client, &c)) != INVALID_SOCKET)
Suppose I have a TCP Server(A) listening on port 8001.
Now, I want to open a TCP Socket to Server(B) from Server(A) using local port 8001. So that, Server(B) will see connection from Server(A) from port 8001.
Is it possible ? Can I use a port for outgoing connection that's already used for listening incoming connections.
You can do that: socket followed by setsockopt(SO_REUSEPORT) and then bind.
man socket(7):
SO_REUSEPORT (since Linux 3.9)
Permits multiple AF_INET or AF_INET6 sockets to be bound to an identical socket address. This option must be set on each socket (including the first socket) prior to calling bind(2) on the socket. To prevent port hijacking, all of the processes binding to the same address must have the same effective UID. This option can be employed with both TCP and UDP sockets.
Here is a working example that has two sockets bound to the same address and port 127.0.0.1:2222. One socket is a listening server socket, another is a client successfully making a connection to 127.0.0.1:22 (ssh):
#include <thread>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <err.h>
#include <unistd.h>
int socket_and_bind() {
int s = socket(AF_INET, SOCK_STREAM, 0);
if(-1 == s)
err(EXIT_FAILURE, "socket");
int flag = 1;
if(-1 == setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &flag, sizeof flag))
err(EXIT_FAILURE, "setsockopt(SO_REUSEPORT)");
sockaddr_in sa = {};
sa.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
sa.sin_port = htons(2222);
sa.sin_family = AF_INET;
if(-1 == bind(s, reinterpret_cast<sockaddr*>(&sa), sizeof sa))
err(EXIT_FAILURE, "bind");
return s;
}
void server(int s) {
int c = accept(s, nullptr, nullptr);
if(-1 == c)
err(EXIT_FAILURE, "accept");
close(c);
}
void client(int s) {
sockaddr_in sa = {};
sa.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
sa.sin_port = htons(22);
sa.sin_family = AF_INET;
if(-1 == connect(s, reinterpret_cast<sockaddr*>(&sa), sizeof sa))
err(EXIT_FAILURE, "connect");
char buf;
if(1 != recv(s, &buf, sizeof buf, 0))
err(EXIT_FAILURE, "recv");
printf("connected\n");
}
int main() {
int s1 = socket_and_bind();
if(-1 == listen(s1, 1))
err(EXIT_FAILURE, "listen");
int s2 = socket_and_bind();
std::thread t1(server, s1);
std::thread t2(client, s2);
t2.join();
t1.detach();
return EXIT_SUCCESS;
}
One thing that is broken in Linux is connecting from an addr:port to the same:addr port.
I've written a code using SOL_SOCKET protocol but getting error as 10043 (error in socket).
The code is as follows:
#include <QCoreApplication>
#include<QDebug>
//#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>
/****************************************/
#pragma comment (lib, "Ws2_32.lib")
#pragma comment (lib, "Mswsock.lib")
#pragma comment (lib, "AdvApi32.lib")
/****************************************/
#define DEFAULT_BUFLEN 512
int recvbuflen = DEFAULT_BUFLEN;
char recvbuf[DEFAULT_BUFLEN];
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
WSADATA wsaData;
int iResult;
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed with error: %d\n", iResult);
return 1;
}
struct addrinfo *result = NULL,
*ptr = NULL,
hints;
ZeroMemory( &hints, sizeof(hints) );
//hints.ai_family = AF_UNSPEC;
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = SOL_SOCKET;
//hints.ai_protocol = IPPROTO_TCP;
#define DEFAULT_PORT "10990"
// Resolve the server address and port
iResult = getaddrinfo(argv[1], DEFAULT_PORT, &hints, &result);
if (iResult != 0) {
printf("getaddrinfo failed: %d\n", iResult);
WSACleanup();
return 1;
}
SOCKET ConnectSocket = INVALID_SOCKET;
// Attempt to connect to the first address returned by
// the call to getaddrinfo
ptr=result;
// Create a SOCKET for connecting to server
ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype,
ptr->ai_protocol);
if (ConnectSocket == INVALID_SOCKET) {
printf("Error at socket(): %ld\n", WSAGetLastError());
freeaddrinfo(result);
WSACleanup();
return 1;
}
int rcvbuf = 8192; /* recv buffer size */
int z = setsockopt(ConnectSocket,SOL_SOCKET,SO_RCVBUF,
(char*)&rcvbuf,sizeof(rcvbuf));
do {
iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);
if (iResult > 0)
printf("Bytes received: %d\n", iResult);
else if (iResult == 0)
printf("Connection closed\n");
else
printf("recv failed: %d\n", WSAGetLastError());
} while (iResult > 0);
return a.exec();
}
When I run it shows::
Error in socket:10043
I googled it and found that the error is because of wrong protocol for the socket type,I tried to find the correct protocol and socket type match but couldn't find.I tried every possible socket option and protocol match.
Any body facing the same problem?
You're putting the wrong value in the ai_protocol field. It needs to be one of the IPPROTO_ constants (like e.g. IPPROTO_TCP or IPPROTO_ICMP).
SOL_SOCKET is used to set socket options (like you do later in the code).
You should normally not set that member, except to zero.
I have a simple program written in C which uses termios to send a basic string to the Raspberry Pi UART and attempts to read and output the response. The Rx and Tx pins on the Raspberry Pi are connected with a jumper so whatever is sent should be immediately received.
Despite the program outputting that it successfully sent and received 5 characters for the chosen string ('Hello'), trying to print the contents of the buffer just produces one or two garbage characters.
The program:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
int main(int argc, char* argv[]) {
struct termios serial;
char* str = "Hello";
char buffer[10];
if (argc == 1) {
printf("Usage: %s [device]\n\n", argv[0]);
return -1;
}
printf("Opening %s\n", argv[1]);
int fd = open(argv[1], O_RDWR | O_NOCTTY | O_NDELAY);
if (fd == -1) {
perror(argv[1]);
return -1;
}
if (tcgetattr(fd, &serial) < 0) {
perror("Getting configuration");
return -1;
}
// Set up Serial Configuration
serial.c_iflag = 0;
serial.c_oflag = 0;
serial.c_lflag = 0;
serial.c_cflag = 0;
serial.c_cc[VMIN] = 0;
serial.c_cc[VTIME] = 0;
serial.c_cflag = B115200 | CS8 | CREAD;
tcsetattr(fd, TCSANOW, &serial); // Apply configuration
// Attempt to send and receive
printf("Sending: %s\n", str);
int wcount = write(fd, &str, strlen(str));
if (wcount < 0) {
perror("Write");
return -1;
}
else {
printf("Sent %d characters\n", wcount);
}
int rcount = read(fd, &buffer, sizeof(buffer));
if (rcount < 0) {
perror("Read");
return -1;
}
else {
printf("Received %d characters\n", rcount);
}
buffer[rcount] = '\0';
printf("Received: %s\n", buffer);
close(fd);
}
Outputs:
Opening /dev/ttyAMA0
Sending: Hello
Sent 5 characters
Received 5 characters
Received: [garbage]
I can't see any major problem with the code myself, but I might be wrong. I can successfully send and receive characters using PuTTY connected with the same settings, so it can't really be a hardware problem. Although I haven't tried it in PuTTY, trying to connect with anything less than 115200 baud with this program will result in nothing being received.
Where am I going wrong?
int wcount = write(fd, &str, strlen(str));
int rcount = read(fd, &buffer, sizeof(buffer));
In these lines, buffer/str are already pointers. You are passing a pointer to a pointer.
The lines should be:
int wcount = write(fd, str, strlen(str));
int rcount = read(fd, buffer, sizeof(buffer));
So I've looked around and noticed some others having a similar problem to mine. However I have yet to find a solution. I've created a client and server in Unix (Cygwin) using UDP. When I try to use sendto() in order to send a message to the server from the client, the server doesn't seem to be receiving the the packet. I've done error checking and it seems like the client isn't having a problem sending the packet, yet still the server cannot receive it correctly. The server just seems to be dead for the most part. I'm using my machine to host the client and the server and I'm attempting to connect to the server on my home address (127.0.0.1) and a random port. Any suggestions at this point would be much appreciated.
Server Code:
#include <stdio.h> /* standard C i/o facilities */
#include <stdlib.h> /* needed for atoi() / atof() */
#include <unistd.h> /* Unix System Calls */
#include <sys/types.h> /* system data type definitions */
#include <sys/socket.h> /* socket specific definitions */
#include <netinet/in.h> /* INET constants and stuff */
#include <arpa/inet.h> /* IP address conversion stuff */
#include <string.h> /* String manipulation */
#include <time.h> /* Used to to measure process execution time */
/* Server main routine - this is an iterative server
1. create a socket
2. bind the socket and print out the port number assigned
3. do forever
get next connection
handle the connection
enddo
*/
int main(int argc, char **argv)
{
int sockfd;
struct sockaddr_in servaddr, cliaddr;
int n;
//Create UDP socket
if( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("Problem creating socket\n");
exit(1);
}
//Setup the UDP server
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(0);
//Bind the UDP to the socket
if (bind(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr))<0)
{
perror("Error bind\n");
exit(1);
}
//Print the port for the UDP server
int length = sizeof( servaddr );
if (getsockname(sockfd, (struct sockaddr *) &servaddr, &length) < 0)
{
perror("Error getsockname\n");
exit(1);
}
printf("The Server passive socket port number is %d\n",ntohs(servaddr.sin_port));
//Send/Recv from client
char msg[100];
for(;;)
{
socklen_t len = sizeof(cliaddr);
if( recvfrom(sockfd, msg, 100, 0, (struct sockaddr*) &cliaddr, &len) < 0)
{
perror("Error on recv\n");
exit(1);
}
printf("Msg: %s\n", msg);
//read(sockfd, msg, 10);
//sendto(sockfd, msg, n, 0, (struct sockaddr*) &cliaddr, len);
}
close(sockfd);
return 0;
}
Client Code:
#include <stdio.h> /* standard C i/o facilities */
#include <stdlib.h> /* needed for atoi() */
#include <unistd.h> /* Unix System Calls */
#include <sys/types.h> /* system data type definitions */
#include <sys/socket.h> /* socket specific definitions */
#include <netinet/in.h> /* INET constants and stuff */
#include <arpa/inet.h> /* IP address conversion stuff */
#include <string.h>
/* client program:
The following must passed in on the command line:
name of the server (argv[1])
port number of the server (argv[2])
*/
int main( int argc, char **argv )
{
int sockfd;
struct sockaddr_in servaddr;
int n;
//Ensure we have full args
if (argc != 3)
{
printf("Usage: client <server name> <server port>\n");
exit(1);
}
//Setup the port number
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(atoi(argv[2]));
//Setup the client IP
//inet_pton(AF_INET, argv[1], &servaddr.sin_addr)) <= 0
if( inet_aton(argv[1], &servaddr.sin_addr) == 0)
{
perror("Error with server IP\n");
exit(1);
}
//Create socket
if( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
perror("Error on socket\n");
exit(1);
}
/*if (connect(sockfd,(struct sockaddr *) &servaddr, sizeof(servaddr)) < 0 )
{
printf("Problem connecting socket\n");
exit(1);
}*/
//Send msg
char msg[10] = "123456789";
for(;;)
{
socklen_t len = sizeof(servaddr);
if( (sendto(sockfd, msg, strlen(msg), 0, (struct sockaddr*) &servaddr, len)) < 0 )
{
perror("Error on sendto():\n");
exit(1);
}
//write(sockfd, msg, strlen(msg));
//n = recvfrom(sockfd, msg2, 10, 0, NULL, NULL);
//printf("Msg: %s\n", msg2);
}
close(sockfd);
return 0;
}
First, your sender just sends data as fast as it possibly can, whether or not anyone or anything is listening. That's not a good thing to do.
Second, your receiver passes msg through to a %s printf specifier. But %s is only for C-style strings, and msg is not a C-style string (nothing puts a zero byte on the end of it). You also throw the return value of recvfrom away, so you can't convert it into a string because you have no idea how many of its bytes are valid.
Third, your server is creating a SOCK_STREAM socket!