I have a specific equipement (IP : 192.168.0.10 port 3000 - it's a signal receiver) that must be controlled through UDP. I should be able to send this equipement basic commands such as 'reset'; 'log' ; 'run' ...
After some struggle and the gentle help of stackoverflow i managed to communicate with my equipment using netcat. It now works perfectly. I used the command nc -u 192.168.0.10 3000 after changing the computer eth IP. (i'm under linux).
Now, and that's the goal, i need to do the same as netcat, but, using C language. Since i'm a beginner i tried myself using internet and wrote this :
/* Standard Linux headers */
#include <stdio.h> //printf
#include <string.h> //memset
#include <stdlib.h> //exit(0);
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <errno.h>
/* DEFINE */
#define SERVER "192.168.0.10"
#define BUFFLEN 1024 //Max length of buffer
#define PORT 3000 //The port on which to send data
int main (void)
{
/*
** Definition of the local variables.
*/
struct sockaddr_in serv_addr; /* Server Socket address structure*/
/* short int status = 0; /* internal status return*/
/* unsigned short int return_status = 0; /* the returnes status value */
char recepbuff[BUFFLEN];
char cmd[BUFFLEN];
int socket_fd;
/*
** Initialisation of the local variables.
*/
memset(recepbuff, '0' ,sizeof(recepbuff)); /*pareil que bzero*/
/*
** Creating the socket
** call socket (it creates an endpoint for communication and
** returns the socket descriptor.
** To create an UDP socket here are the param
** The protocol family should be AF_INET
** The protocol type is SOCK_DGRAM
** The protocol should beset to default ie
** DEF_PROTOCOL wich is default so 0. );
*/
if ( (socket_fd = socket(AF_INET, SOCK_DGRAM, 0) ) < 0 ) /* return 1 if okay */
{
printf("ERROR opening socket");
}
serv_addr.sin_family = AF_INET; /*Define the domain used*/
serv_addr.sin_port = htons(PORT); /*Declare port #PORT to be used*/
/*serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); /*Permit any incoming IP address by declaring INADDR_ANY*/
// Convert IPv4 and IPv6 addresses from text to binary form
if(inet_pton(AF_INET, SERVER, &serv_addr.sin_addr)<=0)
{
printf("\nInvalid address/ Address not supported \n");
return -1;
}
if (connect(socket_fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
{
printf("\nConnection Failed \n");
return -1;
}
else
{
printf("\n Connected \n");
}
/* Messaging*/
while(1)
{
printf("Enter command : ");
gets(cmd);
//send the message
if ( (sendto(socket_fd , cmd , strlen(cmd) , 0 , (struct sockaddr *)&serv_addr, sizeof(serv_addr)) ) < 0 )
{
printf("DEBUG_CMD: Failed sending cmd\n");
}
else
{
printf("DEBUG_CMD : CMD * %s * SENT\n", cmd);
puts(cmd);
}
//receive a reply and print it
//clear the buffer by filling null, it might have previously received data
memset(recepbuff, '0' ,sizeof(recepbuff));
printf("mini-debug memset done\n");
//try to receive some data, this is a blocking call
if ((recvfrom( socket_fd, recepbuff, strlen(recepbuff), 0, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) ) < 0)
{
printf("DEBUG_RECEP: Failed received cmd\n");
}
else
{
printf("DEBUG_RECEP : CMD RECEIVED\n");
}
puts(recepbuff);
}
close(socket_fd);
return 0;
}
So, i launch my program, and it seems to be correctly connected. I type my command, a simple reset and then nothing happens. Like if it's blocked at the recvfrom (because the "mini debug memset done" is printed). And i can't find any clue about what I am doing wrong.
EDIT : Corrected the strlen in the recvfrom => same thing
In fact, i'm not even sure that i'm using the right method and even if i'm really "connected" ...
Related
I'm trying to get into socket programming with C and my problem is that no matter what I try I cannot get my client-server model to connect over the internet except through logging into my router and port forwarding the port I'm inputting in my program. Basically my server.c blocks and waits for a connection, then it sends the time of the server to the client once it connects. I've tried to open ports on both my machines like this:
sudo iptables -A INPUT -p tcp --dport 20001 -j ACCEPT
and I downloaded the iptables-persistent package that makes sure the rules stay on a reboot. iptables -L shows me that the ports are open on both machines, but the connection still times out. I know that somehow this is possible because Steam and Discord don't have to port forward anything and they still make it happen. I have a server at home so if the solution requires a 'middle man' server to facilitate a connection between two clients, then it won't be a problem for me. Also I am on two separate networks, so that's not the problem.
The server.c:
/* --- server.c --- */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <time.h>
int main(int argc, char *argv[])
{
int listenfd = 0, connfd = 0;
struct sockaddr_in serv_addr;
char sendBuff[1025];
time_t ticks;
/* creates an UN-named socket inside the kernel and returns
* an integer known as socket descriptor
* This function takes domain/family as its first argument.
* For Internet family of IPv4 addresses we use AF_INET
*/
listenfd = socket(AF_INET, SOCK_STREAM, 0);
memset(&serv_addr, '0', sizeof(serv_addr));
memset(sendBuff, '0', sizeof(sendBuff));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(20001);
/* The call to the function "bind()" assigns the details specified
* in the structure 『serv_addr' to the socket created in the step above
*/
bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
/* The call to the function "listen()" with second argument as 10 specifies
* maximum number of client connections that server will queue for this listening
* socket.
*/
listen(listenfd, 10);
while(1)
{
/* In the call to accept(), the server is put to sleep and when for an incoming
* client request, the three way TCP handshake* is complete, the function accept()
* wakes up and returns the socket descriptor representing the client socket.
*/
connfd = accept(listenfd, (struct sockaddr*)NULL, NULL);
/* As soon as server gets a request from client, it prepares the date and time and
* writes on the client socket through the descriptor returned by accept()
*/
ticks = time(NULL);
snprintf(sendBuff, sizeof(sendBuff), "%.24s\r\n", ctime(&ticks));
write(connfd, sendBuff, strlen(sendBuff));
close(connfd);
sleep(1);
}
}
and client.c:
/* --- client.c --- */
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>
int main(int argc, char *argv[])
{
int sockfd = 0, n = 0;
char recvBuff[1024];
struct sockaddr_in serv_addr;
if(argc != 2)
{
printf("\n Usage: %s <ip of server> \n",argv[0]);
return 1;
}
memset(recvBuff, '0',sizeof(recvBuff));
/* a socket is created through call to socket() function */
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
printf("\n Error : Could not create socket \n");
return 1;
}
memset(&serv_addr, '0', sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(20001);
if(inet_pton(AF_INET, argv[1], &serv_addr.sin_addr)<=0)
{
printf("\n inet_pton error occured\n");
return 1;
}
/* Information like IP address of the remote host and its port is
* bundled up in a structure and a call to function connect() is made
* which tries to connect this socket with the socket (IP address and port)
* of the remote host
*/
if( connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
{
printf("\n Error : Connect Failed \n");
return 1;
}
/* Once the sockets are connected, the server sends the data (date+time)
* on clients socket through clients socket descriptor and client can read it
* through normal read call on the its socket descriptor.
*/
while ( (n = read(sockfd, recvBuff, sizeof(recvBuff)-1)) > 0)
{
recvBuff[n] = 0;
if(fputs(recvBuff, stdout) == EOF)
{
printf("\n Error : Fputs error\n");
}
}
if(n < 0)
{
printf("\n Read error \n");
}
return 0;
}
This line is saying what port you're connecting to on the server
serv_addr.sin_port = htons(42020);
change it to the same port number as the server and it should work just fine.
serv_addr.sin_port = htons(20001);
#include <stdio.h>
#include "http.h"
#define MAX 4096
int main()
{
char s_msg[MAX], c_msg[MAX];
printf("%d", strlen(s_msg));
// Clean buffers:
memset(s_msg,'\0',sizeof(s_msg));
memset(c_msg,'\0',sizeof(c_msg));
char *msg = "GET / HTTP/1.1\r\nUser-Agent: Hellothere\r\nHost: HOSTNAME\r\n\r\n";
int soc = init_client();
int con = connection("HOSTNAME",80);
if(send(socket_desc, msg, strlen(msg), 0) < 0){
printf("Unable to send message\n");
return -1;
}
if (recv(socket_desc, c_msg , MAX, 0)<0)
{
printf("Failed to read from server\n");
return -1;
}
printf("Recieved from server : %s\n",c_msg);
return 0;
}
Using ngrok you need to use Host header
I try to create a function to open a socket (i will have multiple socket in the future) called libf_build_udp_socket. But when it comes to bind i got the error cannot assign requested address and if i bypass this bind i got an error when sending a cmd.
If i don't use my function and integrate directly the code in my main, it works perfectly.
For the explanation i have a computer under linux that have to send cmd and received log from different equipment such as signal receiver...
Here is my full code, so maybe you will better understand my goals.
/* Standard Linux headers */
#include <stdio.h> //printf
#include <string.h> //memset
#include <stdlib.h> //exit(0);
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/times.h>
#include <unistd.h>
#include <errno.h>
/* DEFINE */
#define IP_RX "192.168.0.10" //notre IP=192.168.0.5
#define BUFFLEN 1024 //Max length of buffer
#define PORT_RX 3000 //The port on which to send data
unsigned short int libf_build_udp_socket(int * udp_socket, char * server_address, unsigned short int udp_port);
int main (void)
{
/*
** Definition of the local variables.
*/
//SOCKET
struct sockaddr_in addr_rx;
int serv_len_rx=sizeof(addr_rx);
int socket_fd_rx;
unsigned short int socketStatus; /* Socket return status */
//FD
fd_set readfds;
//BUFFER & CMD
char recepbuff[BUFFLEN];
char cmd[BUFFLEN], cmd_final[BUFFLEN];
//OTHER
int i, recv;
char choice;
int loop=1;
//TIMEOUT STRUCT
struct timeval tv;
tv.tv_sec=0; /*timeout de 0sec*/
tv.tv_usec=1000; //NE MARCHE PAS SI =0
/*
** Initialisation of the local variables.
*/
memset(recepbuff, '0' ,sizeof(recepbuff)); /*pareil que bzero*/
i=0;
/*
** Creating the socket
** call socket (it creates an endpoint for communication and
** returns the socket descriptor.
** To create an UDP socket here are the param
** The protocol family should be AF_INET
** The protocol type is SOCK_DGRAM
** The protocol should beset to default ie
** DEF_PROTOCOL wich is default so 0. );
*/
//OPENING AND SETTING SOCKET RX
socketStatus = libf_build_udp_socket(&socket_fd_rx, IP_RX, PORT_RX);
if (socketStatus>0)
{
printf("Could not create the socket, code error %d\n", socketStatus);
return 0;
}
/* Messaging*/
while(1)
{
printf ("\n//Boucle %d\n", i);
//clear the buffer by filling null, it might have previously received data
memset(recepbuff, '\0' ,sizeof(recepbuff));
loop=1;
//preparing cmd
printf("Enter command :");
fgets(cmd, sizeof(cmd) , stdin);
snprintf(cmd_final, sizeof (cmd_final), cmd, "\r\n"); /*adding 0d 0a to the cmd*/
//send cmd
if ( (sendto(socket_fd_rx , cmd_final, BUFFLEN , 0 , (struct sockaddr *)&addr_rx, serv_len_rx) ) < 0 )
{
perror("ERROR > send cmd failed to wass : ");
return 0;
}
else
{
printf( "cmd send to %s:%d\n" ,inet_ntoa(addr_rx.sin_addr), ntohs(addr_rx.sin_port) );
}
//printf("\n... waiting answer from %s:%d ... \n" ,inet_ntoa(addr_rx.sin_addr), ntohs(addr_rx.sin_port) );
//strcpy(recepbuff, "whileloop");
//try to receive some data, this is a blocking call
while(loop)
{
memset(recepbuff, '\0' ,sizeof(recepbuff)); //empty buffer
FD_ZERO(&readfds);
FD_SET(socket_fd_rx, &readfds); //set testing for rx
select(socket_fd_rx+1, &readfds, NULL, NULL, &tv); //block until cmd becomes available
if(FD_ISSET(socket_fd_rx, &readfds)) //input rx available
{
//printf("Data to be read \n");
recvfrom( socket_fd_rx, recepbuff , BUFFLEN, 0, (struct sockaddr *)&addr_rx, &serv_len_rx); //recep
printf("[=> Réponse : %s\n", recepbuff);
}
else
{
loop=0;
}
}
printf(".... Réponse done from %s:%d .... \n",inet_ntoa(addr_rx.sin_addr),ntohs(addr_rx.sin_port) );
i++;
}
close(socket_fd_rx);
return 0;
}
//FONCTIONS
//OPENING 1 SETTING A SOCKET
/** libf_build_udp_socket
*
* This function creates an UDP socket.
*
* \param udp_socket socket identifier
* \param server_address IP destination address
* \param udp_port Destination UDP port
* \param server_flag TRUE to bind socket on UDP port
*
* \return 0 if successful; error code otherwise
*/
unsigned short int libf_build_udp_socket(int * udp_socket, char * server_address, unsigned short int udp_port)
{
/*
** Defining of the local variables.
*/
struct sockaddr_in serv_addr; /* Server Socket address structure*/
short int status = 0; /* internal status return*/
unsigned short int return_status = 0; /* the returnes status value */
/*
** creating the socket ;
** call socket (it creates an endpoint for communication and
** returns the socket
** descriptor. To create an UDP socket
** the parameter family is set
** to AF_INET, the type to SOCK_DGRAM, and
** the protocol to
** DEF_PROTOCOL. The socket is a global variable.);
*/
*udp_socket = socket(AF_INET, SOCK_DGRAM, 0);
if (*udp_socket < 0)
{
return_status = 1;
}
else
{
status = 1; //for future check
if (status >= 0)
{
/*
** reset the serv_addr variable
*/
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
/*
** set the sockname.sin_addr.s_addr to server address;
** sockname.sin_addr.s_addr = htonl(server address);
** set the sockname field sockname.sin_port to the used port number;
** sockname.sin_port = htons (udp port);
*/
serv_addr.sin_addr.s_addr = inet_addr(server_address);
serv_addr.sin_port = htons(udp_port);
/*
** Bind this socket to a name;
** call bind (it assigns a name or address to an unnamed socket.
** When a socket is created with socket it exists in
** a name space (address family) but has no name assigned.
** The bind requests the name, be assigned to the socket);
** If (return status signal an error)
** {
** set to return variable to error
** }
*/
status = bind(*udp_socket, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
if (status < 0)
{
printf("bind failed with %s", strerror(errno));
return_status = 2;
}
}
else
{
return_status = 3;
}
}
/*
** return status;
*/
return return_status;
}
Maybe i'm missing something essential in socket programming, i made a lot of research and try different things but it still doesn't want to work ! I would appreciate some help ! Thank you !
I am trying to write a client/server application using RAW sockets.
There are multiple problems:
When the client sends a message to the server using sendto() method, an error invalid argument is returned by sendto() method. Why this error message?. The corresponding code is marked under the section ERROR 1. The code of sendto() is commented in this post.
Since I have commented the send message part, the client should wait for a message; recvfrom() being a blocking system call. Instead, recvfrom() returns with a message E always. From where did this message arrive?. The corresponding code is marked as ERROR 2.
If I change protocol (3rd) argument in socket() to 0 or IPPROTO_RAW I get Protocol not supported error. Why these errors?
The operating system is Ubuntu.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h> // For the socket () etc. functions.
#include <netinet/in.h> // For IPv4 data struct..
#include <string.h> // For memset.
#include <arpa/inet.h> // For inet_pton ().
#define BUF_SIZE 30
void main ()
{
int rst; // Return status of functions.
/**************** Create a socket. *******************************/
int sfd; // Socket file descriptor.
sfd = socket (AF_INET, SOCK_RAW, IPPROTO_UDP); /*
* AF_INET --> IPv4, SOCK_RAW for Raw socket,
* 0 --> for any protocol. */
if (sfd == -1)
{
perror ("Client: socket error");
exit (1);
}
/*********** Server's address ***********************************/
struct sockaddr_in srv_addr;
socklen_t addrlen = sizeof (struct sockaddr_in);
// Initializing the server's address to zero.
memset (&srv_addr, 0, addrlen);
srv_addr.sin_family = AF_INET; // Address is in IPv4 format.
// srv_addr.sin_port = htons (0); // Port number of the server.
rst = inet_pton (AF_INET, "127.0.0.1", &srv_addr.sin_addr); /* Note
* that third field should point to an in_addr (in6_addr). */
if (rst <= 0)
{
perror ("Client Presentation to network address conversion.\n");
exit (1);
}
/****************** ERROR 1 ************************************
******************* Sending message to the server. *************/
const int flags = 0;
const char *msg = "Hello";
/* rst = sendto (sfd, msg, strlen(msg)+1, flags,
(struct sockaddr *) &srv_addr,
sizeof (struct sockaddr_in));
if (rst < 0)
{
perror ("Client: Sendto function call failed");
exit (1);
}
else
printf ("Client: Sent data size = %d\n", rst);
*/
/******************* ERROR 2 ***********************************
******************* Receiving message from server. ************/
// Initializing the server's address to zero.
memset (&srv_addr, 0, addrlen);
char buf[BUF_SIZE] = {'\0'};
rst = recvfrom (sfd, buf, BUF_SIZE, flags,
(struct sockaddr *) &srv_addr,
&addrlen);
if (rst < 0)
{
perror ("Client: couldn't receive");
exit (1);
}
printf ("Message from server = |%s|\n", buf);
/* Address of the server. */
const char *buf2 = inet_ntop (AF_INET,
(struct sockaddr *) &srv_addr, buf, BUF_SIZE);
if (buf2 == NULL)
{
perror ("Client: Conversion of sender's address to presentation failed");
exit (1);
}
printf ("Servers address, = %s\n", buf2);
close (sfd);
}
SOCK_RAW is not for use with UDP. SOCK_DGRAM is correct. For a tutorial, see:
a tutorial from Rutgers
edit: overlooked the init of the srv_addr... sorry.
using AF_INET + SOCK_RAW socket you can send anything - the payload is just added on top of the IP-layer. the IPPROTO_UDP just tells the kernel what the next layer will be (the layer your payload is added to) and which value the protocol field of the IP header must be set to. so to stay save (if you go to send raw data) set the protocol to something not commonly used).
you need the permission to create a raw socket. this commonly means: start as root, create the socket and then drop the privileges.
q2: this is the message you send to yourself (and a strong indication that your code somehow worked). The 'E' is just the first byte (0x45) in the IP-header - version 4 and header length 5. just dump the whole buffer..., eg.
printf ("Message from server = |");
for (i = 0; i < rst; i++)
printf("%c", isprint(buf[i]) ? buf[i] : '?') ;
printf ("|\n");
q3:
0 means: guess what is usually used (eg. INET + DGRAM -> TCP). As you specified raw the kernel is not able to choose a common protocol for the next layer.
IPPROTO_RAW should work (see comment of #nos)
I am working on linux Ubuntu 14.04 and trying to multicast using IPv6. I have a link local address of fe80::9a90:96ff:fe98:a985. Running the following code :
int main (int argc, char *argv[]) {
int sd;
struct in6_addr localInterface;
/* Create a datagram socket on which to send/receive. */
sd = socket(AF_INET6, SOCK_DGRAM, 0);
if(sd < 0) {
perror("Opening datagram socket error");
exit(1);
}
else {
printf("Opening the datagram socket...OK.\n");
}
/* Set local interface for outbound multicast datagrams. */
/* The IP address specified must be associated with a local, */
/* multicast capable interface. */
inet_pton (AF_INET6, "fe80::9a90:96ff:fe98:a985", &(localInterface.s6_addr));
if(setsockopt(sd, IPPROTO_IPV6, IPV6_MULTICAST_IF, (char *)&localInterface, sizeof(localInterface)) < 0)
{
perror("Setting local interface error");
printf ("%d\n", errno);
exit(1);
}
else {
printf("Setting the local interface...OK\n");
}
}
gives the error : Setting local interface error : No such device
I have tested multicast to work with IPv4 and also successfully tested that IPv6 works by pinging a local node using ping6 command.
With a few adjustments I was able to modify your program to get it to send multicast packets (that show up in WireShark) on my Mac (running OS/X 10.10.5). I haven't tried it under other OS's, but it should more or less work on other OS's as well.
Note that the program has hard-coded the interface number to 4, since that is what en0 is on my computer; the interface number will likely be different on your computer, and for a generally useful program you'd want to discover the correct interface number dynamically (using getifaddrs() or GetAdaptersAddresses() or similar); it's only hard-coded here for simplicity.
Modified program follows:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <unistd.h>
int main (int argc, char *argv[])
{
int sd = socket(AF_INET6, SOCK_DGRAM, 0);
if(sd < 0)
{
perror("Opening datagram socket error");
exit(1);
}
else printf("Opening the datagram socket...OK.\n");
// 4 is the interface ID (scope_id) of interface en0 on my Mac,
// as printed by ifconfig; the appropriate interface index
// value on your computer will likely be different --jaf
int my_network_devices_scope_id = 4;
if(setsockopt(sd, IPPROTO_IPV6, IPV6_MULTICAST_IF, (char *)&my_network_devices_scope_id, sizeof(my_network_devices_scope_id)) < 0)
{
perror("Setting local interface error");
printf ("%d\n", errno);
exit(1);
}
else printf("Setting the local interface...OK\n");
struct sockaddr_in6 multicastIP;
multicastIP.sin6_family = AF_INET6;
multicastIP.sin6_scope_id = my_network_devices_scope_id;
multicastIP.sin6_port = htons(9999); // destination port chosen at random
inet_pton(AF_INET6, "ff12::bead:cede:deed:feed", &multicastIP.sin6_addr.s6_addr); // a multicast address I chose at random
while(1)
{
char buf[] = "hello";
if (sendto(sd, buf, sizeof(buf), 0, (const struct sockaddr *) &multicastIP, sizeof(multicastIP)) == sizeof(buf))
{
printf("Sent a %i-byte multicast packet!\n", (int) sizeof(buf));
}
else perror("sendto");
sleep(1);
}
return 0;
}
I complile the following C code of UDP client
after I run './udpclient localhost 9191' in terminal.I put "Enter Text= " as Hello, but it is showing error in sendto as below:
Enter text: hello
hello
: error in sendto()guest-1SDRJ2#md-K42F:~/Desktop$
"
Note: I open 1st the server port as below in other terminal
./server 9191.
I beleive there is no error in server code. The udp client is not passing message to server. If I don't use thread , the message is passing .But I have to do it by thread.
UDP client Code:
/* simple UDP echo client */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <pthread.h>
#define STRLEN 1024
static void *readdata(void *);
static void *writedata(void *);
int sockfd, n, slen;
struct sockaddr_in servaddr;
char sendline[STRLEN], recvline[STRLEN];
int main(int argc, char *argv[]) {
pthread_t readid,writeid;
struct sockaddr_in servaddr;
struct hostent *h;
if(argc != 3) {
printf("Usage: %s <proxy server ip> <port>\n", argv[0]);
exit(0);
}
/* create hostent structure from user entered host name*/
if ( (h = gethostbyname(argv[1])) == NULL) {
printf("\n%s: error in gethostbyname()", argv[0]);
exit(0);
}
/* create server address structure */
bzero(&servaddr, sizeof(servaddr)); /* initialize it */
servaddr.sin_family = AF_INET;
memcpy((char *) &servaddr.sin_addr.s_addr, h->h_addr_list[0], h->h_length);
servaddr.sin_port = htons(atoi(argv[2])); /* get the port number from argv[2]*/
/* create a UDP socket: SOCK_DGRAM */
if ( (sockfd = socket(AF_INET,SOCK_DGRAM, 0)) < 0) {
printf("\n%s: error in socket()", argv[0]);
exit(0);
}
pthread_create(&readid,NULL,&readdata,NULL);
pthread_create(&writeid,NULL,&writedata,NULL);
while(1)
{
};
close(sockfd);
}
static void * writedata(void *arg)
{
/* get user input */
printf("\nEnter text: ");
do {
if (fgets(sendline, STRLEN, stdin) == NULL) {
printf("\n%s: error in fgets()");
exit(0);
}
/* send a text */
if (sendto(sockfd, sendline, sizeof(sendline), 0, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0) {
printf("\n%s: error in sendto()");
exit(0);
}
}while(1);
}
static void * readdata(void *arg)
{
/* wait for echo */
slen = sizeof(servaddr);
if ( (n = recvfrom(sockfd, recvline, STRLEN, 0, (struct sockaddr *) &servaddr, &slen)) < 0) {
printf("\n%s: error in recvfrom()");
exit(0);
}
/* null terminate the string */
recvline[n] = 0;
fputs(recvline, stdout);
}
The problem is that you're using the same sockaddr struct (servaddr) for both the sendto and revfrom calls. The recvfrom happens first, so it clears out servaddr in preparation for writing in the source address of the received packed (once it receives one -- that thread is still blocked in the kernel waiting for a packet). Then, when the sendto call occurs, the sockaddr is all zeros, so it immediately returns EINVAL.
You may be getting confused by the fact that the sockaddr argument to recvfrom is an OUTPUT, not an input -- it gets filled in with the source address of the packet that is received (which could be from anywhere). If you want to only receive packets from a particular place (the server?), you need to check the address after the recvfrom returns and toss the packet if it comes from somewhere else, looping back to recvfrom again.