C language : gethostbyaddr() return : Operation not permitted - c

Currently i'm trying to make a ping-like program and it work pretty good but i've a probleme on the DNS_lookup()
Here is my function :
char *DNS_reverse_lookup(struct sockaddr_in *host_addr)
{
if (host_addr == NULL)
{
printf("host_addr is empty.\n");
return NULL;
}
struct hostent *host_info = NULL;
host_info = gethostbyaddr(&host_addr->sin_addr.s_addr, sizeof(*host_addr), host_addr->sin_family);
if (host_info == NULL)
{
printf("%s:%d : gethostbyaddr() failed : %s\n", __FILE__, __LINE__, strerror(h_errno));
return NULL;
}
return host_info->h_name;
}
Here the gethostbyaddr() return Operation not permitted for some domain for exemple for google.com but for my ovh server it return the expected result and i don't know why
someone can explain ?
Here's all of my code :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <errno.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/time.h>
#include <time.h>
#include <netinet/ip_icmp.h>
#include <signal.h>
#include <ifaddrs.h>
#include "globaldata/gd.h"
#include "netsocket/netsocket.h"
// packet size
#define PING_PKT_S 64
// Automatic port number
#define PORT_NB 0
#define PING_SLEEP_RATE 1000000
// Give the timeout delay for receiving packets
// In seconds
#define RECV_TIMEOUT 2
struct icmp_pkt {
struct icmphdr header;
char msg[PING_PKT_S - sizeof(struct icmphdr)];
};
void sigintHandler(int sig_num);
unsigned short checksum(void *b, int len);
struct sockaddr_in *DNS_lookup(char *host_domain_name);
char *DNS_reverse_lookup(struct sockaddr_in *host_addr);
void send_ping(Socket_t *socket, char *ping_ip, char *host_domain_name);
GlobalData gd;
int main(int argc, char *argv[])
{
/* Declaration */
// information about the host
struct sockaddr_in *host_addr = NULL;
socklen_t host_addr_len = sizeof(*host_addr);
Socket_t *socket = NULL;
char *host_domain_name;
int opt_value = 0, i = 0;
FILE *socket_file = NULL;
int arg_port = 0;
int port = 0;
struct ifaddrs *ifaces;
struct ifaddrs *tmp = NULL;
/* Allocation */
socket = SOCKET_New();
/* Initialisation */
// Correct syntax
if (argc < 2)
{
printf("\nFormat %s <address>\n", argv[0]);
goto FatalError;
}
for (i = 0 ; argv[i] != 0 ; i++)
{
if (strcmp(argv[i], "-p") == 0)
{
arg_port = i;
}
}
if (arg_port)
{
port = atoi(argv[arg_port+1]);
printf("port = %d\n", port);
}
// loop while the ping is performed
gd.ping_loop = 1;
// Open socket
if (SOCKET_OpenSocket(socket, AF_INET, SOCK_RAW, IPPROTO_ICMP) == NULL)
{
printf("SOCKET_OpenSocket() failed.\n");
goto FatalError;
}
opt_value = 1;
if (setsockopt(socket->sockfd, SOL_SOCKET, SO_REUSEADDR, &opt_value, sizeof(opt_value)) == -1)
{
printf("setsockopt() failed : %s\n", strerror(errno));
}
if (SOCKET_SetAddr(socket, inet_addr(argv[1]), AF_INET, port, 5) == NULL)
{
printf("SOCKET_SetAddr() failed?\n");
goto FatalError;
}
// Get host domain name (if there is)
host_domain_name = DNS_reverse_lookup(&socket->addr);
if (host_domain_name == NULL)
{
printf("DNS_reverse_lookup() failed.\n");
host_domain_name = 0;
// goto FatalError;
}
printf("host domain name = %s (%s)\n", host_domain_name, argv[1]);
// printf("\nsockaddr :\nIP = %x\nPort = %d\nFamily = %d\n", socket->addr.sin_addr.s_addr, socket->addr.sin_port, socket->addr.sin_family);
// if (SOCKET_BindToSocket(socket) == NULL)
// {
// printf("SOCKET_BindToSocket() failed.\n");
// goto FatalError;
// }
// handle interrupt signal
signal(SIGINT, sigintHandler);
send_ping(socket, argv[1], host_domain_name);
/* Leave */
if (socket != NULL)
{
if (socket->sockfd > 0)
{
shutdown(socket->sockfd, SHUT_RDWR);
close(socket->sockfd);
printf("\nsocket closed.\n");
}
socket = SOCKET_Free(socket);
}
printf("Terminated : Without Error.\n");
return EXIT_SUCCESS;
FatalError:
if (socket != NULL)
{
if (socket->sockfd > 0)
{
shutdown(socket->sockfd, SHUT_RDWR);
close(socket->sockfd);
printf("\nsocket closed.\n");
}
socket = SOCKET_Free(socket);
}
printf("Terminated : Fatal Error.\n");
return EXIT_FAILURE;
}
void sigintHandler(int sig_num)
{
gd.ping_loop = 0;
}
unsigned short checksum(void *b, int len)
{
unsigned short *buf = b;
unsigned int sum = 0;
unsigned short result;
for (sum = 0 ; len > 1 ; len -= 2)
{
sum += *buf++;
}
if (len == 1)
{
sum += *(unsigned char *)buf;
}
sum = (sum >> 16) + (sum & 0xFFFF);
sum += (sum >> 16);
result = ~sum;
return result;
}
// Return struct sockaddr_in *ptr on success or 0 on error
struct sockaddr_in *DNS_lookup(char *host_domain_name)
{
printf("\nResolving DNS...\n");
// store host info in struct hostent
struct hostent *host_info = NULL;
static struct sockaddr_in host_addr;
memset(&host_addr, 0, sizeof(host_addr));
if ((host_info = gethostbyname(host_domain_name)) == NULL)
{
printf("%s:%d : gethostbyname() failed %s\n", __FILE__, __LINE__, strerror(h_errno));
return NULL;
}
host_addr.sin_addr.s_addr = inet_addr(host_info->h_addr_list[0]);
host_addr.sin_family = host_info->h_addrtype;
host_addr.sin_port = htons(PORT_NB);
printf("Resolved.\n\n");
return &host_addr;
}
// Return char *host_domain_name on success or 0 on error
char *DNS_reverse_lookup(struct sockaddr_in *host_addr)
{
if (host_addr == NULL)
{
printf("host_addr is empty.\n");
return NULL;
}
struct hostent *host_info = NULL;
host_info = gethostbyaddr(&host_addr->sin_addr.s_addr, sizeof(*host_addr), host_addr->sin_family);
if (host_info == NULL)
{
printf("%s:%d : gethostbyaddr() failed : %s\n", __FILE__, __LINE__, strerror(h_errno));
return NULL;
}
return host_info->h_name;
}
void send_ping(Socket_t *socket, char *ping_ip, char *host_domain_name)
{
if (socket == NULL)
{
printf("%s:%d : Bad socket.\n", __FILE__, __LINE__);
return;
}
if (socket->sockfd <= 0)
{
printf("%s:%d : Bad socket file descriptor.\n", __FILE__, __LINE__);
}
int ttl_value, msg_count, i, addr_len, flag, msg_received_count;
struct icmp_pkt packet;
struct sockaddr_in r_addr;
long double rtt_msec, total_msec;
struct timespec time_start, time_end, tfs, tfe;
struct timeval tv_out;
tv_out.tv_sec = RECV_TIMEOUT;
tv_out.tv_usec = 0;
ttl_value = 64;
msg_count = 0;
i = 0;
addr_len = 0;
flag = 1;
msg_received_count = 0;
rtt_msec = total_msec = 0.0;
// time start
clock_gettime(CLOCK_MONOTONIC, &tfs);
// SOL = Set Option Level
// SO = Set Option
// Set time to live value
if (setsockopt(socket->sockfd, SOL_IP, IP_TTL, &ttl_value, sizeof(ttl_value)) == -1)
{
printf("%s:%d : setsockopt() failed : %s\n", __FILE__, __LINE__, strerror(errno));
return;
}
printf("Socket set to TTL : %d\n", ttl_value);
// Set timeout of receiving setting
if (setsockopt(socket->sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char *)&tv_out, sizeof(tv_out)) == -1)
{
printf("%s:%d : setsockopt() failed : %s\n", __FILE__, __LINE__, strerror(errno));
return;
}
printf("Ping to %s (%s).\n", host_domain_name, ping_ip);
while (gd.ping_loop)
{
// flag is whether packet was sent or not
flag = 1;
// filling packet
memset(&packet, 0, sizeof(packet));
packet.header.type = ICMP_ECHO;
packet.header.un.echo.id = getpid();
for (i = 0 ; i < sizeof(packet.msg) ; i++)
{
packet.msg[i] = '\0';
}
char message[] = "Anything";
strncpy(packet.msg, message, strlen(message));
packet.header.un.echo.sequence = msg_count++;
packet.header.checksum = checksum(&packet, sizeof(packet));
usleep(PING_SLEEP_RATE);
// send packet
clock_gettime(CLOCK_MONOTONIC, &time_start);
// if (write(socket->sockfd, &packet, sizeof(packet)) == -1)
// {
// printf("%s:%d : write() failed : %s\n", __FILE__, __LINE__, strerror(errno));
// flag = 0;
// }
if (sendto(socket->sockfd, &packet, sizeof(packet), 0, (struct sockaddr *)&socket->addr, socket->addr_len) == -1)
{
printf("%s:%d : sento() failed : %s\n", __FILE__, __LINE__, strerror(errno));
return;
}
// receiving packet
// printf("reading packet...\n");
// if (read(socket->sockfd, &packet, sizeof(packet)) == -1 && msg_count > 1)
// {
// printf("%s:%d : read() failed : %s\n", __FILE__, __LINE__, strerror(errno));
// flag = 0;
// }
if (recvfrom(socket->sockfd, &packet, sizeof(packet), 0, (struct sockaddr *)&socket->addr, &socket->addr_len) == -1)
{
printf("%s:%d : recvfrom() failed : %s\n", __FILE__, __LINE__, strerror(errno));
return;
}
else
{
clock_gettime(CLOCK_MONOTONIC, &time_end);
double time_elapsed = ((double)time_end.tv_nsec - (double)time_start.tv_nsec) / 1000000.0;
printf("time elapsed = %.4f\n", time_elapsed);
rtt_msec = (double)(time_end.tv_sec - time_start.tv_sec) * 1000.0 + time_elapsed;
// case packet wasn't sent or received
if (!flag)
{
printf("%s:%d : ERROR : Packet received with ICMP type %d code %d\n", __FILE__, __LINE__, packet.header.type, packet.header.code);
}else{
printf("%d bytes from %d (h: %s) (%s) msg_seq=%d ttl=%d rtt = %Lf ms.\n", PING_PKT_S, socket->addr.sin_family, host_domain_name, ping_ip, msg_count, ttl_value, rtt_msec);
msg_received_count++;
}
}
}
clock_gettime(CLOCK_MONOTONIC, &tfe);
double time_elapsed = ((double)(tfe.tv_nsec - tfs.tv_nsec)) / 1000000.0;
total_msec = (tfe.tv_sec - tfs.tv_sec) * 1000 + time_elapsed;
printf("\n===%s ping statistics===\n", ping_ip);
printf("\n%d packets sent, %d packets received, %f percent packet loss. Total time: %Lf ms.\n\n", msg_count, msg_received_count, (double)((msg_count - msg_received_count)/msg_count) * 100.0, total_msec);
}
terminal exec :
kali#kali:~/Code/Network/Ping$ sudo ./pingto 151.101.65.69
main.c:232 : gethostbyaddr() failed : Operation not permitted
DNS_reverse_lookup() failed.
host domain name = (null) (151.101.65.69)
Socket set to TTL : 64
Ping to (null) (151.101.65.69).
time elapsed = 8.1787
64 bytes from 2 (h: (null)) (151.101.65.69) msg_seq=1 ttl=64 rtt = 8.178748 ms.
time elapsed = 7.9054
64 bytes from 2 (h: (null)) (151.101.65.69) msg_seq=2 ttl=64 rtt = 7.905438 ms.
time elapsed = 8.2425
64 bytes from 2 (h: (null)) (151.101.65.69) msg_seq=3 ttl=64 rtt = 8.242489 ms.
^Ctime elapsed = 7.9805
64 bytes from 2 (h: (null)) (151.101.65.69) msg_seq=4 ttl=64 rtt = 7.980547 ms.
===151.101.65.69 ping statistics===
4 packets sent, 4 packets received, 0.000000 percent packet loss. Total time: 3494.951433 ms.
socket closed.
Terminated : Without Error.

You're not decoding the error code properly.
The values of h_errno do not correspond to the values that errno correspond to, so you can't use strerror to get the error text.
There is a function called hstrerror that does the same as strerror but for error codes returned by gethostbyname and other related functions.
The error codes listed in the man page are as follows:
HOST_NOT_FOUND
The specified host is unknown.
NO_ADDRESS or NO_DATA
The requested name is valid but does not have an IP address.
NO_RECOVERY
A nonrecoverable name server error occurred.
TRY_AGAIN
A temporary error occurred on an authoritative name server. Try
again later.
The "operation not permitted" code is EPERM, which on my system is 1. That code corresponds on my system to HOST_NOT_FOUND, so assuming your error codes are the same that's the actual error you're seeing.

Related

Recieve a message from server asynchronously

I have a client program and a server program. There could be multiple servers and multiple
clients that can connect to multiple servers of there choice
The client program lists a menu
connect 4000 // connects to server on port 4000
bid 1000 4000 // send a bid value of 1000 to the server at port 4000
Now a server may recieve bids from several clients connected to it and keeps track of the highest
bid till now. Whenever a new bid is placed the server sends a broadcast to each client connected
to it one by one like - write(users[i].sock_fd, msg, size).
How do I listen to this message on the client side ?
There are two things here
The client needs to listen to the message sent by server.
The client is also reading the text or menu items (connect and bid) from command line from the user.
I have coded the part 2) But confused how to code 1) into client and simultaneously make the 2) also working
Client code :
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#define BUF_SIZE 128
#define MAX_AUCTIONS 5
#ifndef VERBOSE
#define VERBOSE 0
#endif
#define ADD 0
#define SHOW 1
#define BID 2
#define QUIT 3
/* Auction struct - this is different than the struct in the server program
*/
typedef struct auction_data
{
int sock_fd;
char item[BUF_SIZE];
int current_bid;
} auction_data;
auction_data *auction_data_ptr;
/* Displays the command options available for the user.
* The user will type these commands on stdin.
*/
void print_menu()
{
printf("The following operations are available:\n");
printf(" show\n");
printf(" add <server address> <port number>\n");
printf(" bid <item index> <bid value>\n");
printf(" quit\n");
}
/* Prompt the user for the next command
*/
void print_prompt()
{
printf("Enter new command: ");
fflush(stdout);
}
/* Unpack buf which contains the input entered by the user.
* Return the command that is found as the first word in the line, or -1
* for an invalid command.
* If the command has arguments (add and bid), then copy these values to
* arg1 and arg2.
*/
int parse_command(char *buf, int size, char *arg1, char *arg2)
{
int result = -1;
char *ptr = NULL;
if (strncmp(buf, "show", strlen("show")) == 0)
{
return SHOW;
}
else if (strncmp(buf, "quit", strlen("quit")) == 0)
{
return QUIT;
}
else if (strncmp(buf, "add", strlen("add")) == 0)
{
result = ADD;
}
else if (strncmp(buf, "bid", strlen("bid")) == 0)
{
result = BID;
}
ptr = strtok(buf, " "); // first word in buf
ptr = strtok(NULL, " "); // second word in buf
if (ptr != NULL)
{
strncpy(arg1, ptr, BUF_SIZE);
}
else
{
return -1;
}
ptr = strtok(NULL, " "); // third word in buf
if (ptr != NULL)
{
strncpy(arg2, ptr, BUF_SIZE);
return result;
}
else
{
return -1;
}
return -1;
}
/* Connect to a server given a hostname and port number.
* Return the socket for this server
*/
int add_server(char *hostname, int port)
{
// Create the socket FD.
int sock_fd = socket(AF_INET, SOCK_STREAM, 0);
if (sock_fd < 0)
{
perror("client: socket");
exit(1);
}
// Set the IP and port of the server to connect to.
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(port);
struct addrinfo *ai;
/* this call declares memory and populates ailist */
if (getaddrinfo(hostname, NULL, NULL, &ai) != 0)
{
close(sock_fd);
return -1;
}
/* we only make use of the first element in the list */
server.sin_addr = ((struct sockaddr_in *)ai->ai_addr)->sin_addr;
// free the memory that was allocated by getaddrinfo for this list
freeaddrinfo(ai);
// Connect to the server.
if (connect(sock_fd, (struct sockaddr *)&server, sizeof(server)) == -1)
{
perror("client: connect");
close(sock_fd);
return -1;
}
if (VERBOSE)
{
fprintf(stderr, "\nDebug: New server connected on socket %d. Awaiting item\n", sock_fd);
}
return sock_fd;
}
/* ========================= Add helper functions below ========================
* Please add helper functions below to make it easier for the TAs to find the
* work that you have done. Helper functions that you need to complete are also
* given below.
*/
/* Print to standard output information about the auction
*/
void print_auctions(struct auction_data *a, int size)
{
printf("Current Auctions:\n");
for (int i = 0; i < size; i++)
{
struct auction_data auction_data = a[i];
printf("(%d) %s bid = %d\n", i, auction_data.item, auction_data.current_bid);
}
/* TODO Print the auction data for each currently connected
* server. Use the follosing format string:
* "(%d) %s bid = %d\n", index, item, current bid
* The array may have some elements where the auction has closed and
* should not be printed.
*/
}
/* Process the input that was sent from the auction server at a[index].
* If it is the first message from the server, then copy the item name
* to the item field. (Note that an item cannot have a space character in it.)
*/
void update_auction(char *buf, int size, struct auction_data *a, int index)
{
// TODO: Complete this function
// fprintf(stderr, "ERROR malformed bid: %s", buf);
// printf("\nNew bid for %s [%d] is %d (%d seconds left)\n", );
}
int main(void)
{
char name[BUF_SIZE];
int size = 0;
// Declare and initialize necessary variables
// TODO
// Get the user to provide a name.
printf("Please enter a username: ");
fflush(stdout);
int num_read = read(STDIN_FILENO, name, BUF_SIZE);
printf("%s-name\n", name);
if (num_read <= 0)
{
fprintf(stderr, "ERROR: read from stdin failed\n");
exit(1);
}
print_menu();
// TODO
char server_reply[2000];
while (1)
{
print_prompt();
char *command;
scanf("%m[^\n]s", &command);
getchar();
char arg1[100];
char arg2[100];
int commandNumber = parse_command(command, 1000, arg1, arg2);
char dest[100] = "";
strcpy(dest, name);
dest[strlen(dest) - 1] = '\0';
if (commandNumber == ADD)
{
printf("%s-name4\n", dest);
int port = atoi(arg2);
int sock_fd = add_server(arg1, port);
printf("%s-server\n", server_reply);
write(sock_fd, dest, strlen(dest));
auction_data_ptr = (auction_data *)realloc(auction_data_ptr, (size + 1) * sizeof(auction_data_ptr));
auction_data_ptr[size].sock_fd = sock_fd;
size++;
}
else if (commandNumber == SHOW)
{
print_auctions(auction_data_ptr, size);
}
else if (commandNumber == BID)
{
int itemIndex = atoi(arg1);
int bidValue = atoi(arg2);
printf("%d-test\n", auction_data_ptr[itemIndex].sock_fd);
send(auction_data_ptr[itemIndex].sock_fd, arg2, strlen(arg2), 0);
}
else if (commandNumber == QUIT)
{
}
// TODO
}
return 0; // Shoud never get here
}
Server Code :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#ifndef PORT
#define PORT 30000
#endif
#define MAX_BACKLOG 5
#define MAX_CONNECTIONS 20
#define BUF_SIZE 128
#define MAX_NAME 56
int verbose = 0;
struct user
{
int sock_fd;
char name[MAX_NAME];
int bid;
};
typedef struct
{
char *item;
int highest_bid; // value of the highest bid so far
int client; // index into the users array of the top bidder
} Auction;
/*
* Accept a connection. Note that a new file descriptor is created for
* communication with the client. The initial socket descriptor is used
* to accept connections, but the new socket is used to communicate.
* Return the new client's file descriptor or -1 on error.
*/
int accept_connection(int fd, struct user *users)
{
int user_index = 0;
while (user_index < MAX_CONNECTIONS && users[user_index].sock_fd != -1)
{
user_index++;
}
if (user_index == MAX_CONNECTIONS)
{
fprintf(stderr, "server: max concurrent connections\n");
return -1;
}
int client_fd = accept(fd, NULL, NULL);
if (client_fd < 0)
{
perror("server: accept");
close(fd);
exit(1);
}
users[user_index].sock_fd = client_fd;
users[user_index].name[0] = '\0';
return client_fd;
}
/* Remove \r\n from str if the characters are at the end of the string.
* Defensively assuming that \r could be the last or second last character.
*/
void strip_newline(char *str)
{
if (str[strlen(str) - 1] == '\n' || str[strlen(str) - 1] == '\r')
{
if (str[strlen(str) - 2] == '\r')
{
str[strlen(str) - 2] = '\0';
}
else
{
str[strlen(str) - 1] = '\0';
}
}
}
/*
* Read a name from a client and store in users.
* Return the fd if it has been closed or 0 otherwise.
*/
int read_name(int client_index, struct user *users)
{
int fd = users[client_index].sock_fd;
/* Note: This is not the best way to do this. We are counting
* on the client not to send more than BUF_SIZE bytes for the
* name.
*/
int num_read = read(fd, users[client_index].name, MAX_NAME);
if (num_read == 0)
{
users[client_index].sock_fd = -1;
return fd;
}
users[client_index].name[num_read] = '\0';
strip_newline(users[client_index].name);
if (verbose)
{
fprintf(stderr, "[%d] Name: %s\n", fd, users[client_index].name);
}
/*
if (num_read == 0 || write(fd, buf, strlen(buf)) != strlen(buf)) {
users[client_index].sock_fd = -1;
return fd;
}
*/
return 0;
}
/* Read a bid from a client and store it in bid.
* If the client does not send a number, bid will be set to -1
* Return fd if the socket is closed, or 0 otherwise.
*/
int read_bid(int client_index, struct user *users, int *bid)
{
printf("inside bid\n");
int fd = users[client_index].sock_fd;
char buf[BUF_SIZE];
char *endptr;
int num_read = read(fd, buf, BUF_SIZE);
if (num_read == 0)
{
return fd;
}
buf[num_read] = '\0';
if (verbose)
{
fprintf(stderr, "[%d] bid: %s", fd, buf);
}
// Check if the client sent a valid number
// (We are not checking for a good bid here.)
errno = 0;
*bid = strtol(buf, &endptr, 10);
if (errno != 0 || endptr == buf)
{
*bid = -1;
}
return 0;
}
void broadcast(struct user *users, char *msg, int size)
{
for (int i = 0; i < MAX_CONNECTIONS; i++)
{
if (users[i].sock_fd != -1)
{
if (write(users[i].sock_fd, msg, size) == -1)
{
// Design flaw: can't remove this socket from select set
close(users[i].sock_fd);
users[i].sock_fd = -1;
}
}
}
}
int prep_bid(char *buf, Auction *a, struct timeval *t)
{
// send item, current bid, time left in seconds
printf("robin2-%s-%d\n", a->item, a->highest_bid);
printf("robin-%ld\n", t->tv_sec);
sprintf(buf, "%s %d %ld", a->item, a->highest_bid, t->tv_sec);
printf("robin-bid2\n");
return 0;
}
/* Update auction if new_bid is higher than current bid.
* Write to the client who made the bid if it is lower
* Broadcast to all clients if the bid is higher
*/
int update_bids(int client_index, struct user *users,
int new_bid, Auction *auction, struct timeval *t)
{
char buf[BUF_SIZE];
if (new_bid > auction->highest_bid)
{
auction->highest_bid = new_bid;
auction->client = client_index;
prep_bid(buf, auction, t);
if (verbose)
{
fprintf(stderr, "[%d] Sending to %d:\n %s\n",
getpid(), users[client_index].sock_fd, buf);
}
broadcast(users, buf, strlen(buf) + 1);
}
else
{
fprintf(stderr, "Client %d sent bid that was too low. Ignored\n",
client_index);
}
return 0;
}
int main(int argc, char **argv)
{
argc = 7;
argv[1] = "-v";
argv[2] = "-t";
argv[3] = "5";
argv[4] = "-p";
argv[5] = "4000";
argv[6] = "robin";
Auction auction;
int opt;
int port = PORT;
struct timeval timeout;
struct timeval *time_ptr = NULL;
int minutes = 0;
while ((opt = getopt(argc, argv, "vt:p:")) != -1)
{
switch (opt)
{
case 'v':
verbose = 1;
break;
case 't':
minutes = atoi(optarg);
timeout.tv_sec = minutes * 60;
timeout.tv_usec = 0;
time_ptr = &timeout;
break;
case 'p':
port = atoi(optarg);
break;
default:
fprintf(stderr, "Usage: auction_server [-v] [-t timeout] [-p port] item\n");
exit(1);
}
}
if (optind >= argc)
{
fprintf(stderr, "Expected argument after options\n");
exit(1);
}
auction.item = argv[optind];
auction.client = -1;
auction.highest_bid = -1;
struct user users[MAX_CONNECTIONS];
for (int index = 0; index < MAX_CONNECTIONS; index++)
{
users[index].sock_fd = -1;
users[index].name[0] = '\0';
}
// Create the socket FD.
int sock_fd = socket(AF_INET, SOCK_STREAM, 0);
if (sock_fd < 0)
{
perror("server: socket");
exit(1);
}
// Set information about the port (and IP) we want to be connected to.
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(port);
server.sin_addr.s_addr = INADDR_ANY;
// This sets an option on the socket so that its port can be reused right
// away. Since you are likely to run, stop, edit, compile and rerun your
// server fairly quickly, this will mean you can reuse the same port.
int on = 1;
int status = setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR,
(const char *)&on, sizeof(on));
if (status == -1)
{
perror("setsockopt -- REUSEADDR");
}
// This should always be zero. On some systems, it won't error if you
// forget, but on others, you'll get mysterious errors. So zero it.
memset(&server.sin_zero, 0, 8);
// Bind the selected port to the socket.
if (bind(sock_fd, (struct sockaddr *)&server, sizeof(server)) < 0)
{
perror("server: bind");
close(sock_fd);
exit(1);
}
// Announce willingness to accept connections on this socket.
if (listen(sock_fd, MAX_BACKLOG) < 0)
{
perror("server: listen");
close(sock_fd);
exit(1);
}
if (verbose)
{
fprintf(stderr, "[%d] Ready to accept connections on %d\n",
getpid(), port);
}
// The client accept - message accept loop. First, we prepare to listen
// to multiple file descriptors by initializing a set of file descriptors.
int max_fd = sock_fd;
fd_set all_fds;
FD_ZERO(&all_fds);
FD_SET(sock_fd, &all_fds);
while (1)
{
// select updates the fd_set it receives, so we always use a copy
// and retain the original.
fd_set listen_fds = all_fds;
int nready;
if ((nready = select(max_fd + 1, &listen_fds, NULL, NULL, time_ptr)) == -1)
{
perror("server: select");
exit(1);
}
if (nready == 0)
{
char buf[BUF_SIZE];
sprintf(buf, "Auction closed: %s wins with a bid of %d\r\n",
users[auction.client].name, auction.highest_bid);
printf("%s", buf);
broadcast(users, buf, BUF_SIZE);
exit(0);
}
// Is it the original socket? Create a new connection ...
if (FD_ISSET(sock_fd, &listen_fds))
{
int client_fd = accept_connection(sock_fd, users);
if (client_fd != -1)
{
if (client_fd > max_fd)
{
max_fd = client_fd;
}
FD_SET(client_fd, &all_fds);
if (verbose)
{
fprintf(stderr, "[%d] Accepted connection on %d\n",
getpid(), client_fd);
}
}
}
// Next, check the clients.
for (int index = 0; index < MAX_CONNECTIONS; index++)
{
if (users[index].sock_fd > -1 && FD_ISSET(users[index].sock_fd, &listen_fds))
{
int client_closed = 0;
int new_bid = 0;
if (users[index].name[0] == '\0')
{
client_closed = read_name(index, users);
if (client_closed == 0)
{
char buf[BUF_SIZE];
prep_bid(buf, &auction, time_ptr);
if (verbose)
{
fprintf(stderr, "[%d] Sending to %d:\n %s\n",
getpid(), users[index].sock_fd, buf);
}
if (write(users[index].sock_fd, buf, strlen(buf) + 1) == -1)
{
fprintf(stderr, "Write to %d failed\n", sock_fd);
close(sock_fd);
}
}
}
else
{ // read a bid
client_closed = read_bid(index, users, &new_bid);
if (client_closed == 0)
{
update_bids(index, users, new_bid, &auction, time_ptr);
}
}
if (client_closed > 0)
{
FD_CLR(client_closed, &all_fds);
printf("Client %d disconnected\n", client_closed);
}
}
}
}
// Should never get here.
return 1;
}
Caveat: Because you've only posted partial code for server and client, this will be some suggestions.
Your client can attach/connect to multiple bid servers simultaneously. As such, it must be able to keep track of the multiple connections in a manner similar to a server.
Your main [stated] issue is that you're blocking the client on a user prompt (e.g. from stdin via scanf et. al.). Presently, this means that the client is "stuck" at user input prompt and can not field messages from the servers it is connected to. More on how to fix this below.
So, you'll have a bunch of code from the server that needs to be in the client with some minor differences. You may wish to generalize some of the server code a bit, so it can work both in server and client (e.g. you may want to move it to common.c).
You already have code in the server to handle multiple connections. The server needs a select mask that is the OR of the listen fd and all active client fds.
Likewise, your client needs a select mask that is the OR of the fd for user input (e.g. 0) and all active server connections.
Doing select on fd 0 and using stdio.h streams won't work too well. So, replace access to stdin with (e.g.) read(0,line_buffer,sizeof(line_buffer)). You do this if fd 0 is set in the select mask. The role is very similar to what your server does for the accept on sock_fd.
You'll need to allow for partial reads and append to the buffer until you see a newline. So, you'll have to do the work that fgets would normally do in assembling a whole line. Then, you can call parse_command.
Because read doesn't understand newline demarcations, the user could enter more than one line before you can do a read.
So, for user input of:
connect 4000\n
bid 100 4000\n
connect 5000\n
You may get partial reads of:
conn
ect
4000\nbid 100 4000
\nconnect
5000\n
You may also need to use the FIONREAD ioctl on the fd 0 to prevent blocking. And, you may need to set the kernel TTY layer into raw mode via termios calls.
The client now becomes very similar to your server code. It will handle [asynchronously] actions by any connected servers and user input.
A tip: Under the DRY principle ["don't repeat yourself"] ...
You already have a struct user in the server. The client will need something similar/identical, such as struct server. When generalizing the code, rather than having two distinct structs that do essentially the same thing, consider renaming the existing struct to (e.g.) struct connection

Code executes correctly only if prints are present (C) [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 3 years ago.
Improve this question
I'm setting up a prototype for a DAQ system for Zynq FPGAs. I receive data from a server through ethernet, write it to a FIFO using the DMA and viceversa using two different pthreads. However, threads work correctly only if printf are executed. I expect there is a memory leak or some lines leading to a undefined behaviour, but I can't spot it.
Placing output to stderr has the same result. Changing addresses does nothing different.
Sorry for the shameful code, but I tried replacing almost every line by now to spot the problem.
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <sys/mman.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <sys/stat.h>
#include <stdint.h>
#include <errno.h>
#include <time.h>
#define PORT 8080
#define SA struct sockaddr
#define MM2S_CONTROL_REGISTER 0x00
#define MM2S_STATUS_REGISTER 0x04
#define MM2S_START_ADDRESS 0x18
#define MM2S_LENGTH 0x28
#define S2MM_CONTROL_REGISTER 0x30
#define S2MM_STATUS_REGISTER 0x34
#define S2MM_DESTINATION_ADDRESS 0x48
#define S2MM_LENGTH 0x58
#define VIRT_ADDR 0x40400000
#define FIFO_ADDR 0x0c000000
#define SEND_ADDR 0x0a000000
#define RECV_ADDR 0x0b000000
#define TIMEOUT 10
#define MAX_TRANSF 12274
unsigned int dma_set(unsigned int *dma_virtual_address, int offset, unsigned int value);
unsigned int dma_get(unsigned int *dma_virtual_address, int offset);
int dma_mm2s_sync(unsigned int *dma_virtual_address);
int dma_s2mm_sync(unsigned int *dma_virtual_address);
unsigned int dma_s2mm_status(unsigned int *dma_virtual_address);
unsigned int dma_mm2s_status(unsigned int *dma_virtual_address);
void memdump(void *virtual_address, int byte_count);
void print_status(unsigned int status);
unsigned long int elements = 0;
clock_t start_time;
typedef struct arg_struct {
unsigned int *virtual_address;
unsigned int *virtual_buffer;
unsigned int *head;
unsigned int *tail;
unsigned int buffsize;
unsigned int fifosize;
unsigned int sockfd;
pthread_mutex_t *lock;
char verbose;
} arguments;
unsigned int dma_set(unsigned int *dma_virtual_address, int offset, unsigned int value) {
dma_virtual_address[offset >> 2] = value;
}
unsigned int dma_get(unsigned int *dma_virtual_address, int offset) {
return dma_virtual_address[offset >> 2];
}
int dma_mm2s_sync(unsigned int *dma_virtual_address) {
unsigned int mm2s_status = dma_get(dma_virtual_address, MM2S_STATUS_REGISTER);
while (!(mm2s_status & 1 << 12) || !(mm2s_status & 1 << 1)) {
dma_s2mm_status(dma_virtual_address);
dma_mm2s_status(dma_virtual_address);
mm2s_status = dma_get(dma_virtual_address, MM2S_STATUS_REGISTER);
}
}
int dma_s2mm_sync(unsigned int *dma_virtual_address) {
unsigned int s2mm_status = dma_get(dma_virtual_address, S2MM_STATUS_REGISTER);
while (!(s2mm_status & 1 << 12) || !(s2mm_status & 1 << 1)) {
dma_s2mm_status(dma_virtual_address);
dma_mm2s_status(dma_virtual_address);
s2mm_status = dma_get(dma_virtual_address, S2MM_STATUS_REGISTER);
}
}
unsigned int dma_s2mm_status(unsigned int *dma_virtual_address) {
return dma_get(dma_virtual_address, S2MM_STATUS_REGISTER);
}
unsigned int dma_mm2s_status(unsigned int *dma_virtual_address) {
return dma_get(dma_virtual_address, MM2S_STATUS_REGISTER);
}
void print_mm2s_status(unsigned int status) {
fprintf(stderr, "[*] Stream to memory-mapped status (0x%08x#0x%02x):", status, S2MM_STATUS_REGISTER);
print_status(status);
}
void print_s2mm_status(unsigned int status) {
fprintf(stderr, "[*] Memory-mapped to stream status (0x%08x#0x%02x):", status, MM2S_STATUS_REGISTER);
print_status(status);
}
void print_status(unsigned int status) {
if (status & 0x00000001) fprintf(stderr, " halted");
else fprintf(stderr, " running");
if (status & 0x00000002) fprintf(stderr, " idle");
if (status & 0x00000008) fprintf(stderr, " SGIncld");
if (status & 0x00000010) fprintf(stderr, " DMAIntErr");
if (status & 0x00000020) fprintf(stderr, " DMASlvErr");
if (status & 0x00000040) fprintf(stderr, " DMADecErr");
if (status & 0x00000100) fprintf(stderr, " SGIntErr");
if (status & 0x00000200) fprintf(stderr, " SGSlvErr");
if (status & 0x00000400) fprintf(stderr, " SGDecErr");
if (status & 0x00001000) fprintf(stderr, " IOC_Irq");
if (status & 0x00002000) fprintf(stderr, " Dly_Irq");
if (status & 0x00004000) fprintf(stderr, " Err_Irq");
fprintf(stderr, "\n");
}
void memdump(void *virtual_address, int byte_count) {
char * p = virtual_address;
int offset;
for (offset = 0; offset < byte_count; offset++) {
fprintf(stderr, "%02x", p[offset]);
if (offset % 4 == 3) {
fprintf(stderr, " ");
}
}
}
void DMATransfer(unsigned int *virtual_address, long unsigned int src, long unsigned int dest, unsigned int length, char verbose) {
unsigned int s2mm_status = 0;
unsigned int mm2s_status = 0;
dma_set(virtual_address, S2MM_CONTROL_REGISTER, 4);
dma_set(virtual_address, MM2S_CONTROL_REGISTER, 4);
if (verbose > 0) {
print_s2mm_status(dma_s2mm_status(virtual_address));
print_mm2s_status(dma_mm2s_status(virtual_address));
}
dma_set(virtual_address, S2MM_CONTROL_REGISTER, 0);
dma_set(virtual_address, MM2S_CONTROL_REGISTER, 0);
if (verbose > 0) {
print_s2mm_status(dma_s2mm_status(virtual_address));
print_mm2s_status(dma_mm2s_status(virtual_address));
}
dma_set(virtual_address, S2MM_DESTINATION_ADDRESS, dest);
dma_set(virtual_address, MM2S_START_ADDRESS, src);
if (verbose > 0) {
print_s2mm_status(dma_s2mm_status(virtual_address));
print_mm2s_status(dma_mm2s_status(virtual_address));
}
dma_set(virtual_address, S2MM_CONTROL_REGISTER, 0xf001);
dma_set(virtual_address, MM2S_CONTROL_REGISTER, 0xf001);
if (verbose > 0) {
print_s2mm_status(dma_s2mm_status(virtual_address));
print_mm2s_status(dma_mm2s_status(virtual_address));
}
dma_set(virtual_address, S2MM_LENGTH, length);
dma_set(virtual_address, MM2S_LENGTH, length);
if (verbose > 0) {
print_s2mm_status(dma_s2mm_status(virtual_address));
print_mm2s_status(dma_mm2s_status(virtual_address));
}
dma_mm2s_sync(virtual_address);
dma_s2mm_status(virtual_address);
if (verbose > 0) {
print_s2mm_status(dma_s2mm_status(virtual_address));
print_mm2s_status(dma_mm2s_status(virtual_address));
}
}
int GetCPULoad() {
int FileHandler;
char FileBuffer[1024];
float load;
FileHandler = open("/proc/loadavg", O_RDONLY);
if(FileHandler < 0) {
return -1;
}
read(FileHandler, FileBuffer, sizeof(FileBuffer) - 1);
sscanf(FileBuffer, "%f", &load);
close(FileHandler);
return (int)(load * 100);
}
void *sender(void *params) {
arguments *args = params;
if (args->head == NULL) {
fprintf(stderr, "[-] Head pointer not valid\n");
exit(0);
}
if (args->tail == NULL) {
fprintf(stderr, "[-] Tail pointer not valid\n");
exit(0);
}
if (args->virtual_address == NULL) {
fprintf(stderr, "[-] AXI DMA register pointer not valid\n");
exit(0);
}
if (args->virtual_buffer == NULL) {
fprintf(stderr, "[-] Send buffer pointer not valid\n");
exit(0);
}
unsigned long int units_sent = 0;
unsigned int myhead = 0;
unsigned int mytail = 0;
for (;;) {
pthread_mutex_lock(args->lock);
myhead = *(args->head);
mytail = *(args->tail);
pthread_mutex_unlock(args->lock);
fprintf(stderr, "[*] Send Head: %d Tail: %d\n", myhead, mytail);
if (myhead != mytail) {
int remaining = args->buffsize;
int sent = 0;
int src = FIFO_ADDR + mytail * args->buffsize;
if (args->verbose > 2) {
fprintf(stderr, "[*] Sender: DMA is transferring data from 0x%x to 0x%x\n", src, SEND_ADDR);
}
unsigned int length = args->buffsize;
unsigned int verb = args->verbose > 2 ? 1 : 0;
pthread_mutex_lock(args->lock);
while (remaining > 0) {
length = remaining < MAX_TRANSF ? remaining : remaining % MAX_TRANSF;
DMATransfer(args->virtual_address, src + sent, SEND_ADDR, length, verb);
remaining -= args->buffsize;
sent += remaining;
}
pthread_mutex_unlock(args->lock);
elements--;
units_sent++;
if (args->verbose > 2) {
fprintf(stderr, "[*] %f elements in FIFO: %lu\n", ((double)(clock() - start_time)) / CLOCKS_PER_SEC, elements);
fprintf(stderr, "[*] %f DMA tranfer to buffer: %d\n", ((double)(clock() - start_time)) / CLOCKS_PER_SEC, units_sent);
}
remaining = args->buffsize;
sent = 0;
int result = 0;
pthread_mutex_lock(args->lock);
while (remaining > 0) {
result = send(args->sockfd, args->virtual_buffer + sent, remaining, 0);
if (result > 0) {
remaining -= result;
sent += remaining;
} else if (result < 0) {
fprintf(stderr, "[-] Error retrieving configuration from the server\n");
exit(0);
}
}
*(args->tail) = (mytail + 1) % (args->fifosize + 1);
pthread_mutex_unlock(args->lock);
//memset(args->virtual_buffer, 0, args->buffsize);
if (args->verbose > 2) {
fprintf(stderr, "[*] %f Unit sent: %d\n", ((double)(clock() - start_time)) / CLOCKS_PER_SEC, units_sent);
}
if (args->verbose > 0) {
fprintf(stderr, "[*] Packet retrieved");
}
if (args->verbose > 1) {
fprintf(stderr, " content: ");
memdump(args->virtual_buffer, args->buffsize);
}
if (args->verbose > 0) {
fprintf(stderr, "\n");
}
if (args->verbose > 2) {
fprintf(stderr, "[*] %f CPU Usage: %d\n", ((double)(clock() - start_time)) / CLOCKS_PER_SEC, GetCPULoad());
}
}
printf("0000000000000000000000000\n");
}
}
void *receiver(void *params) {
arguments *args = params;
if (args->head == NULL) {
fprintf(stderr, "[-] Head pointer not valid\n");
exit(0);
}
if (args->tail == NULL) {
fprintf(stderr, "[-] Tail pointer not valid\n");
exit(0);
}
if (args->virtual_address == NULL) {
fprintf(stderr, "[-] AXI DMA register pointer not valid\n");
exit(0);
}
if (args->virtual_buffer == NULL) {
fprintf(stderr, "[-] Recv buffer pointer not valid\n");
exit(0);
}
unsigned long int units_received = 0;
unsigned int myhead = 0;
unsigned int mytail = 0;
for (;;) {
pthread_mutex_lock(args->lock);
myhead = *(args->head);
mytail = *(args->tail);
pthread_mutex_unlock(args->lock);
fprintf(stderr, "[*] Recv Head: %d Tail: %d\n", myhead, mytail);
if (mytail != myhead + 1) {
int remaining = args->buffsize;
int received = 0;
int result = 0;
pthread_mutex_lock(args->lock);
while (remaining > 0) {
result = recv(args->sockfd, args->virtual_buffer + received, remaining, 0);
fprintf(stderr, "[*] Recv result: %d\n", result);
if (result > 0) {
remaining -= result;
received += result;
} else if (result == 0) {
fprintf(stderr, "[-] Remote side closed his end of the connection before all data was received\n");
exit(0);
} else if (result < 0) {
fprintf(stderr, "[-] Error retrieving configuration from the server\n");
exit(0);
}
}
printf("++++++++++++++++++++++++++++\n");
pthread_mutex_unlock(args->lock);
units_received++;
if (args->verbose > 2) {
fprintf(stderr, "[*] %f Unit recv: %d\n", ((double)(clock() - start_time)) / CLOCKS_PER_SEC, units_received);
}
remaining = args->buffsize;
received = 0;
int dest = FIFO_ADDR + myhead * args->buffsize;
if (args->verbose > 2) {
fprintf(stderr, "[*] Receiver: DMA is transferring data from 0x%x to 0x%x\n", RECV_ADDR, dest);
}
unsigned int length = args->buffsize;
unsigned int verb = args->verbose > 2 ? 1 : 0;
pthread_mutex_lock(args->lock);
while (remaining > 0) {
printf("############################\n");
length = remaining < MAX_TRANSF ? remaining : remaining % MAX_TRANSF;
DMATransfer(args->virtual_address, RECV_ADDR, dest + received, length, verb);
remaining -= args->buffsize;
received += args->buffsize;
}
printf("*************************\n");
*(args->head) = (myhead + 1) % (args->fifosize + 1);
pthread_mutex_unlock(args->lock);
//memset(args->virtual_buffer, 0, args->buffsize);
elements++;
if (args->verbose > 2) {
fprintf(stderr, "[*] %f elements in FIFO: %lu\n", ((double)(clock() - start_time)) / CLOCKS_PER_SEC, elements);
fprintf(stderr, "[*] %f DMA tranfer to DDR: %d\n", ((double)(clock() - start_time)) / CLOCKS_PER_SEC, units_received);
}
if (args->verbose > 0) {
fprintf(stderr, "[*] Packet received");
}
if (args->verbose > 1) {
fprintf(stderr, " content: ");
memdump(args->virtual_buffer, args->buffsize);
}
if (args->verbose > 0) {
fprintf(stderr, "\n");
}
if (args->verbose > 2) {
fprintf(stderr, "[*] %f CPU Usage: %d\n", ((double)(clock() - start_time)) / CLOCKS_PER_SEC, GetCPULoad());
}
}
printf("77777777777777777777777777777\n");
}
}
int isValidIpAddress(char *ipAddress) {
struct sockaddr_in sa;
int result = inet_pton(AF_INET, ipAddress, &(sa.sin_addr));
if (result != 0) {
return 0;
} else {
return 1;
}
}
int main(int argc, char *argv[]) {
if (argc < 3 || argc > 5) {
fprintf(stderr, "\nUsage: DAQTest [IP address] [fifo size]\nExample: DAQTest 192.168.1.81 64\n\n");
fprintf(stderr, "Optional flags: -v Verbose (print operations)\n");
fprintf(stderr, " -vv Very verbose (also print data content)\n");
fprintf(stderr, " -vvv Extremely verbose (also print DMA info)\n\n");
exit(0);
}
if (isValidIpAddress(argv[1]) == 1) {
fprintf(stderr, "[-] Invalid ip address\n");
exit(0);
}
int fifosize = atoi(argv[2]);
if (fifosize < 0 || fifosize > 8192) {
fprintf(stderr, "[-] Invalid fifo size\n");
exit(0);
}
char verbose = 0;
if (argc == 4) {
if (strcmp(argv[3], "-v") == 0) {
verbose = 1;
} else if (strcmp(argv[3], "-vv") == 0) {
verbose = 2;
} else if (strcmp(argv[3], "-vvv") == 0) {
verbose = 3;
} else {
fprintf(stderr, "[-] Unwanted parameter\n");
exit(0);
}
}
struct sockaddr_in servaddr, cli;
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (-1 == sockfd) {
fprintf(stderr, "[-] Socket creation failed\n");
exit(0);
}
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = inet_addr(argv[1]);
servaddr.sin_port = htons(PORT);
/*
struct timeval tv;
tv.tv_sec = TIMEOUT;
tv.tv_usec = 0;
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof tv);
*/
if (connect(sockfd, (SA * ) & servaddr, sizeof(servaddr)) != 0) {
fprintf(stderr, "[-] Connection failed\n");
exit(0);
}
fprintf(stderr, "[+] Connected to the server\n");
int buffsize = 0;
char* recv_buffer = (char*)&buffsize;
int remaining = sizeof(int);
int received = 0;
int result = 0;
while (remaining > 0) {
result = recv(sockfd, recv_buffer + received, remaining, 0);
if (result > 0) {
remaining -= result;
received += result;
} else if (result == 0) {
fprintf(stderr, "[-] Remote side closed his end of the connection before all data was received\n");
exit(0);
} else if (result < 0) {
fprintf(stderr, "[-] Error retrieving configuration from the server\n");
exit(0);
}
}
//fprintf(stderr, "[*] Page size: %ld\n", sysconf(_SC_PAGE_SIZE));
int dh = open("/dev/mem", O_RDWR | O_SYNC);
unsigned int *virtual_address = mmap(NULL, 65535, PROT_READ | PROT_WRITE, MAP_SHARED, dh, VIRT_ADDR);
unsigned int *virtual_sendbuff = mmap(NULL, buffsize, PROT_READ | PROT_WRITE, MAP_SHARED, dh, SEND_ADDR);
unsigned int *virtual_recvbuff = mmap(NULL, buffsize, PROT_READ | PROT_WRITE, MAP_SHARED, dh, RECV_ADDR);
unsigned int *virtual_fifo = mmap(NULL, (fifosize + 1) * buffsize, PROT_READ | PROT_WRITE, MAP_SHARED, dh, FIFO_ADDR);
if (virtual_address == MAP_FAILED) {
fprintf(stderr, "[-] AXI DMA registers mmap failed\n");
}
if (virtual_sendbuff == MAP_FAILED) {
fprintf(stderr, "[-] Send buffer mmap failed\n");
}
if (virtual_sendbuff == MAP_FAILED) {
fprintf(stderr, "[-] Send buffer mmap failed\n");
}
if (virtual_recvbuff == MAP_FAILED) {
fprintf(stderr, "[-] Receiver buffer mmap failed\n");
}
if (virtual_fifo == MAP_FAILED) {
fprintf(stderr, "[-] Fifo mmap failed\n");
}
memset(virtual_address, 0, buffsize);
memset(virtual_sendbuff, 0, buffsize);
memset(virtual_recvbuff, 0, buffsize);
memset(virtual_fifo, 0, buffsize);
int head = 0, tail = 0;
pthread_t sendth, recvth;
pthread_mutex_t lock;
pthread_mutex_init(&lock, NULL);
arguments send_args;
send_args.virtual_address = virtual_address;
send_args.virtual_buffer = virtual_sendbuff;
send_args.head = &head;
send_args.tail = &tail;
send_args.buffsize = buffsize;
send_args.fifosize = fifosize;
send_args.sockfd = sockfd;
send_args.lock = &lock;
send_args.verbose = verbose;
arguments recv_args;
recv_args.virtual_address = virtual_address;
recv_args.virtual_buffer = virtual_recvbuff;
recv_args.head = &head;
recv_args.tail = &tail;
recv_args.buffsize = buffsize;
recv_args.fifosize = fifosize;
recv_args.sockfd = sockfd;
recv_args.lock = &lock;
recv_args.verbose = verbose;
start_time = clock();
if (pthread_create(&sendth, NULL, sender, &send_args)) {
fprintf(stderr, "[-] Error creating sender thread\n");
exit(0);
}
if (pthread_create(&recvth, NULL, receiver, &recv_args)) {
fprintf(stderr, "[-] Error creating receiver thread\n");
exit(0);
}
if (pthread_join(sendth, NULL)) {
fprintf(stderr, "[-] Error joining sender thread\n");
exit(0);
}
if (pthread_join(recvth, NULL)) {
fprintf(stderr, "[-] Error joining receiver thread\n");
exit(0);
}
pthread_mutex_destroy(&lock);
close(sockfd);
fprintf(stderr, "[+] Exit\n");
return 0;
}
Try replacing the print statements with delays.
As you're doing networking, you're speed constrained by your network connection. If you do not take this into considerations, your transfer buffers may overflow. The print statements add a certain delay, which might prevent this. Replacing them with actual delays would check for this.
A better solution - if this were indeed the problem - would then be to check for buffer availability before writing.

DPDK create a packet for transmission

I am new to DPDK and trying to create a packet to send it from one DPDK enabled machine to another connected directly via an ethernet. I modified an example/rxtx_callbacks/main.c provided with DPDK at both side. However, I am not receiving anything at the receiver. What wrong am I doing?
Modified function at transmitter: lcore_main is modified:
static __attribute__((noreturn)) void lcore_main()
{
uint16_t port;
struct ether_hdr *eth_hdr;
struct ether_addr daddr;
daddr.addr_bytes[0] = 116;
daddr.addr_bytes[1] = 225;
daddr.addr_bytes[2] = 228;
daddr.addr_bytes[3] = 204;
daddr.addr_bytes[4] = 106;
daddr.addr_bytes[5] = 82;
//rte_eth_macaddr_get(portid, &addr);
struct ipv4_hdr *ipv4_hdr;
int32_t i;
int ret;
RTE_ETH_FOREACH_DEV(port)
if (rte_eth_dev_socket_id(port) > 0 &&
rte_eth_dev_socket_id(port) !=
(int)rte_socket_id())
printf("WARNING, port %u is on remote NUMA node to "
"polling thread.\n\tPerformance will "
"not be optimal.\n", port);
printf("\nCore %u forwarding packets. [Ctrl+C to quit]\n",
rte_lcore_id());
//struct rte_mbuf *m_head = rte_pktmbuf_alloc(mbuf_pool);
struct rte_mbuf *m_head[BURST_SIZE];
for (;;) {
RTE_ETH_FOREACH_DEV(port) {
if(rte_pktmbuf_alloc_bulk(mbuf_pool, m_head, BURST_SIZE)!=0)
{
printf("Allocation problem\n");
}
for(i = 0; i < BURST_SIZE; i++) {
eth_hdr = rte_pktmbuf_mtod(m_head[i], struct ether_hdr *);
//eth_hdr = (struct ether_hdr *)rte_pktmbuf_append(m_head[i],
// sizeof(struct ether_hdr));
eth_hdr->ether_type = htons(ETHER_TYPE_IPv4);
rte_memcpy(&(eth_hdr->s_addr), &addr, sizeof(struct ether_addr));
rte_memcpy(&(eth_hdr->d_addr), &daddr, sizeof(struct ether_addr));
}
const uint16_t nb_tx = rte_eth_tx_burst(port, 0, m_head, BURST_SIZE);
if (unlikely(nb_tx < BURST_SIZE)) {
uint16_t buf;
for (buf = nb_tx; buf < BURST_SIZE; buf++)
rte_pktmbuf_free(m_head[buf]);
}
}
}
}
receiver side RTE_ETH_FOREACH_DEV of tx part is modified to:
RTE_ETH_FOREACH_DEV(port) {
struct rte_mbuf *bufs[BURST_SIZE];
const uint16_t nb_rx = rte_eth_rx_burst(port, bufs, BURST_SIZE);
//printf("Number of Packets received %d\n", nb_rx);
for(i = 0; i < nb_rx; i++) {
//ipv4_hdr = rte_pktmbuf_mtod_offset(bufs[i], struct ipv4_hdr *,
// sizeof(struct ether_hdr));
//printf("Packet ip received %d\n", ipv4_hdr->src_addr);
eth_hdr = rte_pktmbuf_mtod(bufs[i], struct ether_hdr *);
printf("Packet ip received %d\n", eth_hdr->ether_type);
}
if (unlikely(nb_rx == 0))
continue;
const uint16_t nb_tx = 0; // = rte_eth_tx_burst(port ^ 1, 0, bufs, nb_rx);
if (unlikely(nb_tx < nb_rx)) {
uint16_t buf;
for (buf = nb_tx; buf < nb_rx; buf++)
rte_pktmbuf_free(bufs[buf]);
}
}
Please let me know if I missed something.
There are few issues with the code:
eth_hdr = rte_pktmbuf_mtod(m_head[i], struct ether_hdr *);
Unlike rte_pktmbuf_append(), the rte_pktmbuf_mtod() does not change the packet length, so it should be set manually before the tx.
eth_hdr->ether_type = htons(ETHER_TYPE_IPv4);
If we set ETHER_TYPE_IPv4, a correct IPv4 header must follow. So we need either to add the header or to change the ether_type.
rte_memcpy(&(eth_hdr->s_addr), &addr, sizeof(struct ether_addr));
Where is the source address comes from?
const uint16_t nb_tx = rte_eth_tx_burst(port, 0, m_head, BURST_SIZE);
Looks like we transmit a burst of zero-sized packets with invalid IPv4 headers. Please also make sure the source/destination addresses are correct.
As suggested by #andriy-berestovsky, I used rte_eth_stats_get() and it shows packets are present in ethernet ring via the field ipackets but rte_eth_rx_burst is not returning any packets. Full code is included here, please let me know what I am doing wrong. (I am using testpmd at transmitter side)
#include <stdint.h>
#include <inttypes.h>
#include <rte_eal.h>
#include <rte_ethdev.h>
#include <rte_ether.h>
#include <rte_cycles.h>
#include <rte_lcore.h>
#include <rte_ip.h>
#include <rte_mbuf.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <signal.h>
#define MAX_SOURCE_SIZE (0x100000)
#define RX_RING_SIZE 1024
#define TX_RING_SIZE 1024
#define NUM_MBUFS 8191
#define MBUF_CACHE_SIZE 250
#define BURST_SIZE 32
static const struct rte_eth_conf port_conf_default = {
.rxmode = {
.max_rx_pkt_len = ETHER_MAX_LEN,
},
};
static struct {
uint64_t total_cycles;
uint64_t total_pkts;
} latency_numbers;
static volatile bool force_quit;
struct rte_mempool *mbuf_pool;
static void
signal_handler(int signum)
{
struct rte_eth_stats eth_stats;
int i;
if (signum == SIGINT || signum == SIGTERM) {
printf("\n\nSignal %d received, preparing to exit...\n",
signum);
RTE_ETH_FOREACH_DEV(i) {
rte_eth_stats_get(i, &eth_stats);
printf("Total number of packets received %llu, dropped rx full %llu and rest= %llu, %llu, %llu\n", eth_stats.ipackets, eth_stats.imissed, eth_stats.ierrors, eth_stats.rx_nombuf, eth_stats.q_ipackets[0]);
}
force_quit = true;
}
}
struct ether_addr addr;
/*
* Initialises a given port using global settings and with the rx buffers
* coming from the mbuf_pool passed as parameter
*/
static inline int
port_init(uint16_t port, struct rte_mempool *mbuf_pool)
{
struct rte_eth_conf port_conf = port_conf_default;
const uint16_t rx_rings = 1, tx_rings = 1;
uint16_t nb_rxd = RX_RING_SIZE;
uint16_t nb_txd = TX_RING_SIZE;
int retval;
uint16_t q;
struct rte_eth_dev_info dev_info;
struct rte_eth_txconf txconf;
if (!rte_eth_dev_is_valid_port(port))
return -1;
rte_eth_dev_info_get(port, &dev_info);
if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE)
port_conf.txmode.offloads |=
DEV_TX_OFFLOAD_MBUF_FAST_FREE;
retval = rte_eth_dev_configure(port, rx_rings, tx_rings, &port_conf);
if (retval != 0)
return retval;
retval = rte_eth_dev_adjust_nb_rx_tx_desc(port, &nb_rxd, &nb_txd);
if (retval != 0) {
printf("Error in adjustment\n");
return retval;
}
for (q = 0; q < rx_rings; q++) {
retval = rte_eth_rx_queue_setup(port, q, nb_rxd,
rte_eth_dev_socket_id(port), NULL, mbuf_pool);
if (retval < 0) {
printf("RX queue setup prob\n");
return retval;
}
}
txconf = dev_info.default_txconf;
txconf.offloads = port_conf.txmode.offloads;
for (q = 0; q < tx_rings; q++) {
retval = rte_eth_tx_queue_setup(port, q, nb_txd,
rte_eth_dev_socket_id(port), &txconf);
if (retval < 0)
return retval;
}
retval = rte_eth_dev_start(port);
if (retval < 0) {
printf("Error in start\n");
return retval;
}
rte_eth_macaddr_get(port, &addr);
printf("Port %u MAC: %02"PRIx8" %02"PRIx8" %02"PRIx8
" %02"PRIx8" %02"PRIx8" %02"PRIx8"\n",
(unsigned)port,
addr.addr_bytes[0], addr.addr_bytes[1],
addr.addr_bytes[2], addr.addr_bytes[3],
addr.addr_bytes[4], addr.addr_bytes[5]);
rte_eth_promiscuous_enable(port);
return 0;
}
/*
* Main thread that does the work, reading from INPUT_PORT
* and writing to OUTPUT_PORT
*/
static __attribute__((noreturn)) void
lcore_main(void)
{
uint16_t port;
struct ether_hdr *eth_hdr;
//struct ether_addr addr;
//rte_eth_macaddr_get(portid, &addr);
struct ipv4_hdr *ipv4_hdr;
int32_t i;
RTE_ETH_FOREACH_DEV(port)
{
if (rte_eth_dev_socket_id(port) > 0 &&
rte_eth_dev_socket_id(port) !=
(int)rte_socket_id())
printf("WARNING, port %u is on remote NUMA node to "
"polling thread.\n\tPerformance will "
"not be optimal.\n", port);
}
printf("\nCore %u forwarding packets. [Ctrl+C to quit]\n",
rte_lcore_id());
for (;;) {
RTE_ETH_FOREACH_DEV(port) {
struct rte_mbuf *bufs[BURST_SIZE];
const uint16_t nb_rx = rte_eth_rx_burst(port, 0,bufs, BURST_SIZE);
for(i = 0; i < nb_rx; i++) {
ipv4_hdr = rte_pktmbuf_mtod_offset(bufs[i], struct ipv4_hdr *, sizeof(struct ether_hdr));
printf("Packet ip received %d\n", ipv4_hdr->src_addr);
}
if (unlikely(nb_rx == 0))
continue;
const uint16_t nb_tx = 0; // = rte_eth_tx_burst(port ^ 1, 0, bufs, nb_rx);
if (unlikely(nb_tx < nb_rx)) {
uint16_t buf;
for (buf = nb_tx; buf < nb_rx; buf++)
rte_pktmbuf_free(bufs[buf]);
}
}
if(force_quit)
break;
}
}
/* Main function, does initialisation and calls the per-lcore functions */
int
main(int argc, char *argv[])
{
uint16_t nb_ports;
uint16_t portid, port;
/* init EAL */
int ret = rte_eal_init(argc, argv);
if (ret < 0)
rte_exit(EXIT_FAILURE, "Error with EAL initialization\n");
argc -= ret;
argv += ret;
force_quit = false;
signal(SIGINT, signal_handler);
signal(SIGTERM, signal_handler);
nb_ports = rte_eth_dev_count_avail();
printf("size ordered %lld\n", NUM_MBUFS *nb_ports);
mbuf_pool = rte_pktmbuf_pool_create("MBUF_POOL",
NUM_MBUFS * nb_ports, MBUF_CACHE_SIZE, 0,
RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
if (nb_ports < 1)
rte_exit(EXIT_FAILURE, "Error: number of ports must be greater than %d\n", nb_ports);
if (mbuf_pool == NULL)
rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n");
// initialize all ports
RTE_ETH_FOREACH_DEV(portid)
if (port_init(portid, mbuf_pool) != 0)
rte_exit(EXIT_FAILURE, "Cannot init port %"PRIu8"\n",
portid);
if (rte_lcore_count() > 1)
printf("\nWARNING: Too much enabled lcores - "
"App uses only 1 lcore\n");
// call lcore_main on master core only
lcore_main();
return 0;
}
It seems to be a problem of ethernet card with ubuntu 14.04. With ubuntu 16.04 it is working fine.

howto: setup a bidirectional UDP connection for a message based communication

The problem I want to solve is to build a stable connection for exchanging data between a PC and my Raspberry Pi(RPi). They are connected via WLAN in a LAN by a router.
I created a simple way, by defining on every device a client(c) and a server(s). I give in short the pseudo-code for that:
#init:
s = createSocket
c = createSocket
s = bind to "localhost"
create thread for message handling
#message handling thread:
msg = recvfrom(s)
#main:
init(serverPort=10001, clientIP="raspberryPi", clientPort=10002)
sendto(c, "hello")
The problem with UDP via WLAN is, that some messages can get lost. So I decided to create a simple protocol for that data exchange. The idea is that the server acknowledges the reception of the data. The problem changes into that kind pseudo-code:
#init:
s = createSocket
c = createSocket
s = bind to "localhost"
create thread for message handling
#message handling thread:
msg = recvfrom(s)
sendto (c, "ack")
#main:
sendto(c, "hello")
wait for 100ms for res = recvfrom(s)
if res == timeout goto sendto
if res <> 'ack' wrong message
I am running into a problem, that the sending and receiving process using both recvfrom(s). Also the easy loop back test by using the same port for client and server can not be done.
Any ideas?
Some not working c code follows:
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <pthread.h>
#include <semaphore.h>
#include <errno.h>
// sockets
#ifdef WIN32
#ifndef WINVER
// set min win version to Win XP
#define WINVER 0x0501
#endif
//use lib: ws2_32
#include <winsock2.h>
#include <ws2tcpip.h>
#else
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/un.h>
#include <unistd.h>
#include <arpa/inet.h>
#define ADDR_ANY INADDR_ANY
#define SOCKET_ERROR (-1)
#define INVALID_SOCKET (SOCKET)(~0)
#define closesocket(x) (close(x))
typedef int SOCKET;
typedef struct sockaddr_in SOCKADDR_IN;
typedef struct sockaddr SOCKADDR;
#endif
typedef int (* TfkpTCPcallback) (uint8_t * pData, size_t amount);
// size of the header
#define dStjTCPSocketControlMsg (sizeof(uint_32))
// start data msg struct
// <uint_32> id = 's'
// <uint_32> len
// res struct
// <uint_32> id = 'r'
// <uint_32> error code (0 = no error)
enum eStjTCPSocketControlMsgIDs {
eStjTCPSocketControlMsgID_start = 's',
eStjTCPSocketControlMsgID_result = 'r'
};
enum eStjTCPSocketControlMsgErrorIDs {
eStjTCPSocketControlMsgErrorID_noError = 0,
eStjTCPSocketControlMsgErrorID_otherError,
eStjTCPSocketControlMsgErrorID_socket,
eStjTCPSocketControlMsgErrorID_msgID,
eStjTCPSocketControlMsgErrorID_realloc,
eStjTCPSocketControlMsgErrorID_amount,
};
//! type to control a udp socket based message communication
typedef struct SstjTCPSocketControl {
pthread_t srvThr;
SOCKET sCli; //!< socket for the input
SOCKET sSrv; //!< socket for the output
struct sockaddr_in sAddrCli; //!< client address
int cliConnectedFlag; //!< <>0 if the client is connected
uint8_t * pMsgBuffer;
size_t msgBufferSize;
sem_t serverSign;
TfkpTCPcallback rxCB;
} TstjTCPSocketControl;
//! a global variable to control a udp message based communication
TstjTCPSocketControl gTCPsocketControl = {
.srvThr = NULL,
.sCli = -1,
.sSrv = -1,
.cliConnectedFlag = 0,
.pMsgBuffer = NULL,
.msgBufferSize = 0,
};
int recvResult(SOCKET s) {
int r;
uint32_t contrlMsg[2];
// recv that the server is ready to transmit
r = recv(s , (char *)contrlMsg , sizeof(contrlMsg) , 0);
if(r < 0) {
return eStjTCPSocketControlMsgErrorID_socket;
}
if (r != sizeof(contrlMsg)) {
return eStjTCPSocketControlMsgErrorID_amount;
}
if (contrlMsg[0] != eStjTCPSocketControlMsgID_result) {
return eStjTCPSocketControlMsgErrorID_msgID;
}
return contrlMsg[1];
}
int sendResult(SOCKET s, uint32_t errorCode) {
uint32_t contrlMsg[2];
int r;
contrlMsg[0] = eStjTCPSocketControlMsgID_result;
contrlMsg[1] = errorCode;
r = send(s , (char *)contrlMsg , sizeof(contrlMsg) , 0);
if (r < 0) return eStjTCPSocketControlMsgErrorID_socket;
return eStjTCPSocketControlMsgErrorID_noError;
}
//! sends a block of data
int TCPcontrolSend(uint8_t * pD, size_t dataSize) {
int r;
uint32_t contrlMsg[2];
// check if we have to connect
if (!gTCPsocketControl.cliConnectedFlag) {
if (connect(gTCPsocketControl.sCli , (struct sockaddr *)&gTCPsocketControl.sAddrCli , sizeof(gTCPsocketControl.sAddrCli)) < 0){
gTCPsocketControl.cliConnectedFlag = 0;
return -1;
} else {
gTCPsocketControl.cliConnectedFlag = 1;
}
}
// ok we are connected - lets send the data
start:
contrlMsg[0] = eStjTCPSocketControlMsgID_start;
contrlMsg[1] = dataSize;
// send that we what to transmit some data
r = send(gTCPsocketControl.sCli , (char *)contrlMsg , sizeof(contrlMsg) , 0);
if(r < 0) {
return -2;
}
// recv that the server is ready to transmit
r = recvResult(gTCPsocketControl.sCli);
if (eStjTCPSocketControlMsgErrorID_socket == r) return -3;
if (eStjTCPSocketControlMsgErrorID_amount == r) goto start;
// ok let's send
r = send(gTCPsocketControl.sCli , pD ,dataSize , 0);
if(r < 0) {
return -2;
}
// get ack from the server
r = recvResult(gTCPsocketControl.sCli);
if (eStjTCPSocketControlMsgErrorID_socket == r) return -3;
if (eStjTCPSocketControlMsgErrorID_amount == r) goto start;
return r;
}
//! the message pump
void * TCPcontrolMsgPump (void *pParams) {
int r;
uint32_t contrlMsg[2];
struct sockaddr_in cliAddr;
SOCKET sCli;
uint32_t dataSize;
socklen_t cliAddrSize;
sem_post(&gTCPsocketControl.serverSign);
//accept connection from an incoming client
cliAddrSize = sizeof(struct sockaddr_in);
sCli = accept(gTCPsocketControl.sSrv, (struct sockaddr *)&cliAddr, (socklen_t*)&cliAddrSize);
if (sCli < 0) goto end;
// run the pump
for (;;) {
// ok we are connected
// read start message
r = recv(sCli , (char *)contrlMsg , sizeof(contrlMsg), 0);
if (r < 0) goto end;
if (r != sizeof(contrlMsg)) {
sendResult(sCli, eStjTCPSocketControlMsgErrorID_amount);
continue;
}
if (contrlMsg[0] != eStjTCPSocketControlMsgID_start) {
sendResult(sCli, eStjTCPSocketControlMsgErrorID_msgID);
continue;
}
dataSize = contrlMsg[1];
// check if we have to realloc the rx buffer
if (gTCPsocketControl.msgBufferSize < dataSize) {
uint8_t *pNB = realloc(gTCPsocketControl.pMsgBuffer, dataSize);
if (!pNB) {
sendResult(sCli, eStjTCPSocketControlMsgErrorID_realloc);
continue;
}
gTCPsocketControl.pMsgBuffer = pNB;
gTCPsocketControl.msgBufferSize = dataSize;
}
sendResult(sCli, eStjTCPSocketControlMsgErrorID_noError);
// recv data
r = recv(sCli , gTCPsocketControl.pMsgBuffer , gTCPsocketControl.msgBufferSize, 0);
if (r < 0) goto end;
if (r != dataSize) {
sendResult(sCli, eStjTCPSocketControlMsgErrorID_amount);
continue;
}
sendResult(sCli, eStjTCPSocketControlMsgErrorID_noError);
// handle message
gTCPsocketControl.rxCB(gTCPsocketControl.pMsgBuffer , gTCPsocketControl.msgBufferSize);
continue;
}
end:
sem_post(&gTCPsocketControl.serverSign);
return (void *) -1;
}
//! init
int TCPcontrolInit (
int serverPort, //!< server tx port number - best over 1000
const char * szClient, //!< "family-PC" or "192.168.1.3"
int clientPort, //!< client tx port number
TfkpTCPcallback rxCB, //!< the rx data callback
long timeOut, //!< the time out of the rx operation in ms
size_t rxBufferSize, //!< the size of the rx buffer
size_t maxTCPdataSize //!< maximum size of a TCP datagram (400 Bytes seems a good size)
) {
#ifdef WIN32
// local data
WSADATA wsaData;
// start sockets
if ((WSAStartup(MAKEWORD(2, 2), &wsaData))) {
perror("WSAStartup failed!");
return -1;
}
#endif
char * szIPserver;
char * szIPclient;
struct hostent * pHostDescr;
struct sockaddr_in sAddr;
//if (serverPort == clientPort) return -1;
// -----------------
// get ip strings
// get ip of the server
pHostDescr = gethostbyname("localhost");
// check if found a host
if (!pHostDescr) {
return -11;
}
szIPserver = inet_ntoa(*(struct in_addr*)*pHostDescr->h_addr_list);
// get ip of the client
if (strcmp(szClient, "")) {
pHostDescr = gethostbyname(szClient);
} else {
pHostDescr = gethostbyname("localhost");
}
// check if found a host
if (!pHostDescr) {
return -12;
}
szIPclient = inet_ntoa(*(struct in_addr*)*pHostDescr->h_addr_list);
// -----------------
// try to create sockets
// try to create socket for the server
gTCPsocketControl.sSrv = socket(PF_INET , SOCK_STREAM, IPPROTO_TCP);
if (-1 == gTCPsocketControl.sSrv) return -21;
// try to create socket for the client
gTCPsocketControl.sCli = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (-1 == gTCPsocketControl.sCli) return -22;
// -----------------
// bind input to IP and port
memset(&sAddr,0,sizeof(sAddr));
sAddr.sin_family = PF_INET;
sAddr.sin_addr.s_addr = INADDR_ANY;
sAddr.sin_port = htons( serverPort );
// bind server socket to address
if (bind(gTCPsocketControl.sSrv, (SOCKADDR *)&sAddr, sizeof(SOCKADDR_IN))) {
return -31;
}
// and listen for incoming connections
if (listen(gTCPsocketControl.sSrv , 3)) {
return -32;
}
// -----------------
// connect output to IP and port
memset(&gTCPsocketControl.sAddrCli,0,sizeof(sAddr));
gTCPsocketControl.sAddrCli.sin_family = PF_INET;
gTCPsocketControl.sAddrCli.sin_addr.s_addr = inet_addr(szIPclient);
gTCPsocketControl.sAddrCli.sin_port = htons( clientPort );
if (connect(gTCPsocketControl.sCli , (struct sockaddr *)&gTCPsocketControl.sAddrCli , sizeof(gTCPsocketControl.sAddrCli)) < 0){
gTCPsocketControl.cliConnectedFlag = 0;
} else {
gTCPsocketControl.cliConnectedFlag = 1;
}
// create sign semaphore
sem_init(&gTCPsocketControl.serverSign, 0, 0);
// create buffers
gTCPsocketControl.pMsgBuffer = malloc(rxBufferSize);
if (!gTCPsocketControl.pMsgBuffer) {
return -32;
}
gTCPsocketControl.msgBufferSize = rxBufferSize;
// set callback
gTCPsocketControl.rxCB = rxCB;
// start rx thread
if(pthread_create(&gTCPsocketControl.srvThr , NULL, TCPcontrolMsgPump, NULL)) {
return -40;
}
// wait till rx server is running
sem_wait(&gTCPsocketControl.serverSign);
return 0;
}
//! closes the TCP server and client
void TCPcontrolClose () {
closesocket (gTCPsocketControl.sSrv);
closesocket (gTCPsocketControl.sCli);
free(gTCPsocketControl.pMsgBuffer);
memset(&gTCPsocketControl, 0, sizeof(TstjTCPSocketControl));
#ifdef WIN32
WSACleanup();
#endif
}
// -----------------------------------------
// test
int stFlag = 0;
#define dSTsize (1024 * 1024)
uint8_t STB[dSTsize];
int rxCB (uint8_t * pData, size_t amount) {
if (!stFlag) {
pData[amount] = 0;
printf("rx: %s\n",pData);
} else {
size_t i;
for (i = 0; i < dSTsize; i++) {
if (pData[i] != (uint8_t)((size_t)i & 0xFF)) {
fprintf(stderr, "stress test error at position %i\n",(int) i);
return 0;
}
}
printf("rx: stress test successful\n");
}
fflush(stdout);
return 0;
}
int main(void) {
int srvPort;
int clientPort;
const size_t ipLen = 256;
char szIP[ipLen];
const size_t dummyStrLen = 1024;
char szDummy[dummyStrLen];
size_t i;
int r;
// pre init for the stress test
for (i = 0; i < dSTsize; i++) {
STB[i] = (uint8_t)((size_t)i & 0xFF);
}
printf("TCP demo\n");
printf("enter server port: ");
fgets(szDummy, dummyStrLen, stdin);
szDummy[strcspn(szDummy, "\r\n")] = 0;
srvPort = atoi(szDummy);
printf("enter IP address of the other server: ");
fgets(szIP, 255, stdin);
szIP[strcspn(szIP, "\r\n")] = 0;
printf("enter client port: ");
fgets(szDummy, dummyStrLen, stdin);
szDummy[strcspn(szDummy, "\r\n")] = 0;
clientPort = atoi(szDummy);
if (TCPcontrolInit (
srvPort, //!< server port number - best over 1000
szIP, //!< "family-PC" or "192.168.1.3"
clientPort, //!< client port number
rxCB, //!< the rx data callback
100, //!< the time out of the rx operation in ms
10,//!< the size of the rx buffer
400 //!< maximum size of a TCP datagram (400 Bytes seems a good size)
) < 0 ){
fprintf(stderr, "TCP control setup failed!");
goto errorExit;
}
printf("commands:\n s - send\n t - tx stress test\n a - activate/deactivate rx for stress test\n h - help\n e - exit\n");
for(;;) {
printf("command: ");
fgets(szDummy, dummyStrLen, stdin);
switch(tolower(szDummy[0])) {
case 's':
fgets(szDummy, dummyStrLen, stdin);
szDummy[strcspn(szDummy, "\r\n")] = 0;
r = TCPcontrolSend((uint8_t *)szDummy, strlen(szDummy)+1);
if(r) {
fprintf(stderr,"sending data failed with code %i(%s)\n", r, strerror(errno));
}
break;
case 't':
r = TCPcontrolSend(STB, dSTsize);
if (r) {
fprintf(stderr,"stress test sending data failed with code %i\n", r);
}
break;
case 'a':
stFlag = (!stFlag) ? 1 : 0;
if (stFlag) {
printf("stress test RX now active\n");
} else {
printf("stress test RX deactivated\n");
}
break;
case 'h':
printf("commands:\n s - send\n t - tx stress test\n a - activate/deactivate rx for stress test\n h - help\n e - exit\n");
break;
case 'e':
goto stdExit;
}
}
stdExit:
TCPcontrolClose ();
return EXIT_SUCCESS;
errorExit:
TCPcontrolClose ();
return EXIT_FAILURE;
}
If you need a UDP file transfer application, try UFTP.
I wrote it primarily for multicast, but it works just as well with unicast. Give it a try, and let me know how it goes.
The TCP approach works fine. With the code below a full duplex connection with asynchronous RX TX works fine. Its tested in Linux and Windows:
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <pthread.h>
#include <semaphore.h>
#include <errno.h>
// sockets
#ifdef WIN32
#ifndef WINVER
// set min win version to Win XP
#define WINVER 0x0501
#endif
//use lib: ws2_32
#include <winsock2.h>
#include <ws2tcpip.h>
#else
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/un.h>
#include <unistd.h>
#include <arpa/inet.h>
#define ADDR_ANY INADDR_ANY
#define SOCKET_ERROR (-1)
#define INVALID_SOCKET (SOCKET)(~0)
#define closesocket(x) (close(x))
typedef int SOCKET;
typedef struct sockaddr_in SOCKADDR_IN;
typedef struct sockaddr SOCKADDR;
#endif
typedef int (* TfkpTCPcallback) (uint8_t * pData, size_t amount);
// size of the header
#define dStjTCPSocketControlMsg (sizeof(uint_32))
// start data msg struct
// <uint_32> id = 's'
// <uint_32> len
// res struct
// <uint_32> id = 'r'
// <uint_32> error code (0 = no error)
enum eStjTCPSocketControlMsgIDs {
eStjTCPSocketControlMsgID_start = 's',
eStjTCPSocketControlMsgID_packet = 'p',
eStjTCPSocketControlMsgID_result = 'r'
};
enum eStjTCPSocketControlMsgErrorIDs {
eStjTCPSocketControlMsgErrorID_noError = 0,
eStjTCPSocketControlMsgErrorID_otherError,
eStjTCPSocketControlMsgErrorID_socket,
eStjTCPSocketControlMsgErrorID_msgID,
eStjTCPSocketControlMsgErrorID_realloc,
eStjTCPSocketControlMsgErrorID_amount,
eStjTCPSocketControlMsgErrorID_wrongPacket,
};
//! type to control a udp socket based message communication
typedef struct SstjTCPSocketControl {
pthread_t srvThr;
SOCKET sCli; //!< socket for the input
SOCKET sSrv; //!< socket for the output
struct sockaddr_in sAddrCli; //!< client address
int cliConnectedFlag; //!< <>0 if the client is connected
uint8_t * pMsgBuffer;
size_t msgBufferSize;
sem_t serverSign;
TfkpTCPcallback rxCB;
int maxTXsize;
} TstjTCPSocketControl;
//! a global variable to control a udp message based communication
TstjTCPSocketControl gTCPsocketControl = {
.srvThr = NULL,
.sCli = -1,
.sSrv = -1,
.cliConnectedFlag = 0,
.pMsgBuffer = NULL,
.msgBufferSize = 0,
};
static inline int _TCPcontrolRecvResult(SOCKET s) {
int r;
uint32_t contrlMsg[2];
// recv that the server is ready to transmit
r = recv(s , (char *)contrlMsg , sizeof(contrlMsg) , 0);
if(r < 0) {
return eStjTCPSocketControlMsgErrorID_socket;
}
if (r != sizeof(contrlMsg)) {
return eStjTCPSocketControlMsgErrorID_amount;
}
if (contrlMsg[0] != eStjTCPSocketControlMsgID_result) {
return eStjTCPSocketControlMsgErrorID_msgID;
}
return contrlMsg[1];
}
static inline int _TCPcontrolSendResult(SOCKET s, uint32_t errorCode) {
uint32_t contrlMsg[2];
int r;
contrlMsg[0] = eStjTCPSocketControlMsgID_result;
contrlMsg[1] = errorCode;
r = send(s , (char *)contrlMsg , sizeof(contrlMsg) , 0);
if (r < 0) return eStjTCPSocketControlMsgErrorID_socket;
return eStjTCPSocketControlMsgErrorID_noError;
}
//! sends a block of data
int TCPcontrolSend(uint8_t * pD, size_t dataSize) {
int r;
uint32_t contrlMsg[2];
uint32_t p;
uint32_t packets;
uint8_t * pB;
size_t am, amTotal;
// check if we have to connect
if (!gTCPsocketControl.cliConnectedFlag) {
if (connect(gTCPsocketControl.sCli , (struct sockaddr *)&gTCPsocketControl.sAddrCli , sizeof(gTCPsocketControl.sAddrCli)) < 0){
gTCPsocketControl.cliConnectedFlag = 0;
return -1;
} else {
gTCPsocketControl.cliConnectedFlag = 1;
}
}
// ok we are connected - lets send the data
start:
contrlMsg[0] = eStjTCPSocketControlMsgID_start;
contrlMsg[1] = dataSize;
// send that we what to transmit some data
r = send(gTCPsocketControl.sCli , (char *)contrlMsg , sizeof(contrlMsg) , 0);
if(r < 0) {
return -2;
}
// recv that the server is ready to transmit
r = _TCPcontrolRecvResult(gTCPsocketControl.sCli);
if (eStjTCPSocketControlMsgErrorID_socket == r) return -3;
if (eStjTCPSocketControlMsgErrorID_amount == r) goto start;
// ok let's send
packets = dataSize / gTCPsocketControl.maxTXsize;
if (dataSize % gTCPsocketControl.maxTXsize) packets++;
pB = pD;
amTotal = dataSize;
for (p = 0; p < packets; p++) {
// send packet pre header
contrlMsg[0] = eStjTCPSocketControlMsgID_packet;
contrlMsg[1] = p;
r = send(gTCPsocketControl.sCli , (char *)contrlMsg , sizeof(contrlMsg) , 0);
if(r < 0) {
return -4;
}
r = _TCPcontrolRecvResult(gTCPsocketControl.sCli);
if (eStjTCPSocketControlMsgErrorID_socket == r) return -5;
if (eStjTCPSocketControlMsgErrorID_amount == r) goto start;
am = (amTotal > gTCPsocketControl.maxTXsize) ? gTCPsocketControl.maxTXsize : amTotal;
sendPacket:
r = send(gTCPsocketControl.sCli ,(char *) pB ,am , 0);
if(r < 0) {
return -5;
}
// get ack from the server
r = _TCPcontrolRecvResult(gTCPsocketControl.sCli);
if (eStjTCPSocketControlMsgErrorID_socket == r) return -3;
if (eStjTCPSocketControlMsgErrorID_amount == r) goto sendPacket;
pB += am;
amTotal -= am;
}
return r;
}
//! the message pump
void * TCPcontrolMsgPump (void *pParams) {
int r;
uint32_t contrlMsg[2];
struct sockaddr_in cliAddr;
SOCKET sCli;
uint32_t dataSize;
socklen_t cliAddrSize;
uint32_t packets;
uint8_t * pB;
size_t am, amTotal;
uint32_t p;
sem_post(&gTCPsocketControl.serverSign);
//accept connection from an incoming client
cliAddrSize = sizeof(struct sockaddr_in);
sCli = accept(gTCPsocketControl.sSrv, (struct sockaddr *)&cliAddr, (socklen_t*)&cliAddrSize);
if (sCli < 0) goto end;
// run the pump
for (;;) {
// ok we are connected
// read start message
r = recv(sCli , (char *)contrlMsg , sizeof(contrlMsg), 0);
if (r < 0) goto end;
if (r != sizeof(contrlMsg)) {
_TCPcontrolSendResult(sCli, eStjTCPSocketControlMsgErrorID_amount);
continue;
}
if (contrlMsg[0] != eStjTCPSocketControlMsgID_start) {
_TCPcontrolSendResult(sCli, eStjTCPSocketControlMsgErrorID_msgID);
continue;
}
dataSize = contrlMsg[1];
// check if we have to realloc the rx buffer
if (gTCPsocketControl.msgBufferSize < dataSize) {
uint8_t *pNB = realloc(gTCPsocketControl.pMsgBuffer, dataSize);
if (!pNB) {
_TCPcontrolSendResult(sCli, eStjTCPSocketControlMsgErrorID_realloc);
continue;
}
gTCPsocketControl.pMsgBuffer = pNB;
gTCPsocketControl.msgBufferSize = dataSize;
}
_TCPcontrolSendResult(sCli, eStjTCPSocketControlMsgErrorID_noError);
// recv data
packets = dataSize / gTCPsocketControl.maxTXsize;
if (dataSize % gTCPsocketControl.maxTXsize) packets++;
pB = gTCPsocketControl.pMsgBuffer;
amTotal = dataSize;
for (p = 0; p < packets; p++) {
// receive packet header
r = recv(sCli , (char *)contrlMsg , sizeof(contrlMsg), 0);
if (r < 0) goto end;
if (r != sizeof(contrlMsg)) {
_TCPcontrolSendResult(sCli, eStjTCPSocketControlMsgErrorID_amount);
continue;
}
if (contrlMsg[0] != eStjTCPSocketControlMsgID_packet) {
_TCPcontrolSendResult(sCli, eStjTCPSocketControlMsgErrorID_msgID);
continue;
}
if (contrlMsg[1] != p) {
_TCPcontrolSendResult(sCli, eStjTCPSocketControlMsgErrorID_wrongPacket);
continue;
}
_TCPcontrolSendResult(sCli, eStjTCPSocketControlMsgErrorID_noError);
am = (amTotal > gTCPsocketControl.maxTXsize) ? gTCPsocketControl.maxTXsize : amTotal;
// ok the next message will contain the data
recvPacket:
r = recv(sCli , (char *)pB , am, 0);
if (r < 0) goto end;
if (r != am) {
_TCPcontrolSendResult(sCli, eStjTCPSocketControlMsgErrorID_amount);
goto recvPacket;
}
_TCPcontrolSendResult(sCli, eStjTCPSocketControlMsgErrorID_noError);
pB += am;
amTotal -= am;
}
// handle message
gTCPsocketControl.rxCB(gTCPsocketControl.pMsgBuffer , dataSize);
continue;
}
end:
sem_post(&gTCPsocketControl.serverSign);
return (void *) -1;
}
//! init
int TCPcontrolInit (
int serverPort, //!< server tx port number - best over 1000
const char * szClient, //!< "family-PC" or "192.168.1.3"
int clientPort, //!< client tx port number
TfkpTCPcallback rxCB, //!< the rx data callback
size_t rxBufferSize, //!< the size of the rx buffer
size_t maxTCPdataSize //!< maximum size of a TCP datagram (400 Bytes seems a good size)
) {
#ifdef WIN32
// local data
WSADATA wsaData;
// start sockets
if ((WSAStartup(MAKEWORD(2, 2), &wsaData))) {
perror("WSAStartup failed!");
return -1;
}
#endif
char * szIPserver;
char * szIPclient;
struct hostent * pHostDescr;
struct sockaddr_in sAddr;
// -----------------
// get ip strings
// get ip of the server
pHostDescr = gethostbyname("localhost");
// check if found a host
if (!pHostDescr) {
return -11;
}
szIPserver = inet_ntoa(*(struct in_addr*)*pHostDescr->h_addr_list);
// get ip of the client
if (strcmp(szClient, "")) {
pHostDescr = gethostbyname(szClient);
} else {
pHostDescr = gethostbyname("localhost");
}
// check if found a host
if (!pHostDescr) {
return -12;
}
szIPclient = inet_ntoa(*(struct in_addr*)*pHostDescr->h_addr_list);
// -----------------
// try to create sockets
// try to create socket for the server
gTCPsocketControl.sSrv = socket(PF_INET , SOCK_STREAM, IPPROTO_TCP);
if (-1 == gTCPsocketControl.sSrv) return -21;
// try to create socket for the client
gTCPsocketControl.sCli = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (-1 == gTCPsocketControl.sCli) return -22;
// -----------------
// bind input to IP and port
memset(&sAddr,0,sizeof(sAddr));
sAddr.sin_family = PF_INET;
sAddr.sin_addr.s_addr = INADDR_ANY;
sAddr.sin_port = htons( serverPort );
// bind server socket to address
if (bind(gTCPsocketControl.sSrv, (SOCKADDR *)&sAddr, sizeof(SOCKADDR_IN))) {
return -31;
}
// and listen for incoming connections
if (listen(gTCPsocketControl.sSrv , 3)) {
return -32;
}
// -----------------
// connect output to IP and port
memset(&gTCPsocketControl.sAddrCli,0,sizeof(sAddr));
gTCPsocketControl.sAddrCli.sin_family = PF_INET;
gTCPsocketControl.sAddrCli.sin_addr.s_addr = inet_addr(szIPclient);
gTCPsocketControl.sAddrCli.sin_port = htons( clientPort );
if (connect(gTCPsocketControl.sCli , (struct sockaddr *)&gTCPsocketControl.sAddrCli , sizeof(gTCPsocketControl.sAddrCli)) < 0){
gTCPsocketControl.cliConnectedFlag = 0;
} else {
gTCPsocketControl.cliConnectedFlag = 1;
}
// create sign semaphore
sem_init(&gTCPsocketControl.serverSign, 0, 0);
// create buffers
gTCPsocketControl.pMsgBuffer = malloc(rxBufferSize);
if (!gTCPsocketControl.pMsgBuffer) {
return -32;
}
gTCPsocketControl.msgBufferSize = rxBufferSize;
// set callback
gTCPsocketControl.rxCB = rxCB;
gTCPsocketControl.maxTXsize = maxTCPdataSize;
// start rx thread
if(pthread_create(&gTCPsocketControl.srvThr , NULL, TCPcontrolMsgPump, NULL)) {
return -40;
}
// wait till rx server is running
sem_wait(&gTCPsocketControl.serverSign);
return 0;
}
//! closes the TCP server and client
void TCPcontrolClose () {
closesocket (gTCPsocketControl.sSrv);
closesocket (gTCPsocketControl.sCli);
free(gTCPsocketControl.pMsgBuffer);
memset(&gTCPsocketControl, 0, sizeof(TstjTCPSocketControl));
#ifdef WIN32
WSACleanup();
#endif
}
//! inits the TCP control via stdin inputs
int TCPcontrolInitFromStdIn (
TfkpTCPcallback rxCB, //!< the rx data callback
size_t rxBufferSize, //!< the size of the rx buffer
size_t maxTCPdataSize //!< maximum size of a TCP datagram (400 Bytes seems a good size)
) {
int srvPort;
int clientPort;
const size_t ipLen = 256;
char szIP[ipLen];
const size_t dummyStrLen = 100;
char szDummy[dummyStrLen];
int r;
printf("====| TCP client/server setup |====\n");
printf("server listen port: ");
fgets(szDummy, dummyStrLen, stdin);
szDummy[strcspn(szDummy, "\r\n")] = 0;
srvPort = atoi(szDummy);
printf("client send IP address or name: ");
fgets(szIP, 255, stdin);
szIP[strcspn(szIP, "\r\n")] = 0;
printf("client port: ");
fgets(szDummy, dummyStrLen, stdin);
szDummy[strcspn(szDummy, "\r\n")] = 0;
clientPort = atoi(szDummy);
r = TCPcontrolInit (
srvPort, //!< server port number - best over 1000
szIP, //!< "family-PC" or "192.168.1.3"
clientPort, //!< client port number
rxCB, //!< the rx data callback
rxBufferSize, //!< the size of the rx buffer
maxTCPdataSize //!< maximum size of a TCP datagram (400 Bytes seems a good size)
);
if (!r) {
printf("setup finished successfully!\n");
printf("===================================\n");
} else {
printf("setup error: %i \n", r);
printf("===================================\n");
}
return r;
}
// -----------------------------------------
// test
enum eStates {
eState_std = 0,
eState_stressTest = 1,
eState_multiTX = 2
};
int stateID = eState_std;
#define dSTsize (1024 * 1024)
uint8_t STB[dSTsize];
int rxCB (uint8_t * pData, size_t amount) {
size_t i;
switch (stateID) {
case eState_std:
pData[amount] = 0;
printf("rx: %s\n",pData);
break;
case eState_stressTest:
for (i = 0; i < dSTsize; i++) {
if (pData[i] != (uint8_t)((size_t)i & 0xFF)) {
fprintf(stderr, "stress test error at position %i\n",(int) i);
fflush(stdout);
return 0;
}
}
printf("rx: stress test successful\n");
break;
case eState_multiTX:
printf("rx %iBytes\n", (int)amount);
break;
}
fflush(stdout);
return 0;
}
int main(void) {
const size_t dummyStrLen = 1024;
char szDummy[dummyStrLen];
size_t i;
int r, am, j;
// pre init for the stress test
for (i = 0; i < dSTsize; i++) {
STB[i] = (uint8_t)((size_t)i & 0xFF);
}
printf("TCP demo\n");
if (TCPcontrolInitFromStdIn(rxCB, 4096, 500)) goto errorExit;
printf("commands:\n s - send\n t - tx stress test\n a - activate/deactivate rx for stress test\n m - multi tx test\n h - help\n e - exit\n");
for(;;) {
printf("command: ");
fgets(szDummy, dummyStrLen, stdin);
switch(tolower(szDummy[0])) {
case 's':
stateID = eState_std;
fgets(szDummy, dummyStrLen, stdin);
szDummy[strcspn(szDummy, "\r\n")] = 0;
r = TCPcontrolSend((uint8_t *)szDummy, strlen(szDummy)+1);
if(r) {
fprintf(stderr,"sending data failed with code %i(%s)\n", r, strerror(errno));
} else {
printf("succeeded\n");
}
break;
case 't':
printf("sending packets...\n");
r = TCPcontrolSend(STB, dSTsize);
if (r) {
fprintf(stderr,"stress test sending data failed with code %i\n", r);
} else {
printf("succeeded\n");
}
break;
case 'a':
stateID = eState_stressTest;
printf("stress test RX now active\n");
break;
case 'm':
stateID = eState_multiTX;
printf("amount of transmissions: ");
fgets(szDummy, dummyStrLen, stdin);
szDummy[strcspn(szDummy, "\r\n")] = 0;
am = atoi(szDummy);
for (j = 0; j < am; j++) {
printf("tm %i...", j);
sprintf(szDummy,"tm %i",j);
r = TCPcontrolSend((uint8_t *)szDummy, strlen(szDummy)+1);
if (!r) printf("successful\n");
else printf("failed\n");
}
break;
case 'h':
printf("commands:\n s - send\n t - tx stress test\n a - activate/deactivate rx for stress test\n m - multi tx test\n h - help\n e - exit\n");
break;
case 'e':
goto stdExit;
}
}
stdExit:
TCPcontrolClose ();
return EXIT_SUCCESS;
errorExit:
TCPcontrolClose ();
return EXIT_FAILURE;
}
a note to the stress test and the initial connection. Under weak WLAN connections it could took some time.

libssh2: libssh2_channel_write() doesn't seem to write data on the channel

I am trying to execute a command on a router via ssh. After the login, when I execute the command on the device, it asks for an additional password. I am not able to send the password using libssh2_channel_write(). Here is the code snippet (modified the ssh2_exec.c that comes with the library). This is a snippet where the device is authenticated and the command has been issued. This loop just tries to get read the output of the executed command:
for( ;; )
{
/* loop until we block */
int rc;
do
{
char buffer[0x4000];
rc = libssh2_channel_read( channel, buffer, sizeof(buffer) );
if( rc > 0 )
{
int i;
char *enable = "stic-isr2951-t1";
int ret;
bytecount += rc;
fprintf(stderr, "We read [%d] bytes:\n", bytecount);
for( i=0; i < rc; ++i )
fputc( buffer[i], stderr);
**if ( strstr(buffer, "assword:") != NULL ){
fprintf(stderr, "Sending the additional password now\n");
ret = libssh2_channel_write(channel, enable, strlen(enable));
fprintf(stderr, "Wrote [%d] bytes\n", ret);
}**
}
else {
if( rc != LIBSSH2_ERROR_EAGAIN )
/* no need to output this for the EAGAIN case */
fprintf(stderr, "libssh2_channel_read returned %d\n", rc);
}
}
while( rc > 0 );
/* this is due to blocking that would occur otherwise so we loop on
this condition */
if( rc == LIBSSH2_ERROR_EAGAIN )
{
waitsocket(sock, session);
}
else
break;
}
In the snippet above, the code that detects that the device is posting a password prompt is:
if ( strstr(buffer, "assword:") != NULL ){
fprintf(stderr, "Sending the additional password now\n");
ret = libssh2_channel_write(channel, enable, strlen(enable));
fprintf(stderr, "Wrote [%d] bytes\n", ret);
}
That's where I have a problem. The password being sent on the channel isn't working as the device continues to timeout expecting the password. There is no indication that libssh2_channel_write() failed as the return value says it wrote the password properly.
Am I missing something?
EDIT:
The problem with the continuous timeout password prompted was because the password didn't have \n at the end. I was expecting the lib to take care of it but it didn't.
Now that I am able to send the password to the remote device, I run into another issue. After I send the password via libssh2_channel_write(), subsequent libssh2_channel_read() fails with
LIBSSH2_ERROR_SOCKET_RECV
I am not sure why is this happening. Logic was to check if the libssh2_channel_write() was successful by doing a subsequent read() (which would give the command prompt on the remote device) and then issue the command to be executed on the remote device followed by a subsequent read to get the command output. Am I doing something wrong? This doesn't seem to be working. Here's the complete code snippet:
/*
* Sample showing how to use libssh2 to execute a command remotely.
*
* The sample code has fixed values for host name, user name, password
* and command to run.
*
* Run it like this:
*
* $ ./ssh2_exec 127.0.0.1 user password "uptime"
*
*/
#include "libssh2_config.h"
#include <libssh2.h>
#include <string.h>
#ifdef HAVE_WINSOCK2_H
#include <winsock2.h>
#endif
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
#include <sys/time.h>
#include <sys/types.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <ctype.h>
static int waitsocket(int socket_fd, LIBSSH2_SESSION *session)
{
struct timeval timeout;
int rc;
fd_set fd;
fd_set *writefd = NULL;
fd_set *readfd = NULL;
int dir;
timeout.tv_sec = 10;
timeout.tv_usec = 0;
FD_ZERO(&fd);
FD_SET(socket_fd, &fd);
/* now make sure we wait in the correct direction */
dir = libssh2_session_block_directions(session);
if(dir & LIBSSH2_SESSION_BLOCK_INBOUND)
readfd = &fd;
if(dir & LIBSSH2_SESSION_BLOCK_OUTBOUND)
writefd = &fd;
rc = select(socket_fd + 1, readfd, writefd, NULL, &timeout);
return rc;
}
int main(int argc, char *argv[])
{
const char *hostname = "10.10.10.10";
const char *commandline = "show version";
const char *username = "user1";
const char *password = "password1";
unsigned long hostaddr;
int flag = 0;
int sock;
struct sockaddr_in sin;
const char *fingerprint;
LIBSSH2_SESSION *session;
LIBSSH2_CHANNEL *channel;
int rc;
int exitcode;
char *exitsignal=(char *)"none";
int bytecount = 0;
size_t len;
LIBSSH2_KNOWNHOSTS *nh;
int type;
if (argc > 1)
/* must be ip address only */
hostname = argv[1];
if (argc > 2) {
username = argv[2];
}
if (argc > 3) {
password = argv[3];
}
if (argc > 4) {
commandline = argv[4];
}
rc = libssh2_init (0);
if (rc != 0) {
fprintf (stderr, "libssh2 initialization failed (%d)\n", rc);
return 1;
}
hostaddr = inet_addr(hostname);
printf("host address is: %ld\n", hostaddr);
/* Ultra basic "connect to port 22 on localhost"
* Your code is responsible for creating the socket establishing the
* connection
*/
sock = socket(AF_INET, SOCK_STREAM, 0);
sin.sin_family = AF_INET;
sin.sin_port = htons(22);
sin.sin_addr.s_addr = hostaddr;
if (connect(sock, (struct sockaddr*)(&sin),
sizeof(struct sockaddr_in)) != 0) {
fprintf(stderr, "failed to connect!\n");
return -1;
}
/* Create a session instance */
session = libssh2_session_init();
if (!session)
return -1;
//libssh2_trace(session, LIBSSH2_TRACE_AUTH|LIBSSH2_TRACE_SOCKET);
/* tell libssh2 we want it all done non-blocking */
libssh2_session_set_blocking(session, 0);
/* ... start it up. This will trade welcome banners, exchange keys,
* and setup crypto, compression, and MAC layers
*/
while ((rc = libssh2_session_handshake(session, sock)) ==
LIBSSH2_ERROR_EAGAIN);
if (rc) {
fprintf(stderr, "Failure establishing SSH session: %d\n", rc);
return -1;
}
nh = libssh2_knownhost_init(session);
if(!nh) {
/* eeek, do cleanup here */
return 2;
}
/* read all hosts from here */
libssh2_knownhost_readfile(nh, "known_hosts",
LIBSSH2_KNOWNHOST_FILE_OPENSSH);
/* store all known hosts to here */
libssh2_knownhost_writefile(nh, "dumpfile",
LIBSSH2_KNOWNHOST_FILE_OPENSSH);
fingerprint = libssh2_session_hostkey(session, &len, &type);
if(fingerprint) {
struct libssh2_knownhost *host;
#if LIBSSH2_VERSION_NUM >= 0x010206
/* introduced in 1.2.6 */
int check = libssh2_knownhost_checkp(nh, hostname, 22,
fingerprint, len,
LIBSSH2_KNOWNHOST_TYPE_PLAIN|
LIBSSH2_KNOWNHOST_KEYENC_RAW,
&host);
#else
/* 1.2.5 or older */
int check = libssh2_knownhost_check(nh, hostname,
fingerprint, len,
LIBSSH2_KNOWNHOST_TYPE_PLAIN|
LIBSSH2_KNOWNHOST_KEYENC_RAW,
&host);
#endif
fprintf(stderr, "Host check: %d, key: %s\n", check,
(check <= LIBSSH2_KNOWNHOST_CHECK_MISMATCH)?
host->key:"<none>");
/*****
* At this point, we could verify that 'check' tells us the key is
* fine or bail out.
*****/
}
else {
/* eeek, do cleanup here */
return 3;
}
libssh2_knownhost_free(nh);
if ( strlen(password) != 0 ) {
/* We could authenticate via password */
while ((rc = libssh2_userauth_password(session, username, password)) ==
LIBSSH2_ERROR_EAGAIN);
if (rc) {
fprintf(stderr, "Authentication by password failed.\n");
goto shutdown;
}
}
else {
/* Or by public key */
while ((rc = libssh2_userauth_publickey_fromfile(session, username,
"/home/user/"
".ssh/id_rsa.pub",
"/home/user/"
".ssh/id_rsa",
password)) ==
LIBSSH2_ERROR_EAGAIN);
if (rc) {
fprintf(stderr, "\tAuthentication by public key failed\n");
goto shutdown;
}
}
#if 1
//libssh2_trace(session, ~0 );
#endif
/* Exec non-blocking on the remove host */
while( (channel = libssh2_channel_open_session(session)) == NULL &&
libssh2_session_last_error(session,NULL,NULL,0) ==
LIBSSH2_ERROR_EAGAIN )
{
waitsocket(sock, session);
}
if( channel == NULL )
{
fprintf(stderr,"Error\n");
exit( 1 );
}
while( (rc = libssh2_channel_exec(channel, commandline)) ==
LIBSSH2_ERROR_EAGAIN )
{
waitsocket(sock, session);
}
if( rc != 0 )
{
fprintf(stderr,"Error\n");
exit( 1 );
}
for( ;; )
{
/* loop until we block */
int rc;
do
{
char buffer[0x4000];
rc = libssh2_channel_read( channel, buffer, sizeof(buffer) );
if( rc > 0 )
{
int i;
char *enable = "check-password\n";
int ret;
bytecount += rc;
fprintf(stderr, "We read [%d] bytes:\n", bytecount);
fputc('[', stderr);
for( i=0; i < rc; ++i )
fputc( buffer[i], stderr);
fputc(']', stderr);
if ( strstr(buffer, "Password:") != NULL ){
fprintf(stderr, "Sending the password now\n");
while((ret = libssh2_channel_write(channel, enable, strlen(enable))) == LIBSSH2_ERROR_EAGAIN) {
printf("ERROR_EAGAIN - sending password again\n");
}
fprintf(stderr, "Wrote [%d] bytes: \n", ret);
flag = 1;
continue;
}
if (!flag){ // start
char *cmd = "show clock\n";
int ret;
fprintf(stderr, "THIS is Fetching show clock command now\n");
while((ret = libssh2_channel_write(channel, cmd, strlen(cmd))) == LIBSSH2_ERROR_EAGAIN) {
printf("ERROR_EAGAIN - sending show clock again\n");
}
flag = 1;
} // end
}
else {
if(rc != LIBSSH2_ERROR_EAGAIN)
fprintf(stderr, "libssh2_channel_read returned [%d]:\n ", rc);
}
}
while( rc > 0 );
/* this is due to blocking that would occur otherwise so we loop on
this condition */
if( rc == LIBSSH2_ERROR_EAGAIN )
{
int check;
check = waitsocket(sock, session);
}
else
break;
}
exitcode = 127;
while( (rc = libssh2_channel_close(channel)) == LIBSSH2_ERROR_EAGAIN )
waitsocket(sock, session);
if( rc == 0 )
{
exitcode = libssh2_channel_get_exit_status( channel );
libssh2_channel_get_exit_signal(channel, &exitsignal,
NULL, NULL, NULL, NULL, NULL);
}
if (exitsignal)
fprintf(stderr, "\nGot signal: %s\n", exitsignal);
else
fprintf(stderr, "\nEXIT: %d bytecount: %d\n", exitcode, bytecount);
libssh2_channel_free(channel);
channel = NULL;
shutdown:
libssh2_session_disconnect(session,
"Normal Shutdown, Thank you for playing");
libssh2_session_free(session);
#ifdef WIN32
closesocket(sock);
#else
close(sock);
#endif
fprintf(stderr, "all done\n");
libssh2_exit();
return 0;
}
Any thoughts?

Resources