#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
//#include <strings.h>
#include<sys/wait.h>
//#include <string.h>
#include <errno.h>
#include <sys/un.h>
#include <sys/uio.h>
#include <fcntl.h>
#include <limits.h>
#include <sys/stat.h>
///
/********************************* head files **************************************/
//#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>
#include <vector>
#include <iostream>
#include <string>
//#define NULL 0
#include <stdlib.h>
#include <time.h>
using namespace std;
/**************************** Function declaration *********************************/
/* class CUnixSockBase */
class CUnixSockBase
{
protected:
/* 'm_SharePathList' include every proccess's shared path
For example:
m_SharePathList[0] is proccess_0's shared path
m_SharePathList[1] is proccess_1's shared path ...
*/
//vector<string> m_SharePathList;
/* 'm_ProccessNum' is the number of the owner proccess.
For example:
proccess_0's m_ProccessNum is 0
proccess_1's m_ProccessNum is 1
*/
static int m_ProccessNum;
struct sockaddr_un addr;
int m_uSockFd;
public:
CUnixSockBase(){ }
~CUnixSockBase(){ }
int Init(const char* path); //return usock fd
virtual int CreateUnixSock(const char* path)=0;
virtual int SendFd(int sockfd, int fd)=0;
virtual int RecvFd(int fd)=0;
};
/* class CSendUnixSock */
class CSendUnixSock:public CUnixSockBase
{
public:
CSendUnixSock(){ }
~CSendUnixSock(){ }
int CreateUnixSock(const char* path);
int SendFd(int sockfd, int fd);
int RecvFd(int fd){}
};
/* class CSendUnixSock */
class CRecvUnixSock:public CUnixSockBase
{
protected:
//
public:
CRecvUnixSock(){ }
~CRecvUnixSock(){ }
int CreateUnixSock(const char* path);
int RecvFd(int fd);
int SendFd(int sockfd, int fd){}
};
/**************************** Function realize *********************************/
/* class CUnixSockBase */
//vector<string> CServerMgr::m_Programs;
int CUnixSockBase::Init(const char* path)
{
printf("input path name :%s. \r\n",path);
if( path == NULL )
{
printf("input path name error. \r\n");
return -1;
}
m_uSockFd = CreateUnixSock(path);
if(m_uSockFd == -1)
{
printf("serv_create_usockfd error. \r\n");
return -1;
}
return 0;
}
/* class CSendUnixSock */
int CSendUnixSock::CreateUnixSock(const char* path)
{
if( path == NULL )
{
printf("input path name error. \r\n");
return -1;
}
//struct sockaddr_un addr = {0};
int fd;
addr.sun_family = AF_UNIX; //mostly, PF_UNIX=AF_UNIX
strcpy(addr.sun_path, path);
if( (fd = socket(AF_UNIX, SOCK_DGRAM, 0)) == -1)
{
printf("creat unix domain socket failed. \r\n");
return -1;
}
printf("connect unix domain socket ok.\n");
return fd;
}
int CSendUnixSock::SendFd(int sockfd, int fd)
{
/* remember close fd(fd to send) after call SendFd()! */
//struct sockaddr_un addr = {0};
struct msghdr msg = {0};
char ccmsg[CMSG_SPACE(sizeof(fd))];
struct cmsghdr* cmsg; int rv;
msg.msg_name = (struct sockaddr*)&addr;
msg.msg_namelen = sizeof(addr);
msg.msg_control = ccmsg;
msg.msg_controllen = sizeof(ccmsg);
cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
*(int*)CMSG_DATA(cmsg) = fd;
msg.msg_control = ccmsg;
msg.msg_controllen = cmsg->cmsg_len;
msg.msg_flags = 0;
printf("send client fd[%d] to socket fd[%d]\n",fd, sockfd);
rv = sendmsg(sockfd, &msg, 0) ;
//printf("sendmsg return %d \r\n",rv);
if(rv == -1)
{
if(errno == EAGAIN)
{
return 1;
}
else
{
//error
printf("sendmsg error, ret is %d\n", fd);
//close fd_to_send out side
return -1;
}
}
/*else if( rv == 0 )
{
//close fd_to_send out side
printf("sendmsg error, ret is %d\n", rv);
return -1;
} */
printf("send fd[%d] to shared file finish.\r\n", fd);
return 0;
}
/* class CRecvUnixSock */
int CRecvUnixSock::CreateUnixSock(const char* path)
/* server creat unix domain socket. failed return -1. */
{
//struct sockaddr_un addr = {0};
int fd;
unlink(path); //in case it already exists.
if( (fd = socket(AF_UNIX, SOCK_DGRAM, 0)) == -1)
{
printf("creat unix domain socket failed. \r\n");
return -1;
}
addr.sun_family = AF_UNIX; //mostly, PF_UNIX=AF_UNIX
strcpy(addr.sun_path, path);
if( bind(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1 ){
printf(" bind unix domain socket failed, %d, %s\n", errno, strerror(errno));
return -1;
}
printf("bind unix domain socket ok.\n");
return fd;
}
int CRecvUnixSock::RecvFd(int fd)
/* recv internet socket fd. return value >0:succeed ,0:need retry, -1:failed. */
{
struct msghdr msg = {0};
int rv = 0;
int cfd = -1,clientFd=-1;
char ccmsg[CMSG_SPACE(sizeof(cfd))];
struct cmsghdr* cmptr;
msg.msg_control = ccmsg;
msg.msg_controllen = sizeof(ccmsg);
rv = recvmsg(fd, &msg, 0);
if(rv == -1)
{
if(errno == EAGAIN)
{
return 0;
}
else
{
//error
printf("sendmsg error, file fd is %d\n", fd);
return -1;
}
}
/*
else if( rv == 0 )
{
//error
printf("sendmsg error, file fd is %d\n", fd);
return -1;
} */
cmptr = CMSG_FIRSTHDR(&msg);
if((cmptr != NULL) && (cmptr->cmsg_len == CMSG_LEN(sizeof(int))))
{
if(cmptr->cmsg_level != SOL_SOCKET)
{
printf("control level != SOL_SOCKET/n");
return -1;
}
if(cmptr->cmsg_type != SCM_RIGHTS)
{
printf("control type != SCM_RIGHTS/n");
return -1;
}
clientFd = *((int*)CMSG_DATA(cmptr));
}
else
{
if(cmptr == NULL)
printf("null cmptr, fd not passed./n");
else
printf("message len[%d] if incorrect./n", cmptr->cmsg_len);
return -1;
}
printf("recieved client socket fd[%d].\n",clientFd);
return clientFd;
}
/**************************** End *********************************/
using namespace std;
int main(int argc, char* argv[])
{
//***** socket *****
int s_listen_f;
struct sockaddr_in cliaddr,servaddr;
s_listen_f = socket(AF_INET,SOCK_STREAM,0);
//set non_block
int flags = fcntl(s_listen_f, F_GETFL, 0);
if( -1 == fcntl(s_listen_f, F_SETFL, flags|O_NONBLOCK) )
{
printf("Set NONBLOCK for socket fd %d failed", s_listen_f);
exit(1);
}
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(8060);
bind(s_listen_f, (struct sockaddr*)&servaddr, sizeof(struct sockaddr));
listen(s_listen_f, 1024);
//***** socket *****
//string sharePathBase("/home/") ;
string basePath("shareFile_");
//string basePath;
int res = -1,i=0;
int CPU_Num = 5, proccess_num = 2;
char* tmpStr= new char[64];
//fork...
//in child proccess...
// 1,connect server side share file
vector<CSendUnixSock *> m_cliAddrList(CPU_Num,NULL);
for(i=0;i<CPU_Num;i++)
{
if(i != proccess_num)
{
CSendUnixSock *sendSock = new CSendUnixSock;
//ltoa(i,tmpStr,10);
sprintf(tmpStr, "%d",i);
string tmp(basePath.c_str());
res = sendSock->Init((tmp.append(tmpStr)).c_str());
if(res == -1)
{
//error
printf("sendSock init error");
return -1;
}
else
{
m_cliAddrList[i]=sendSock;
}
}
}
//print
for(i=0;i<CPU_Num;i++)
{
cout << "pos:"<<i<<" sendSock ptr:"<< m_cliAddrList[i]<< endl;
}
// 2,listen my own share file
CRecvUnixSock *recvSock = new CRecvUnixSock;
sprintf(tmpStr, "%d",proccess_num);
string tmp(basePath.c_str());
res = recvSock->Init((tmp.append(tmpStr)).c_str());
if(res == -1)
{
//error
printf("recvSock init error");
return -1;
}
// 3,accept internet socket
int s_conn_fd = -1,cli_usock_fd = -1;
for(;;)
{
sleep(2);
printf("[%d] call accept .... \r\n",proccess_num);
socklen_t clilen = sizeof(cliaddr);
// 1, put in internet socket listen main loop
if((s_conn_fd = accept(s_listen_f,(struct sockaddr*)&cliaddr, &clilen)) < 0)
{
if(errno == EAGAIN)
{
continue;
}
else
{
printf("[%d] accept error.\r\n",proccess_num);
return -1;
}
}
printf("[%d] accept succeed. fd:%d \r\n",proccess_num,s_conn_fd);
// 2,(when init unix domain socket)add u_cli_fd to epoll
// 3,when u_cli_fd is writeable
// 4,send internet socket fd to next proccess
int nextProcNum = (proccess_num+1)%CPU_Num;
CSendUnixSock *tmp = m_cliAddrList[nextProcNum];
//int cli_usock_fd = tmp->m_uSockFd;
int cli_usock_fd = -100;
res = tmp->SendFd(cli_usock_fd, s_conn_fd);
printf("[%d] send internet socket fd[%d] to proccess[%d] usock fd[%d] \r\n",proccess_num,s_conn_fd,proccess_num+1, cli_usock_fd);
if(res <= 0)
{
printf("[%d]close socket internet fd[%d]. \r\n",proccess_num,s_conn_fd);
close(s_conn_fd);
}
printf("[%d]send socket fd[%d] to other proccess finish. \r\n",proccess_num,s_conn_fd);
}
return 0;
}