so I'm new to socket programming, and I was asked to write the server side that sends data to a client according to a certain request. I'm trying to server multiple clients at the same time. When a client first connects, the server accepts with no troubles whatsoever, but when a client sends a certain request, I get stuck in an infinity loop and it's not clear at all to me why the server keeps sending the same info to the client over and over and over again, below is my code for the server side:
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <math.h>
#include <windows.h>
#include <winsock.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <io.h>
#include <fstream>
#include <vector>
#define MAX_CONNECTION 100
#ifndef max
#define max(a,b) ((a) < (b) ? (a) : (b))
#endif
typedef struct connection{
char ipaddr[16];
int port;
int sd;
} connection;
static unsigned short SERVER_PORT = 4118;
int main(int argc, char* argv[])
{
int maxfd =-1;
fd_set rset, allset;
connection client[MAX_CONNECTION];
int passiveSock; /* Main Server Socket */
struct sockaddr_in servSock_in;
#ifdef WIN32
WSADATA wsaData;
WSAStartup(0x0101, &wsaData);
#endif
int port;
if (argc > 1)
port = atoi(argv[1]);
else
port = SERVER_PORT;
for(int i=0; i < MAX_CONNECTION ; i++)
client[i].sd = -1;
memset((char *)&servSock_in, 0, sizeof(servSock_in));
servSock_in.sin_family = PF_INET;
servSock_in.sin_addr.s_addr = htonl(INADDR_ANY);
servSock_in.sin_port = htons((u_short)port);
passiveSock = socket(PF_INET, SOCK_STREAM, 0);
if (passiveSock < 0) {
fprintf(stderr, "I am too tired... I failed to open gate...\n");
return -1;
}
if (bind(passiveSock, (struct sockaddr *)&servSock_in, sizeof(servSock_in)) < 0){
fprintf(stderr, "I couldn't attach gate to port...\n");
return -1;
}
if (listen(passiveSock, 5) < 0) {
fprintf(stderr, "I am not hearing anything...\n");
return -1;
}
FD_SET(passiveSock, &allset);
maxfd = max(maxfd, passiveSock);
struct sockaddr_in cliSock_in;
int cliSockLen;
int connectedSock;
cliSockLen = sizeof(cliSock_in);
printf("\n Waiting for an incoming connection at port number %d", port);
int bytesread = 0;
for (;;)
{
//FD_ZERO(&allset);
rset = allset;
int nready = select(maxfd+1,&rset, NULL, NULL, NULL);
if(FD_ISSET(passiveSock, &rset)){
printf("In the first if");
connectedSock = accept(passiveSock, (struct sockaddr *)&cliSock_in, &cliSockLen);
/* if an error occurs while accepting */
if (connectedSock == -1) {
printf("\n Server: Accept error (errno = %d: %s)\n", errno, strerror(errno));
continue;
}
for (int i=0; i<MAX_CONNECTION; i++)
if (client[i].sd < 0){
client[i].sd=connectedSock;
strcpy(client[i].ipaddr, inet_ntoa(cliSock_in.sin_addr));
client[i].port= ntohs(cliSock_in.sin_port);
printf("\n Server: connection established with %s:%d\n",
client[i].ipaddr, client[i].port);
break;
}
FD_SET(connectedSock, &allset);
maxfd = max(maxfd, connectedSock);
}
else{
for(int j = 0 ; j < MAX_CONNECTION; j++){
connectedSock = client[j].sd;
printf("connectedSock is %d", connectedSock);
if(connectedSock < 0)
continue;
if(FD_ISSET(client[j].sd, &rset)){
unsigned char buffer[66000];
int index = 0;
bytesread = recv(connectedSock, (char *)buffer, 66000, 0);
int type;
type = (buffer[0] & 0xE0) >> 5;
if (type == 0)
{
char fname[100];
int i = 0;
int length = (buffer[i++] & 0x1F);
memcpy(&fname[0], &buffer[i], length);
fname[length] = '\0';
i += length;
int fs = 0;
fs += (buffer[i++] << 8) & 0xff00;
fs += buffer[i++];
char* filedata = (char*)malloc(fs*sizeof(char));
memcpy(&filedata[0], &buffer[i], fs);
filedata[fs] = '\0';
for (int i = 0; i < fs; i++)
printf("%c", filedata[i]);
printf("type=%d,length=%d,data=%s,fs=%d,filedata=%s", type, length, fname, fs, filedata);
std::ofstream of;
of.open(fname, std::ios::binary);
for (int i = 0; i < fs; i++)
of.write(filedata + i, 1);
of.close();
unsigned char rep;
int reptype = 0;
rep = (unsigned char)(reptype & 0x07);
send(connectedSock, (char*)(&rep), 1, 0);
}
else if (type == 1)
{
char fname[100];
int i = 0;
int length = (buffer[i++] & 0x1F);
memcpy(&fname[0], &buffer[i], length);
fname[length] = '\0';
i += length;
std::ifstream t;
int fs;
t.open(fname, std::ios::binary);
std::vector<char> vec((
std::istreambuf_iterator<char>(t)),
(std::istreambuf_iterator<char>()));// open input file
t.close();
fs = vec.size();
char* filedata = (char*)malloc(fs*sizeof(char)); // allocate memory for a buffer of appropriate dimension
filedata = &vec[0];
filedata[fs] = '\0';
i = 0;
unsigned char* repbuffer = (unsigned char*)malloc(3 + length + fs);
repbuffer[i] = (unsigned char)(type & 0x07);
repbuffer[i] = repbuffer[i] << 5;
repbuffer[i] = repbuffer[i] | (length & 0x0000003F);
i++;
memcpy(&repbuffer[i], fname, length);
i = i + length;
printf("sizeof fs=%d", sizeof(fs));
repbuffer[i++] = (unsigned char)((fs & 0xff00) >> 8);
repbuffer[i++] = (unsigned char)(fs & 0xff);
memcpy(&repbuffer[i], filedata, fs);
printf("sizeof buffer=%d", sizeof(repbuffer));
i = i + fs;
// printf("the buffer contains %s\n",&repbuffer[11]);
if (send(connectedSock, (char*)repbuffer, i, 0) == -1)
{
printf("A local error was detected while sending data! (errno = %d: %s)\n", errno, strerror(errno));
return -1;
}
}
else if (type == 2)
{
char fname[100],nfname[100];
int i = 0;
int length = (buffer[i++] & 0x1F);
memcpy(&fname[0], &buffer[i], length);
fname[length] = '\0';
i += length;
int nlength = (buffer[i++] & 0x1F);
memcpy(&nfname[0], &buffer[i], nlength);
nfname[nlength] = '\0';
rename(fname,nfname);
}
else if (type == 3)
{
char rep[32];
strcpy(rep, "bye change get help put");
int length = strlen(rep);
unsigned char* repbuffer = (unsigned char*)malloc(1 + length);
int type = 6;
repbuffer[0] = (unsigned char)(type & 0x07);
repbuffer[0] = repbuffer[0] << 5;
repbuffer[0] = repbuffer[0] | (length & 0x0000003F);
memcpy(&repbuffer[1], rep, length);
if (send(connectedSock, (char*)repbuffer, length+1, 0) == -1)
{
perror("A local error was detected while sending data!!");
return -1;
}
}
else if (type == 4)
{
closesocket(connectedSock);
}
break;
}
}
}
}
closesocket(passiveSock);
WSACleanup();
return 0;
}
I feel there's something wrong with the usage of FD_ISSET() method, I've been trying to figure out the error for 2 hours now, pleeassse help
Related
I have a program which reads a file of domain names (one domain per line) and performs asynchronous DNS resolution and then downloads the landing page for each domain. The network communication is performed with an epoll based event loop. Testing has shown that increasing the number of concurrent connections does not increase performance in terms of Mbits/s throughput and in terms of number of pages downloaded. The results of my test are as follows. The first test is for 1024 concurrent connections, the second test for 2048, the third for 4096 and the fourth for 8192:
:~$ ./crawler com.lowercase
iterations=156965 total domains=5575 elapsed=65.51s domains/s=85.10 KB=28163 Mbit/s=2.86
:~$ ./crawler com.lowercase
iterations=88339 total domains=10525 elapsed=64.98s domains/s=161.98 KB=52936 Mbit/s=5.41
:~$ ./crawler com.lowercase
iterations=143989 total domains=9409 elapsed=64.80s domains/s=145.20 KB=48166 Mbit/s=4.94
:~$ ./crawler com.lowercase
iterations=109597 total domains=10532 elapsed=65.13s domains/s=161.71 KB=51874 Mbit/s=5.29
As you can see there is really no trend of increase in terms of domains downloaded per second or Mbits/s throughput. These results run contrary to expectations. Can anyone explain these results? Suggest a fix to improve performance with increasing number of connections?
For those interested a full code listing is provided below:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <resolv.h>
#include <sys/epoll.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <time.h>
#include <ares.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#define MAXWAITING 1000 /* Max. number of parallel DNS queries */
#define MAXTRIES 3 /* Max. number of tries per domain */
#define DNSTIMEOUT 3000 /* Max. number of ms for first try */
#define DNS_MAX_EVENTS 10000
#define DNS_MAX_SERVERS 2
#define SERVERS "1.0.0.1,8.8.8.8" /* DNS server to use (Cloudflare & Google) */
#define MAXDOMAINS 8192
#define PORT 80
#define MAXBUF 1024
#define MAX_EPOLL_EVENTS 8192
#define MAX_CONNECTIONS 8192
#define TIMEOUT 10000
ares_socket_t dns_client_fds[ARES_GETSOCK_MAXNUM] = {0};
struct epoll_event ev, dns_events[DNS_MAX_EVENTS];
int i,bitmask,nfds, epollfd, timeout, fd_count, ret;
int epfd;
int sockfd[MAX_CONNECTIONS];
struct epoll_event event[MAX_CONNECTIONS];
struct sockaddr_in dest[MAX_CONNECTIONS];
char resolved[MAXDOMAINS][254];
char ips[MAXDOMAINS][128];
int current = 0, active = 0, next = 0;
char servers[MAX_CONNECTIONS][128];
char domains[MAX_CONNECTIONS][254];
char get_buffer[MAX_CONNECTIONS][1024];
char buffer[MAX_CONNECTIONS][MAXBUF];
int buffer_used[MAX_CONNECTIONS];
struct timespec startTime, stopTime;
int i, num_ready, connections = 0, done = 0, total_bytes = 0, total_domains = 0, iterations = 0, count = 0;
FILE * fp;
struct epoll_event events[MAX_EPOLL_EVENTS];
static int nwaiting;
static void state_cb(void *data, int s, int read, int write)
{
//printf("Change state fd %d read:%d write:%d\n", s, read, write);
}
static void callback(void *arg, int status, int timeouts, struct hostent *host)
{
nwaiting--;
if(!host || status != ARES_SUCCESS){
//fprintf(stderr, "Failed to lookup %s\n", ares_strerror(status));
return;
}
char ip[INET6_ADDRSTRLEN];
if (host->h_addr_list[0] != NULL){
inet_ntop(host->h_addrtype, host->h_addr_list[0], ip, sizeof(ip));
strcpy(resolved[current], host->h_name);
strcpy(ips[current], ip);
if (current < MAXDOMAINS - 1) current++; else current = 0;
active++;
printf("active %d\r", active);
}
}
static void wait_ares(ares_channel channel)
{
nfds=0;
bitmask=0;
for (i =0; i < DNS_MAX_SERVERS ; i++) {
if (dns_client_fds[i] > 0) {
if (epoll_ctl(epollfd, EPOLL_CTL_DEL, dns_client_fds[i], NULL) < 0) {
continue;
}
}
}
memset(dns_client_fds, 0, sizeof(dns_client_fds));
bitmask = ares_getsock(channel, dns_client_fds, DNS_MAX_SERVERS);
for (i =0; i < DNS_MAX_SERVERS ; i++) {
if (dns_client_fds[i] > 0) {
ev.events = 0;
if (ARES_GETSOCK_READABLE(bitmask, i)) {
ev.events |= EPOLLIN;
}
if (ARES_GETSOCK_WRITABLE(bitmask, i)) {
ev.events |= EPOLLOUT;
}
ev.data.fd = dns_client_fds[i];
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, dns_client_fds[i], &ev) < 0) {
if(errno == EEXIST) {
nfds++;
continue;
}
continue;
}
nfds++;
}
}
if(nfds==0)
{
return;
}
timeout = 1000;//millisecs
fd_count = epoll_wait(epollfd, dns_events, DNS_MAX_EVENTS, timeout);
if (fd_count < 0) {
return;
}
if (fd_count > 0) {
for (i = 0; i < fd_count; ++i) {
ares_process_fd(channel, ((dns_events[i].events) & (EPOLLIN) ? dns_events[i].data.fd:ARES_SOCKET_BAD), ((dns_events[i].events) & (EPOLLOUT)? dns_events[i].data.fd:ARES_SOCKET_BAD));
}
} else {
ares_process_fd(channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
}
}
void make_socket_and_connect (int sock)
{
if ( (sockfd[sock] = socket(AF_INET, SOCK_STREAM|SOCK_NONBLOCK, 0)) < 0 ) {
perror("Socket");
exit(errno);
}
count++;
event[sock].events = EPOLLIN|EPOLLOUT;
event[sock].data.fd = sockfd[sock];
epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd[sock], &event[sock]);
bzero(&dest[sock], sizeof(dest[sock]));
dest[sock].sin_family = AF_INET;
dest[sock].sin_port = htons(PORT);
if ( inet_pton(AF_INET, servers[sock], &dest[sock].sin_addr.s_addr) == 0 ) {
printf("\n");
perror(servers[sock]);
exit(errno);
}
if ( connect(sockfd[sock], (struct sockaddr*)&dest[sock], sizeof(dest[sock])) != 0 ) {
if(errno != EINPROGRESS) {
printf("%s\n", servers[sock]);
perror("Connect again ");
//exit(errno);
}
buffer_used[sock] = 0;
}
}
int is_valid_ip(char *domain)
{
if (!strcmp(domain, "255.255.255.255"))
return 0;
if (!strcmp(domain, "192.168.1.0"))
return 0;
if (!strcmp(domain, "127.0.0.0"))
return 0;
return 1;
}
void close_socket (int socket)
{
close(sockfd[socket]);
count--;
epoll_ctl(epfd, EPOLL_CTL_DEL, sockfd[socket], &event[socket]);
}
void get_domain_and_ip(int id)
{
//close_socket(id);
active--;
get_domain_name:
strcpy(servers[id], ips[next]);
strcpy(domains[id], resolved[next]);
if (next < (MAXDOMAINS - 1)) next++; else next = 0;
if (is_valid_ip(servers[id]))
{
make_socket_and_connect(id);
total_domains++;
}
else
goto get_domain_name;
}
void get_domain_and_ip_without_connect(int id)
{
get_domain_name2:
strcpy(servers[id], ips[next]);
strcpy(domains[id], resolved[next]);
if (next < (MAXDOMAINS - 1)) next++; else next = 0;
if (!is_valid_ip(servers[id]))
goto get_domain_name2;
}
void get_time()
{
clock_gettime(CLOCK_MONOTONIC, &stopTime);
uint64_t msElapsed = (stopTime.tv_nsec - startTime.tv_nsec) / 1000000 + (stopTime.tv_sec - startTime.tv_sec) * 1000;
double seconds = (double)msElapsed / 1000.0;
iterations++;
fprintf(stderr, "iterations=%d total domains=%d elapsed=%2.2fs domains/s=%2.2f KB=%d Mbit/s=%2.2f num_ready=%d count=%d active=%d next=%d current=%d.....\r"
, iterations, total_domains, seconds, total_domains/seconds, total_bytes/1024, 8*total_bytes/seconds/1024/1204, num_ready, count, active, next, current);
}
ssize_t send_data(int id)
{
ssize_t nByte = send(sockfd[id], get_buffer[id] + buffer_used[id], strlen(get_buffer[id]) - buffer_used[id], 0);
return nByte;
}
ssize_t recv_data(int id)
{
ssize_t nByte = recv(sockfd[id], buffer[id], sizeof(buffer[id]), 0);
return nByte;
}
int wait()
{
int ret = epoll_wait(epfd, events, MAX_EPOLL_EVENTS, TIMEOUT/*timeout*/);
return ret;
}
int main(int argc, char *argv[]) {
sigaction(SIGPIPE, &(struct sigaction){SIG_IGN}, NULL);
FILE * fp;
char domain[254];
size_t len = 0;
ssize_t read;
ares_channel channel;
int status, dns_done = 0;
int optmask;
status = ares_library_init(ARES_LIB_INIT_ALL);
if (status != ARES_SUCCESS) {
printf("ares_library_init: %s\n", ares_strerror(status));
return 1;
}
struct ares_options options = {
.timeout = DNSTIMEOUT, /* set first query timeout */
.tries = MAXTRIES /* set max. number of tries */
};
optmask = ARES_OPT_TIMEOUTMS | ARES_OPT_TRIES;
status = ares_init_options(&channel, &options, optmask);
if (status != ARES_SUCCESS) {
printf("ares_init_options: %s\n", ares_strerror(status));
return 1;
}
status = ares_set_servers_csv(channel, SERVERS);
if (status != ARES_SUCCESS) {
printf("ares_set_servers_csv: %s\n", ares_strerror(status));
return 1;
}
memset(dns_client_fds, 0, sizeof(dns_client_fds));
memset((char *)&ev, 0, sizeof(struct epoll_event));
memset((char *)&dns_events[0], 0, sizeof(dns_events));
epollfd = epoll_create(DNS_MAX_SERVERS);
fp = fopen(argv[1], "r");
if (!fp)
exit(EXIT_FAILURE);
do{
if (nwaiting >= MAXWAITING || dns_done) {
do {
wait_ares(channel);
} while (nwaiting > MAXWAITING);
}
if (!dns_done) {
if (fscanf(fp, "%253s", domain) == 1) {
ares_gethostbyname(channel, domain, AF_INET, callback, NULL);
nwaiting++;
} else {
//fprintf(stderr, "done sending\n");
dns_done = 1;
}
}
} while (active < MAX_CONNECTIONS);
/*---Open sockets for streaming---*/
for (i = 0; i < MAX_CONNECTIONS; i++)
{
if ( (sockfd[i] = socket(AF_INET, SOCK_STREAM|SOCK_NONBLOCK, 0)) < 0 ) {
perror("Socket");
exit(errno);
}
count++;
}
/*---Add sockets to epoll---*/
epfd = epoll_create1(0);
for (i = 0; i < MAX_CONNECTIONS; i++)
{
event[i].events = EPOLLIN|EPOLLOUT;
event[i].data.fd = sockfd[i];
epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd[i], &event[i]);
}
/*---Initialize server address/port structs---*/
for (i = 0; i < MAX_CONNECTIONS; i++)
{
get_domain_and_ip_without_connect(i);
//printf("%s %s\n", servers[i], domains[i]);
bzero(&dest[i], sizeof(dest[i]));
dest[i].sin_family = AF_INET;
dest[i].sin_port = htons(PORT);
if ( inet_pton(AF_INET, servers[i], &dest[i].sin_addr.s_addr) == 0 ) {
perror(servers[i]);
exit(errno);
}
}
/*---Connect to servers---*/
for (i = 0; i < MAX_CONNECTIONS; i++)
{
if ( connect(sockfd[i], (struct sockaddr*)&dest[i], sizeof(dest[i])) != 0 ) {
if(errno != EINPROGRESS) {
perror("Connect ");
//exit(errno);
}
buffer_used[i] = 0;
}
}
clock_gettime(CLOCK_MONOTONIC, &startTime);
while (1)
{
/*---Do async DNS---*/
while (active < MAXDOMAINS && nwaiting > 0) {
//printf("active = %d MAXDOMAINS = %d nwaiting = %d MAXWAITING = %d\n", active, MAXDOMAINS, nwaiting, MAXWAITING);
if (nwaiting >= MAXWAITING || dns_done) {
do {
wait_ares(channel);
} while (nwaiting > MAXWAITING);
}
if (!dns_done) {
if (fscanf(fp, "%253s", domain) == 1) {
ares_gethostbyname(channel, domain, AF_INET, callback, NULL);
nwaiting++;
} else {
//fprintf(stderr, "done sending\n");
dns_done = 1;
}
}
} //while (active < MAXDOMAINS);
/*---Wait to be able to send---*/
num_ready = wait();
get_time();
if (!num_ready) break;
for(i = 0; i < num_ready; i++) {
int index;
if(events[i].events & EPOLLOUT) {
for (int j = 0; j < MAX_CONNECTIONS; j++)
{
if (events[i].data.fd == sockfd[j])
{
index = j;
break;
}
}
snprintf(get_buffer[index], sizeof(get_buffer[index]),
"GET %s HTTP/1.1\r\nHost: %s\r\nUser-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36\r\n\r\n", "/", domains[i]);
ssize_t nByte = 0;
if (buffer_used[index] < strlen(get_buffer[index]))
nByte = send_data(index);
if (nByte > 0)
{
buffer_used[index] += nByte;
total_bytes += nByte;
}
if (nByte == -1 && errno == EPIPE)
{
get_domain_and_ip(index);
}
}
if(events[i].events & EPOLLIN) {
for (int j = 0; j < MAX_CONNECTIONS; j++)
{
if (events[i].data.fd == sockfd[j])
{
index = j;
break;
}
}
bzero(buffer[index], MAXBUF);
ssize_t nByte = recv_data(index);
//if (nByte > 0) printf("Received: %s from %s at %s \n", buffer[index], domains[index], servers[index]);
if (nByte > 0) total_bytes += nByte;
if (nByte == 0)
{
close_socket(index);
if (!done)
{
get_domain_and_ip(index);
}
}
}
}
get_time();
if (done && count == 0) break;
}
ares_destroy(channel);
ares_library_cleanup();
fclose(fp);
printf("\nFinished without errors\n");
return 0;
}
EDIT
As requested I've performed more extensive testing with smaller numbers of concurrent connections. The results are below. The results are for 2, 4, 8, 16, 32, 64, 128, 256 and 512 concurrent connections.
total domains=4 elapsed=60.37s domains/s=0.07 KB=5 Mbit/s=0.00
total domains=0 elapsed=60.39s domains/s=0.00 KB=5 Mbit/s=0.00
total domains=17 elapsed=60.40s domains/s=0.28 KB=73 Mbit/s=0.01
total domains=17 elapsed=60.48s domains/s=0.28 KB=106 Mbit/s=0.01
total domains=40 elapsed=60.45s domains/s=0.66 KB=189 Mbit/s=0.02
total domains=172 elapsed=60.37s domains/s=2.85 KB=907 Mbit/s=0.10
total domains=312 elapsed=60.56s domains/s=5.15 KB=1272 Mbit/s=0.14
total domains=1165 elapsed=60.65s domains/s=19.21 KB=5687 Mbit/s=0.62
total domains=1966 elapsed=60.34s domains/s=32.58 KB=9884 Mbit/s=1.09
The tests show that for smaller numbers of concurrent connections we do see an increase in performance for increasing numbers of concurrent connections.
EDIT
As requested in chat here is a link to the file of domains I am testing with. Warning - the file is over 2GB in size. It has over 130M domains. domains Or if you just want 100,000 here is another link to play with 100,000 domains
I am learning socket programming in C language, and this is an incomprehensible problem I encountered during my study.
Today I am trying to send a HTTP request to my test server which host an Apache example website, then receive the response from test server. Here is a part of my receive code.
unsigned long recv_size = 0;
unsigned long response_size = 4096;
int ret = 0;
char *recv_buff = (char *)malloc(response_size);
while (1)
{
// ret = recv(socket, recv_buff, response_size, MSG_WAITALL); // cannot get all data
ret = read(socket, recv_buff, response_size); // same effect as the above
recv_size += ret;
if (ret < 0)
error(strerror(errno));
else if (ret == 0)
break; // all data recved
}
The normal result of my test with burpsuit is this.
But what I received with the C language program was incomplete data.
I searched the reason for one night, but I still did not find a solution for my problem. Whether it is to set the buff to a super large size or any other method, the complete data cannot be accepted at all.
The traffic monitored from wireshark is ok, but my program still cannot receive the complete data. What is the problem?
If you know why, please let me know. THX. (o゜▽゜)o☆
UPDATE
The while loop will execute twice, and first time the value of ret is 3343, and second time is 0, so the loop will stop here.
You can get a short read on a socket.
But, your code to handle that has a few issues.
You're allocating a buffer of size response_size. You are always reading that amount instead of reducing the amount read by the amount you've already read on a prior loop iteration.
This can cause you to read past the end of the buffer causing UB (undefined behavior).
Your termination condition is if (ret == 0). This can fail if another packet arrives "early". You'll never see a ret of 0, because the partial data from the next packet will make it non-zero
Here's the corrected code:
#if 0
unsigned long recv_size = 0;
#endif
unsigned long response_size = 4096;
int ret = 0;
char *recv_buff = (char *) malloc(response_size);
#if 1
unsigned long remaining_size = response_size;
unsigned long offset = 0;
#endif
for (; remaining_size > 0; remaining_size -= ret, offset += ret) {
ret = read(socket, &recv_buff[offset], remaining_size);
if (ret < 0)
error(strerror(errno));
}
UPDATE:
The above code corrects some of the issues. But, for a variable length source [such as http], we don't know how much to read at the outset.
So, we have to parse the headers and look for the "Content-Length" field. This will tell us how much to read.
So, we'd like to have line oriented input for the headers. Or, manage our own buffer
Assuming we can parse that value, we have to wait for the empty line to denote the start of the payload. And, then we can loop on that exact amount.
Here's some code that attempts the header parsing and saving of the payload. I've coded it, but not compiled it. So, you can take it as pseudo code:
unsigned long recv_size = 0;
unsigned long response_size = 4096;
char *recv_buff = malloc(response_size + 1);
// line oriented header buffer
char *endl = NULL;
unsigned long linelen;
char linebuf[1000];
int ret = 0;
// read headers
while (1) {
// fill up a chunk of data
while (recv_size < response_size) {
recv_buff[recv_size] = 0;
// do we have a line end?
endl = strstr(recv_buff,"\r\n");
if (endl != NULL)
break;
ret = read(socket, &recv_buff[recv_size], response_size - recv_size);
if (ret < 0)
error(strerror(errno));
if (ret == 0)
break;
recv_size += ret;
}
// error -- no line end but short read
if (endl == NULL)
error(strerror(errno));
// copy header to work buffer
linelen = endl - recv_buff;
memcpy(linebuf,recv_buff,linelen);
linebuf[linelen] = 0;
// remove header from receive buffer
linelen += 2;
recv_size -= linelen;
if (recv_size > 0)
memcpy(recv_buff,&recv_buff[linelen],recv_size);
// stop on end of headers (back to back "\r\n")
if ((recv_size >= 2) && (recv_buff[0] == '\r') && (recv_buff[1] == '\n')) {
memcpy(recv_buff,&recv_buff[2],recv_size - 2);
recv_size -= 2;
break;
}
// parse line work buffer for keywords ... (e.g.)
content_length = ...;
}
// save payload to file
while (content_length > 0) {
// write out prior payload amount
if (recv_size > 0) {
write(file_fd,recv_buff,recv_size);
content_length -= recv_size;
recv_size = 0;
continue;
}
recv_size = read(socket,recv_buff,response_size);
if (recv_size < 0)
error(strerror(errno));
if (recv_size == 0)
break;
}
UPDATE #2:
Yeah, it hard to make the pseudo code run, and the returned values are all garbled
Okay, here is a soup-to-nuts working version that I've tested against my own http server.
I had to create my own routines for the parts you didn't post (e.g. connect, etc.).
At the core, there might have been a minor tweak to the buffer slide code [it was sliding by an extra 2 bytes in one place], but, otherwise it was pretty close to my previous version
// htprcv/htprcv.c -- HTTP receiver
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <error.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
typedef unsigned char byte;
#define HTPSLIDE(_rmlen) \
recv_size = htpslide(recv_buff,recv_size,_rmlen)
#define _dbgprt(_fmt...) \
fprintf(stderr,_fmt)
#if DEBUG || _USE_ZPRT_
#define dbgprt(_lvl,_fmt...) \
do { \
if (dbgok(_lvl)) \
_dbgprt(_fmt); \
} while (0)
#define dbgexec(_lvl,_expr) \
do { \
if (dbgok(_lvl)) \
_expr; \
} while (0)
#else
#define dbgprt(_lvl,_fmt...) \
do { \
} while (0)
#define dbgexec(_lvl,_expr) \
do { \
} while (0)
#endif
#define dbgok(_lvl) \
opt_d[(byte) #_lvl[0]]
byte opt_d[256];
char *opt_o;
#define HEXMAX 16
// htpconn -- do connect to server
int
htpconn(const char *hostname,unsigned short portno)
{
struct addrinfo hints, *res;
struct hostent *hostent;
int ret;
char portstr[20];
int sockfd;
/* Prepare hint (socket address input). */
hostent = gethostbyname(hostname);
if (hostent == NULL)
error(1,errno,"htpconn: gethostbyname -- %s\n",hostname);
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET; // ipv4
hints.ai_socktype = SOCK_STREAM; // tcp
hints.ai_flags = AI_PASSIVE; // fill in my IP for me
sprintf(portstr, "%d", portno);
getaddrinfo(NULL, portstr, &hints, &res);
sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (sockfd < 0)
error(1,errno,"htpconn: socket\n");
// do the actual connection
ret = connect(sockfd, res->ai_addr, res->ai_addrlen);
if (ret < 0)
error(1,errno,"htprcv: read header\n");
return sockfd;
}
// htpslide -- slide buffer (strip out processed data)
size_t
htpslide(char *recv_buff,size_t recv_size,int slidelen)
{
size_t new_size;
if (slidelen > recv_size)
slidelen = recv_size;
new_size = recv_size - slidelen;
dbgprt(S,"htpslide: slidelen=%d recv_size=%zu new_size=%zu\n",
slidelen,recv_size,new_size);
memcpy(&recv_buff[0],&recv_buff[slidelen],new_size);
return new_size;
}
// _htphex -- dump a line in hex
void
_htphex(unsigned long off,const void *vp,size_t xlen)
{
const byte *bp = vp;
int idx;
int chr;
char hexbuf[200];
char alfbuf[200];
char *hexptr = hexbuf;
char *alfptr = alfbuf;
for (idx = 0; idx < HEXMAX; ++idx) {
chr = bp[idx];
if ((idx % 4) == 0)
*hexptr++ = ' ';
if (idx < xlen) {
hexptr += sprintf(hexptr,"%2.2X",chr);
if ((chr < 0x20) || (chr > 0x7E))
chr = '.';
}
else {
hexptr += sprintf(hexptr," ");
chr = ' ';
}
*alfptr++ = chr;
}
*hexptr = 0;
*alfptr = 0;
_dbgprt(" %8.8lX: %s *%s*\n",off,hexbuf,alfbuf);
}
// htphex -- dump a buffer in hex
void
htphex(const char *buf,size_t buflen,const char *reason)
{
size_t off = 0;
size_t xlen;
if (reason != NULL)
_dbgprt("htphex: DUMP buf=%p buflen=%zu (from %s)\n",
buf,buflen,reason);
for (; buflen > 0; buflen -= xlen, buf += xlen, off += xlen) {
xlen = buflen;
if (xlen > HEXMAX)
xlen = HEXMAX;
_htphex(off,buf,xlen);
}
}
// htpsym -- get symbol/value
int
htpsym(char *linebuf,char *sym,char *val)
{
char *cp;
int match;
dbgprt(H,"htpsym: PARAM linebuf='%s'\n",linebuf);
// FORMAT:
// foo-bar: baz
do {
match = 0;
cp = strchr(linebuf,':');
if (cp == NULL)
break;
*cp++ = 0;
strcpy(sym,linebuf);
for (; (*cp == ' ') || (*cp == '\t'); ++cp);
strcpy(val,cp);
match = 1;
dbgprt(H,"htpsym: SYMBOL sym='%s' val='%s'\n",sym,val);
} while (0);
return match;
}
// htprcv -- receive server response
void
htprcv(int sockfd,int fdout)
{
size_t recv_size = 0;
size_t response_size = 4096;
char *recv_buff = malloc(response_size + 1);
// line oriented header buffer
char *endl = NULL;
size_t linelen;
char linebuf[1000];
ssize_t ret = 0;
off_t content_length = 0;
// read headers
while (1) {
// fill up a chunk of data
while (recv_size < response_size) {
recv_buff[recv_size] = 0;
// do we have a line end?
endl = strstr(recv_buff,"\r\n");
if (endl != NULL)
break;
// read a chunk of data
ret = read(sockfd,&recv_buff[recv_size],response_size - recv_size);
if (ret < 0)
error(1,errno,"htprcv: read header\n");
if (ret == 0)
break;
recv_size += ret;
dbgprt(R,"htprcv: READ ret=%zd\n",ret);
dbgexec(R,htphex(recv_buff,recv_size,"htprcv/READ"));
}
// error -- no line end but short read
if (endl == NULL)
error(1,0,"htprcv: no endl\n");
// copy header to work buffer
linelen = endl - recv_buff;
memcpy(linebuf,recv_buff,linelen);
linebuf[linelen] = 0;
// remove header from receive buffer
linelen += 2;
HTPSLIDE(linelen);
// stop on end of headers (back to back "\r\n")
if ((recv_size >= 2) &&
(recv_buff[0] == '\r') && (recv_buff[1] == '\n')) {
HTPSLIDE(2);
break;
}
// parse line work buffer for keywords ...
char sym[100];
char val[1000];
if (! htpsym(linebuf,sym,val))
continue;
if (strcasecmp(sym,"Content-Length") == 0) {
content_length = atoi(val);
continue;
}
}
// save payload to file
while (content_length > 0) {
// write out prior payload amount
if (recv_size > 0) {
dbgexec(W,htphex(recv_buff,recv_size,"htprcv/WRITE"));
ret = write(fdout,recv_buff,recv_size);
if (ret < 0)
error(1,errno,"htprcv: write body\n");
content_length -= recv_size;
recv_size = 0;
continue;
}
// read in new chunk of payload
ret = read(sockfd,recv_buff,response_size);
if (ret < 0)
error(1,errno,"htprcv: read body\n");
if (ret == 0)
break;
recv_size = ret;
}
free(recv_buff);
}
// htpget -- do initial dialog
void
htpget(int sockfd,const char *hostname,const char *file)
{
char *bp;
char buf[1024];
ssize_t resid;
ssize_t xlen;
size_t off;
bp = buf;
if (file == NULL)
file = "/";
bp += sprintf(bp,"GET %s HTTP/1.1\r\n",file);
if (hostname == NULL)
hostname = "localhost";
bp += sprintf(bp,"Host: %s\r\n",hostname);
if (0) {
bp += sprintf(bp,"User-Agent: %s\r\n","curl/7.61.1");
}
else {
bp += sprintf(bp,"User-Agent: %s\r\n","htprcv");
}
bp += sprintf(bp,"Accept: */*\r\n");
bp += sprintf(bp,"\r\n");
resid = bp - buf;
off = 0;
for (; resid > 0; resid -= xlen, off += xlen) {
xlen = write(sockfd,buf,resid);
if (xlen < 0)
error(1,errno,"htpget: write error\n");
}
}
// main -- main program
int
main(int argc,char **argv)
{
char *cp;
char *portstr;
unsigned short portno;
int sockfd;
int filefd;
char url[1000];
--argc;
++argv;
//setlinebuf(stdout);
setlinebuf(stderr);
for (; argc > 0; --argc, ++argv) {
cp = *argv;
if (*cp != '-')
break;
cp += 2;
switch(cp[-1]) {
case 'd': // debug options
if (*cp == 0)
cp = "SHRW";
for (; *cp != 0; ++cp)
opt_d[(byte) *cp] = 1;
break;
case 'o': // output file
opt_o = cp;
break;
}
}
// get the remote host:port
do {
if (argc <= 0) {
strcpy(url,"localhost:80");
break;
}
strcpy(url,*argv++);
--argc;
} while (0);
// get remote port number
portstr = strchr(url,':');
if (portstr != NULL)
*portstr++ = 0;
else
portstr = "80";
portno = atoi(portstr);
// open the output file (or send to stdout)
do {
if (opt_o == NULL) {
filefd = 1;
break;
}
filefd = open(opt_o,O_WRONLY | O_CREAT,0644);
if (filefd < 0)
filefd = 1;
} while (0);
// establish connection
sockfd = htpconn(url,portno);
// send the file request
htpget(sockfd,NULL,"/");
// receive the server response
htprcv(sockfd,filefd);
close(sockfd);
return 0;
}
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, ð_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.
I've been working on websockets with a library called cwebsockets lately in C, and can now send a message to a client. The problem is that the application closes whenever the page on the client-side is reloaded. I want the server-side to look for a new connection after the previous connection is lost due to reload.
The message I get is send failed: connection reset by peer, which what I have understood after some research is that the sender doesn't get acknowledge from the client. But how can I handle this?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
#include <ctype.h>
#include <termios.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <errno.h>
#include <signal.h>
#include "websocket.h"
#define PORT 8081
#define BUF_LEN 0xFFFF
#define FILE_BUF_SIZE 30
void error(const char *msg) {
perror(msg);
exit(EXIT_FAILURE);
}
int safeSend(int clientSocket, const uint8_t *buffer, size_t bufferSize) {
#ifdef PACKET_DUMP
printf("out packet:\n");
fwrite(buffer, 1, bufferSize, stdout);
printf("\n");
#endif
ssize_t written = send(clientSocket, buffer, bufferSize, 0);
if (written == -1) {
close(clientSocket);
perror("send failed");
return EXIT_FAILURE;
}
if (written != bufferSize) {
close(clientSocket);
perror("written not all bytes");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
void clientWorker(int clientSocket) {
FILE *f;
unsigned char f_ch_a_buf[FILE_BUF_SIZE];
unsigned char f_ch_b_buf[FILE_BUF_SIZE];
short *ch_a_data = (short*)f_ch_a_buf;
short *ch_b_data = (short*)f_ch_b_buf;
int n,i;
int memfd;
void *map_base, *virt_addr;
short *ch_data;
uint8_t buffer[BUF_LEN];
memset(buffer, 0, BUF_LEN);
size_t readedLength = 0;
size_t frameSize = BUF_LEN;
enum wsState state = WS_STATE_OPENING;
uint8_t *data = NULL;
size_t dataSize = 0;
enum wsFrameType frameType = WS_INCOMPLETE_FRAME;
struct handshake hs;
nullHandshake(&hs);
uint8_t msg[BUF_LEN];
#define prepareBuffer frameSize = BUF_LEN; memset(buffer, 0, BUF_LEN);
#define initNewFrame frameType = WS_INCOMPLETE_FRAME; readedLength = 0; memset(buffer, 0, BUF_LEN);
while (frameType == WS_INCOMPLETE_FRAME) {
ssize_t readed = recv(clientSocket, buffer+readedLength, BUF_LEN-readedLength, 0);
if(readed <= 0){
if(state == WS_STATE_NORMAL){
/*
temp_raw = sys_file_read("/sys/devices/soc0/amba/f8007100.adc/iio:device0/in_temp0_raw");
temp_scale = sys_file_read("/sys/devices/soc0/amba/f8007100.adc/iio:device0/in_temp0_scale");
temp_offset = sys_file_read("/sys/devices/soc0/amba/f8007100.adc/iio:device0/in_temp0_offset");
// Formel brukt for å regne SoC temperatur: (in_temp0_raw - temp_offset)/temp_scale
dash_temp = ((temp_raw - temp_offset)/temp_scale);
*/
int EXTS[8];
int CPS[8];
int CAM[4];
int i;
for(i=0;i<8;i++){
EXTS[i] = (double)rand() / RAND_MAX;
}
for(i=0;i<8;i++){
CPS[i] = rand() % 30 + 2;
}
for(i=0;i<8;i++){
CAM[i] = rand() % 30 + 2;
}
int dash_kmt = rand() % 9 + 35;
int FSS1 = rand() % 1 + 4;
int FTWS2 = rand() % 2 + 90;
int FPFS2 = 28.5;
int MAP = rand() % 10 + 120;
int FTFS1 = rand() % 5 + 50;
int FTOS3 = rand() % 5 + 50;
int FPOS1 = rand() % 5 + 50;
int TPDS1 = rand() % 5 + 50;
int TPAS2 = rand() % 5 + 50;
int MAF = rand() % 5 + 50;
int ATFS2 = rand() % 5 + 50;
int TDC2S2 = rand() % 5 + 10;
int L1S1 = rand() % 5 + 10;
int L2S2 = rand() % 5 + 10;
int K1S1 = rand() % 5 + 10;
int K2S2 = rand() % 5 + 15;
dataSize = sprintf((char *)msg, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
dash_kmt,FSS1,FTWS2,FPFS2,MAP,EXTS[0],EXTS[1],EXTS[2],EXTS[3],EXTS[4],EXTS[5],EXTS[6],EXTS[7],
CPS[0],CPS[1],CPS[2],CPS[3],CPS[4],CPS[5],CPS[6],CPS[7],CAM[1],CAM[2],CAM[3],CAM[4],
FTFS1, FTOS3, FPOS1, TPDS1, TPAS2, MAF, ATFS2, TDC2S2, L1S1, L2S2, K1S1, K2S2
);
usleep(1000);
prepareBuffer;
wsMakeFrame(msg, dataSize, buffer, &frameSize, WS_TEXT_FRAME);
if (safeSend(clientSocket, buffer, frameSize) == EXIT_FAILURE)
break;
initNewFrame;
}
}
if(readed > 0){
readedLength+= readed;
assert(readedLength <= BUF_LEN);
if (state == WS_STATE_OPENING) {
frameType = wsParseHandshake(buffer, readedLength, &hs);
} else {
frameType = wsParseInputFrame(buffer, readedLength, &data, &dataSize);
}
if ((frameType == WS_INCOMPLETE_FRAME && readedLength == BUF_LEN) || frameType == WS_ERROR_FRAME) {
if (frameType == WS_INCOMPLETE_FRAME)
printf("buffer too small");
else
printf("error in incoming frame\n");
if (state == WS_STATE_OPENING) {
prepareBuffer;
frameSize = sprintf((char *)buffer,
"HTTP/1.1 400 Bad Request\r\n"
"%s%s\r\n\r\n",
versionField,
version);
safeSend(clientSocket, buffer, frameSize);
break;
} else {
prepareBuffer;
wsMakeFrame(NULL, 0, buffer, &frameSize, WS_CLOSING_FRAME);
if (safeSend(clientSocket, buffer, frameSize) == EXIT_FAILURE)
break;
state = WS_STATE_CLOSING;
initNewFrame;
}
}
if (state == WS_STATE_OPENING) {
assert(frameType == WS_OPENING_FRAME);
if (frameType == WS_OPENING_FRAME) {
// if resource is right, generate answer handshake and send it
if (strcmp(hs.resource, "/osc") != 0) {
frameSize = sprintf((char *)buffer, "HTTP/1.1 404 Not Found\r\n\r\n");
if (safeSend(clientSocket, buffer, frameSize) == EXIT_FAILURE)
break;
}
prepareBuffer;
wsGetHandshakeAnswer(&hs, buffer, &frameSize);
if (safeSend(clientSocket, buffer, frameSize) == EXIT_FAILURE)
break;
state = WS_STATE_NORMAL;
initNewFrame;
}
} else {
if (frameType == WS_CLOSING_FRAME) {
if (state == WS_STATE_CLOSING) {
break;
} else {
prepareBuffer;
wsMakeFrame(NULL, 0, buffer, &frameSize, WS_CLOSING_FRAME);
safeSend(clientSocket, buffer, frameSize);
break;
}
} else if (frameType == WS_TEXT_FRAME) {
uint8_t *recievedString = NULL;
recievedString = malloc(dataSize+1);
assert(recievedString);
memcpy(recievedString, data, dataSize);
recievedString[ dataSize ] = 0;
wsMakeFrame(recievedString, dataSize, buffer, &frameSize, WS_TEXT_FRAME);
if (safeSend(clientSocket, buffer, frameSize) == EXIT_FAILURE)
break;
initNewFrame;
}
}
}
}
close(clientSocket);
}
int main(int argc, char** argv)
{
int i;
int listenSocket = socket(AF_INET, SOCK_STREAM, 0);
if (listenSocket == -1) {
error("create socket failed");
}
struct sockaddr_in local;
memset(&local, 0, sizeof(local));
local.sin_family = AF_INET;
local.sin_addr.s_addr = INADDR_ANY;
local.sin_port = htons(PORT);
if (bind(listenSocket, (struct sockaddr *) &local, sizeof(local)) == -1) {
error("bind failed");
}
if (listen(listenSocket, 1) == -1) {
error("listen failed");
}
#ifdef DEBUG
printf("opened %s:%d\n", inet_ntoa(local.sin_addr), ntohs(local.sin_port));
#endif
while (TRUE) {
struct sockaddr_in remote;
socklen_t sockaddrLen = sizeof(remote);
int clientSocket = accept(listenSocket, (struct sockaddr*)&remote, &sockaddrLen);
if (clientSocket == -1) {
error("accept failed");
}
#ifdef DEBUG
printf("Websocket server: Connected %s:%d\n", inet_ntoa(remote.sin_addr), ntohs(remote.sin_port));
#endif
if(fcntl(clientSocket, F_SETFL, fcntl(clientSocket, F_GETFL) | O_NONBLOCK) < 0) {
// handle error
printf("Error to put socket in non-blocking mode\n");
}
clientWorker(clientSocket);
#ifdef DEBUG
printf("Websocket server: Disconnected\n");
#endif
}
close(listenSocket);
return EXIT_SUCCESS;
}
I am trying to print a partition table using C programming language, everything seems to work fine: Opening and reading, but I don't understand why it is printing garbage values.
Here is the code:
struct partition
{
unsigned char drive;
unsigned char chs_begin[3];
unsigned char sys_type;
unsigned char chs_end[3];
unsigned char start_sector[4];
unsigned char nr_sector[4];
};
int main()
{
int gc = 0, i = 1, nr = 0, pos = -1, nw = 0;
int fd =0;
char buf[512] ;
struct partition *sp;
printf("Ok ");
if ( (fd = open("/dev/sda", O_RDONLY | O_SYNC )) == -1)
{
perror("Open");
exit(1);
}
printf("fd is %d \n", fd);
pos = lseek (fd, 0, SEEK_CUR);
printf("Position of pointer is :%d\n", pos);
if ((nr = read(fd, buf, sizeof(buf))) == -1)
{
perror("Read");
exit(1);
}
close(fd);
printf("Size of buf = %d\n and number of bytes read are %d ", sizeof(buf), nr);
if ((nw = write(1, buf, 64)) == -1)
{
printf("Write: Error");
exit(1);
}
printf("\n\n %d bytes are just been written on stdout\n", nw,"this can also be printed\n");
printf("\n\t\t*************Partition Table****************\n\n");
for (i=0 ; i<4 ; i++)
{
sp = (struct partition *)(buf + 446 + (16 * i));
putchar(sp -> drive);
}
return 0;
}
It is printing garbage instead of partition table.
I might have some basic understanding issues but I searched with Google for a long time but it did not really help. I also saw the source code of fdisk but it is beyond my understanding at this point. Could anyone please guide me? I am not expecting someone to clear my mistake and give me the working code. Just a sentence or two - or any link.
Try this:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
struct partition
{
unsigned char boot_flag; /* 0 = Not active, 0x80 = Active */
unsigned char chs_begin[3];
unsigned char sys_type; /* For example : 82 --> Linux swap, 83 --> Linux native partition, ... */
unsigned char chs_end[3];
unsigned char start_sector[4];
unsigned char nr_sector[4];
};
void string_in_hex(void *in_string, int in_string_size);
void dump_partition(struct partition *part, int partition_number);
void dump_partition(struct partition *part, int partition_number)
{
printf("Partition /dev/sda%d\n", partition_number + 1);
printf("boot_flag = %02X\n", part->boot_flag);
printf("chs_begin = ");
string_in_hex(part->chs_begin, 3);
printf("sys_type = %02X\n", part->sys_type);
printf("chs_end = ");
string_in_hex(part->chs_end, 3);
printf("start_sector = ");
string_in_hex(part->start_sector, 4);
printf("nr_sector = ");
string_in_hex(part->nr_sector, 4);
}
void string_in_hex(void *in_string, int in_string_size)
{
int i;
int k = 0;
for (i = 0; i < in_string_size; i++)
{
printf("%02x ", ((char *)in_string)[i]& 0xFF);
k = k + 1;
if (k == 16)
{
printf("\n");
k = 0;
}
}
printf("\n");
}
int main(int argc, char **argv)
{
int /*gc = 0,*/ i = 1, nr = 0, pos = -1/*, nw = 0*/;
int fd = 0;
char buf[512] ;
struct partition *sp;
int ret = 0;
printf("Ok ");
if ((fd = open("/dev/sda", O_RDONLY | O_SYNC)) == -1)
{
perror("Open");
exit(1);
}
printf("fd is %d\n", fd);
pos = lseek (fd, 0, SEEK_CUR);
printf("Position of pointer is :%d\n", pos);
if ((nr = read(fd, buf, sizeof(buf))) == -1)
{
perror("Read");
exit(1);
}
ret = close(fd);
if (ret == -1)
{
perror("close");
exit(1);
}
/* Dump the MBR buffer, you can compare it on your system with the output of the command:
* hexdump -n 512 -C /dev/sda
*/
string_in_hex(buf, 512);
printf("Size of buf = %d - and number of bytes read are %d\n", sizeof(buf), nr);
/*if ((nw = write(1, buf, 64)) == -1)
{
printf("Write: Error");
exit(1);
}
printf("\n\n%d bytes are just been written on stdout\nthis can also be printed\n", nw);
*/
//printf("\n\t\t*************Partition Table****************\n\n");
printf("\n\t\t*************THE 4 MAIN PARTITIONS****************\n\n");
/* Dump main partitions (4 partitions) */
/* Note : the 4 partitions you are trying to dump are not necessarily existing! */
for (i = 0 ; i < 4 ; i++)
{
sp = (struct partition *)(buf + 446 + (16 * i));
//putchar(sp->boot_flag);
dump_partition(sp, i);
}
return 0;
}