/** * Accepts an incoming connection by forking a receiver process. * @param server_sock - socket that this connection came in to * @param new_sock - socket to be update with the value of the accepter socket * @returns 1 on success, 0 on error */ inline static int accept_connection(int server_sock,int *new_sock) { unsigned int length; struct sockaddr_in remote; int pid; /* do accept */ length = sizeof( struct sockaddr_in); *new_sock = accept( server_sock, (struct sockaddr*)&remote, &length); if (*new_sock==-1) { LOG(L_ERR,"ERROR:accept_connection(): accept failed!\n"); goto error; } else { LOG(L_INFO,"INFO:accept_connection(): new tcp connection accepted!\n"); } /* initialise stuff for the new socket, to handle later. */ receiver_init(*new_sock,0); #ifdef CDP_FOR_SER pid = fork_process(server_sock,"receiver R",0); #else pid = fork(); #endif if (pid<0){ LOG(L_ERR,"ERROR:accept_connection(): fork() failed > %s\n",strerror(errno)); goto error; } if (pid==0){ /* child */ if (listening_socks) { pkg_free(listening_socks); listening_socks=0; } dp_add_pid(pid); /* jump to this method in recieve.c */ receiver_process(*new_sock); LOG(L_CRIT,"ERROR:accept_connection(): receiver_process finished without exit!\n"); exit(-1); }else{ /* parent */ LOG(L_INFO,"INFO:accept_connection(): Receiver process forked [%d]\n",pid); } return 1; error: return 0; }
/** * Start the CDiameterPeer operations. * It forks all the processes required. * @param blocking - if this is set, use the calling processes for the timer and never * return; else fork a new one for the timer and return * @returns 1 on success, 0 on error, never if blocking */ int diameter_peer_start(int blocking) { int pid; int k=0; peer *p; /* fork workers */ for(k=0;k<config->workers;k++){ pid = fork_process(1001+k,"cdp_worker",1); if (pid==-1){ LM_CRIT("init_diameter_peer(): Error on fork() for worker!\n"); return 0; } if (pid==0) { srandom(time(0)*k); snprintf(pt[process_no].desc, MAX_PT_DESC,"cdp worker child=%d", k ); if (cfg_child_init()) return 0; worker_process(k); LM_CRIT("init_diameter_peer(): worker_process finished without exit!\n"); exit(-1); }else{ dp_add_pid(pid); } } /* init the fd_exchange pipes */ receiver_init(NULL); for(p = peer_list->head,k=0;p;p=p->next,k++) receiver_init(p); /* fork receiver for unknown peers */ pid = fork_process(1001+k,"cdp_receiver_peer_unkown",1); if (pid==-1){ LM_CRIT("init_diameter_peer(): Error on fork() for unknown peer receiver!\n"); return 0; } if (pid==0) { srandom(time(0)*k); snprintf(pt[process_no].desc, MAX_PT_DESC, "cdp receiver peer unknown"); if (cfg_child_init()) return 0; receiver_process(NULL); LM_CRIT("init_diameter_peer(): receiver_process finished without exit!\n"); exit(-1); }else{ dp_add_pid(pid); } /* fork receivers for each pre-configured peers */ lock_get(peer_list_lock); for(p = peer_list->head,k=-1;p;p = p->next,k--){ pid = fork_process(1001+k,"cdp_receiver_peer",1); if (pid==-1){ LM_CRIT("init_diameter_peer(): Error on fork() for peer receiver!\n"); return 0; } if (pid==0) { srandom(time(0)*k); snprintf(pt[process_no].desc, MAX_PT_DESC, "cdp_receiver_peer=%.*s", p->fqdn.len,p->fqdn.s ); if (cfg_child_init()) return 0; receiver_process(p); LM_CRIT("init_diameter_peer(): receiver_process finished without exit!\n"); exit(-1); }else{ dp_add_pid(pid); } } lock_release(peer_list_lock); /* Fork the acceptor process (after receivers, so it inherits all the right sockets) */ pid = fork_process(1000,"cdp_acceptor",1); if (pid==-1){ LM_CRIT("init_diameter_peer(): Error on fork() for acceptor!\n"); return 0; } if (pid==0) { if (cfg_child_init()) return 0; acceptor_process(config); LM_CRIT("init_diameter_peer(): acceptor_process finished without exit!\n"); exit(-1); }else{ dp_add_pid(pid); } /* fork/become timer */ if (blocking) { dp_add_pid(getpid()); if (cfg_child_init()) return 0; timer_process(1); } else{ pid = fork_process(1001,"cdp_timer",1); if (pid==-1){ LM_CRIT("init_diameter_peer(): Error on fork() for timer!\n"); return 0; } if (pid==0) { if (cfg_child_init()) return 0; timer_process(0); LM_CRIT("init_diameter_peer(): timer_process finished without exit!\n"); exit(-1); }else{ dp_add_pid(pid); } } return 1; }
/** * Initiate a connection to a peer. * @param p - peer to connect to * @returns socket if OK, -1 on error */ int peer_connect(peer *p) { int sock; int pid; unsigned char servip[4]; struct sockaddr_in servaddr; unsigned int option = 1; struct hostent *host=0; host = gethostbyname(p->fqdn.s); if (!host){ LOG(L_WARN,"WARNING:peer_connect(): Error opening connection to %.*s:%d >%s\n", p->fqdn.len,p->fqdn.s,p->port,strerror(h_errno)); goto error; } sock = socket(AF_INET, SOCK_STREAM, 0); if ( sock==-1) { LOG(L_ERR,"ERROR:peer_connect(): cannot connect, failed to create " "new socket\n"); goto error; } memset( &servip, 0, sizeof(servip) ); memcpy( &servip, host->h_addr_list[0], 4); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(p->port); servaddr.sin_addr.s_addr = *(unsigned int*)servip; if (connect(sock,(struct sockaddr*)&servaddr, sizeof(struct sockaddr_in))!=0) { LOG(L_WARN,"WARNING:peer_connect(): Error opening connection to %.*s:%d >%s\n", p->fqdn.len,p->fqdn.s,p->port,strerror(errno)); goto error; } setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&option,sizeof(option)); LOG(L_INFO,"INFO:peer_connect(): Peer %.*s:%d connected\n",p->fqdn.len,p->fqdn.s,p->port); receiver_init(sock,p); #ifdef CDP_FOR_SER pid = fork_process(p->port,"receiver I",0); #else pid = fork(); #endif if (pid<0){ LOG(L_ERR,"ERROR:peer_connect(): fork() failed > %s\n",strerror(errno)); goto error; } if (pid==0){ /* child */ receiver_process(sock); LOG(L_CRIT,"ERROR:peer_connect(): receiver_process finished without exit!\n"); exit(-1); }else{ /* parent */ LOG(L_INFO,"INFO:peer_connect(): Receiver process forked [%d]\n",pid); dp_add_pid(pid); } return sock; error: return -1; }
/** * Initiate a connection to a peer. * @param p - peer to connect to * @returns socket if OK, -1 on error */ int peer_connect(peer *p) { int sock; int pid; unsigned int option = 1; struct addrinfo *ainfo=0,*res=0,hints; char buf[256],host[256],serv[256]; int error; memset (&hints, 0, sizeof(hints)); //hints.ai_protocol = IPPROTO_SCTP; //hints.ai_protocol = IPPROTO_TCP; hints.ai_flags = AI_ADDRCONFIG; hints.ai_socktype = SOCK_STREAM; sprintf(buf,"%d",p->port); error = getaddrinfo(p->fqdn.s, buf, &hints, &res); if (error!=0){ LOG(L_WARN,"WARNING:peer_connect(): Error opening connection to %.*s:%d >%s\n", p->fqdn.len,p->fqdn.s,p->port,gai_strerror(error)); goto error; } for(ainfo = res;ainfo;ainfo = ainfo->ai_next) { if (getnameinfo(ainfo->ai_addr,ainfo->ai_addrlen, host,256,serv,256,NI_NUMERICHOST|NI_NUMERICSERV)==0){ LOG(L_WARN,"INFO:peer_connect(): Trying to connect to %s port %s\n", host,serv); } if ((sock = socket(ainfo->ai_family, ainfo->ai_socktype, ainfo->ai_protocol)) == -1) { LOG(L_ERR,"ERROR:create_socket(): error creating client socket to %s port %s >" " %s\n",host,serv,strerror(errno)); continue; } if (connect(sock,ainfo->ai_addr,ainfo->ai_addrlen)!=0) { LOG(L_WARN,"WARNING:peer_connect(): Error opening connection to to %s port %s >%s\n", host,serv,strerror(errno)); close(sock); continue; } setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&option,sizeof(option)); LOG(L_INFO,"INFO:peer_connect(): Peer %.*s:%d connected\n",p->fqdn.len,p->fqdn.s,p->port); receiver_init(sock,p); #ifdef CDP_FOR_SER pid = fork_process(p->port,"receiver I",0); #else pid = fork(); #endif if (pid<0){ LOG(L_ERR,"ERROR:peer_connect(): fork() failed > %s\n",strerror(errno)); goto error; } if (pid==0){ /* child */ receiver_process(sock); LOG(L_CRIT,"ERROR:peer_connect(): receiver_process finished without exit!\n"); exit(-1); }else{ /* parent */ LOG(L_INFO,"INFO:peer_connect(): Receiver process forked [%d]\n",pid); dp_add_pid(pid); } if (res) freeaddrinfo(res); return sock; } error: if (res) freeaddrinfo(res); return -1; }
/** * Start the CDiameterPeer operations. * It forks all the processes required. * @param blocking - if this is set, use the calling processes for the timer and never * return; else fork a new one for the timer and return * @returns 1 on success, 0 on error, never if blocking */ int diameter_peer_start(int blocking) { int pid; int k=0; /* Fork the acceptor process */ #ifdef CDP_FOR_SER pid = fork_process(1000,"cdp_acceptor",1); #else pid = fork(); #endif if (pid==-1){ LOG(L_CRIT,"ERROR:init_diameter_peer(): Error on fork() for acceptor!\n"); return 0; } if (pid==0) { acceptor_process(config); LOG(L_CRIT,"ERROR:init_diameter_peer(): acceptor_process finished without exit!\n"); exit(-1); }else{ dp_add_pid(pid); } /* fork workers */ for(k=0;k<config->workers;k++){ #ifdef CDP_FOR_SER pid = fork_process(1001+k,"cdp_worker",1); #else pid = fork(); #endif if (pid==-1){ LOG(L_CRIT,"ERROR:init_diameter_peer(): Error on fork() for worker!\n"); return 0; } if (pid==0) { srandom(time(0)*k); #ifdef CDP_FOR_SER snprintf(pt[process_no].desc, MAX_PT_DESC, "cdp worker child=%d", k ); #endif worker_process(k); LOG(L_CRIT,"ERROR:init_diameter_peer(): worker_process finished without exit!\n"); exit(-1); }else{ dp_add_pid(pid); } } /* fork/become timer */ if (blocking) { dp_add_pid(getpid()); timer_process(1); } else{ #ifdef CDP_FOR_SER pid = fork_process(1001,"cdp_timer",1); #else pid = fork(); #endif if (pid==-1){ LOG(L_CRIT,"ERROR:init_diameter_peer(): Error on fork() for timer!\n"); return 0; } if (pid==0) { timer_process(0); LOG(L_CRIT,"ERROR:init_diameter_peer(): timer_process finished without exit!\n"); exit(-1); }else{ dp_add_pid(pid); } } return 1; }