I'll apologise for any lack of clarity, and I'll do my best to update with any missed info, but I'm struggling to understand what I need to do to figure out why the network is unreachable.
I'm getting the output "sendto failed Network is unreachable" from the function
int send_dhcp_packet(void * buffer, int buffer_size, int sock, struct sockaddr_in* dest)
{
int result;
result = sendto(sock, (char*) buffer, buffer_size, 0, (struct sockaddr*)dest, sizeof(*dest));
if(result < 0)
{
printf("sendto failed %s\n", strerror(errno));
return -1;
}
return 0;
}
Where buffer is a struct of type dhcp_packet
typedef struct dhcp_packet_struct
{
uint8_t op; //Packet type
uint8_t htype; //Type of hardware address for this machine
uint8_t hlen; //Length of hardware address for this machine
uint8_t hops; //Number of hops to the gateway
uint32_t xid; //Random transaction ID to match this boot request with responses
uint16_t secs; //Seconds since booted
uint16_t flags; //Flags for the packet
struct in_addr ciaddr; //IP of this machine if it has one
struct in_addr yiaddr; //IP of this machine offered by the DHCP server
struct in_addr siaddr; //IP of the DHCP server
struct in_addr giaddr; //IP of the DHCP relay
unsigned char chaddr[MAX_DHCP_CHADDR_LENGTH]; //Hardware address of this machine
char sname[MAX_DHCP_SNAME_LENGTH]; //Name of DHCP server
char file[MAX_DHCP_FILE_LENGTH]; //Boot file name (full path qualified, null terminated string. Used by later sessions)
char options[MAX_DHCP_OPTIONS_LENGTH]; //DHCP options. Variable length octet strings
}dhcp_packet;
And I'm setting it up in the following function
int send_dhcp_discover(int sock)
{
dhcp_packet discover_packet;
struct sockaddr_in sockaddr_bcast;
//We're setting up the discover packet
bzero(&discover_packet, sizeof(discover_packet));
discover_packet.op = BOOTREQUEST;
discover_packet.htype = ETHERNET_HARDWARE_ADDRESS;
discover_packet.hlen = ETHERNET_HARDWARE_ADDRESS_LENGTH;
discover_packet.hops = 0;
srand(time(NULL));
packet_xid = random();
discover_packet.xid = htonl(packet_xid);
ntohl(packet_xid);
discover_packet.secs = DHCP_PACKET_SECS;
//Tell the server to broadcast it's response
discover_packet.flags = htons(DHCP_BROADCAST_FLAG);
memcpy(discover_packet.chaddr, client_hardware_address, ETHERNET_HARDWARE_ADDRESS_LENGTH); //Our hw address
//First 4 bytes is a magic cookie
discover_packet.options[0] = '\x63';
discover_packet.options[1] = '\x82';
discover_packet.options[2] = '\x53';
discover_packet.options[3] = '\x63';
discover_packet.options[4] = DHCP_OPTION_MESSAGE_TYPE;
discover_packet.options[5] = '\x01'; //Message option length (bytes)
discover_packet.options[6] = DHCPDISCOVER;
if(request_specific_address)
{
discover_packet.options[7] = DHCP_OPTION_REQUESTED_ADDRESS;
discover_packet.options[8] = '\x04'; //Length (bytes)
memcpy(&discover_packet.options[9], &requested_address, sizeof(requested_address));
}
//Send the discover packet to the broadcast address
//Set up the struct
sockaddr_bcast.sin_family = AF_INET;
sockaddr_bcast.sin_port = htons(DHCP_SERVER_PORT);
sockaddr_bcast.sin_addr.s_addr = INADDR_BROADCAST;
bzero(&sockaddr_bcast.sin_zero, sizeof(sockaddr_bcast.sin_zero));
//Send the damn packet already
send_dhcp_packet(&discover_packet, sizeof(discover_packet), sock, &sockaddr_bcast);
return 0;
}
How the socket is set up
int create_dhcp_socket()
{
struct sockaddr_in name;
struct ifreq interface;
int sock;
int flag = 1;
//Set up the address that we're going to use
bzero(&name, sizeof(name));
name.sin_family = AF_INET;
name.sin_port = htons(DHCP_CLIENT_PORT); //Converts from host byte order to network byte order
name.sin_addr.s_addr = INADDR_ANY; //Listen on any address
//Create a socket
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); //Creates endpoint using ipv4, supporting datagrams over UDP
if(sock < 0)
{
printf("Error: couldn't create socket\n");
return -1;
}
flag = 1;
//Set the reuse option so there aren't errors on restarting
if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&flag, sizeof(flag)) < 0)
{
printf("Error: couldn't set reuse option on DHCP socket\n");
return -1;
}
//Set the broadcast option
if(setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char*)&flag, sizeof(flag)) < 0)
{
printf("Error: couldn't set broadcast option on DHCP socket\n");
return -1;
}
strncpy(interface.ifr_ifrn.ifrn_name, network_interface_name, IFNAMSIZ);
if(bind(sock, (struct sockaddr*)&name, sizeof(name)) < 0)
{
printf("Error: couldn't bind DHCP socket (port %d). Check yo privilage\n", DHCP_CLIENT_PORT);
return -1;
}
return sock;
}
I guess the question is; why is the network unreachable and how do I fix it so that it's reachable?
Related
/client.c/
void main()
{
static int s = 0;
char url_or_ip[130] = {0};
int port = 0;
ip_type_or_dns_enum ip_dns_type = -1;
char *sptr = ext_sio_recv_buff;
char *ip_str = NULL;
char ip_buf[128] = {0};
int isipv6 = 0;
char buff[NWY_UART_RECV_SINGLE_MAX + 1] = {0};
int on = 1;
int opt = 1, ret = 0, send_len;
uint64_t start;
ip6_addr_t addr;
struct sockaddr_in6 sa;
struct sockaddr_in6 *to6 = (struct sockaddr_in6 *)&sa;
port = 8000;
addr.addr[0] = 0x25035959;
addr.addr[1] = 0x87493683;
addr.addr[2] = 0x2abf3de2;
addr.addr[3] = 0x1ab43f8e;
/*socket creation*/
s = socket_open(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
sa.sin6_len = sizeof(struct sockaddr_in6);
sa.sin6_family = AF_INET6;
sa.sin6_port = htons(port);
/*assigning the address for ipv6*/
sa.sin6_addr.un.u32_addr[0] = htonl(addr.addr[0]);
sa.sin6_addr.un.u32_addr[1] = htonl(addr.addr[1]);
sa.sin6_addr.un.u32_addr[2] = htonl(addr.addr[2]);
sa.sin6_addr.un.u32_addr[3] = htonl(addr.addr[3]);
socket_setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void *)&on,sizeof(on));
socket_setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (void *)&opt, sizeof(opt));
/*connect to the particular server*/
int ret = socket_connect(s, (struct sockaddr *)&sa, sizeof(sa));
if(ret >0)
{
socket_send(s, uart_rec_buffer, uart_length, 0);
socket_shutdown(s, SHUT_RD);
socket_close(s);
s=0;
}
}
here i am trying to make ipv6 client connection to the ipv6 server, but in the connect system call it is failing . i tried to change the ip and checked still same issue. But the code fails in connect system call and returning -1 and showing invalid argument. Any suggestions. And the API's i am using are similar to the socket programming api's and the socket_open is similar to the socket creation and the socket_connect is similar to the connect system call and assinging the values to the ipv6 predefined structures, the socket is created successfully but socket_connect is failed, why? and it is showing invalid argument passed to the connect call..
I am trying to make tcp server using raw sockets. this way I can learn more about tcp. the problem with my tcp server is that I am getting different destination port at receiving end (client's end). the server (source port) is correct but desitination port is different. so my telnet/nc client keep trying to connect. it doesn't get to connected and gives error to client that refused to connect. the problem is I am getting packet with SYN+ACK at destination system but port is not what the source port of client is (I checked it on Client using wireshark) something is changing the destination port address (client port address) or I am not assignning it correctly at originating server before raw sockets send. I think the problem may be with this line. I am running the code (client and server) in two virtual machines Linux on both
temp->dest=tcp->source;
tcp is the tcp header of received packet at server from client
and temp->dest is the tcp client port address in sending packet from server to client
//Following is the main method, it listens to requests
// Packet length
#define PCKT_LEN 8192
int main(int argc, char *argv[])
{
int sd;
char buffer[PCKT_LEN];
int one = 1;
const int *val = &one;
memset(buffer, 0, PCKT_LEN);
sd = socket(PF_INET, SOCK_RAW, IPPROTO_TCP);
if(sd < 0)
{
perror("socket() error");
exit(-1);
}
else
printf("socket()-SOCK_RAW and tcp protocol is OK.\n");
if(setsockopt(sd, IPPROTO_IP, IP_HDRINCL, val, sizeof(one)) < 0)
{
perror("setsockopt() error");
exit(-1);
}
else
printf("setsockopt() is OK\n");
struct sockaddr_in sa;
sa.sin_family=AF_INET;
sa.sin_port=htons(80);
sa.sin_addr.s_addr=inet_addr("0.0.0.0");
if(bind(sd,&sa,sizeof (sa))==0){
printf("Port Bound\n");
}
unsigned int count;
while(1)
{
char buffer1[8192];
struct sockaddr_in saddr;
int in_len;
if((recvfrom(sd,buffer1,sizeof (buffer1),0,&saddr,&in_len))!=-1){
connect1(saddr,buffer1);
sleep(5);
}//if recvfrom()
else{
int err=errno;
printf("recv error %s\n",errno);
}
sleep(2);
}
close(sd);
return 0;
}
//below is the method which sends response (ACK+SYN)
#define PCKT_LEN 100
void processBuffer(char buffer1[]);
int connect1(struct sockaddr_in sa,char buffer[]) {
printf("Connecting client...!\n");
char *c=inet_ntoa(sa.sin_addr);
// processBuffer(buffer);
int cp=ntohl(sa.sin_port);
printf("%s (%d)\n",c,cp);
struct iphdr *ip1=(struct iphdr *)buffer;
struct tcphdr *tcp=(struct tcphdr *)buffer;
sa.sin_port=tcp->source;
printf("%d %d --------- \n",tcp->source,ntohl(tcp->source));
printf("%d \n",ntohs(sa.sin_port));
int sd;
int one = 1;
const int *val = &one;
sd = socket(PF_INET, SOCK_RAW, IPPROTO_TCP);
if(sd < 0)
{
perror("Connecting --socket() error");
exit(-1);
}
else
printf("socket()-SOCK_RAW and tcp protocol is OK.\n");
if(setsockopt(sd, IPPROTO_IP, IP_HDRINCL, val, sizeof(one)) < 0)
{
perror("Connecting--setsockopt() error");
exit(-1);
}
else
printf("Connecting setsockopt() is OK\n");
if(bind(sd,&sa,sizeof (sa))==0){
printf("Port Bound\n");
}
char b[PCKT_LEN];
struct iphdr *i=(struct iphdr *)b;
struct tcphdr *t=(struct tcphdr *)(b+sizeof (struct iphdr));
ip(ip1,i);
sync_ack(tcp,t);
int ret=sendto(sd,&b,sizeof (b),0,&sa,sizeof (sa));
strerror("Error: ");
printf("%d\n",errno);
printf("%d\n",ret);
return 0;
}
//and this is how I am making ip header
int id=121333;
struct iphdr * ip(struct iphdr * ip, struct iphdr *temp)
{
temp->saddr=ip->daddr;
temp->daddr=ip->saddr;
temp->ihl=5;
temp->version=4;
temp->tos=0;
temp->tot_len = sizeof (struct ip) + sizeof (struct tcphdr);
temp->id=htons(id);id++;
temp->frag_off = htons(16384);
temp->ttl = 64;
temp->protocol=IPPROTO_TCP;
temp->check=0;
temp->check = csum ((unsigned short *) temp, temp->tot_len >> 1);
return temp;
}
//and following is I am making tcp header ACK+SYN
int seq=1105024978;
struct tcphdr * sync_ack(struct tcphdr * tcp,struct tcphdr *temp)
{
temp->source=htonl(80);
temp->dest=tcp->source;
temp->seq=htonl(seq);seq++;
temp->ack_seq=htonl(ntohl(tcp->seq)+1);
temp->doff = sizeof(struct tcphdr) / 4;
temp->fin=0;
temp->syn=1;
temp->ack=1;
temp->th_ack=tcp->seq;
temp->rst=0;
temp->psh=0;
temp->urg=0;
temp->window=htons ( 14600 );
temp->check = 0;
temp->urg_ptr = 0;
temp->check = csum( (unsigned short*) temp , sizeof (struct tcphdr));
return temp;
}
Please check the code what wrong. I will handle re-transmission but I am not get in to correct port address with first packet. any help will be appreciated
I am running it on Linux (specifically Debian version 5.9 OS)
I asked a question on this work before.
DOES router or linux kernel change the tcp headers and ip headers of packets
i suspect this line
temp->dest=tcp->source;
This is wireshark info received at Server .11 is client ip and .14 is server ip. 80 is server port
this is wireshark at client
after iptables changes, syn+ack is sending but client port in received packet at client is different. client port wire shark is showing is 60 as before question update pics
# iptables -A OUTPUT -p tcp --tcp-flags RST RST -j DROP
I am trying to create multiple TUN devices to tunnel the multi-device traffic through a common physical interface.
This is the schema I have:
Socket 1 is sending traffic through tun1 with destiny IP 1.1.1.2 and Socket 2 is doing the same on the other interface.
I have a program running between both TUN devices and the physical interface (eth0) that encapsulates IP packets from the TUN devices into UDP packets and then it sends them to the server. The server unpacks the received packets and answers both clients with echo packets (also encapsulated).
When those packets arrive in eth0, another program reads the packets and forwards them to its TUN device. After that, both programs that are running behind the sockets are blocked on recv() function waiting for the server answer on tunX devices. However, it seems like the kernel is discarding those packets on the TUN devices even when they are well-formed.
I tried by change the netmask of both interfaces to 255.255.255.0 and then only one of the sockets receives correctly the answer.
All this software has been written in C.
This is the function to create a new TUN device:
#define MTU_SIZE 1500
#define SUBNET_MASK 0xFFFFFFFF
int open_tun_iface(char * name, uint8_t * ip)
{
int sock;
struct ifreq ifr_tun;
struct sockaddr_in * sa;
int tunfd = tun_init(name, &ifr_tun, IFF_TUN | IFF_NO_PI);
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
perror("Open socket");
tun_close(tunfd);
return -1;
}
/* Set tun IP */
if (set_ip(&ifr_tun, sock, ip) < 0) {
tun_close(tunfd);
return -1;
}
sa = (struct sockaddr_in *)&ifr_tun.ifr_netmask;
memset(sa,0,sizeof(*sa));
sa->sin_family = AF_INET;
sa->sin_addr.s_addr = htonl(SUBNET_MASK);
/* Set the mask */
if (ioctl(sock, SIOCSIFNETMASK, &ifr_tun) < 0)
{
perror("SIOCSIFNETMASK");
tun_close(tunfd);
close(sock);
return -1;
}
/* Read flags */
if (ioctl(sock, SIOCGIFFLAGS, &ifr_tun) < 0) {
perror("SIOCGIFFLAGS");
tun_close(tunfd);
close(sock);
return -1;
}
/* Set Iface up and flags */
ifr_tun.ifr_flags |= IFF_UP;
ifr_tun.ifr_flags |= IFF_RUNNING;
if (ioctl(sock, SIOCSIFFLAGS, &ifr_tun) < 0) {
perror("SIOCGIFFLAGS");
tun_close(tunfd);
close(sock);
return -1;
}
/* Set MTU size */
ifr_tun.ifr_mtu = MTU_SIZE;
if (ioctl(sock, SIOCSIFMTU, &ifr_tun) < 0) {
perror("SIOCSIFMTU");
tun_close(tunfd);
close(sock);
return -1;
}
close(sock);
return tunfd;
}
The function that reads packets from eth0 and forward them to the correct TUN interface is the following one:
void * downlink_distributor(void * args)
{
uint8_t buffer[BUFFER_DATA_LEN];
struct sockaddr_in spgw_addr;
int sockfd;
int sockaddr_len = sizeof(spgw_addr);
int len, packet_len, teid;
eNB * enb = (eNB *) args;
sockfd = get_spgw_socket(enb);
while(1)
{
/* Read packets from the server */
len = recvfrom(sockfd, buffer, BUFFER_DATA_LEN, 0, ( struct sockaddr *) &spgw_addr, (socklen_t *)&sockaddr_len);
if(len < 0)
{
perror("recv downlink_distributor");
return NULL;
}
/* Get the TEID that identifies the TUN device */
teid = analyze_gtp_header(buffer, &packet_len);
if(teid > -1)
{
/* Write the packet in the TUN device associated with the packet TEID */
tun_write(get_tun_device(tun_descriptors[teid % MAX_TUN_DESCRIPTORS]), buffer + 8, packet_len);
}
}
return NULL;
}
Finally, this is the function that is running on both sockets and generate some traffic:
void * _generate_udp_traffic(void * args)
{
uint8_t buffer[BUFFER_DATA_LEN];
struct sockaddr_in dest_addr, spgw_addr;
fd_set fds;
struct timeval timeout;
int retval;
timeout.tv_sec = 0;
timeout.tv_usec = 1;
int tunfd;
char msg[] = "Uplink traffic";
int sockfd;
int len;
int sockaddr_len = sizeof(dest_addr);
udp_generator gen;
/* Copy args */
memcpy(&gen, args, sizeof(udp_generator));
free(args);
/* Get TUN device */
tunfd = get_tun_device(gen.ue);
/* Get UE data socket (TUN socket) */
sockfd = get_data_plane_socket(gen.ue);
/* Configure destiny address */
memset(&dest_addr, 0, sizeof(dest_addr));
dest_addr.sin_family = AF_INET;
dest_addr.sin_port = htons(gen.port_dest);
memcpy((void*) &dest_addr.sin_addr.s_addr, gen.dest_ip, sizeof(struct in_addr));
/* Configure SPGW address */
memset(&spgw_addr, 0, sizeof(spgw_addr));
spgw_addr.sin_family = AF_INET;
spgw_addr.sin_port = htons(S1_U_PORT);
memcpy((void*) &spgw_addr.sin_addr.s_addr, get_spgw_ip(gen.ue), sizeof(struct in_addr));
while(1)
{
sendto(sockfd, msg, strlen(msg), 0, (const struct sockaddr *) &dest_addr, sizeof(dest_addr));
while(1)
{
FD_ZERO(&fds);
FD_SET(tunfd, &fds);
retval = select(tunfd+1, &fds, 0, 0, &timeout);
if (retval == -1){
perror("select()");
}
else if (retval){
/* Reuse of the buffer with enough space for the GTP header */
len = tun_read(tunfd, buffer+8, BUFFER_DATA_LEN); /* We call read to clean the buffer from external traffic */
/* Detect IPv4 packets*/
if((buffer[8] & 0xF0) == 0x40)
{
generate_gtp_header(buffer, gen.ue, len);
break;
}
}
}
/* Protect the access to the eNB socket with a lock*/
pthread_mutex_lock(&lock);
/* Send tho the SPGW */
sendto(get_spgw_socket(gen.enb), buffer, len+8, 0, (const struct sockaddr *) &spgw_addr, sizeof(spgw_addr));
/* Unlock the mutex */
pthread_mutex_unlock(&lock);
/* Receive server answer listening on the TUN device */
len = recvfrom(sockfd, buffer, BUFFER_DATA_LEN, 0, ( struct sockaddr *) &dest_addr, (socklen_t *)&sockaddr_len);
printf("UE %d has received: %s\n", get_ue_id(gen.ue), buffer);
/* Sleep 5 seconds */
sleep(5);
}
return NULL;
}
If the netmask is 32 both programs that are generating client traffic get blocked on recvfrom() inside _generate_udp_traffic function. If I set both netmask to 24 only one of them receive the answer from the server and the other gets stuck at recvfrom.
How can I configure both TUN devices to make both attached sockets work correctly?
UPDATE: I think that my problem is a kernel route table problem. If I use just one socket, I only receive traffic with netmask <= 30. With a netmask of 32, I can see that the server answer is introduced correctly on the TUN interface but somehow, the socket that is blocked in recv() does not receive anything.
I am having trouble getting my TCP/IP connection between my client and server working.
Here is the server code -
int main() {
int servSock; /* Socket descriptor for server */
int clntSock; /* Socket descriptor for client */
unsigned short echoServPort; /* Server port */
struct sockaddr_in echoServAddr; /* Local address */
struct sockaddr_in echoClntAddr; /* Local address */
pid_t processID; /* Process ID from fork()*/
unsigned int childProcCount = 0; /* Number of child processes */
unsigned int clntLen;
unsigned int recvMsgSize;
echoServPort = 22;
if ((servSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0){
printf("Socket failed");
}
echoServAddr.sin_family = AF_INET; //Internet address family
echoServAddr.sin_addr.s_addr = htonl(INADDR_ANY); //Any incoming interface
echoServAddr.sin_port = htons(echoServPort); // Local port
if (bind(servSock, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr)) < 0){
printf("bind failed");
}
if (listen(servSock, MAXPENDING) < 0){
printf("listen() failed");
}
clntLen = sizeof(echoClntAddr);
if ((clntSock=accept(servSock,(struct sockaddr *)&echoClntAddr,&clntLen))<0){
printf("accept() failed");
}
if ((recvMsgSize = recv(clntSock, buf, 1024, 0)) < 0){
printf("recv() failed");
}
/* Send received string and receive again until end of transmission */
while (recvMsgSize > 0) { /* zero indicates end of transmission */
printf("%d", recvMsgSize);
if (send(clntSock, buf, recvMsgSize, 0) != recvMsgSize){
//printf(“send() failed”);
}
if ((recvMsgSize = recv(clntSock, buf, 1024, 0)) < 0){
//printf(“recv() failed”);
}
}
sleep(60);
}
}
return EXIT_SUCCESS;
}
And the client code, which is a CGI application.
int main(void) {
int servSock; /* Socket descriptor for server */
int clntSock; /* Socket descriptor for client */
unsigned short echoServPort; /* Server port */
struct sockaddr_in echoServAddr; /* Local address */
struct sockaddr_in echoClntAddr; /* Local address */
struct sockaddr_in {
__uint8_t sin_len;
sa_family_t sin_family;
in_port_t sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
/*pid_t processID; Process ID from fork()
unsigned int childProcCount = 0; Number of child processes
unsigned int clntLen;*/
//char echoservIP = "10.0.0.2";
printf("Content-type: text/html\n\n");
puts("<HTML>");
puts("<BODY>");
echoServPort = 22;
servSock = 22;
clntSock = 22;
puts("<br>");
if ((clntSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0){
printf("socket() failed");
}
echoServAddr.sin_family = AF_INET; //Internet address family
echoServAddr.sin_addr.s_addr = inet_addr("10.0.0.2"); //Server IP address
echoServAddr.sin_port = htons(echoServPort); //Server port
echoClntAddr.sin_addr.s_addr = inet_addr("10.0.0.1");
if (connect(clntSock, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr)) < 0){
printf("connect() failed\n");
}
int clntLen;
clntLen = sizeof(echoClntAddr);
if ((clntSock=accept(servSock,(struct sockaddr *)&echoClntAddr,&clntLen))<0){
printf("accept() failed\n");
}
char echoString[4] = "helo";
int echoStringLen;
echoStringLen = strlen(echoString); //Determine input length
//Send the string to the server
if (send(clntSock, echoString, echoStringLen, 0) != echoStringLen){
printf("send() sent a different number of bytes than expected");
}
puts("<p>Hello <b>CGI</b</p>");
puts("</BODY>");
puts("</HTML>");
return EXIT_SUCCESS;
}
When debugging, the problem occurs on the client side at the line
if ((clntSock=accept(servSock,(struct sockaddr
*)&echoClntAddr,&clntLen))<0){
printf("accept() failed\n");
}
And at
if(send(clntSock, echoString, echoStringLen, 0) != echoStringLen){
printf("send() sent a different number of bytes than expected");
}
I get the output
<HTML>
<BODY>
<br>
accept() failed
send() sent a different number of bytes than expected<p>Hello
<b>CGI</b</p>
Need help fixing this!, thanks.
You don't need to call accept() on the client - you just need to connect.
And
char echoString[4] = "helo";
is wrong. It's not NUL-terminated. Just do
char echoString[] = "helo";
If accept fails you shouldn't be proceeding with other operations on socket like recv. TCP connections is not in place for you to proceed in data exchange between server and client. You need to handle error conditions with out fail.
On the client side you have a custom error message on send. That does not help. Usually, partial sends are not common. Hence your print `sent a different number of bytes than expected' can be misleading. You need to find the real reason.
Calling accept in client code is not needed. Its the server which accepts and clients the ones which connect
Use errno and perror like - perror("Accept Failed") on ALL of your system calls for easier debugging and remove custom prints
The following c function I wrote returns a file descriptor that accepts IPv4 connections but not IPv6.
Could someone help me figure out what went wrong?
I suspect I did not use getaddrinfo() correctly.
Open file descriptor that listens to connections.
/*
* open_listenfd - open and return a listening socket on port
* Returns -1 and sets errno on Unix error.
*/
int open_listenfd(int port)
{
const char* hostname=0;
// Converts port to string
char* pName = malloc(numPlaces(port) + 1);
sprintf(pName, "%d", port);
const char* portname= pName;
struct addrinfo hints;
memset(&hints,0,sizeof(hints));
hints.ai_family=AF_UNSPEC;
hints.ai_socktype=SOCK_STREAM;
hints.ai_protocol= 0;
hints.ai_flags=AI_PASSIVE|AI_ADDRCONFIG;
struct addrinfo* res=0;
int err=getaddrinfo(hostname,portname,&hints,&res);
free(pName);
if (err!=0) {
return -1;
}
int listenfd, optval=1;
struct sockaddr_in serveraddr;
/* Create a socket descriptor */
if ((listenfd = socket(res->ai_family,res->ai_socktype, res->ai_protocol)) < 0)
return -1;
/* Eliminates "Address already in use" error from bind. */
if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR,
(const void *)&optval , sizeof(int)) < 0)
return -1;
/* Listenfd will be an endpoint for all requests to port
on any IP address for this host */
bzero((char *) &serveraddr, sizeof(serveraddr));
serveraddr.sin_family = /*AF_INET;*/ AF_UNSPEC;
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
serveraddr.sin_port = htons((unsigned short)port);
if (bind(listenfd, res->ai_addr, res->ai_addrlen/*(SA *)&serveraddr, sizeof(serveraddr)*/) < 0)
return -1;
freeaddrinfo(res);
/* Make it a listening socket ready to accept connection requests */
if (listen(listenfd, 1024) < 0)
return -1;
return listenfd;
}
If you want your server to listen on IPV4 and IPV6 addresses you need to could set up two socket to listen on.
getaddrinfo() might return information for more then one internet address for given host and/or service.
The member ai_family of the hints structure passed specifies which address family the caller is interest in. If AF_UNSPEC is specified IPV4 and IPV6 addresses might be returned.
To find out if there are such addresses available you might like to mod you code like so:
int open_listenfd(int port, int * pfdSocketIpV4, int * pfdSocketIpV6)
{
...
struct addrinfo hints = {0};
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE|AI_ADDRCONFIG;
hints.ai_next = NULL;
struct addrinfo * res = NULL;
int err=getaddrinfo(hostname, portname, &hints, &res);
free(pName);
if (err)
{
return -1;
}
struct addrinfo * pAddrInfoIpV4 = NULL;
struct addrinfo * pAddrInfoIpV6 = NULL;
{
struct addrinfo * pAddrInfo = res;
/* Loop over all address infos found until a IPV4 and a IPV6 address is found. */
while (pAddrInfo)
{
if (!pAddrInfoIpV4 && AF_INET == pAddrInfo->ai_family)
{
pAddrInfoIpV4 = pAddrInfo; /* Take first IPV4 address available */
}
else if (!pAddrInfoIpV6 && AF_INET6 == pAddrInfo->ai_family)
{
pAddrInfoIpV6 = pAddrInfo; /* Take first IPV6 address available */
}
else
{
break; /* Already got an IPV4 and IPV6 address, so skip the rest */
}
pAddrInfo= pAddrInfo->ai_next; /* Get next address info, if any */
}
}
if (pAddrInfoIpV4)
{
... /* create, bind and make IPV4 socket listen */
int fdSocketIpV4 = socket(pAddrInfoIpV4->ai_family,...
*pfdSocketIpV4 = fdSocketIpV4;
}
if (pAddrInfoIpV6)
{
/* create, bind and make IPV6 socket listen */
int fdSocketIpV6 = socket(pAddrInfoIpV6->ai_family,...
*pfdSocketIpV6 = fdSocketIpV6;
}
freeaddrinfo(res);
...
Then call it like so:
...
int fdSocketIpV4 = -1;
int fdSocketIpV6 = -1;
if (0 > open_listenfd(port, &fdSocketIpV4, &fdSocketIpV6))
{
printf("Error executing 'open_listenfd()'\n");
}
else
{
... /* go for accepting connectings on 'fdSocketIpV4' and 'fdSocketIpV6' */
Update:
As commented by Per Johansson an alternative approach would be to set up a dual stack socket, supporting both, Ipv4 and Ipv6, as mentioned by this answer: How to support both IPv4 and IPv6 connections