Socket connection in Linux - c

I just got a error from connect API in linux.
I knew 'connect' will return zero if connection is successful, I got return value "3"
is it error code? or is there something else what don't know?
connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
I got value 3 from sock.

To get the return value of connect(), it is most straight forward to use a variable that is used as the left hand side of an assignment.
int result = connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
printf("connect returned: %d\n", result);
sock must be a socket, and was assigned a file descriptor number as a result of a call to socket(). Most UNIX APIs that return a new file descriptor will return the lowest available one. A program usually starts off with descriptors 0, 1, and 2 already in use (for STDIN, STDOUT, and STDERR). So, it is not unexpected that socket() returned 3.

In linux systems (and posix generally), you can use perror function to know the failure reason:
if (0 != connect(...))
{
perror("connect");
}
see man perror

Related

Using the POSIX "write" function after killing my TCP/IP connection crashes my application - why?

I'm working on a C application that uses POSIX TCP/IP functions for communicating with a server. I'm currently doing some testing to see how the application responds when the connection unexpectedly closes.
The main workhouse function is shown below:
uint32_t netWriteMsg(uint8_t * pmsg, size_t msg_size)
{
if(write(m_sockfd, pmsg, msg_size) < msg_size)
return ERR_NET_NOT_ALL_BYTES_SENT;
return ERR_NONE;
}
This function works as expected when I have a good connection with the server. However, calling this function after killing the connection crashes my application.
Ideally, I would want the write function to return an error indicating that the write failed. This would then allow me to handle the error and transition my program to the appropriate state. However, this is not what happens.
I'm curious as to why this function call would crash the application. I'm somewhat thinking that it may be a problem where the function call doesn't lock, and then the pointer its referencing becomes 'bad' resulting in a segmentation fault.
Here is how I configured my socket:
uint32_t netConnect()
{
/* locals */
struct sockaddr_in serv_addr;
fd_set fdset_sock; // only 1 file descriptor (socket fd) will be placed in this set
fd_set fdset_empty;
struct timeval time = {NET_TIMEOUT_CONNECT, 0};
int sock_error;
socklen_t optlen;
int error = ERR_NONE;
/* obtain socket file descriptor and set it to non-blocking */
m_sockfd = socket(AF_INET, SOCK_STREAM, 0);
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT_NO);
inet_pton(AF_INET, IP_ADDR, &(serv_addr.sin_addr.s_addr));
/* attempt to connect */
error = connect(m_sockfd, &serv_addr, sizeof(serv_addr));
if(error) return ERR_NET_CONNECT_FAILED_IMMEDIATELY;
select(m_sockfd, &fdset_empty, &fdset_sock, &fdset_empty, &time); // blocks until socket is good or timeout occured
error = getsockopt(m_sockfd, SOL_SOCKET, SO_ERROR, &sock_error, &optlen);
if(error) return ERR_NET_COULD_NOT_GET_SOCKET_OPTION;
if(sock_error)
return ERR_NET_CONNECT_ATTEMPT_TIMEOUT;
m_is_connected = 1;
return ERR_NONE;
}
Any help would be appreciated
Further to the missing error-checking #RemyLebeau mentioned, you are also not error-checking the write() itself:
if(write(m_sockfd, pmsg, msg_size) < msg_size)
return ERR_NET_NOT_ALL_BYTES_SENT;
Here you are ignoring the possibilty that it returned -1, in which case you should call perror() or construct an error message string with strerror() and print it, and close the socket, and tell the caller so he doesn't keep writing.
You also need to set SIGPIPE to SIG_IGNORE or whatever it is, so that EPIPE write errors don't cause SIGPIPE signals.
And all this ERR_NET_COULD_NOT_GET_SOCKET_OPTION stuff is poor practice. You should return the actual errno value, or at least print it, not just in the getsockopt() case but in all error cases.
And you are doing the connect() in blocking mode. The following select() is therefore completely pointless.

why write() doesn't return 0 when it should?

I've encountered a case where using write() server-side on a remotely closed client doesn't return 0.
According to man 2 write :
On success, the number of bytes written is returned (zero indicates
nothing was written). On error, -1 is returned, and errno is set
appropriately.
From my understanding: when using read/write on a remotely closed socket, the first attempt is supposed to fail (thus return 0), and the next try should trigger a broken pipe. But it doesn't. write() acts as if it succeeded in sending the data on the first attempt, and then i get a broken pipe on the next try.
My question is why?
I know how to handle a broken pipe properly, that's not the issue. I'm just trying to understand why write doesn't return 0 in this case.
Below is the server code I wrote. Client-side, I tried a basic C client (with close() and shutdown() for closing the socket) and netcat. All three gave me the same result.
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#define MY_STR "hello world!"
int start_server(int port)
{
int fd;
struct sockaddr_in sin;
fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd == -1)
{
perror(NULL);
return (-1);
}
memset(&sin, 0, sizeof(struct sockaddr_in));
sin.sin_addr.s_addr = htonl(INADDR_ANY);
sin.sin_family = AF_INET;
sin.sin_port = htons(port);
if (bind(fd, (struct sockaddr *)&sin, sizeof(struct sockaddr)) == -1
|| listen(fd, 0) == -1)
{
perror(NULL);
close(fd);
return (-1);
}
return (fd);
}
int accept_client(int fd)
{
int client_fd;
struct sockaddr_in client_sin;
socklen_t client_addrlen;
client_addrlen = sizeof(struct sockaddr_in);
client_fd = accept(fd, (struct sockaddr *)&client_sin, &client_addrlen);
if (client_fd == -1)
return (-1);
return (client_fd);
}
int main(int argc, char **argv)
{
int fd, fd_client;
int port;
int ret;
port = 1234;
if (argc == 2)
port = atoi(argv[1]);
fd = start_server(port);
if (fd == -1)
return (EXIT_FAILURE);
printf("Server listening on port %d\n", port);
fd_client = accept_client(fd);
if (fd_client == -1)
{
close(fd);
printf("Failed to accept a client\n");
return (EXIT_FAILURE);
}
printf("Client connected!\n");
while (1)
{
getchar();
ret = write(fd_client, MY_STR, strlen(MY_STR));
printf("%d\n", ret);
if (ret < 1)
break ;
}
printf("the end.\n");
return (0);
}
The only way to make write return zero on a socket is to ask it to write zero bytes. If there's an error on the socket you will always get -1.
If you want to get a "connection closed" indicator, you need to use read which will return 0 for a remotely closed connection.
This is just how the sockets interface was written. When you have a connected socket or pipe, you are supposed to close the transmitting end first, and then the receiving end will get EOF and can shut down. Closing the receiving end first is "unexpected" and so it returns an error instead of returning 0.
This is important for pipes, because it allows complicated commands to finish much more quickly than they would otherwise. For example,
bunzip2 < big_file.bz2 | head -n 10
Suppose big_file.bz2 is huge. Only the first part will be read, because bunzip2 will get killed once it tries sending more data to head. This makes the whole command finish much quicker, and with less CPU usage.
Sockets inherited the same behavior, with the added complication that you have to close the transmitting and receiving parts of the socket separately.
The point to be observed is that, in TCP, when one side of the connection closes its
socket, it is actually ceasing to transmit on that socket; it sends a packet to
inform its remote peer that it will not transmit anymore through that
connection. It doesn't mean, however, that it stopped receiving too. (To
continue receiving is a local decision of the closing side; if it stops receiving, it can
lose packets transmitted by the remote peer.)
So, when you write() to a socket that is remotely closed, but
not locally closed, you can't know if the other end is still waiting to read
more packets, and so the TCP stack will buffer your data and try to send it. As
stated in send() manual page,
No indication of failure to deliver is implicit in a send(). Locally detected
errors are indicated by a return value of -1.
(When you write() to a socket, you are actually send()ing to it.)
When you write() a second time, though, and the remote peer has definitely
closed the socket (not only shutdown() writing), the local TCP stack has probably
already received a reset packet from the peer informing it about the error on
the last transmitted packet. Only then can write() return an error, telling
its user that this pipe is broken (EPIPE error code).
If the remote peer has only shutdown() writing, but still has the socket open,
its TCP stack will successfully receive the packet and will acknowledge the
received data back to the sender.
if you read the whole man page then you would read, in error return values:
"EPIPE fd is connected to a pipe or *socket whose reading end is closed*."
So, the call to write() will not return a 0 but rather -1 and errno will be set to 'EPIPE'

C, Bind faild: `Address Already in Use`

I am writing a client-server program in C. I am getting an error in Bind function says: Address Already in Use. So I tired to use memset() and I got error says: Invalid Argument. Finally, I looked for similar questions on here, and some of them suggesting the use of setsocketopt() function. I used it and I am getting error says:
/tmp/ccBNsJtU.o: In function main:
socket.c:(.text+0xd0): undefined reference to setsocket
collect2: error: ld returned 1 exit status
I looked at almost-if-not all the similar questions even in different programing languages. Now I am stuck. Do I have to use setsocket() and if I do, is it causing a problem in my code? Or I don't have to use it and the problem is somewhere else? Could the problem be in the client or the server functions where I listen and send messages? This is the part of the code where the bind() and setsocket() functions are:
int main (void) {
int sl, sa, bn, erro, lis;
int status;
//server log socket
struct sockaddr_un server = {AF_UNIX, "log_server"};
sl = socket (AF_UNIX, SOCK_STREAM, 0);
if(sl < 0) {
perror("Faild to create socket - in main");
exit(1);
}
//I added this part
if (setsocket(sl, SOL_SOCKET, SO_REUSEADDR, &server, sizeof(server)) == -1) {
perror("setsocket - in main");
exit(1);
}
bn = bind (sl, (struct sockaddr *)&server, sizeof(server));
if(bn < 0){
perror("Faild to bind - in main");
exit(1);
}
lis = listen (sl, 1); //to be changed to 4
if (lis < 0) {
perror("Faild to listen - in main");
}
"Address already in use" typically means that some other socket is already bound to the given port. This could mean that there's a running program actively listening on that port, or it could mean that a prior instance of your program which is no longer running still has some socket resources open in the OS.
In the latter case, a call to setsockopt (not setsocket) with the SO_REUSEADDR parameter will address this. The fourth parameter should be a pointer to a char whose value is 1, while the fifth parameter should be sizeof(char).
For the users who are facing the problem in bind() function that generate error of the type: Address Already in Use. Here is one tip:
My problem was because the program ran and an address being used by the bind() and then the program generated errors and stopped/terminated. So the unlink() function at the end of the code had no chance to do its job and the address kept in use. So simplest way is at the beginning of the function unlink the processes you are going to bind later in the function.
This seems like so simple and I don't know if it is a good practice but it worked for my purpose.

select() returning 1 even in case process on remote host bound to a given port is killed

I have written a program using non-blocking connect() and select() combination to check the connection to a remote host at a
particular port. select() has some timeout value also, in my case 2.5s. I am testing the program to connect to a process running the SMTP service on the remote host which is
which is bound to port 25 . If I kill that process running on remote host , then also select() returning 1 to tell that writing (socket added to write fd_set ) to that process
is possible. What can be the reason behind this, and also Is it possible to use select() in this case. I tried using connect() which returns immediately when such connection is not possible but it doesn't work in case some timeout is required for connection, that is why I am using select().
select() doesn't tell you that reading or writing is possible, it just tells you that it won't block (or return the error EWOULDBLOCK if the socket is in non-blocking mode). A socket is always writable as long as the local socket buffer is not full. Also, if anything was sent after the remote process has died, you will receive a RST packet, and attempts to write after that will return ECONNRESET immediately. So the socket will be marked writable when that happens.
I was able to accomplish by using another connect() after select() function call.
Posting the code snippet
error = connect(soc, (struct sockaddr *)serveraddr, sizeof(struct sockaddr)) ;
if(error == 0){
DIAGC("vsrserv", 1, "Returning while connect is 0");
return 0;
}
if(errno != EINPROGRESS)
return -1;
int retVal = select (soc+1, &writeFD, (fd_set *)NULL, (fd_set *)NULL, (struct timeval *)(&timeout));
if (retVal == 0){
close(soc);
return -1;
}
socklen_t len = 0;
int m = getsockopt(soc, SOL_SOCKET, SO_ERROR, &error, &len) ;
if(m < 0){
close(soc);
return -1;
}
//connect() returns immediately if it is able to connect to that particular port
//Since select() returned 1 it means host was reachable so just need to verify the port on the remote host which we can do with another with connect() call
error = connect(soc, (struct sockaddr *)serveraddr, sizeof(struct sockaddr)) ;
if(error < 0){
close(soc);
return -1;
}

sendto : Resource temporarily unavailable (errno 11)

I am having a problem with sendto.
I have a receiver who receives UPD packets with recvfrom and then replies to the sender using sendto.
Unfortunately, I am getting errno 11 (Resource temporarily unavailable). I am using two sockets.
The first packet is actually sent but not the ones afterwards:
sendto :: Success
error: 0.
sendto :: Resource temporarily unavailable
error: 11.
sendto :: Resource temporarily unavailable
...
This is an extract of my code:
int sockfd, sockSend;
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
perror("socket");
if ((sockSend = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
perror("socket");
if (fcntl(sockfd, F_SETOWN, getpid()) < 0) {
perror("fcntl");
}
if (fcntl(sockfd, F_SETFL, O_RDONLY | O_NONBLOCK | FASYNC) < 0) {
perror("fcntl");
}
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr))
< 0)
perror("bind");
And in a SIGIO handler:
len = sizeof(recv_addr);
char buffer[payload];
bzero(buffer, payload);
n = recvfrom(sockfd, buffer, payload, MSG_DONTWAIT, (struct sockaddr *)&recv_addr, &len);
while (n > 0) {
sprintf(response, "%d\n%d\n%d\n", items, target_buf, pb_sp);
sendto(sockSend, response, strlen(response), 0, (struct sockaddr *) &recv_addr, sizeof(recv_addr));
// sleep(1);
perror("sendto :");
printf("error: %d.\n", errno);
}
Could this issue come because the port is still hot, and I need to wait before reusing it? I've tried to change port but it hasn't helped.
Update: If the sleep(1) is commented out, then the packets actually get send!
Thanks a lot for your help.
The error you are getting:
EAGAIN or EWOULDBLOCK: The socket is marked nonblocking and the requested operation would block. POSIX.1-2001 allows either error to be returned for this case, and does not require these constants to have the same value, so a portable application should check for both possibilities.
You set the socket to non-blocking (O_NONBLOCK). The socket is still busy sending the previous message. You cannot send another until the first has finished sending. That's why sleeping helped.
Don't set it to non-blocking, or try again after select says you can.
If you have to set the socket to non-blocking, you can do it safely (and only?) using select:
select() and pselect() allow a program to monitor multiple file descriptors, waiting until one or more of the file descriptors become "ready" for some class of I/O operation (e.g., input possible). A file descriptor is considered ready if it is possible to perform the corresponding I/O operation (e.g., read(2)) without blocking.

Resources