/* * Find an empty file descriptor entry, and mark it busy. */ int get_unused_fd(void) { struct files_struct * files = current->files; int fd, error; error = -EMFILE; write_lock(&files->file_lock); repeat: fd = find_next_zero_bit(files->open_fds, files->max_fdset, files->next_fd); /* * N.B. For clone tasks sharing a files structure, this test * will limit the total number of files that can be opened. */ if (fd >= current->rlim[RLIMIT_NOFILE].rlim_cur) goto out; /* Do we need to expand the fdset array? */ if (fd >= files->max_fdset) { error = expand_fdset(files, fd); if (!error) { error = -EMFILE; goto repeat; } goto out; } /* * Check whether we need to expand the fd array. */ if (fd >= files->max_fds) { error = expand_fd_array(files, fd); if (!error) { error = -EMFILE; goto repeat; } goto out; } FD_SET(fd, files->open_fds); FD_CLR(fd, files->close_on_exec); files->next_fd = fd + 1; #if 1 /* Sanity check */ if (files->fd[fd] != NULL) { printk(KERN_WARNING "get_unused_fd: slot %d not NULL!\n", fd); files->fd[fd] = NULL; } #endif error = fd; out: write_unlock(&files->file_lock); return error; }
static int copy_files(unsigned long clone_flags, struct task_struct * tsk) { struct files_struct *oldf, *newf; struct file **old_fds, **new_fds; int open_files, nfds, size, i, error = 0; /* * A background process may not have any files ... */ oldf = current->files; if (!oldf) goto out; if (clone_flags & CLONE_FILES) { atomic_inc(&oldf->count); goto out; } /* * Note: we may be using current for both targets (See exec.c) * This works because we cache current->files (old) as oldf. Don't * break this. */ tsk->files = NULL; error = -ENOMEM; newf = kmem_cache_alloc(files_cachep, SLAB_KERNEL); if (!newf) goto out; atomic_set(&newf->count, 1); newf->file_lock = SPIN_LOCK_UNLOCKED; newf->next_fd = 0; newf->max_fds = NR_OPEN_DEFAULT; newf->max_fdset = __FD_SETSIZE; newf->close_on_exec = &newf->close_on_exec_init; newf->open_fds = &newf->open_fds_init; newf->fd = &newf->fd_array[0]; /* We don't yet have the oldf readlock, but even if the old fdset gets grown now, we'll only copy up to "size" fds */ size = oldf->max_fdset; if (size > __FD_SETSIZE) { newf->max_fdset = 0; spin_lock(&newf->file_lock); error = expand_fdset(newf, size-1); spin_unlock(&newf->file_lock); if (error) goto out_release; } spin_lock(&oldf->file_lock); open_files = count_open_files(oldf, size); /* * Check whether we need to allocate a larger fd array. * Note: we're not a clone task, so the open count won't * change. */ nfds = NR_OPEN_DEFAULT; if (open_files > nfds) { spin_unlock(&oldf->file_lock); newf->max_fds = 0; spin_lock(&newf->file_lock); error = expand_fd_array(newf, open_files-1); spin_unlock(&newf->file_lock); if (error) goto out_release; nfds = newf->max_fds; spin_lock(&oldf->file_lock); } old_fds = oldf->fd; new_fds = newf->fd; memcpy(newf->open_fds->fds_bits, oldf->open_fds->fds_bits, open_files/8); memcpy(newf->close_on_exec->fds_bits, oldf->close_on_exec->fds_bits, open_files/8); for (i = open_files; i != 0; i--) { struct file *f = *old_fds++; if (f) get_file(f); *new_fds++ = f; } spin_unlock(&oldf->file_lock); /* compute the remainder to be cleared */ size = (newf->max_fds - open_files) * sizeof(struct file *); /* This is long word aligned thus could use a optimized version */ memset(new_fds, 0, size); if (newf->max_fdset > open_files) { int left = (newf->max_fdset-open_files)/8; int start = open_files / (8 * sizeof(unsigned long)); memset(&newf->open_fds->fds_bits[start], 0, left); memset(&newf->close_on_exec->fds_bits[start], 0, left); } tsk->files = newf; error = 0; out: return error; out_release: free_fdset (newf->close_on_exec, newf->max_fdset); free_fdset (newf->open_fds, newf->max_fdset); kmem_cache_free(files_cachep, newf); goto out; }
void udp_relayX(Connection *Conn,int csc,int csv[]) { int svsock; int sockv[1024],readyv[1024],sx; /* must be lt/eq FD_SESIZE */ int nsock; /* number of clients */ CStr(buff,0x8000); int rcc,wcc; int nready; CStr(ihost,64); int iport; CStr(svhost,64); int svport; const char *clhost; int clport; UDP_Assoc *ua; UDP_Assoc *udpav[MAXASSOC*4]; /**/ int udpxv[MAXASSOC*4]; int lastrelay,idle; const char *aaddr; int svportmap; int portnumv[64]; int csi; int istcp[MAXASSOC]; int ccc = 0; /* tcp clients */ int usocks = 0; /* UDP SOCKS */ int update = 0; int ai; /* is this necessary or effective ? */ socks_addservers(); if( MAXASSOC < UDPRELAY_MAXASSOC ){ UDPRELAY_MAXASSOC = MAXASSOC; } sv1log("MAXIMA=udprelay:%d (max. udp assoc.)\n",UDPRELAY_MAXASSOC); if( (aaddr = gethostaddr(DST_HOST)) == NULL ){ sv1log("#### ERROR: bad destination host [%s]\n",DST_HOST); return; } strcpy(svhost,aaddr); svport = DST_PORT; svportmap = DFLT_PORTMAP; if( svportmap ){ /* get port numbers of incoming ports ... */ for( csi = 0; csi < csc; csi++ ){ portnumv[csi] = sockPort(csv[csi]) + svportmap; portnumv[csi] &= ~0x40000000; /* clear IS_PORTMAP */ } } expand_fdset(MAXASSOC); uassocv = (UDP_Assoc**)calloc(MAXASSOC+1,sizeof(UDP_Assoc*)); for( csi = 0; csi < csc; csi++ ) sockv[csi] = csv[csi]; for( csi = 0; csi < csc; csi++ ) istcp[csi] = !isUDPsock(sockv[csi]); nsock = 0; lastrelay = 0; for(;;){ UPDATE: if( update ){ int ai; update = 0; ccc = 0; for( ai = 0; ua = uassocv[ai]; ai++ ){ if( ua->ua_clpriv ){ udpxv[csc + ccc] = ai; udpav[csc + ccc] = ua; sockv[csc + ccc++] = ua->ua_clsock; } } nsock = 0; for( ai = 0; ua = uassocv[ai]; ai++ ){ udpxv[csc+ccc + nsock] = ai; udpav[csc+ccc + nsock] = ua; sockv[csc+ccc + nsock++] = ua->ua_svsock; } usocks = 0; for( ai = 0; ua = uassocv[ai]; ai++ ){ int ns = csc+ccc+nsock; if( 0 <= ua->ua_svSOCKS ){ udpxv[ns+usocks] = ai; udpav[ns+usocks] = ua; sockv[ns+usocks] = ua->ua_svSOCKS; usocks++; } } } /* nready = PollIns(10*1000,csc+nsock+ccc,sockv,readyv); */ nready = PollIns(10*1000,csc+ccc+nsock+usocks,sockv,readyv); if( nready < 0 ){ /* sv1log("UDPRELAY: ABORT PollIns(%d) = %d\n",nready); */ sv1log("UDPRELAY: ABORT PollIns(%d+%d+%d+%d)=%d\n", csc,ccc,nsock,usocks,nready); for( ai = 0; ai < csc+ccc+nsock+usocks; ai++ ){ sv1log("[%2d] %d\n",ai,sockv[ai]); } break; } if( nready == 0 ){ idle = time(0) - lastrelay; if( SERVER_TIMEOUT && lastrelay ) if( SERVER_TIMEOUT < idle){ sv1log("UDPRELAY: SERVER TIMEOUT (idle %ds)\n", idle); break; } killTimeouts(uassocv); /* nsock = getsocks(uassocv,&sockv[csc]); */ update = 1; continue; } lastrelay = time(0); for( sx = 0; sx < csc; sx++ ) if( 0 < readyv[sx] && istcp[sx] ){ CStr(local,256); CStr(remote,256); int clsk; strcpy(remote,"*:*"); strcpy(local,"*:*"); clsk = VSocket(Conn,"ACPT/",sockv[sx],AVStr(local),AVStr(remote),""); /* setNonblockingIO("UDPRELAY-CL",clsk,1); */ SetNonblockingIO("UDPRELAY-CL",clsk,1); iport = getpeerAddr(clsk,AVStr(ihost)); if( clsk <= 0 || iport <= 0 ){ sv1log("UDPRELAY: accept() errno=%d\n",errno); continue; } if( svportmap ){ svport = portnumv[sx]; } ua = newUA(Conn,uassocv,ihost,iport,svhost,svport); ua->ua_clsock = clsk; ua->ua_clpriv = 1; update = 1; }else if( 0 < readyv[sx] ){ rcc = recvFromA(sockv[sx],AVStr(buff),sizeof(buff),0,AVStr(ihost),&iport); if( rcc <= 0 ){ sv1log("UDPRELAY: recv() == 0, errno=%d\n",errno); break; } if( svportmap ){ svport = portnumv[sx]; } ua = findUAbysrc(uassocv,ihost,iport,svhost,svport); if( ua == NULL ){ ua = newUA(Conn,uassocv,ihost,iport,svhost,svport); if( ua == NULL ){ continue; } ua->ua_clsock = sockv[sx]; if( ua->ua_svsock < 0 ) continue; /* nsock = getsocks(uassocv,&sockv[csc]); */ update = 1; } toServ(ua,buff,rcc,svhost,svport,ihost,iport); /* ua->ua_mtime = time(0); ua->ua_upcnt++; ua->ua_upbytes += rcc; if( UDPRELAY_RPORT_FIX ) wcc = Send(ua->ua_svsock,buff,rcc); else wcc = SendTo(ua->ua_svsock,buff,rcc,svhost,svport); Verbose("TO SERV#%d: %s:%d %3d> %s:%d\n", ua->ua_id,ihost,iport,rcc,svhost,svport); */ if( nready == 1 ) continue; } for( sx = csc; sx < csc+ccc; sx++ ) if( 0 < readyv[sx] ){ rcc = recv(sockv[sx],buff,sizeof(buff),0); if( rcc <= 0 ){ int ux = getUAx(uassocv,udpav[sx]); if( ux < 0 ){ sv1log("## delUA-CL(%d)?\n",ux); continue; } delUA(uassocv,ux,"TCPreset-CL",1); /* here udpxv[] becomes inconsistent */ update = 1; }else{ ua = udpav[sx]; toServ(ua,buff,rcc,svhost,svport,NULL,0); } } /* for( sx = csc; sx < csc+nsock; sx++ ){ */ for( sx = csc+ccc; sx < csc+ccc+nsock; sx++ ){ if( readyv[sx] <= 0 ) continue; ua = udpav[sx]; svsock = sockv[sx]; if( 0 <= ua->ua_svSOCKS ) rcc = RecvFrom(svsock,buff,sizeof(buff),AVStr(ihost),&iport); else rcc = recvFromA(svsock,AVStr(buff),sizeof(buff),0,AVStr(ihost),&iport); if( rcc <= 0 ){ if( ua->ua_svtcp ){ int ux = getUAx(uassocv,udpav[sx]); if( ux < 0 ){ sv1log("## delUA-SV(%d)?\n",ux); continue; } delUA(uassocv,ux,"TCPreset-SV",1); update = 1; } readyv[sx] = -1; continue; } /* ua = findUAbysock(uassocv,svsock); */ ua->ua_mtime = time(0); ua->ua_downcnt++; ua->ua_downbytes += rcc; clhost = ua->ua_clhost; clport = ua->ua_clport; /* wcc = SendTo(ua->ua_clsock,buff,rcc,clhost,clport); */ wcc = sendToA(ua->ua_clsock,buff,rcc,0,clhost,clport); Verbose("TO CLNT#%d: %s:%d <%-3d %s:%d\n", ua->ua_id,clhost,clport,rcc,ihost,iport); } for( sx = csc+ccc+nsock; sx < csc+ccc+nsock+usocks; sx++ ){ int ux; if( readyv[sx] <= 0 ) continue; ua = udpav[sx]; ux = getUAx(uassocv,udpav[sx]); if( ux < 0 ){ sv1log("## delUA-CTL(%d)?\n",ux); continue; } sv1log("## detected disconn. by SOCKS CTL [%d]\n",ux); delUA(uassocv,ux,"SOCKSCTLreset-SV",1); update = 1; } } }