segmentation fault in linux (socket programming (TCP) in C) - c

I am just learning socket programming on Linux by some websites and here are some parts of my code on server side by using TCP:
#define BufferLength 100
#define SERVPORT 3111
int main()
{
/* Variable and structure definitions. */
int sd, sd2, rc, length = sizeof(int);
int totalcnt = 0, on = 1;
char temp;
char buffer[BufferLength];
struct sockaddr_in serveraddr;
struct sockaddr_in their_addr;
fd_set read_fd;
/* Get a socket descriptor */
if((sd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("Server-socket() error");
exit (-1);
}
else
printf("Server-socket() is OK\n");
/* Allow socket descriptor to be reusable */
if((rc = setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on))) < 0)
{
perror("Server-setsockopt() error");
close(sd);
exit (-1);
}
else
printf("Server-setsockopt() is OK\n");
/* bind to an address */
memset(&serveraddr, 0x00, sizeof(struct sockaddr_in));
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(SERVPORT);
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
printf("Using %s, listening at %d\n", inet_ntoa(serveraddr.sin_addr), SERVPORT);
/* continue */
}
When I did the last line (printf("using......")), I got a segmentation fault, why? Thanks.

The code as shown misses to #include any headers, so as it stands won't compile due to some undefined symbols.
It would compile however if you missed to just prototype any library functions referenced by the code, which would lead to any function being assumed to return int.
The latter fact might be fatal or not.
On a 64bit system at least it is fatal in the case of inet_ntoa() used as a parameter to printf(), as on a 64bit system it most likely is expected to return a 64bit (char-pointer) value (but a 32bit int). So (assuming the prototype misses) when generating the code the compilers assumes inet_ntoa() to return a 32bit int which would lead to "chopping-off" the most significant 32bits of the address returned. Trying to printf() from such a "crippled" and therefore (most likely) invalid address provokes undefined behaviour and in your case leads to the segmentation violation observed.
To fix this, add the relevant prototype (for inet_ntoa()) by adding:
#include <arpa/inet.h>
The compiler should have warned you about this. To enable all compiler's warnings for gcc use the options -Wall -Wextra -pedantic. Take such warnings serious.

It seems likely that inet_ntoa() is somehow returning NULL, leading to the segfault when it is dereferenced in the printf(). I can't find a direct reference plainly stating that this is possible with the Linux version of inet_ntoa, but I found several people who made that claim, and it is the only point in that code where a pointer is being dereferenced.
The answer at the bottom of this question: segmentation fault for inet_ntoa makes the claim that inet_ntoa can return NULL. However, following his reference links, I couldn't find an actual statement of that fact.
There is an MSDN article (which is suggestive, but of course doesn't apply directly to Linux code) that does state plainly that inet_ntoa() can return NULL here: https://msdn.microsoft.com/en-us/library/windows/desktop/ms738564%28v=vs.85%29.aspx

Related

Why do we need an unused char array for a successfull bind?

We're currently developing a small tool that reads CAN-messages and evaluates the data contained. The bind() command doesn't return 0 (for a successfull bind) when the char array empty is too short, too long or not present. This bug is present in the shortened program below.
#include <sys/socket.h> // socket, bind, PF_CAN, SOCK_RAW
#include <linux/if.h> // ifreq
#include <linux/can.h> // sockaddr_can, CAN_RAW
#include <stdio.h> // printf
int main()
{
struct sockaddr_can addr;
struct ifreq ifr;
int socketFd = socket(PF_CAN, SOCK_RAW, CAN_RAW);
addr.can_ifindex = ifr.ifr_ifindex;
char empty[5]; // change length or comment out to provoke the error
if(bind(socketFd, (struct sockaddr *) &addr, sizeof(addr)) != 0)
{
printf("Unable to bind the CAN-socket.\n");
}
}
The behaviour changes with the length of our char array empty.
For example [5] works, while [24] doesn't.
We tested this with GCC 5.4.0 and 7.2.0 which both showed this behaviour.
Under GCC 5.3.0 the presence and lentgh of empty do not influence our bind().
For reference we used
gcc main.c
./a.out
Why do we need an unused char array with GCC 5.4.0 and 7.2.0 for a successfull bind?
You're causing all sorts of undefined behavior due to use of uninitialized variables.
You never initialize ifr, then you use ifr.ifr_ifindex.
You never initialize addr.tp, then you pass addr as the sockaddr parameter to bind().
That it ever succeeds at all is more surprising than the fact that the failure depends on the size of the empty array. What address are you expecting the socket to be bound to?
We followed the documentation found at kernel.org.
In "4. How to use SocketCAN" (approx. line 60) this example is given:
int s;
struct sockaddr_can addr;
struct ifreq ifr;
s = socket(PF_CAN, SOCK_RAW, CAN_RAW);
strcpy(ifr.ifr_name, "can0" );
ioctl(s, SIOCGIFINDEX, &ifr);
addr.can_family = AF_CAN;
addr.can_ifindex = ifr.ifr_ifindex;
bind(s, (struct sockaddr *)&addr, sizeof(addr));
(..)
While it states that no error checking has been implemented neither addr nor ifr have been fully initialised (like all of you mentioned here). Therefore the given example encounters the same problem as our program.
Initialising them with memset like #zwol mentioned to ensure all values are set to 0 before working with them fixes this unexpected behaviour completely.
Thanks everyone.

Linux TCP recv() with MSG_TRUNC - writes to buffer?

I've just encountered a surprising buffer overflow, while trying to use the flag MSG_TRUNC in recv on a TCP socket.
And it seems to only happen with gcc (not clang) and only when compiling with optimization.
According to this link: http://man7.org/linux/man-pages/man7/tcp.7.html
Since version 2.4, Linux supports the use of MSG_TRUNC in the flags argument of recv(2) (and recvmsg(2)). This flag causes the received bytes of data to be discarded, rather than passed back in a caller-supplied buffer. Since Linux 2.4.4, MSG_PEEK also has this effect when used in conjunction with MSG_OOB to receive out-of-band data.
Does this mean that a supplied buffer will not be written to? I expected so, but was surprised.
If you pass a buffer (non-zero pointer) and size bigger than the buffer size, it results in buffer overflow when client sends something bigger than buffer. It doesn't actually seem to write the message to the buffer if the message is small and fits in the buffer (no overflow).
Apparently if you pass a null pointer the problem goes away.
Client is a simple netcat sending a message bigger than 4 characters.
Server code is based on:
http://www.linuxhowtos.org/data/6/server.c
Changed read to recv with MSG_TRUNC, and buffer size to 4 (bzero to 4 as well).
Compiled on Ubuntu 14.04. These compilations work fine (no warnings):
gcc -o server.x server.c
clang -o server.x server.c
clang -O2 server.x server.c
This is the buggy (?) compilation, it also gives a warning hinting about the problem:
gcc -O2 -o server.x server.c
Anyway like I mentioned changing the pointer to null fixes the problem, but is this a known issue? Or did I miss something in the man page?
UPDATE:
The buffer overflow happens also with gcc -O1.
Here is the compilation warning:
In function ‘recv’,
inlined from ‘main’ at server.c:47:14:
/usr/include/x86_64-linux-gnu/bits/socket2.h:42:2: warning: call to ‘__recv_chk_warn’ declared with attribute warning: recv called with bigger length than size of destination buffer [enabled by default]
return __recv_chk_warn (__fd, __buf, __n, __bos0 (__buf), __flags);
Here is the buffer overflow:
./server.x 10003
* buffer overflow detected *: ./server.x terminated
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x7338f)[0x7fcbdc44b38f]
/lib/x86_64-linux-gnu/libc.so.6(__fortify_fail+0x5c)[0x7fcbdc4e2c9c]
/lib/x86_64-linux-gnu/libc.so.6(+0x109b60)[0x7fcbdc4e1b60]
/lib/x86_64-linux-gnu/libc.so.6(+0x10a023)[0x7fcbdc4e2023]
./server.x[0x400a6c]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf5)[0x7fcbdc3f9ec5]
./server.x[0x400879]
======= Memory map: ========
00400000-00401000 r-xp 00000000 08:01 17732 > /tmp/server.x
... more messages here
Aborted (core dumped)
And gcc version:
gcc (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4
The buffer and recv call:
char buffer[4];
n = recv(newsockfd,buffer,255,MSG_TRUNC);
And this seems to fix it:
n = recv(newsockfd,NULL,255,MSG_TRUNC);
This will not generate any warnings or errors:
gcc -Wall -Wextra -pedantic -o server.x server.c
And here is the complete code:
/* A simple server in the internet domain using TCP
The port number is passed as an argument */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
void error(const char *msg)
{
perror(msg);
exit(1);
}
int main(int argc, char *argv[])
{
int sockfd, newsockfd, portno;
socklen_t clilen;
char buffer[4];
struct sockaddr_in serv_addr, cli_addr;
int n;
if (argc < 2) {
fprintf(stderr,"ERROR, no port provided\n");
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if (bind(sockfd, (struct sockaddr *) &serv_addr,
sizeof(serv_addr)) < 0)
error("ERROR on binding");
listen(sockfd,5);
clilen = sizeof(cli_addr);
newsockfd = accept(sockfd,
(struct sockaddr *) &cli_addr,
&clilen);
if (newsockfd < 0)
error("ERROR on accept");
bzero(buffer,4);
n = recv(newsockfd,buffer,255,MSG_TRUNC);
if (n < 0) error("ERROR reading from socket");
printf("Here is the message: %s\n",buffer);
n = write(newsockfd,"I got your message",18);
if (n < 0) error("ERROR writing to socket");
close(newsockfd);
close(sockfd);
return 0;
}
UPDATE:
Happens also on Ubuntu 16.04, with gcc version:
gcc (Ubuntu 5.4.0-6ubuntu1~16.04.2) 5.4.0 20160609
I think you have misunderstood.
With datagram sockets, MSG_TRUNC option behaves as described in man 2 recv man page (at Linux man pages online for most accurate and up to date information).
With TCP sockets, the explanation in the man 7 tcp man page is a bit poorly worded. I believed it is not a discard flag, but a truncate (or "throw away the rest") operation. However, the implementation (in particular, net/ipv4/tcp.c:tcp_recvmsg() function in the Linux kernel handles the details for TCP/IPv4 and TCP/IPv6 sockets) indicates otherwise.
There is also a separate MSG_TRUNC socket flag. These are stored in the error queue associated with the socket, and can be read using recvmsg(socketfd, &msg, MSG_ERRQUEUE). It indicates a datagram that was read was longer than the buffer, so some of it was lost (truncated). This is rarely used, because it is really only relevant to datagram sockets, and there are much easier ways to determine overlength datagrams.
Datagram sockets:
With datagram sockets, the messages are separate, and not merged. When read, the unread part of each received datagram is discarded.
If you use
nbytes = recv(socketfd, buffer, buffersize, MSG_TRUNC);
it means that the kernel will copy up to first buffersize bytes of the next datagram, and discard the rest of the datagram if it is longer (as usual), but nbytes will reflect the true length of the datagram.
In other words, with MSG_TRUNC, nbytes may exceed buffersize, even though only up to buffersize bytes are copied to buffer.
TCP sockets in Linux, kernels 2.4 and later, edited:
A TCP connection is stream-like; there are no "messages" or "message boundaries", just a sequence of bytes flowing. (Although, there can be out-of-band data, but that is not pertinent here).
If you use
nbytes = recv(socketfd, buffer, buffersize, MSG_TRUNC);
the kernel will discard up to next buffersize bytes, whatever is already buffered (but will block until at least one byte is buffered, unless the socket is in non-blocking mode or MSG_TRUNC | MSG_DONTWAIT is used instead). The number of bytes discarded is returned in nbytes.
However, both buffer and buffersize should be valid, because a recv() or recvfrom() call goes through the kernel net/socket.c:sys_recvfrom() function, which verifies buffer and buffersize are valid, and if so, populates the internal iterator structure to match, before calling the aforementioned net/ipv4/tcp.c:tcp_recvmsg().
In other words, the recv() with a MSG_TRUNC flag does not actually try to modify buffer. However, the kernel does check if buffer and buffersize are valid, and if not, will cause the recv() syscall to fail with -EFAULT.
When buffer overflow checks are enabled, GCC and glibc recv() does not just return -1 with errno==EFAULT; it instead halts the program, producing the shown backtraces. Some of these checks include mapping the zero page (where the target of a NULL pointer resides in Linux on x86 and x86-64), in which case the access check done by the kernel (before actually trying to read or write to it) succeeds.
To avoid the GCC/glibc wrappers (so that code compiled with e.g. gcc and clang should behave the same), one can use real_recv() instead,
#define _GNU_SOURCE
#include <unistd.h>
#include <sys/syscall.h>
#include <errno.h>
ssize_t real_recv(int fd, void *buf, size_t n, int flags)
{
long retval = syscall(SYS_recvfrom, fd, buf, n, flags, NULL, NULL);
if (retval < 0) {
errno = -retval;
return -1;
} else
return (ssize_t)retval;
}
which calls the syscall directly. Note that this does not include the pthreads cancellation logic; use this only in single-threaded test programs.
In summary, with the stated problem regarding MSG_TRUNC flag for recv() when using TCP sockets, there are several factors complicating the full picture:
recv(sockfd, data, size, flags) actually calls the recvfrom(sockfd, data, size, flags, NULL, NULL) syscall (there is no recv syscall in Linux)
With a TCP socket, recv(sockfd, data, size, MSG_TRUNC) acts as if it were to read up to size bytes into data, if (char *)data+0 to (char *)data+size-1 are valid; it just does not copy them into data. The number of bytes thus skipped is returned.
The kernel verifies data (from (char *)data+0 to (char *)data+size-1, inclusive) is readable, first. (I suspect this check is erroneous, and might be turned into a writability check sometime in the future, so do not rely on this being a readability test.)
Buffer overflow checks can detect the -EFAULT result from the kernel, and instead halts the program with some kind of "out of bounds" error message (with a stack trace)
Buffer overflow checks may make NULL pointer seem like valid from the kernel point of view (because the kernel test is for reading, currently), in which case the kernel verification accepts the NULL pointer as valid. (One can verify if this is the case by recompiling without buffer overflow checks, using e.g. the above real_recv(), and seeing if a NULL pointer causes an -EFAULT result then.)
The reason for such a mapping (that, if allowed by hardware and the kernel structures, only exists, and is not readable or writable) is that with such a mapping, any access generates a SIGBUS signal, which a (library or compiler-provided signal handler) can catch, and dump not just a stack trace, but more details about the exact access (address, code that attempted the access, and so on).
I do believe the kernel access check treats such mappings readable and writable, because there needs to be a read or write attempt for the signal to be generated.
Buffer overflow checks are done by both the compiler and the C library, so different compilers may implement the checks, and the NULL pointer case, differently.
Nota bene: I’m adding this answer here after all this time, as this is still one of the first results on google for recv buffer overflow MSG_TRUNC, and if someone else ends up here, they’ll save themselves a lot of grief, searching and trial-and-error.
The original question is answered well enough already, but the subtlety I wanted to highlight, is the difference between stream and datagram sockets.
A common code pattern is to use recv( socket_, NULL, 0, MSG_DONTWAIT | MSG_PEEK | MSG_TRUNC ) to find how much data is queued before a read. This works perfectly for stream sockets (TCP and SCTP) but for datagram sockets (UDP, UDPL and DCCP) it will intermittently buffer overflow, but only if the executable is compiled with gcp and with optimisations enabled. Without optimisations it seems to work perfectly, which means it will sail through development QA, only to fail in staging/live.
Finding this was a total PITA. You’re welcome. ;)

c- recvfrom error 22

Okay first here is the code:
int recvMast_sock;
struct sockaddr_in serv_addr, cli_addr;
socklen_t cli_len;
if ((recvMast_sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
{
critErr("listen:socket=");
}
fillSockaddrAny(&serv_addr, UDP_NODE_LISTEN_PORT);// fills the sockaddr_in works fine elsewhere
if ((bind(recvMast_sock, (struct sockaddr*) &serv_addr, sizeof serv_addr)) < 0)
{
critErr("listen:bind recv_mast_sock:");
}
recvReturn_i = recvfrom(recvMast_sock, &recvBuff[0], (size_t)1, 0, (struct sockaddr*) &cli_addr, &cli_len);
if(recvReturn_i <0)
printf("recv error%d\n",errno);
critErr is a function to handle errors which also includes a print of the error and an exit.
This runs in a thread, if this is of any relevance. If I compile and run this on a Zedboard (ZYNQ-7000 SoC) which has an ARM Cortex A9 and Linaro Linux (based on precise Ubuntu). It prints error 22 but still has the received value in recvBuff[0].
Running this in my VM with xubuntu it works fine.
Error 22 equals EINVAL which is described as Invalid argument.
In the manpage of recvfrom(2) it states EINVAL means that the MSG_OOB flag is set but I don't use any flags (passing 0).
Before leaving on friday I started an apt-get upgrade because I hope it is a faulty library or something like this. I can check back at monday but maybe someone here has another idea what is wrong.
You need to initialize cli_len before passing it to recvfrom():
cli_len = sizeof(cli_addr);
You are not initializing it, so it has a random value. If that value happens to be < sizeof(cli_addr), recvfrom() can fail with EINVAL, or at least truncate the address, because it thinks cli_addr is not large enough to receive the client address. If the value is vastly larger than sizeof(cli_addr), recvfrom() might consider the buffer to be outside of the valid memory range.
You have to tell recvfrom() how large cli_addr actually is. This is clearly stated in the documentation:
The argument addrlen is a value-result argument, which the caller should initialize before the call to the size of the buffer associated with src_addr, and modified on return to indicate the actual size of the source address. The returned address is truncated if the buffer provided is too small; in this case, addrlen will return a value greater than was supplied to the call.
So you have to initialize cli_len with the total size of cli_addr before calling recvfrom(), then recvfrom() updates cli_len with the size of the address that was actually written into cli_addr. cli_addr can be larger than the address, for instance when using a sockaddr_storage structure to accept either IPv4 or IPv6 addresses on a dual-stack socket. In the example in the question, an IPv4 socket is being used, so cli_len must be initialized to a value >= sizeof(sockaddr_in).
This was not caused by the OS or the architecture. The function was not called on the x86-system because of a blocked mutex. So I didn't got the error there.
The problem was that I passed the socket to this function from 'main' (which i did not state in the question because I thought it was irrelevant, my bad...)
In 'main' I used it and used it in this function. Even though it was mutually exclusive, there was this error.
Remy's answer was also relevant but not a solution to the problem. Not setting cli_len beforehand just leads to a cut of sockaddr if its too small. No error was generated for that.

Linux UDP client, how?

#include <stdio.h>
#include <sys/socket.h>
#include <netdb.h>
int main () {
char buf[4] = { 0xff, 0xff, 0xff, 0xff };
struct addrinfo adr, *res;
adr.ai_family = AF_INET;
adr.ai_socktype = SOCK_DGRAM;
getaddrinfo ("192.168.1.1", NULL, &adr, &res);
int sd = socket (res->ai_family, res->ai_socktype, res->ai_protocol);
if (sendto (sd, buf, sizeof (buf), MSG_OOB, res->ai_addr, res->ai_addrlen) < 0)
perror ("ERROR sendto"); //I have added an if tag and an error message posiblility
return 0;
}
ERROE sendto: Operation not supported
This is the all of message. The beej's guide network programming, i have read the getaddrinfo second parameter is NULL, and i had compiling it, it will be good, there was no problem this line. At now time the problem is Operation not supported error message.
There seem to be several mistakes.
First, I believe MSG_OOB is illegal for UDP. This is probably what the error message is trying to say. Try 0 instead.
Then, the getaddrinfo() call looks weird (at least I don't understand the point). You say "i had compiling it, it will be good, there was no problem this line" but then you don't have the error handling to prove it...
My hunch is that the address or port of the socket address you use in sendto() are incorrect and you will still get errors after fixing MSG_OOB. Is there a reason you aren't just setting them manually like here — Are you trying to make getaddrinfo() pick a suitable port for you? I don't think that works:
If service is NULL, then the port number of the returned socket
addresses will be left uninitialized.

How to connect two computers over internet using socket programming in C?

This is simple Client-Server chat program.This code is working fine on computers connected on Network, how to modify it such that it can connect between computers over the Internet. Using Public IP of the server in gethostbyname() isn't working.
//Client.c
#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<netdb.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
int main(void)
{
int clientSocket; /* Socket Decriptor for Client */
struct sockaddr_in server_addr;
struct hostent *ptrh;
char message[100];
char received[100];
int n = 0;
clientSocket=socket(AF_INET, SOCK_STREAM, 0);
memset((char*)&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(10000);
/* bind(clientSocket, (struct sockaddr*)&server_addr, sizeof(struct sockaddr)); */
ptrh=gethostbyname("110.172.156.2");
memcpy(&server_addr.sin_addr,ptrh->h_addr,ptrh->h_length);
if( -1 == (connect(clientSocket, (struct sockaddr*)&server_addr, sizeof(server_addr))))
{ printf("\nServer Not Ready !!\n"); exit(1); }
while(1)
{
printf("\nUser:-");
// memset(message, '\0', 10);
gets(message);
n = write(clientSocket, message, strlen(message)+1);
if( (strcmp(message,"q") == 0 ) || (strcmp(message,"Q") == 0 ))
{
printf("Wrong place...Socket Closed\n");
close(clientSocket);
break;
}
//printf("Write:<%u>\n", n);
read(clientSocket, received, sizeof(received));
if( (strcmp(received,"q") == 0 ) || (strcmp(received,"Q") == 0 ))
{
printf("Wrong place...Socket Closed\n");
close(clientSocket);
break;
}
else
printf("Server:- %s\n", received);
}
return 0;
}
//Server.c
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<netdb.h>
int main(void)
{
int serverSocket,client_connected,len;
struct sockaddr_in client_addr,server_addr;
struct hostent *ptrh;
int n=0;
char message[100],received[100];
serverSocket=socket(AF_INET, SOCK_STREAM, 0);
memset((char*)&server_addr,0,sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(10000);
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
if(bind(serverSocket,
(struct sockaddr*)&server_addr,sizeof(server_addr)) == -1)
printf("Bind Failure\n");
else
printf("Bind Success:<%u>\n", serverSocket);
while(1)
{
listen(serverSocket,5);
len=sizeof(struct sockaddr_in);
client_connected=accept(serverSocket,
(struct sockaddr*)&client_addr,&len);
if (-1 != client_connected)
printf("Connection accepted:<%u>\n", client_connected);
while(1)
{
n = read(client_connected, received, sizeof(received));
if( (strcmp(received,"q") == 0 ) || (strcmp(received,"Q") == 0 ))
{
printf("Wrong place...Socket Closed of Client\n");
close(client_connected);
break;
}
else{
printf("\nUser:-%s", received);}
printf("\nServer:-");
// memset(message, '\0', 10);
gets(message);
write(client_connected, message, sizeof(message));
if( (strcmp(message,"q") == 0 ) || (strcmp(message,"Q") == 0 ))
{
printf("Wrong place...Socket Closed of Client\n");
close(client_connected);
break;
}
}
}
close(serverSocket); printf("\nServer Socket Closed !!\n");
return 0;
}
Based on the information you've given, I don't think it's possible to provide a solution to the question you're asking. You've stated that your code works when the two computers are on the same local network, so clearly the code (which, yes, has issues) works at least well enough to connect from client to server.
If (as is established,) the code works, then it shouldn't matter whether the client and server are on the same network or separate networks, so long as there's a route, a path, a connection between the two networks. Therefore, if the client can't connect to the server, the conclusion is that this path is missing. The path being missing, however, is not a problem we can troubleshoot for you: It might be "my 'Windows Firewall' is blocking this app", it might be "my ISP (or the other guy's ISP) is blocking this port", it might be "The other guy's terms of service with his ISP includes a "no servers" clause which they enforce by blocking all ports", it might even be "my ISP is on the outs with the other guy's ISP and won't route packets to them anymore".
However, since you've gone to all the trouble of posting this code, and I've gone to the trouble of (a) reading it, and (b) writing a response, I've decided to include some commentary on issues I see in your code. Note that this is guaranteed not to be an exhaustive list.
In Client.c:
You're calling memset(), and casting the first argument to char *. The memset() function is defined to take a void * as the first argument. Since you've #included <string.h> you have a correct prototype in scope, so whatever you pass to it will be converted to a void * automatically. The cast is therefore both incorrect and pointless.
You're calling gethostbyname(), and the string you're passing is an IPv4 address.
The gethostbyname() and gethostbyaddr() functions were deprecated in POSIX.1-2004 and were excluded from POSIX.1-2008. They are replaced by getaddrinfo() (and getnameinfo()), and I refer you to System Calls/getaddrinfo() section of Beej's Guide to Network Programming for further information.
According to POSIX.1-2004, "the behavior of gethostbyname() when passed a numeric address string is unspecified". The gethostbyname() function expects to be passed an actual hostname, for IP addresses there's gethostbyaddr(). (Or getaddrinfo() now, of course.)
You're using the gets() function. The gets() function was deprecated in C99, marked as Obsolete in POSIX.1-2008, and excluded from C11, because it is fundamentally unsafe due to not having any way of limiting input size. The generally recommended alternative is fgets(), note that unlike gets(), the fgets() function doesn't discard the \n character.
In Server.c:
You're still casting the first argument to memset() to char *, which is still unnecessary and wrong,
You're still using the gets() function, which is still inherently problematic,
You're doing write(client_connected, message, sizeof(message));. Every response from the server will be the full 100 bytes long, with garbage bytes being written after the response string. Use strlen(message)+1 instead.
In both:
Your message is a string that was input by the user, but when the client sends the message, it doesn't include the terminal null byte. The recipient can only read what the sender writes, so it isn't receiving a terminal null byte... which is only a problem because the receiving code assumes that what it received is a valid string. Make sure your messages include the null at the end of the string, by having the specified message size be one more than strlen(message).
Well after my research I came up with this answer. If you want to connect Devices over Internet you need to have a Server having a unique IP Address Eg you could buy one online. When you try to create a device in your home network as Server you need to provide the Global IP Address and since the ISP provides you with a single Public IP shared by a lot of devices over the Network using a router, you cant create a ServerSocket over a Home network shared by many Devices
You can't connect to a device only by the global IP but if you open a port, port forward, only for the server then the socket can be made.

Resources