exec other program and connect to it with unix domain - linux

i exec a server program(it is a socket server, unix domain), and connect to it.
maybe the server is starting, so connect awalys fail with errno is ENOENT.
i have
setsockopt(m_socketfd, SOL_SOCKET, SO_SNDTIMEO, &timeout, len);
it still fails.
does anybody know a good solution.
thanks.

bool KRpcSelectThread::connectToServer(const string &port, timeval timeout)
{
int ret;
if ((m_socketfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
return false;
socklen_t len;
timeval oldtimeout;
if (getsockopt(m_socketfd, SOL_SOCKET, SO_SNDTIMEO, &oldtimeout, &len) < 0 || len < 0)
oldtimeout = timeout;
len = sizeof(timeout);
setsockopt(m_socketfd, SOL_SOCKET, SO_SNDTIMEO, &timeout, len);
//int flag = 1;
//setsockopt(m_socketfd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int));
struct sockaddr_un server_addr;
bzero(&server_addr,sizeof(server_addr));
server_addr.sun_family = AF_UNIX;
strncpy(server_addr.sun_path, port.c_str(), strlen(port.c_str()));
socklen_t server_addr_length = sizeof(server_addr);
ret = ::connect(m_socketfd, (struct sockaddr*)&server_addr, server_addr_length);
if (ret < 0)
{
int er = errno;
return false;
}
steps:
1. fork and exec another server program(listen unix domain)
2. run this function connectToServer
maybe server is starting(before listen), so it cause connect failed ?

Related

Can a single request image display, request page only display page content?

I use epoll to get the file descriptor that needs to be read, and when I request a page with an image, my socket only receives one request for the page, and no further events are fired.
When I requested the image individually, it successfully accepted the request and returned.
When I looked at the browser's request, it also requested twice, once for a page and once for an image.
I tried not to use epoll, but it still does.
There are times when I can request an image, such as when I go to the next page and return.
Also, when using epoll, the listening socket accepts multiple connections, shouldn't you only use the same connection? Why would it accept other connections when it seems to do nothing?
void Server::serverListen()
{
int listenfd = socket(AF_INET, SOCK_STREAM, 0);
assert(listenfd >= 0);
sockaddr_in addr;
bzero(&addr, sizeof(addr));
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(port);
addr.sin_family = AF_INET;
int tmp = 1;
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
int ret = bind(listenfd, (sockaddr*)&addr, sizeof(addr));
assert(ret >= 0);
ret = listen(listenfd, 5);
assert(ret >= 0);
int epollfd = epoll_create(5);
assert(epollfd != -1);
epoll_event events;
events.data.fd = listenfd;
events.events = EPOLLIN;
int n = epoll_ctl(epollfd, EPOLL_CTL_ADD, listenfd, &events);
assert(n != -1);
epoll_event eve[10000];
while (true)
{
int num = epoll_wait(epollfd, eve, 10000, -1);
assert(num != -1);
for (int i = 0; i < num; ++i)
{
int fd = eve[i].data.fd;
if (fd == listenfd)
{
sockaddr_in caddr;
socklen_t tmplen = sizeof(caddr);
connfd = accept(listenfd, (sockaddr*)&caddr, &tmplen);
assert(connfd != -1);
int flag = fcntl(connfd, F_GETFL);
flag |= O_NONBLOCK;
fcntl(connfd, F_SETFL, flag);
epoll_event even;
even.data.fd = connfd;
even.events = EPOLLIN | EPOLLET | EPOLLONESHOT;
int n = epoll_ctl(epollfd, EPOLL_CTL_ADD, connfd, &even);
assert(n != -1);
}
else
{
worker.init(eve[i].data.fd, epollfd, "localhost", "us", "mm", "usersdb", 3306, 5);
threadpool->add(&worker);
}
}
}
close(epollfd);
close(listenfd);
}

getsockopt doesn't return error when trying to connect to a closed port

I try to use connect() & O_NONBLOCK to connect to a port in localhost asynchronously. In order to get the connect result, I use getsockopt to check the socket error status. I can sure no one listen to this port, so ECONNREFUSED should be returned. But in my test, this error may not be returned in some cases.
My test program:
int main() {
uint64_t p = 0;
while (1) {
int fd = ::socket(PF_INET, SOCK_STREAM, 0);
assert(fd > 0);
int flags = ::fcntl(fd, F_GETFL, 0);
flags |= O_NONBLOCK;
int ret = ::fcntl(fd, F_SETFL, flags);
assert(ret != -1);
sockaddr_in addr;
bzero(&addr, sizeof(sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_port = htons(25400);
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
ret = ::connect(fd, (sockaddr *)&addr, sizeof(sockaddr));
assert(ret != 0);
switch (errno) {
case EINPROGRESS:
case EINTR:
case EISCONN:
break;
default:
assert(false);
}
int epfd = epoll_create1(0);
assert(epfd > 0);
epoll_event ev;
ev.events = EPOLLOUT;
ev.data.fd = fd;
ret = epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev);
assert(ret == 0);
epoll_event events;
auto nfds = epoll_wait(epfd, &events, 1, -1);
assert(nfds == 1);
assert(events.data.fd == fd);
int err;
socklen_t optlen = static_cast<socklen_t>(sizeof err);
ret = ::getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &optlen);
assert(ret == 0);
assert(err != 0);
::close(fd);
::close(epfd);
if (p++ % 10000 == 0) {
std::cout << p << std::endl;
}
}
}
assert(err != 0); will be triggered.
In this test code, I use connect() without bind(), in this case, the source port is choosen by kernel. So the source port may be the same as destination port 25400. Due to the destination ip address is localhost, this TCP connection can be established in this case.

Understandng the reason for recv blocking forever

I run a Linux program written in C that would periodically receive data by parsing an HTTP response, crunch some numbers and then report the result by HTTP GET of another web page.
My problem is that sometimes, one of the instances would "freeze".
Looking at top I can see that it is in sk_wait_data state and attaching a debugger reveals that it is blocked by a recv call.
Here is a minimal version of the code that does the TCP connection (it was adapted from http://www.linuxhowtos.org/C_C++/socket.htm):
int connectTCP(const char* host, const char* page, int portno) {
int sockfd;
struct sockaddr_in serv_addr;
struct hostent *server;
// Create socket //
sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sockfd < 0)
error("ERROR opening socket");
// Get ip from hostname //
server = gethostbyname(host);
if (server == NULL)
error("ERROR, can not find host\n");
memset((char *) &serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
memcpy((char *)&serv_addr.sin_addr.s_addr, // Destination
(char *)server->h_addr, // Source
server->h_length); // Size
serv_addr.sin_port = htons(portno);
// Conect to socket //
if (connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
error("ERROR connecting");
return sockfd;
}
char* httpGet(const char* host, const char* page, int portno) {
int sockfd, n;
sockfd = connectTCP(host, page, portno);
memset(buffer, 0, sizeof(buffer));
sprintf(buffer, "GET /%s HTTP/1.0\r\nHost: %s\r\n\r\n", page, host);
n = send(sockfd,buffer,strlen(buffer), 0);
if (n < 0)
error("ERROR writing to socket");
int count = 0;
do {
n = recv(sockfd, buffer + count, BUFFER_MAX_SIZE - count, 0);
if (n < 0) {
error("ERROR reading from socket");
}
count += n;
} while(n != 0);
close(sockfd);
return buffer;
}
Bugs in your code:
If recv() returns zero you whould close the socket and stop reading.
If recv() returns -1 you should report the error, close the socket, and stop reading, unless you had set a read timeout and errno was EAGAIN/EWOULDBLOCK, in which case you should handle the timeout however is appropriate for your application.

how to read/write from/to a SOCK_SEQPACKET socket?

I try to use a SOCK_SEQPACKET socket with this:
int rc, len;
int worker_sd, pass_sd;
char buffer[80];
struct iovec iov[1];
struct msghdr msg;
memset(&msg, 0, sizeof(msg));
memset(iov, 0, sizeof(iov));
iov[0].iov_base = buffer;
iov[0].iov_len = sizeof(buffer);
msg.msg_iov = iov;
msg.msg_iovlen = 1;
if((socket_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0)) < 0)
{
perror("server: socket");
exit -1;
}
memset(&server_address, 0, sizeof(server_address));
server_address.sun_family = AF_UNIX;
strcpy(server_address.sun_path, "/mysocket");
unlink("/mysocket");
if(bind(socket_fd, (const struct sockaddr *) &server_address, sizeof(server_address)) < 0)
{
close(socket_fd);
perror("server: bind error");
return 1;
}
while(1)
{
printf("wait for message\n");
bytes_received = recvmsg(socket_fd, &msg, MSG_WAITALL);
printf("%d bytes\n", bytes_received);
}
The problem is that the process does not wait but receives -1 from recvmsg and loops forever. Nowhere in the manpages is there any reference what functions shall be used with SOCK_SEQPACKET-style sockets, for example I am not really sure whether recvmsg is even the correct function.
SOCK_SEQPACKET is connection-orientated so you must first accept a connection then do your IO on the accepted client socket.
recvmsg() returns -1 when an error has occured - errno will be set to the error number.
Read here: http://pubs.opengroup.org/onlinepubs/009695399/functions/recvmsg.html

Non blocking connect call doesn't return connection refused

I have setup a timeout on a non-blocking connect call, which timesout correctly when the connection is attempted to an address that will not respond.
However, when the connection is refused by the destination, it does not seem to return the connection refused call.
int x = fcntl(iSock,F_GETFL, 0);
fcntl(iSock,F_SETFL, x | O_NONBLOCK);
fd_set writeFD;
FD_ZERO(&writeFD);
FD_SET(iSock, &writeFD);
timeval timeout;
timeout.tv_sec = 30;
timeout.tv_usec = 0;
errno = 0;
if ((iStat = connect(iSock, (struct sockaddr *)&addr, sizeof(addr))) < 0)
{
if(errno == EINPROGRESS)
{
if(int retval = (select (iSock+1, (fd_set *)NULL, &writeFD, (fd_set *)NULL, (struct timeval *)(&timeout)) > 0) )
{
socklen_t len = 0;
int error = 0;
if (getsockopt(iSock, SOL_SOCKET, SO_ERROR, &error, &len) < 0)
return (-1);
if (error == EINPROGRESS)
{
close(iSock);
errno = error;
return (-1);
}
else
{
printf("Connected \n");
return 0;
}
}
else
{
printf("Not Connected - %d\n", errno);
close(iSock);
return iStat;
}
}
else
{
close(iSock);
return iStat;
}
}
From the connect call, it always seems to return EINPROGRESS, then the select call will return > 0 with error set as 0.
When I change this to a blocking connect call, I get the return code of CONNECTIONREFUSED immediately from the connect call.
The socklen_t len = 0; is incorrect.
This needs to be set to
socklen_t len = sizeof(int);
Setting this value fixed the issue, and the correct return code (CONNREFUSED) was set from the select call
I think that socklen_t len = sizeof(error); better than sizeof(int).
It is same result.

Resources