/*********************************************************************** * server_init_process * * Start the server and create the initial socket pair. */ void server_init_process(void) { obj_handle_t version; const char *env_socket = getenv( "WINESERVERSOCKET" ); server_pid = -1; if (env_socket) { fd_socket = atoi( env_socket ); if (fcntl( fd_socket, F_SETFD, 1 ) == -1) fatal_perror( "Bad server socket %d", fd_socket ); unsetenv( "WINESERVERSOCKET" ); } else fd_socket = server_connect(); /* setup the signal mask */ sigemptyset( &server_block_set ); sigaddset( &server_block_set, SIGALRM ); sigaddset( &server_block_set, SIGIO ); sigaddset( &server_block_set, SIGINT ); sigaddset( &server_block_set, SIGHUP ); sigaddset( &server_block_set, SIGUSR1 ); sigaddset( &server_block_set, SIGUSR2 ); sigaddset( &server_block_set, SIGCHLD ); pthread_sigmask( SIG_BLOCK, &server_block_set, NULL ); /* receive the first thread request fd on the main socket */ #ifdef SO_PASSCRED if (server_pid == -1) { int enable = 1; setsockopt( fd_socket, SOL_SOCKET, SO_PASSCRED, &enable, sizeof(enable) ); ntdll_get_thread_data()->request_fd = receive_fd( &version ); enable = 0; setsockopt( fd_socket, SOL_SOCKET, SO_PASSCRED, &enable, sizeof(enable) ); } else #endif ntdll_get_thread_data()->request_fd = receive_fd( &version ); if (version != SERVER_PROTOCOL_VERSION) server_protocol_error( "version mismatch %d/%d.\n" "Your %s binary was not upgraded correctly,\n" "or you have an older one somewhere in your PATH.\n" "Or maybe the wrong wineserver is still running?\n", version, SERVER_PROTOCOL_VERSION, (version > SERVER_PROTOCOL_VERSION) ? "wine" : "wineserver" ); #ifdef __APPLE__ send_server_task_port(); #endif #if defined(__linux__) && defined(HAVE_PRCTL) /* work around Ubuntu's ptrace breakage */ if (server_pid != -1) prctl( 0x59616d61 /* PR_SET_PTRACER */, server_pid ); #endif }
static void parent_bind(int fd) { int sock, status; struct sockaddr_storage ss; socklen_t sslen; int er; logmsg(LOG_DEBUG, "[priv]: msg PRIV_BIND received"); sock = receive_fd(fd); must_read(fd, &sslen, sizeof(sslen)); if (sslen == 0 || sslen > sizeof(ss)) _exit(1); must_read(fd, &ss, sslen); if (check_bind((struct sockaddr *) &ss, sslen)) _exit(1); status = bind(sock, (struct sockaddr *)&ss, sslen); er = errno; must_write(fd, &er, sizeof(er)); must_write(fd, &status, sizeof(status)); if (sock >= 0) close(sock); }
/*********************************************************************** * server_init_process * * Start the server and create the initial socket pair. */ void server_init_process(void) { obj_handle_t dummy_handle; const char *env_socket = getenv( "WINESERVERSOCKET" ); if (env_socket) { fd_socket = atoi( env_socket ); if (fcntl( fd_socket, F_SETFD, 1 ) == -1) fatal_perror( "Bad server socket %d", fd_socket ); unsetenv( "WINESERVERSOCKET" ); } else fd_socket = server_connect(); /* setup the signal mask */ sigemptyset( &server_block_set ); sigaddset( &server_block_set, SIGALRM ); sigaddset( &server_block_set, SIGIO ); sigaddset( &server_block_set, SIGINT ); sigaddset( &server_block_set, SIGHUP ); sigaddset( &server_block_set, SIGUSR1 ); sigaddset( &server_block_set, SIGUSR2 ); sigaddset( &server_block_set, SIGCHLD ); pthread_functions.sigprocmask( SIG_BLOCK, &server_block_set, NULL ); /* receive the first thread request fd on the main socket */ ntdll_get_thread_data()->request_fd = receive_fd( &dummy_handle ); #ifdef __APPLE__ send_server_task_port(); #endif }
/** * Request the fd corresponding to the given connection id to the TCP main process. * You may want to close() the fd after use. * * @param conid - connection id * @param fd - placeholder to return the fd * @return 1 on success, 0 on failure * */ int tcpops_acquire_fd_from_tcpmain(int conid, int *fd) { struct tcp_connection *s_con, *tmp; long msg[2]; int n; if (unlikely((s_con = tcpconn_get(conid, 0, 0, 0, 0)) == NULL)) { LM_ERR("invalid connection id %d, (must be a TCP connid)\n", conid); return 0; } msg[0] = (long)s_con; msg[1] = CONN_GET_FD; n = send_all(unix_tcp_sock, msg, sizeof(msg)); if (unlikely(n <= 0)){ LM_ERR("failed to send fd request: %s (%d)\n", strerror(errno), errno); goto error_release; } n = receive_fd(unix_tcp_sock, &tmp, sizeof(tmp), fd, MSG_WAITALL); if (unlikely(n <= 0)){ LM_ERR("failed to get fd (receive_fd): %s (%d)\n", strerror(errno), errno); goto error_release; } tcpconn_put(s_con); return 1; error_release: tcpconn_put(s_con); return 0; }
static void remote_mobile_open (char *unix_sock_name, int from_tty) { int source_fd; int md_fd; char *name; /* So first we have to get the file descriptor from our provider. */ source_fd = open_unix_socket (unix_sock_name); if (source_fd <= 0) error ("Could not open socket: %s to get mobile device file descriptor.", unix_sock_name); md_fd = receive_fd (source_fd); close (source_fd); if (md_fd < 0) error ("Could not get the mobile device fd - error: %d.\n", md_fd); /* Now construct the file descriptor target name, and push the remote target. */ name = malloc (strlen ("filedesc:") + 12); sprintf (name, "filedesc:%d", md_fd); push_remote_macosx_target (name, from_tty); /* Now that we've gotten the remote target, let's fix up a few things. */ current_target.to_shortname = remote_mobile_shortname; current_target.to_longname = remote_mobile_longname; current_target.to_doc = remote_mobile_doc; }
pcap_dumper_t * priv_pcap_dump_open(pcap_t *p, char *fname) { int fd, err; FILE *f; if (priv_fd < 0) errx(1, "%s: called from privileged portion", __func__); if (fname[0] == '-' && fname[1] == '\0') { f = stdout; priv_init_done(); } else { write_command(priv_fd, PRIV_OPEN_OUTPUT); fd = receive_fd(priv_fd); must_read(priv_fd, &err, sizeof(err)); if (fd < 0) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Failed to open output file %s: %s", fname, strerror(err)); return (NULL); } f = fdopen(fd, "w"); if (f == NULL) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s: %s", fname, pcap_strerror(errno)); close(fd); return (NULL); } } (void)sf_write_header(f, p->linktype, p->tzoff, p->snapshot); return ((pcap_dumper_t *)f); }
int priv_snmp_socket(struct sockaddr_un *addr) { int rc; enum priv_cmd cmd = PRIV_SNMP_SOCKET; must_write(&cmd, sizeof(enum priv_cmd)); must_write(addr, sizeof(struct sockaddr_un)); must_read(&rc, sizeof(int)); if (rc < 0) return rc; return receive_fd(); }
/* Open log-file */ int priv_open_log(void) { int cmd, fd; if (priv_fd < 0) errx(1, "%s: called from privileged portion", __func__); cmd = PRIV_OPEN_LOG; must_write(priv_fd, &cmd, sizeof(int)); fd = receive_fd(priv_fd); return (fd); }
int priv_iface_init(int index, char *iface) { int rc; char dev[IFNAMSIZ]; enum priv_cmd cmd = PRIV_IFACE_INIT; must_write(&cmd, sizeof(enum priv_cmd)); must_write(&index, sizeof(int)); strlcpy(dev, iface, IFNAMSIZ); must_write(dev, IFNAMSIZ); must_read(&rc, sizeof(int)); if (rc != 0) return -1; return receive_fd(); }
/* Proxy for open */ int priv_open(char *file) { int len, rc; enum priv_cmd cmd = PRIV_OPEN; must_write(PRIV_UNPRIVILEGED, &cmd, sizeof(enum priv_cmd)); len = strlen(file); must_write(PRIV_UNPRIVILEGED, &len, sizeof(int)); must_write(PRIV_UNPRIVILEGED, file, len); priv_wait(); must_read(PRIV_UNPRIVILEGED, &rc, sizeof(int)); if (rc == -1) return rc; return receive_fd(PRIV_UNPRIVILEGED); }
/* Open pseudo-tty */ int priv_openpty(int *pty_ptr, int *tty_ptr) { int cmd; int pty, tty; if (priv_fd != -1) { cmd = PRIV_OPEN_PTY; write(priv_fd, &cmd, sizeof(int)); pty = receive_fd(priv_fd); tty = receive_fd(priv_fd); if (tty < 0 || pty < 0) { fprintf(stderr, "openpty: %d %d %d\n", pty, tty, errno); return -1; } if (pty_ptr != NULL) *pty_ptr = pty; if (tty_ptr != NULL) *tty_ptr = tty; return 0; } else return openpty(pty_ptr, tty_ptr, NULL, NULL, NULL); }
/*********************************************************************** * server_get_unix_fd * * The returned unix_fd should be closed iff needs_close is non-zero. */ int server_get_unix_fd( HANDLE handle, unsigned int wanted_access, int *unix_fd, int *needs_close, enum server_fd_type *type, unsigned int *options ) { sigset_t sigset; obj_handle_t fd_handle; int ret = 0, fd; unsigned int access = 0; *unix_fd = -1; *needs_close = 0; wanted_access &= FILE_READ_DATA | FILE_WRITE_DATA; server_enter_uninterrupted_section( &fd_cache_section, &sigset ); fd = get_cached_fd( handle, type, &access, options ); if (fd != -1) goto done; SERVER_START_REQ( get_handle_fd ) { req->handle = wine_server_obj_handle( handle ); if (!(ret = wine_server_call( req ))) { if (type) *type = reply->type; if (options) *options = reply->options; access = reply->access; if ((fd = receive_fd( &fd_handle )) != -1) { assert( wine_server_ptr_handle(fd_handle) == handle ); *needs_close = (reply->removable || !add_fd_to_cache( handle, fd, reply->type, reply->access, reply->options )); } else ret = STATUS_TOO_MANY_OPENED_FILES; } } SERVER_END_REQ; done: server_leave_uninterrupted_section( &fd_cache_section, &sigset ); if (!ret && ((access & wanted_access) != wanted_access)) { ret = STATUS_ACCESS_DENIED; if (*needs_close) close( fd ); } if (!ret) *unix_fd = fd; return ret; }
/*********************************************************************** * server_init_process * * Start the server and create the initial socket pair. */ void server_init_process(void) { obj_handle_t version; const char *env_socket = getenv( "WINESERVERSOCKET" ); if (env_socket) { fd_socket = atoi( env_socket ); if (fcntl( fd_socket, F_SETFD, 1 ) == -1) fatal_perror( "Bad server socket %d", fd_socket ); unsetenv( "WINESERVERSOCKET" ); } else fd_socket = server_connect(); /* setup the signal mask */ sigemptyset( &server_block_set ); sigaddset( &server_block_set, SIGALRM ); sigaddset( &server_block_set, SIGIO ); sigaddset( &server_block_set, SIGINT ); sigaddset( &server_block_set, SIGHUP ); sigaddset( &server_block_set, SIGUSR1 ); sigaddset( &server_block_set, SIGUSR2 ); sigaddset( &server_block_set, SIGCHLD ); pthread_functions.sigprocmask( SIG_BLOCK, &server_block_set, NULL ); /* receive the first thread request fd on the main socket */ ntdll_get_thread_data()->request_fd = receive_fd( &version ); if (version != SERVER_PROTOCOL_VERSION) server_protocol_error( "version mismatch %d/%d.\n" "Your %s binary was not upgraded correctly,\n" "or you have an older one somewhere in your PATH.\n" "Or maybe the wrong wineserver is still running?\n", version, SERVER_PROTOCOL_VERSION, (version > SERVER_PROTOCOL_VERSION) ? "wine" : "wineserver" ); #ifdef __APPLE__ send_server_task_port(); #endif }
int main(int argc, char *argv[]) { int control_channel_fd, magic_socket; struct sockaddr_nl addr; unsigned int pid = 0; unsigned int gmask = 1; if (argc < 3) { printf("This script is called by vsys.\n"); exit(1); } control_channel_fd = atoi(argv[2]); /* receive pid paramater */ receive_argument(control_channel_fd, &pid); /* receive gmask paramater */ receive_argument(control_channel_fd, &gmask); magic_socket = receive_fd(control_channel_fd); if (magic_socket == -1) { fprintf(stderr, "Error creating socket: %d\n", errno); exit(1); } memset(&addr, 0, sizeof(struct sockaddr_nl)); addr.nl_family = AF_NETLINK; addr.nl_pid = pid; addr.nl_groups = gmask; if (bind(magic_socket, (struct sockaddr *)&addr, sizeof(addr)) < 0) { fprintf(stderr, "Error calling bind for AF_NETLINK: %d\n", errno); exit(1); } send_fd(control_channel_fd, magic_socket); }
pid_t createChildProcess(string serverRootDirectory,int sp[],int sockfd) { pid_t pid; if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sp) == -1) { perror("socketpair"); exit(1); } if((pid=fork())==0) { char pidStr[10]; memset(pidStr, 0, 10); sprintf(pidStr, "%ld", (long)getpid()); string lgname = "CHServer-"; lgname.append(pidStr); Logger plogger = LoggerFactory::getLogger(lgname); servd = serverRootDirectory; string filename; stringstream ss; ss << serverRootDirectory; ss << getpid(); ss >> filename; filename.append(".cntrl"); plogger << ("generated file " + filename) << endl; ofstream cntrlfile; cntrlfile.open(filename.c_str()); cntrlfile << "Process Running" << endl; cntrlfile.close(); close(sockfd); //SelEpolKqEvPrt selEpolKqEvPrtHandler; //selEpolKqEvPrtHandler.initialize(sp[1]); ThreadPool pool; if(!isThreadprq) { pool.init(30); } struct stat buffer; while(stat (serverCntrlFileNm.c_str(), &buffer) == 0) { /*int nfds = selEpolKqEvPrtHandler.getEvents(); if (nfds == -1) { perror("poller wait child process"); plogger << "\n----------poller child process----" << endl; } else*/ { int fd = receive_fd(sp[1]); //selEpolKqEvPrtHandler.reRegisterServerSock(); #ifdef OS_MINGW u_long bMode = 0; ioctlsocket(fd, FIONBIO, &bMode); #else fcntl(fd, F_SETFL, O_SYNC); #endif char buf[10]; memset(buf, 0, 10); int err; if((err=recv(fd,buf,10,MSG_PEEK))==0) { close(fd); plogger << "Socket conn closed before being serviced" << endl; continue; } try { if(isThreadprq) { ServiceTask *task = new ServiceTask(fd,serverRootDirectory); Thread pthread(&service, task); pthread.execute(); } else { ServiceTask *task = new ServiceTask(fd,serverRootDirectory); task->setCleanUp(true); pool.submit(task); } } catch(const char* err) { plogger << "Exception occurred while processing ServiceTask request - " << err << endl; } catch(...) { plogger << "Standard exception occurred while processing ServiceTask request " << endl; } } } }
static int fuse_mount_fusermount(const char *mountpoint, const char *opts, int quiet) { int fds[2], pid; int res; int rv; if (!mountpoint) { fprintf(stderr, "fuse: missing mountpoint\n"); return -1; } res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds); if(res == -1) { perror("fuse: socketpair() failed"); return -1; } pid = fork(); if(pid == -1) { perror("fuse: fork() failed"); close(fds[0]); close(fds[1]); return -1; } if(pid == 0) { char env[10]; const char *argv[32]; int a = 0; if (quiet) { int fd = open("/dev/null", O_RDONLY); dup2(fd, 1); dup2(fd, 2); } argv[a++] = FUSERMOUNT_PROG; if (opts) { argv[a++] = "-o"; argv[a++] = opts; } argv[a++] = "--"; argv[a++] = mountpoint; argv[a++] = NULL; close(fds[1]); fcntl(fds[0], F_SETFD, 0); snprintf(env, sizeof(env), "%i", fds[0]); setenv(FUSE_COMMFD_ENV, env, 1); exec_fusermount(argv); perror("fuse: failed to exec fusermount"); _exit(1); } close(fds[0]); rv = receive_fd(fds[1]); close(fds[1]); waitpid(pid, NULL, 0); /* bury zombie */ return rv; }
/* old code known to work, kept arround for debuging */ void tcp_receive_loop(int unix_sock) { struct tcp_connection* list; /* list with connections in use */ struct tcp_connection* con; struct tcp_connection* c_next; int n; int nfds; int s; long resp; fd_set master_set; fd_set sel_set; int maxfd; struct timeval timeout; int ticks; /* init */ list=con=0; FD_ZERO(&master_set); FD_SET(unix_sock, &master_set); maxfd=unix_sock; /* listen on the unix socket for the fd */ for(;;){ timeout.tv_sec=TCP_CHILD_SELECT_TIMEOUT; timeout.tv_usec=0; sel_set=master_set; nfds=select(maxfd+1, &sel_set, 0 , 0 , &timeout); #ifdef EXTRA_DEBUG for (n=0; n<maxfd; n++){ if (FD_ISSET(n, &sel_set)) LM_DBG("fd %d is set\n", n); } #endif if (nfds<0){ if (errno==EINTR) continue; /* just a signal */ /* errors */ LM_ERR("select:(%d) %s\n", errno, strerror(errno)); continue; } if (FD_ISSET(unix_sock, &sel_set)){ nfds--; /* a new conn from "main" */ n=receive_fd(unix_sock, &con, sizeof(con), &s, 0); if (n<0){ if (errno == EWOULDBLOCK || errno == EAGAIN || errno == EINTR){ goto skip; }else{ LM_CRIT("read_fd: %s\n",strerror(errno)); abort(); /* big error*/ } } LM_DBG("received n=%d con=%p, fd=%d\n", n, con, s); if (n==0){ LM_WARN("0 bytes read\n"); goto skip; } if (con==0){ LM_CRIT("null pointer\n"); goto skip; } con->fd=s; if (s==-1) { LM_ERR("read_fd: no fd read\n"); resp=CONN_ERROR; con->state=S_CONN_BAD; release_tcpconn(con, resp, unix_sock); goto skip; } con->timeout=get_ticks()+TCP_CHILD_TIMEOUT; FD_SET(s, &master_set); if (maxfd<s) maxfd=s; if (con==list){ LM_CRIT("duplicate" " connection received: %p, id %d, fd %d, refcnt %d" " state %d (n=%d)\n", con, con->id, con->fd, con->refcnt, con->state, n); resp=CONN_ERROR; release_tcpconn(con, resp, unix_sock); goto skip; /* try to recover */ } tcpconn_listadd(list, con, c_next, c_prev); } skip: ticks=get_ticks(); for (con=list; con ; con=c_next){ c_next=con->c_next; /* safe for removing*/ #ifdef EXTRA_DEBUG LM_DBG("list fd=%d, id=%d, timeout=%d, refcnt=%d\n", con->fd, con->id, con->timeout, con->refcnt); #endif if (con->state<0){ /* S_CONN_BAD or S_CONN_ERROR, remove it */ resp=CONN_ERROR; FD_CLR(con->fd, &master_set); tcpconn_listrm(list, con, c_next, c_prev); con->state=S_CONN_BAD; release_tcpconn(con, resp, unix_sock); continue; } if (nfds && FD_ISSET(con->fd, &sel_set)){ #ifdef EXTRA_DEBUG LM_DBG("match, fd:isset\n"); #endif nfds--; resp=tcp_read_req(con); if (resp<0){ FD_CLR(con->fd, &master_set); tcpconn_listrm(list, con, c_next, c_prev); con->state=S_CONN_BAD; release_tcpconn(con, resp, unix_sock); }else{ /* update timeout */ con->timeout=ticks+TCP_CHILD_TIMEOUT; } }else{ /* timeout */ if (con->timeout<=ticks){ /* expired, return to "tcp main" */ LM_DBG("%p expired (%d, %d)\n", con, con->timeout, ticks); resp=CONN_RELEASE; FD_CLR(con->fd, &master_set); tcpconn_listrm(list, con, c_next, c_prev); release_tcpconn(con, resp, unix_sock); } } } } }
/*! \brief handles io from a "generic" ser process (get fd or new_fd from a tcp_send) * * \param p - pointer in the ser processes array (pt[]), to the entry for * which an io event was detected * \param fd_i - fd index in the fd_array (usefull for optimizing * io_watch_deletes) * \return handle_* return convention: * - -1 on error reading from the fd, * - 0 on EAGAIN or when no more io events are queued * (receive buffer empty), * - >0 on successfull reads from the fd (the receive buffer might * be non-empty). */ inline static int handle_ser_child(struct process_table* p, int fd_i) { struct tcp_connection* tcpconn; long response[2]; int cmd; int bytes; int ret; int fd; ret=-1; if (p->unix_sock<=0){ /* (we can't have a fd==0, 0 is never closed )*/ LM_CRIT("fd %d for %d (pid %d)\n", p->unix_sock, (int)(p-&pt[0]), p->pid); goto error; } /* get all bytes and the fd (if transmitted) * (this is a SOCK_STREAM so read is not atomic) */ bytes=receive_fd(p->unix_sock, response, sizeof(response), &fd, MSG_DONTWAIT); if (bytes<(int)sizeof(response)){ /* too few bytes read */ if (bytes==0){ /* EOF -> bad, child has died */ LM_DBG("dead child %d, pid %d" " (shutting down?)\n", (int)(p-&pt[0]), p->pid); /* don't listen on it any more */ io_watch_del(&io_h, p->unix_sock, fd_i, 0); goto error; /* child dead => no further io events from it */ }else if (bytes<0){ /* EAGAIN is ok if we try to empty the buffer * e.g: SIGIO_RT overflow mode or EPOLL ET */ if ((errno!=EAGAIN) && (errno!=EWOULDBLOCK)){ LM_CRIT("read from child %d (pid %d): %s [%d]\n", (int)(p-&pt[0]), p->pid, strerror(errno), errno); ret=-1; }else{ ret=0; } /* try to ignore ? */ goto end; }else{ /* should never happen */ LM_CRIT("too few bytes received (%d)\n", bytes ); ret=0; /* something was read so there is no error; otoh if receive_fd returned less then requested => the receive buffer is empty => no more io queued on this fd */ goto end; } } ret=1; /* something was received, there might be more queued */ LM_DBG("read response= %lx, %ld, fd %d from %d (%d)\n", response[0], response[1], fd, (int)(p-&pt[0]), p->pid); cmd=response[1]; tcpconn=(struct tcp_connection*)response[0]; if (tcpconn==0){ LM_CRIT("null tcpconn pointer received from child %d (pid %d)" "%lx, %lx\n", (int)(p-&pt[0]), p->pid, response[0], response[1]) ; goto end; } switch(cmd){ case CONN_ERROR: if (!(tcpconn->flags & F_CONN_REMOVED) && (tcpconn->s!=-1)){ io_watch_del(&io_h, tcpconn->s, -1, IO_FD_CLOSING); tcpconn->flags|=F_CONN_REMOVED; } tcpconn_destroy(tcpconn); /* will close also the fd */ break; case CONN_GET_FD: /* send the requested FD */ /* WARNING: take care of setting refcnt properly to * avoid race condition */ if (send_fd(p->unix_sock, &tcpconn, sizeof(tcpconn), tcpconn->s)<=0){ LM_ERR("send_fd failed\n"); } break; case CONN_NEW: /* update the fd in the requested tcpconn*/ /* WARNING: take care of setting refcnt properly to * avoid race condition */ if (fd==-1){ LM_CRIT(" cmd CONN_NEW: no fd received\n"); break; } tcpconn->s=fd; /* add tcpconn to the list*/ tcpconn_add(tcpconn); /* update the timeout*/ tcpconn->timeout=get_ticks()+tcp_con_lifetime; io_watch_add(&io_h, tcpconn->s, F_TCPCONN, tcpconn); tcpconn->flags&=~F_CONN_REMOVED; break; default: LM_CRIT("unknown cmd %d\n", cmd); } end: return ret; error: return -1; }
/*! \brief * handle io routine, based on the fd_map type * (it will be called from io_wait_loop* ) * params: fm - pointer to a fd hash entry * idx - index in the fd_array (or -1 if not known) * return: -1 on error, or when we are not interested any more on reads * from this fd (e.g.: we are closing it ) * 0 on EAGAIN or when by some other way it is known that no more * io events are queued on the fd (the receive buffer is empty). * Usefull to detect when there are no more io events queued for * sigio_rt, epoll_et, kqueue. * >0 on successfull read from the fd (when there might be more io * queued -- the receive buffer might still be non-empty) */ inline static int handle_io(struct fd_map* fm, int idx) { int ret; int n; struct tcp_connection* con; int s; long resp; switch(fm->type){ case F_TCPMAIN: again: ret=n=receive_fd(fm->fd, &con, sizeof(con), &s, 0); LM_DBG("received n=%d con=%p, fd=%d\n", n, con, s); if (n<0){ if (errno == EWOULDBLOCK || errno == EAGAIN){ ret=0; break; }else if (errno == EINTR) goto again; else{ LM_CRIT("read_fd: %s \n", strerror(errno)); abort(); /* big error*/ } } if (n==0){ LM_WARN("0 bytes read\n"); break; } if (con==0){ LM_CRIT("null pointer\n"); break; } con->fd=s; if (s==-1) { LM_ERR("read_fd:no fd read\n"); goto con_error; } if (con==tcp_conn_lst){ LM_CRIT("duplicate" " connection received: %p, id %d, fd %d, refcnt %d" " state %d (n=%d)\n", con, con->id, con->fd, con->refcnt, con->state, n); release_tcpconn(con, CONN_ERROR, tcpmain_sock); break; /* try to recover */ } /* reset the per process TCP req struct */ init_tcp_req(¤t_req); /* 0 attempts so far for this SIP MSG */ con->msg_attempts = 0; /* must be before io_watch_add, io_watch_add might catch some * already existing events => might call handle_io and * handle_io might decide to del. the new connection => * must be in the list */ tcpconn_listadd(tcp_conn_lst, con, c_next, c_prev); con->timeout=get_ticks()+TCP_CHILD_MAX_MSG_TIME; if (io_watch_add(&io_w, s, F_TCPCONN, con)<0){ LM_CRIT("failed to add new socket to the fd list\n"); tcpconn_listrm(tcp_conn_lst, con, c_next, c_prev); goto con_error; } break; case F_TCPCONN: con=(struct tcp_connection*)fm->data; resp=tcp_read_req(con, &ret); if (resp<0) { ret=-1; /* some error occured */ io_watch_del(&io_w, con->fd, idx, IO_FD_CLOSING); tcpconn_listrm(tcp_conn_lst, con, c_next, c_prev); con->state=S_CONN_BAD; release_tcpconn(con, resp, tcpmain_sock); } break; case F_NONE: LM_CRIT("empty fd map %p (%d): " "{%d, %d, %p}\n", fm, (int)(fm-io_w.fd_hash), fm->fd, fm->type, fm->data); goto error; default: LM_CRIT("uknown fd type %d\n", fm->type); goto error; } return ret; con_error: con->state=S_CONN_BAD; release_tcpconn(con, CONN_ERROR, fm->fd); return ret; error: return -1; }
/*! \brief _tcpconn_find with locks and acquire fd */ int tcp_conn_get(int id, struct ip_addr* ip, int port, enum sip_protos proto, struct tcp_connection** conn, int* conn_fd) { struct tcp_connection* c; struct tcp_connection* tmp; struct tcp_conn_alias* a; unsigned hash; long response[2]; int part; int n; int fd; if (id) { part = id; TCPCONN_LOCK(part); if ( (c=_tcpconn_find(part))!=NULL ) goto found; TCPCONN_UNLOCK(part); } /* continue search based on IP address + port + transport */ #ifdef EXTRA_DEBUG LM_DBG("%d port %d\n",id, port); if (ip) print_ip("tcpconn_find: ip ", ip, "\n"); #endif if (ip){ hash=tcp_addr_hash(ip, port); for( part=0 ; part<TCP_PARTITION_SIZE ; part++ ) { TCPCONN_LOCK(part); for (a=TCP_PART(part).tcpconn_aliases_hash[hash]; a; a=a->next) { #ifdef EXTRA_DEBUG LM_DBG("a=%p, c=%p, c->id=%d, alias port= %d port=%d\n", a, a->parent, a->parent->id, a->port, a->parent->rcv.src_port); print_ip("ip=",&a->parent->rcv.src_ip,"\n"); #endif c = a->parent; if (c->state != S_CONN_BAD && port == a->port && proto == c->type && ip_addr_cmp(ip, &c->rcv.src_ip)) goto found; } TCPCONN_UNLOCK(part); } } /* not found */ *conn = NULL; if (conn_fd) *conn_fd = -1; return 0; found: c->refcnt++; TCPCONN_UNLOCK(part); LM_DBG("con found in state %d\n",c->state); if (c->state!=S_CONN_OK || conn_fd==NULL) { /* no need to acquired, just return the conn with an invalid fd */ *conn = c; if (conn_fd) *conn_fd = -1; return 1; } if (c->proc_id == process_no) { LM_DBG("tcp connection found (%p) already in this process ( %d ) , fd = %d\n", c, c->proc_id, c->fd); /* we already have the connection in this worker's reactor, no need to acquire FD */ *conn = c; *conn_fd = c->fd; return 1; } /* acquire the fd for this connection too */ LM_DBG("tcp connection found (%p), acquiring fd\n", c); /* get the fd */ response[0]=(long)c; response[1]=CONN_GET_FD; n=send_all(unix_tcp_sock, response, sizeof(response)); if (n<=0){ LM_ERR("failed to get fd(write):%s (%d)\n", strerror(errno), errno); n=-1; goto error; } LM_DBG("c= %p, n=%d, Usock=%d\n", c, n, unix_tcp_sock); tmp = c; n=receive_fd(unix_tcp_sock, &c, sizeof(c), &fd, MSG_WAITALL); if (n<=0){ LM_ERR("failed to get fd(receive_fd):" " %s (%d)\n", strerror(errno), errno); n=-1; goto error; } if (c!=tmp){ LM_CRIT("got different connection:" " %p (id= %d, refcnt=%d state=%d != " " %p (id= %d, refcnt=%d state=%d (n=%d)\n", c, c->id, c->refcnt, c->state, tmp, tmp->id, tmp->refcnt, tmp->state, n ); n=-1; /* fail */ close(fd); goto error; } LM_DBG("after receive_fd: c= %p n=%d fd=%d\n",c, n, fd); *conn = c; *conn_fd = fd; return 1; error: tcpconn_put(c); *conn = NULL; *conn_fd = -1; return -1; }
/*! \brief handles io from a "generic" ser process (get fd or new_fd from a tcp_send) * * \param p - pointer in the ser processes array (pt[]), to the entry for * which an io event was detected * \param fd_i - fd index in the fd_array (useful for optimizing * io_watch_deletes) * \return handle_* return convention: * - -1 on error reading from the fd, * - 0 on EAGAIN or when no more io events are queued * (receive buffer empty), * - >0 on successfull reads from the fd (the receive buffer might * be non-empty). */ inline static int handle_worker(struct process_table* p, int fd_i) { struct tcp_connection* tcpconn; long response[2]; int cmd; int bytes; int ret; int fd; ret=-1; if (p->unix_sock<=0){ /* (we can't have a fd==0, 0 is never closed )*/ LM_CRIT("fd %d for %d (pid %d)\n", p->unix_sock, (int)(p-&pt[0]), p->pid); goto error; } /* get all bytes and the fd (if transmitted) * (this is a SOCK_STREAM so read is not atomic) */ bytes=receive_fd(p->unix_sock, response, sizeof(response), &fd, MSG_DONTWAIT); if (bytes<(int)sizeof(response)){ /* too few bytes read */ if (bytes==0){ /* EOF -> bad, child has died */ LM_DBG("dead child %d, pid %d" " (shutting down?)\n", (int)(p-&pt[0]), p->pid); /* don't listen on it any more */ reactor_del_reader( p->unix_sock, fd_i, 0/*flags*/); goto error; /* child dead => no further io events from it */ }else if (bytes<0){ /* EAGAIN is ok if we try to empty the buffer * e.g: SIGIO_RT overflow mode or EPOLL ET */ if ((errno!=EAGAIN) && (errno!=EWOULDBLOCK)){ LM_CRIT("read from child %d (pid %d): %s [%d]\n", (int)(p-&pt[0]), p->pid, strerror(errno), errno); ret=-1; }else{ ret=0; } /* try to ignore ? */ goto end; }else{ /* should never happen */ LM_CRIT("too few bytes received (%d)\n", bytes ); ret=0; /* something was read so there is no error; otoh if receive_fd returned less then requested => the receive buffer is empty => no more io queued on this fd */ goto end; } } ret=1; /* something was received, there might be more queued */ LM_DBG("read response= %lx, %ld, fd %d from %d (%d)\n", response[0], response[1], fd, (int)(p-&pt[0]), p->pid); cmd=response[1]; tcpconn=(struct tcp_connection*)response[0]; if (tcpconn==0){ LM_CRIT("null tcpconn pointer received from child %d (pid %d)" "%lx, %lx\n", (int)(p-&pt[0]), p->pid, response[0], response[1]) ; goto end; } switch(cmd){ case CONN_ERROR: if (!(tcpconn->flags & F_CONN_REMOVED) && (tcpconn->s!=-1)){ reactor_del_all( tcpconn->s, -1, IO_FD_CLOSING); tcpconn->flags|=F_CONN_REMOVED; } tcpconn_destroy(tcpconn); /* will close also the fd */ break; case CONN_GET_FD: /* send the requested FD */ /* WARNING: take care of setting refcnt properly to * avoid race condition */ if (send_fd(p->unix_sock, &tcpconn, sizeof(tcpconn), tcpconn->s)<=0){ LM_ERR("send_fd failed\n"); } break; case CONN_NEW: /* update the fd in the requested tcpconn*/ /* WARNING: take care of setting refcnt properly to * avoid race condition */ if (fd==-1){ LM_CRIT(" cmd CONN_NEW: no fd received\n"); break; } tcpconn->s=fd; /* add tcpconn to the list*/ tcpconn_add(tcpconn); reactor_add_reader( tcpconn->s, F_TCPCONN, RCT_PRIO_NET, tcpconn); tcpconn->flags&=~F_CONN_REMOVED; break; case ASYNC_CONNECT: /* connection is not yet linked to hash = not yet * available to the outside world */ if (fd==-1){ LM_CRIT(" cmd CONN_NEW: no fd received\n"); break; } tcpconn->s=fd; /* add tcpconn to the list*/ tcpconn_add(tcpconn); /* FIXME - now we have lifetime==default_lifetime - should we * set a shorter one when waiting for a connect ??? */ /* only maintain the socket in the IO_WATCH_WRITE watcher * while we have stuff to write - otherwise we're going to get * useless events */ reactor_add_writer( tcpconn->s, F_TCPCONN, RCT_PRIO_NET, tcpconn); tcpconn->flags&=~F_CONN_REMOVED; break; case ASYNC_WRITE: if (tcpconn->state==S_CONN_BAD){ tcpconn->lifetime=0; break; } /* must be after the de-ref*/ reactor_add_writer( tcpconn->s, F_TCPCONN, RCT_PRIO_NET, tcpconn); tcpconn->flags&=~F_CONN_REMOVED; break; default: LM_CRIT("unknown cmd %d\n", cmd); } end: return ret; error: return -1; }
/*! \brief Finds a tcpconn & sends on it */ int tcp_send(struct socket_info* send_sock, int type, char* buf, unsigned len, union sockaddr_union* to, int id) { struct tcp_connection *c; struct tcp_connection *tmp; struct ip_addr ip; int port; int fd; long response[2]; int n; struct timeval get,rcv,snd; port=0; reset_tcp_vars(tcpthreshold); start_expire_timer(get,tcpthreshold); if (to){ su2ip_addr(&ip, to); port=su_getport(to); c=tcpconn_get(id, &ip, port, tcp_con_lifetime); }else if (id){ c=tcpconn_get(id, 0, 0, tcp_con_lifetime); }else{ LM_CRIT("tcp_send called with null id & to\n"); get_time_difference(get,tcpthreshold,tcp_timeout_con_get); return -1; } if (id){ if (c==0) { if (to){ /* try again w/o id */ c=tcpconn_get(0, &ip, port, tcp_con_lifetime); goto no_id; }else{ LM_ERR("id %d not found, dropping\n", id); get_time_difference(get,tcpthreshold,tcp_timeout_con_get); return -1; } }else goto get_fd; } no_id: if (c==0){ if (tcp_no_new_conn) { return -1; } LM_DBG("no open tcp connection found, opening new one\n"); /* create tcp connection */ if ((c=tcpconn_connect(send_sock, to, type))==0){ LM_ERR("connect failed\n"); get_time_difference(get,tcpthreshold,tcp_timeout_con_get); return -1; } c->refcnt++; /* safe to do it w/o locking, it's not yet available to the rest of the world */ fd=c->s; /* send the new tcpconn to "tcp main" */ response[0]=(long)c; response[1]=CONN_NEW; n=send_fd(unix_tcp_sock, response, sizeof(response), c->s); get_time_difference(get,tcpthreshold,tcp_timeout_con_get); if (n<=0){ LM_ERR("failed send_fd: %s (%d)\n", strerror(errno), errno); n=-1; goto end; } goto send_it; } get_fd: get_time_difference(get,tcpthreshold,tcp_timeout_con_get); /* todo: see if this is not the same process holding * c and if so send directly on c->fd */ LM_DBG("tcp connection found (%p), acquiring fd\n", c); /* get the fd */ response[0]=(long)c; response[1]=CONN_GET_FD; start_expire_timer(rcv,tcpthreshold); n=send_all(unix_tcp_sock, response, sizeof(response)); if (n<=0){ LM_ERR("failed to get fd(write):%s (%d)\n", strerror(errno), errno); n=-1; get_time_difference(rcv,tcpthreshold,tcp_timeout_receive_fd); goto release_c; } LM_DBG("c= %p, n=%d\n", c, n); tmp=c; n=receive_fd(unix_tcp_sock, &c, sizeof(c), &fd, MSG_WAITALL); get_time_difference(rcv,tcpthreshold,tcp_timeout_receive_fd); if (n<=0){ LM_ERR("failed to get fd(receive_fd):" " %s (%d)\n", strerror(errno), errno); n=-1; goto release_c; } if (c!=tmp){ LM_CRIT("got different connection:" " %p (id= %d, refcnt=%d state=%d != " " %p (id= %d, refcnt=%d state=%d (n=%d)\n", c, c->id, c->refcnt, c->state, tmp, tmp->id, tmp->refcnt, tmp->state, n ); n=-1; /* fail */ goto end; } LM_DBG("after receive_fd: c= %p n=%d fd=%d\n",c, n, fd); send_it: LM_DBG("sending...\n"); lock_get(&c->write_lock); #ifdef USE_TLS if (c->type==PROTO_TLS) n=tls_blocking_write(c, fd, buf, len); else #endif /* n=tcp_blocking_write(c, fd, buf, len); */ start_expire_timer(snd,tcpthreshold); n=tsend_stream(fd, buf, len, tcp_send_timeout*1000); get_time_difference(snd,tcpthreshold,tcp_timeout_send); stop_expire_timer(get,tcpthreshold,0,buf,(int)len,1); lock_release(&c->write_lock); LM_DBG("after write: c= %p n=%d fd=%d\n",c, n, fd); LM_DBG("buf=\n%.*s\n", (int)len, buf); if (n<0){ LM_ERR("failed to send\n"); /* error on the connection , mark it as bad and set 0 timeout */ c->state=S_CONN_BAD; c->timeout=0; /* tell "main" it should drop this (optional it will t/o anyway?)*/ response[0]=(long)c; response[1]=CONN_ERROR; n=send_all(unix_tcp_sock, response, sizeof(response)); /* CONN_ERROR will auto-dec refcnt => we must not call tcpconn_put !!*/ if (n<=0){ LM_ERR("return failed (write):%s (%d)\n", strerror(errno), errno); } close(fd); return -1; /* error return, no tcpconn_put */ } end: close(fd); release_c: tcpconn_put(c); /* release c (lock; dec refcnt; unlock) */ return n; }
/*! \brief * handle io routine, based on the fd_map type * (it will be called from reactor_main_loop ) * params: fm - pointer to a fd hash entry * idx - index in the fd_array (or -1 if not known) * return: -1 on error, or when we are not interested any more on reads * from this fd (e.g.: we are closing it ) * 0 on EAGAIN or when by some other way it is known that no more * io events are queued on the fd (the receive buffer is empty). * Usefull to detect when there are no more io events queued for * sigio_rt, epoll_et, kqueue. * >0 on successfull read from the fd (when there might be more io * queued -- the receive buffer might still be non-empty) */ inline static int handle_io(struct fd_map* fm, int idx,int event_type) { int ret=0; int n; struct tcp_connection* con; int s,rw; long resp; long response[2]; switch(fm->type){ case F_TIMER_JOB: handle_timer_job(); break; case F_SCRIPT_ASYNC: async_resume_f( fm->fd, fm->data); return 0; case F_TCPMAIN: again: ret=n=receive_fd(fm->fd, response, sizeof(response), &s, 0); if (n<0){ if (errno == EWOULDBLOCK || errno == EAGAIN){ ret=0; break; }else if (errno == EINTR) goto again; else{ LM_CRIT("read_fd: %s \n", strerror(errno)); abort(); /* big error*/ } } if (n==0){ LM_WARN("0 bytes read\n"); break; } con = (struct tcp_connection *)response[0]; rw = (int)response[1]; if (con==0){ LM_CRIT("null pointer\n"); break; } if (s==-1) { LM_BUG("read_fd:no fd read\n"); /* FIXME? */ return -1; } if (con==tcp_conn_lst){ LM_CRIT("duplicate" " connection received: %p, id %d, fd %d, refcnt %d" " state %d (n=%d)\n", con, con->id, con->fd, con->refcnt, con->state, n); tcpconn_release(con, CONN_ERROR,0); break; /* try to recover */ } LM_DBG("We have received conn %p with rw %d on fd %d\n",con,rw,s); if (rw & IO_WATCH_READ) { /* 0 attempts so far for this SIP MSG */ con->msg_attempts = 0; /* must be before reactor_add, as the add might catch some * already existing events => might call handle_io and * handle_io might decide to del. the new connection => * must be in the list */ tcpconn_listadd(tcp_conn_lst, con, c_next, c_prev); con->timeout = con->lifetime; if (reactor_add_reader( s, F_TCPCONN, RCT_PRIO_NET, con )<0) { LM_CRIT("failed to add new socket to the fd list\n"); tcpconn_listrm(tcp_conn_lst, con, c_next, c_prev); goto con_error; } /* mark that the connection is currently in our process future writes to this con won't have to acquire FD */ con->proc_id = process_no; /* save FD which is valid in context of this TCP worker */ con->fd=s; } else if (rw & IO_WATCH_WRITE) { LM_DBG("Received con for async write %p ref = %d\n",con,con->refcnt); lock_get(&con->write_lock); resp = protos[con->type].net.write( (void*)con, s ); lock_release(&con->write_lock); if (resp<0) { ret=-1; /* some error occured */ con->state=S_CONN_BAD; tcpconn_release(con, CONN_ERROR,1); break; } else if (resp==1) { tcpconn_release(con, ASYNC_WRITE,1); } else { tcpconn_release(con, CONN_RELEASE,1); } ret = 0; /* we always close the socket received for writing */ close(s); } break; case F_TCPCONN: if (event_type & IO_WATCH_READ) { con=(struct tcp_connection*)fm->data; resp = protos[con->type].net.read( (void*)con, &ret ); if (resp<0) { ret=-1; /* some error occured */ con->state=S_CONN_BAD; reactor_del_all( con->fd, idx, IO_FD_CLOSING ); tcpconn_listrm(tcp_conn_lst, con, c_next, c_prev); con->proc_id = -1; if (con->fd!=-1) { close(con->fd); con->fd = -1; } tcpconn_release(con, CONN_ERROR,0); } else if (con->state==S_CONN_EOF) { reactor_del_all( con->fd, idx, IO_FD_CLOSING ); tcpconn_listrm(tcp_conn_lst, con, c_next, c_prev); con->proc_id = -1; if (con->fd!=-1) { close(con->fd); con->fd = -1; } tcpconn_release(con, CONN_EOF,0); } else { //tcpconn_release(con, CONN_RELEASE); /* keep the connection for now */ break; } } break; case F_NONE: LM_CRIT("empty fd map %p: " "{%d, %d, %p}\n", fm, fm->fd, fm->type, fm->data); goto error; default: LM_CRIT("uknown fd type %d\n", fm->type); goto error; } return ret; con_error: con->state=S_CONN_BAD; tcpconn_release(con, CONN_ERROR,0); return ret; error: return -1; }
/* * XXX reimplement pcap_open_live with privsep, this is the * unprivileged part. */ pcap_t * priv_pcap_live(const char *dev, int slen, int prom, int to_ms, char *ebuf, u_int dlt, u_int dirfilt) { int fd, err; struct bpf_version bv; u_int v; pcap_t *p; if (priv_fd < 0) errx(1, "%s: called from privileged portion", __func__); if (dev == NULL) { snprintf(ebuf, PCAP_ERRBUF_SIZE, "No interface specified"); return (NULL); } p = malloc(sizeof(*p)); if (p == NULL) { snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); return (NULL); } bzero(p, sizeof(*p)); write_command(priv_fd, PRIV_OPEN_BPF); must_write(priv_fd, &slen, sizeof(int)); must_write(priv_fd, &prom, sizeof(int)); must_write(priv_fd, &dlt, sizeof(u_int)); must_write(priv_fd, &dirfilt, sizeof(u_int)); write_string(priv_fd, dev); fd = receive_fd(priv_fd); must_read(priv_fd, &err, sizeof(int)); if (fd < 0) { snprintf(ebuf, PCAP_ERRBUF_SIZE, "Failed to open bpf device for %s: %s", dev, strerror(err)); goto bad; } /* fd is locked, can only use 'safe' ioctls */ if (ioctl(fd, BIOCVERSION, &bv) < 0) { snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCVERSION: %s", pcap_strerror(errno)); goto bad; } if (bv.bv_major != BPF_MAJOR_VERSION || bv.bv_minor < BPF_MINOR_VERSION) { snprintf(ebuf, PCAP_ERRBUF_SIZE, "kernel bpf filter out of date"); goto bad; } p->fd = fd; p->snapshot = slen; /* Get the data link layer type. */ if (ioctl(fd, BIOCGDLT, &v) < 0) { snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCGDLT: %s", pcap_strerror(errno)); goto bad; } p->linktype = v; /* XXX hack */ if (p->linktype == DLT_PFLOG && p->snapshot < 160) p->snapshot = 160; /* set timeout */ if (to_ms != 0) { struct timeval to; to.tv_sec = to_ms / 1000; to.tv_usec = (to_ms * 1000) % 1000000; if (ioctl(p->fd, BIOCSRTIMEOUT, &to) < 0) { snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCSRTIMEOUT: %s", pcap_strerror(errno)); goto bad; } } if (ioctl(fd, BIOCGBLEN, &v) < 0) { snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCGBLEN: %s", pcap_strerror(errno)); goto bad; } p->bufsize = v; p->buffer = malloc(p->bufsize); if (p->buffer == NULL) { snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno)); goto bad; } return (p); bad: if (fd >= 0) close(fd); free(p); return (NULL); }
pcap_t * priv_pcap_offline(const char *fname, char *errbuf) { pcap_t *p; FILE *fp = NULL; struct pcap_file_header hdr; int linklen, err; if (priv_fd < 0) errx(1, "%s: called from privileged portion", __func__); p = malloc(sizeof(*p)); if (p == NULL) { strlcpy(errbuf, "out of swap", PCAP_ERRBUF_SIZE); return (NULL); } memset((char *)p, 0, sizeof(*p)); if (fname[0] == '-' && fname[1] == '\0') { p->fd = -1; fp = stdin; } else { write_command(priv_fd, PRIV_OPEN_DUMP); p->fd = receive_fd(priv_fd); must_read(priv_fd, &err, sizeof(int)); if (p->fd < 0) { snprintf(errbuf, PCAP_ERRBUF_SIZE, "Failed to open input file %s: %s", fname, strerror(err)); goto bad; } fp = fdopen(p->fd, "r"); if (fp == NULL) { snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", fname, pcap_strerror(errno)); close(p->fd); p->fd = -1; goto bad; } } if (fread((char *)&hdr, sizeof(hdr), 1, fp) != 1) { snprintf(errbuf, PCAP_ERRBUF_SIZE, "fread: %s", pcap_strerror(errno)); goto bad; } if (hdr.magic != TCPDUMP_MAGIC) { if (swap32(hdr.magic) != TCPDUMP_MAGIC) { snprintf(errbuf, PCAP_ERRBUF_SIZE, "bad dump file format"); goto bad; } p->sf.swapped = 1; swap_hdr(&hdr); } if (hdr.version_major < PCAP_VERSION_MAJOR) { snprintf(errbuf, PCAP_ERRBUF_SIZE, "archaic file format"); goto bad; } p->tzoff = hdr.thiszone; p->snapshot = hdr.snaplen; p->linktype = hdr.linktype; p->sf.rfile = fp; p->bufsize = hdr.snaplen; /* Align link header as required for proper data alignment */ /* XXX should handle all types */ switch (p->linktype) { case DLT_EN10MB: linklen = 14; break; case DLT_FDDI: linklen = 13 + 8; /* fddi_header + llc */ break; case DLT_NULL: default: linklen = 0; break; } if (p->bufsize < 0) p->bufsize = BPF_MAXBUFSIZE; p->sf.base = malloc(p->bufsize + BPF_ALIGNMENT); if (p->sf.base == NULL) { strlcpy(errbuf, "out of swap", PCAP_ERRBUF_SIZE); goto bad; } p->buffer = p->sf.base + BPF_ALIGNMENT - (linklen % BPF_ALIGNMENT); p->sf.version_major = hdr.version_major; p->sf.version_minor = hdr.version_minor; #ifdef PCAP_FDDIPAD /* XXX what to do with this? */ /* XXX padding only needed for kernel fcode */ pcap_fddipad = 0; #endif return (p); bad: if (fp != NULL && p->fd != -1) fclose(fp); free(p); return (NULL); }
/* finds a tcpconn & sends on it */ int tcp_send(int type, char* buf, unsigned len, union sockaddr_union* to, int id) { struct tcp_connection *c; struct tcp_connection *tmp; struct ip_addr ip; int port; int fd; long response[2]; int n; port=0; if (to){ su2ip_addr(&ip, to); port=su_getport(to); c=tcpconn_get(id, &ip, port, TCP_CON_SEND_TIMEOUT); }else if (id){ c=tcpconn_get(id, 0, 0, TCP_CON_SEND_TIMEOUT); }else{ LOG(L_CRIT, "BUG: tcp_send called with null id & to\n"); return -1; } if (id){ if (c==0) { if (to){ /* try again w/o id */ c=tcpconn_get(0, &ip, port, TCP_CON_SEND_TIMEOUT); goto no_id; }else{ LOG(L_ERR, "ERROR: tcp_send: id %d not found, dropping\n", id); return -1; } }else goto get_fd; } no_id: if (c==0){ DBG("tcp_send: no open tcp connection found, opening new one\n"); /* create tcp connection */ if ((c=tcpconn_connect(to, type))==0){ LOG(L_ERR, "ERROR: tcp_send: connect failed\n"); return -1; } c->refcnt++; /* safe to do it w/o locking, it's not yet available to the rest of the world */ fd=c->s; /* send the new tcpconn to "tcp main" */ response[0]=(long)c; response[1]=CONN_NEW; n=send_all(unix_tcp_sock, response, sizeof(response)); if (n<=0){ LOG(L_ERR, "BUG: tcp_send: failed write: %s (%d)\n", strerror(errno), errno); n=-1; goto end; } n=send_fd(unix_tcp_sock, &c, sizeof(c), c->s); if (n<=0){ LOG(L_ERR, "BUG: tcp_send: failed send_fd: %s (%d)\n", strerror(errno), errno); n=-1; goto end; } goto send_it; } get_fd: /* todo: see if this is not the same process holding * c and if so send directly on c->fd */ DBG("tcp_send: tcp connection found (%p), acquiring fd\n", c); /* get the fd */ response[0]=(long)c; response[1]=CONN_GET_FD; n=send_all(unix_tcp_sock, response, sizeof(response)); if (n<=0){ LOG(L_ERR, "BUG: tcp_send: failed to get fd(write):%s (%d)\n", strerror(errno), errno); n=-1; goto release_c; } DBG("tcp_send, c= %p, n=%d\n", c, n); tmp=c; n=receive_fd(unix_tcp_sock, &c, sizeof(c), &fd); if (n<=0){ LOG(L_ERR, "BUG: tcp_send: failed to get fd(receive_fd):" " %s (%d)\n", strerror(errno), errno); n=-1; goto release_c; } if (c!=tmp){ LOG(L_CRIT, "BUG: tcp_send: get_fd: got different connection:" " %p (id= %d, refcnt=%d state=%d != " " %p (id= %d, refcnt=%d state=%d (n=%d)\n", c, c->id, c->refcnt, c->state, tmp, tmp->id, tmp->refcnt, tmp->state, n ); n=-1; /* fail */ goto end; } DBG("tcp_send: after receive_fd: c= %p n=%d fd=%d\n",c, n, fd); send_it: DBG("tcp_send: sending...\n"); lock_get(&c->write_lock); #ifdef USE_TLS if (c->type==PROTO_TLS) n=tls_blocking_write(c, fd, buf, len); else #endif n=tcp_blocking_write(c, fd, buf, len); lock_release(&c->write_lock); DBG("tcp_send: after write: c= %p n=%d fd=%d\n",c, n, fd); DBG("tcp_send: buf=\n%.*s\n", (int)len, buf); if (n<0){ LOG(L_ERR, "ERROR: tcp_send: failed to send\n"); /* error on the connection , mark it as bad and set 0 timeout */ c->state=S_CONN_BAD; c->timeout=0; /* tell "main" it should drop this (optional it will t/o anyway?)*/ response[0]=(long)c; response[1]=CONN_ERROR; n=send_all(unix_tcp_sock, response, sizeof(response)); /* CONN_ERROR will auto-dec refcnt => we must not call tcpconn_put !!*/ if (n<=0){ LOG(L_ERR, "BUG: tcp_send: error return failed (write):%s (%d)\n", strerror(errno), errno); n=-1; } close(fd); return n; /* error return, no tcpconn_put */ } end: close(fd); release_c: tcpconn_put(c); /* release c (lock; dec refcnt; unlock) */ return n; }
int priv_init(uid_t uid, gid_t gid) { int i, on, result, fd; int pty, tty; pid_t pid; int socks[2]; int cmd; /* Create sockets */ if (socketpair(AF_LOCAL, SOCK_STREAM, PF_UNSPEC, socks) == -1) { return -1; } pid = fork(); if (pid < 0) { /* can't fork */ return -1; } if (pid != 0) { /* Father - drop privileges and return */ if (uid != -1 && gid != -1) { if (setgroups(1, &gid) == -1) return -1; if (setresgid(gid, gid, gid) == -1) return -1; if (setresuid(uid, uid, uid) == -1) return -1; } close(socks[0]); priv_fd = socks[1]; return 0; } /* son */ for (i = 1; i <= _NSIG; i++) signal(i, SIG_DFL); #ifdef HAVE_SETPROCTILE setproctitle("[priv]"); #endif close(socks[1]); while (1) { if (read(socks[0], &cmd, sizeof(int)) == 0) { exit(0); } switch (cmd) { case PRIV_OPEN_PTY: if (openpty(&pty, &tty, NULL, NULL, NULL) == -1) { warn("%s: openpty", __func__); pty = -1; tty = -1; } send_fd(socks[0], pty); send_fd(socks[0], tty); if (pty != -1) close(pty); if (tty != -1) close(tty); break; case PRIV_REDIRECT_CONSOLE: on = 1; fd = receive_fd(socks[0]); result = ioctl(fd, TIOCCONS, (char *) &on); if (result < 0) { warn("%s: ioctl(TIOCCONS)", __func__); } write(socks[0], &result, sizeof(int)); close(fd); break; default: errx(1, "%s: unknown command %d", __func__, cmd); break; } } _exit(1); }
/* handle io routine, based on the fd_map type * (it will be called from io_wait_loop* ) * params: fm - pointer to a fd hash entry * idx - index in the fd_array (or -1 if not known) * return: -1 on error, or when we are not interested any more on reads * from this fd (e.g.: we are closing it ) * 0 on EAGAIN or when by some other way it is known that no more * io events are queued on the fd (the receive buffer is empty). * Usefull to detect when there are no more io events queued for * sigio_rt, epoll_et, kqueue. * >0 on successfull read from the fd (when there might be more io * queued -- the receive buffer might still be non-empty) */ inline static int handle_io(struct fd_map* fm, short events, int idx) { int ret; int n; int read_flags; struct tcp_connection* con; int s; long resp; ticks_t t; /* update the local config */ cfg_update(); switch(fm->type){ case F_TCPMAIN: again: ret=n=receive_fd(fm->fd, &con, sizeof(con), &s, 0); LM_DBG("received n=%d con=%p, fd=%d\n", n, con, s); if (unlikely(n<0)){ if (errno == EWOULDBLOCK || errno == EAGAIN){ ret=0; break; }else if (errno == EINTR) goto again; else{ LM_CRIT("read_fd: %s \n", strerror(errno)); abort(); /* big error*/ } } if (unlikely(n==0)){ LM_ERR("0 bytes read\n"); goto error; } if (unlikely(con==0)){ LM_CRIT("null pointer\n"); goto error; } con->fd=s; if (unlikely(s==-1)) { LM_ERR("read_fd: no fd read\n"); goto con_error; } con->reader_pid=my_pid(); if (unlikely(con==tcp_conn_lst)){ LM_CRIT("duplicate connection received: %p, id %d, fd %d, refcnt %d" " state %d (n=%d)\n", con, con->id, con->fd, atomic_get(&con->refcnt), con->state, n); goto con_error; break; /* try to recover */ } if (unlikely(con->state==S_CONN_BAD)){ LM_WARN("received an already bad connection: %p id %d refcnt %d\n", con, con->id, atomic_get(&con->refcnt)); goto con_error; } /* if we received the fd there is most likely data waiting to * be read => process it first to avoid extra sys calls */ read_flags=((con->flags & (F_CONN_EOF_SEEN|F_CONN_FORCE_EOF)) && !(con->flags & F_CONN_OOB_DATA))? RD_CONN_FORCE_EOF :0; #ifdef USE_TLS repeat_1st_read: #endif /* USE_TLS */ resp=tcp_read_req(con, &n, &read_flags); if (unlikely(resp<0)){ /* some error occured, but on the new fd, not on the tcp * main fd, so keep the ret value */ if (unlikely(resp!=CONN_EOF)) con->state=S_CONN_BAD; LM_WARN("%s:%d %s releasing\n", __FILE__, __LINE__, __PRETTY_FUNCTION__); release_tcpconn(con, resp, tcpmain_sock); break; } #ifdef USE_TLS /* repeat read if requested (for now only tls might do this) */ if (unlikely(read_flags & RD_CONN_REPEAT_READ)) goto repeat_1st_read; #endif /* USE_TLS */ /* must be before io_watch_add, io_watch_add might catch some * already existing events => might call handle_io and * handle_io might decide to del. the new connection => * must be in the list */ tcpconn_listadd(tcp_conn_lst, con, c_next, c_prev); t=get_ticks_raw(); con->timeout=t+S_TO_TICKS(TCP_CHILD_TIMEOUT); /* re-activate the timer */ con->timer.f=tcpconn_read_timeout; local_timer_reinit(&con->timer); local_timer_add(&tcp_reader_ltimer, &con->timer, S_TO_TICKS(TCP_CHILD_TIMEOUT), t); if (unlikely(io_watch_add(&io_w, s, POLLIN, F_TCPCONN, con)<0)){ LM_CRIT("io_watch_add failed for %p id %d fd %d, state %d, flags %x," " main fd %d, refcnt %d\n", con, con->id, con->fd, con->state, con->flags, con->s, atomic_get(&con->refcnt)); tcpconn_listrm(tcp_conn_lst, con, c_next, c_prev); local_timer_del(&tcp_reader_ltimer, &con->timer); goto con_error; } break; case F_TCPCONN: con=(struct tcp_connection*)fm->data; if (unlikely(con->state==S_CONN_BAD)){ resp=CONN_ERROR; if (!(con->send_flags.f & SND_F_CON_CLOSE)) LM_WARN("F_TCPCONN connection marked as bad: %p id %d refcnt %d\n", con, con->id, atomic_get(&con->refcnt)); goto read_error; } read_flags=(( #ifdef POLLRDHUP (events & POLLRDHUP) | #endif /* POLLRDHUP */ (events & (POLLHUP|POLLERR)) | (con->flags & (F_CONN_EOF_SEEN|F_CONN_FORCE_EOF))) && !(events & POLLPRI))? RD_CONN_FORCE_EOF: 0; #ifdef USE_TLS repeat_read: #endif /* USE_TLS */ resp=tcp_read_req(con, &ret, &read_flags); if (unlikely(resp<0)){ read_error: ret=-1; /* some error occured */ if (unlikely(io_watch_del(&io_w, con->fd, idx, IO_FD_CLOSING) < 0)){ LM_CRIT("io_watch_del failed for %p id %d fd %d," " state %d, flags %x, main fd %d, refcnt %d\n", con, con->id, con->fd, con->state, con->flags, con->s, atomic_get(&con->refcnt)); } tcpconn_listrm(tcp_conn_lst, con, c_next, c_prev); local_timer_del(&tcp_reader_ltimer, &con->timer); if (unlikely(resp!=CONN_EOF)) con->state=S_CONN_BAD; LM_WARN("%s:%d %s releasing\n", __FILE__, __LINE__, __PRETTY_FUNCTION__); release_tcpconn(con, resp, tcpmain_sock); }else{ #ifdef USE_TLS if (unlikely(read_flags & RD_CONN_REPEAT_READ)) goto repeat_read; #endif /* USE_TLS */ /* update timeout */ con->timeout=get_ticks_raw()+S_TO_TICKS(TCP_CHILD_TIMEOUT); /* ret= 0 (read the whole socket buffer) if short read & * !POLLPRI, bytes read otherwise */ ret&=(((read_flags & RD_CONN_SHORT_READ) && !(events & POLLPRI)) - 1); } break; case F_NONE: LM_CRIT("empty fd map %p (%d): {%d, %d, %p}\n", fm, (int)(fm-io_w.fd_hash), fm->fd, fm->type, fm->data); goto error; default: LM_CRIT("uknown fd type %d\n", fm->type); goto error; } return ret; con_error: con->state=S_CONN_BAD; LM_WARN("%s:%d %s releasing\n", __FILE__, __LINE__, __PRETTY_FUNCTION__); release_tcpconn(con, CONN_ERROR, tcpmain_sock); return ret; error: return -1; }
void tcp_main_loop() { int r; int n; fd_set master_set; fd_set sel_set; int maxfd; struct tcp_connection* tcpconn; unsigned h; long response[2]; int cmd; int bytes; struct timeval timeout; int fd; /*init */ maxfd=0; FD_ZERO(&master_set); /* set all the listen addresses */ for (r=0; r<sock_no; r++){ if ((tcp_info[r].proto==PROTO_TCP) &&(tcp_info[r].socket!=-1)){ FD_SET(tcp_info[r].socket, &master_set); if (tcp_info[r].socket>maxfd) maxfd=tcp_info[r].socket; } #ifdef USE_TLS if ((!tls_disable)&&(tls_info[r].proto==PROTO_TLS) && (tls_info[r].socket!=-1)){ FD_SET(tls_info[r].socket, &master_set); if (tls_info[r].socket>maxfd) maxfd=tls_info[r].socket; } #endif } /* set all the unix sockets used for child comm */ for (r=1; r<process_no; r++){ if (pt[r].unix_sock>0){ /* we can't have 0, we never close it!*/ FD_SET(pt[r].unix_sock, &master_set); if (pt[r].unix_sock>maxfd) maxfd=pt[r].unix_sock; } } for (r=0; r<tcp_children_no; r++){ if (tcp_children[r].unix_sock>0){ /* we can't have 0, we never close it!*/ FD_SET(tcp_children[r].unix_sock, &master_set); if (tcp_children[r].unix_sock>maxfd) maxfd=tcp_children[r].unix_sock; } } /* main loop*/ while(1){ sel_set=master_set; timeout.tv_sec=TCP_MAIN_SELECT_TIMEOUT; timeout.tv_usec=0; n=select(maxfd+1, &sel_set, 0 ,0 , &timeout); if (n<0){ if (errno==EINTR) continue; /* just a signal */ /* errors */ LOG(L_ERR, "ERROR: tcp_main_loop: select:(%d) %s\n", errno, strerror(errno)); n=0; } for (r=0; r<sock_no && n; r++){ handle_new_connect(&tcp_info[r], &sel_set, &n); #ifdef USE_TLS if (!tls_disable) handle_new_connect(&tls_info[r], &sel_set, &n); #endif } /* check all the read fds (from the tcpconn_addr_hash ) */ for (h=0; h<TCP_ADDR_HASH_SIZE; h++){ for(tcpconn=tcpconn_addr_hash[h]; tcpconn && n; tcpconn=tcpconn->next){ /* FIXME: is refcnt==0 really necessary? */ if ((tcpconn->refcnt==0)&&(FD_ISSET(tcpconn->s, &sel_set))){ /* new data available */ n--; /* pass it to child, so remove it from select list */ DBG("tcp_main_loop: data available on %p [h:%d] %d\n", tcpconn, h, tcpconn->s); FD_CLR(tcpconn->s, &master_set); tcpconn_ref(tcpconn); /* refcnt ++ */ if (send2child(tcpconn)<0){ LOG(L_ERR,"ERROR: tcp_main_loop: no " "children available\n"); TCPCONN_LOCK; tcpconn->refcnt--; if (tcpconn->refcnt==0){ fd=tcpconn->s; _tcpconn_rm(tcpconn); close(fd); }else tcpconn->timeout=0; /* force expire*/ TCPCONN_UNLOCK; } } } } /* check unix sockets & listen | destroy connections */ /* tcp_children readers first */ for (r=0; r<tcp_children_no && n; r++){ if ( (tcp_children[r].unix_sock>0) && FD_ISSET(tcp_children[r].unix_sock, &sel_set)){ /* (we can't have a fd==0, 0 is never closed )*/ n--; /* read until sizeof(response) * (this is a SOCK_STREAM so read is not atomic */ bytes=recv_all(tcp_children[r].unix_sock, response, sizeof(response)); if (bytes==0){ /* EOF -> bad, child has died */ DBG("DBG: tcp_main_loop: dead tcp child %d" " (shutting down?)\n", r); /* don't listen on it any more */ FD_CLR(tcp_children[r].unix_sock, &master_set); /*exit(-1);*/ continue; /* skip this and try the next one */ }else if (bytes<0){ LOG(L_CRIT, "ERROR: tcp_main_loop: read from tcp child %d " "%s\n", r, strerror(errno)); /* try to ignore ? */ continue; /* skip this and try the next one */ } DBG("tcp_main_loop: reader response= %lx, %ld from %d \n", response[0], response[1], r); cmd=response[1]; tcpconn=(struct tcp_connection*)response[0]; switch(cmd){ case CONN_RELEASE: tcp_children[r].busy--; if (tcpconn){ if (tcpconn->state==S_CONN_BAD){ tcpconn_destroy(tcpconn); break; } FD_SET(tcpconn->s, &master_set); if (maxfd<tcpconn->s) maxfd=tcpconn->s; /* update the timeout*/ tcpconn->timeout=get_ticks()+TCP_CON_TIMEOUT; tcpconn_put(tcpconn); DBG("tcp_main_loop: CONN_RELEASE %p" " refcnt= %d\n", tcpconn, tcpconn->refcnt); } break; case CONN_ERROR: case CONN_DESTROY: case CONN_EOF: /* WARNING: this will auto-dec. refcnt! */ tcp_children[pt[r].idx].busy--; if (tcpconn){ if (tcpconn->s!=-1) FD_CLR(tcpconn->s, &master_set); tcpconn_destroy(tcpconn); } break; default: LOG(L_CRIT, "BUG: tcp_main_loop: unknown cmd %d" " from tcp reader %d\n", cmd, r); } } } /* check "send" unix sockets & listen | destroy connections */ /* start from 1, the "main" process does not transmit anything*/ for (r=1; r<process_no && n; r++){ if ( (pt[r].unix_sock>0) && FD_ISSET(pt[r].unix_sock, &sel_set)){ /* (we can't have a fd==0, 0 is never closed )*/ n--; /* read until sizeof(response) * (this is a SOCK_STREAM so read is not atomic */ bytes=recv_all(pt[r].unix_sock, response, sizeof(response)); if (bytes==0){ /* EOF -> bad, child has died */ DBG("DBG: tcp_main_loop: dead child %d" " (shutting down?)\n", r); /* don't listen on it any more */ FD_CLR(pt[r].unix_sock, &master_set); /*exit(-1);*/ continue; /* skip this and try the next one */ }else if (bytes<0){ LOG(L_CRIT, "ERROR: tcp_main_loop: read from child: %s\n", strerror(errno)); /* try to ignore ? */ continue; /* skip this and try the next one */ } DBG("tcp_main_loop: read response= %lx, %ld from %d (%d)\n", response[0], response[1], r, pt[r].pid); cmd=response[1]; tcpconn=(struct tcp_connection*)response[0]; switch(cmd){ case CONN_ERROR: if (tcpconn){ if (tcpconn->s!=-1) FD_CLR(tcpconn->s, &master_set); tcpconn_destroy(tcpconn); } break; case CONN_GET_FD: /* send the requested FD */ /* WARNING: take care of setting refcnt properly to * avoid race condition */ if (tcpconn){ if (send_fd(pt[r].unix_sock, &tcpconn, sizeof(tcpconn), tcpconn->s)<=0){ LOG(L_ERR, "ERROR: tcp_main_loop:" "send_fd failed\n"); } }else{ LOG(L_CRIT, "BUG: tcp_main_loop: null pointer\n"); } break; case CONN_NEW: /* update the fd in the requested tcpconn*/ /* WARNING: take care of setting refcnt properly to * avoid race condition */ if (tcpconn){ bytes=receive_fd(pt[r].unix_sock, &tcpconn, sizeof(tcpconn), &tcpconn->s); if (bytes<sizeof(tcpconn)){ if (bytes<0){ LOG(L_CRIT, "BUG: tcp_main_loop:" " CONN_NEW: receive_fd " "failed\n"); }else{ LOG(L_CRIT, "BUG: tcp_main_loop:" " CONN_NEW: to few bytes " "received (%d)\n", bytes ); } break; /* try to ignore */ } /* add tcpconn to the list*/ tcpconn_add(tcpconn); FD_SET(tcpconn->s, &master_set); if (maxfd<tcpconn->s) maxfd=tcpconn->s; /* update the timeout*/ tcpconn->timeout=get_ticks()+TCP_CON_TIMEOUT; }else{ LOG(L_CRIT, "BUG: tcp_main_loop: null pointer\n"); } break; default: LOG(L_CRIT, "BUG: tcp_main_loop: unknown cmd %d\n", cmd); } } } /* for */ /* remove old connections */ tcpconn_timeout(&master_set); } }
/** * Selects once on sockets for receiving and sending stuff. * Monitors: * - the fd exchange pipe, for receiving descriptors to be handled here * - the tcp sockets of all serviced peers, triggering the incoming messages do_receive() * - the send pipes of all serviced peers, triggering the sending of outgoing messages * @returns 0 on normal exit or -1 on error */ int receive_loop(peer *original_peer) { fd_set rfds,efds; struct timeval tv; int n,max=0,cnt=0; AAAMessage *msg=0; serviced_peer_t *sp,*sp2; peer *p; int fd=-1; int fd_exchange_pipe_local=0; if (original_peer) fd_exchange_pipe_local = original_peer->fd_exchange_pipe_local; else fd_exchange_pipe_local = fd_exchange_pipe_unknown_local; // if (shutdownx) return -1; while(shutdownx&&!*shutdownx){ n = 0; while(!n){ if (shutdownx&&*shutdownx) break; cfg_update(); log_serviced_peers(); max =-1; FD_ZERO(&rfds); FD_ZERO(&efds); FD_SET(fd_exchange_pipe_local,&rfds); if (fd_exchange_pipe_local>max) max = fd_exchange_pipe_local; for(sp=serviced_peers;sp;sp=sp->next){ if (sp->tcp_socket>=0){ FD_SET(sp->tcp_socket,&rfds); FD_SET(sp->tcp_socket,&efds); if (sp->tcp_socket>max) max = sp->tcp_socket; } if (sp->send_pipe_fd>=0) { FD_SET(sp->send_pipe_fd,&rfds); if (sp->send_pipe_fd>max) max = sp->send_pipe_fd; } } tv.tv_sec=1; tv.tv_usec=0; n = select(max+1,&rfds,0,&efds,&tv); if (n==-1){ if (shutdownx&&*shutdownx) return 0; LM_ERR("select_recv(): %s\n",strerror(errno)); for(sp=serviced_peers;sp;sp=sp2){ sp2 = sp->next; disconnect_serviced_peer(sp,0); if (sp->p && sp->p->is_dynamic) drop_serviced_peer(sp,0); } sleep(1); break; }else if (n){ if (FD_ISSET(fd_exchange_pipe_local,&rfds)){ /* fd exchange */ LM_DBG("select_recv(): There is something on the fd exchange pipe\n"); p = 0; fd = -1; if (!receive_fd(fd_exchange_pipe_local,&fd,&p)){ LM_ERR("select_recv(): Error reading from fd exchange pipe\n"); }else{ LM_DBG("select_recv(): fd exchange pipe says fd [%d] for peer %p:[%.*s]\n",fd, p, p?p->fqdn.len:0, p?p->fqdn.s:0); if (p){ sp2=0; for(sp=serviced_peers;sp;sp=sp->next) if (sp->p==p){ sp2 = sp; break; } if (!sp2) sp2 = add_serviced_peer(p); else make_send_pipe(sp2); if (!sp2) { LM_ERR("Error on add_serviced_peer()\n"); continue; } sp2->tcp_socket = fd; if (p->state == Wait_Conn_Ack){ p->I_sock = fd; sm_process(p,I_Rcv_Conn_Ack,0,0,fd); }else{ p->R_sock = fd; } }else{ sp2 = add_serviced_peer(NULL); if (!sp2) { LM_ERR("Error on add_serviced_peer()\n"); continue; } sp2->tcp_socket = fd; } } } for(sp=serviced_peers;sp;){ if (sp->tcp_socket>=0 && FD_ISSET(sp->tcp_socket,&efds)) { LM_INFO("select_recv(): [%.*s] Peer socket [%d] found on the exception list... dropping\n", sp->p?sp->p->fqdn.len:0, sp->p?sp->p->fqdn.s:0, sp->tcp_socket); goto drop_peer; } if (sp->send_pipe_fd>=0 && FD_ISSET(sp->send_pipe_fd,&rfds)) { /* send */ LM_DBG("select_recv(): There is something on the send pipe\n"); cnt = read(sp->send_pipe_fd,&msg,sizeof(AAAMessage *)); if (cnt==0){ //This is very stupid and might not work well - droped messages... to be fixed LM_INFO("select_recv(): ReOpening pipe for read. This should not happen...\n"); close(sp->send_pipe_fd); sp->send_pipe_fd = open(sp->send_pipe_name.s, O_RDONLY | O_NDELAY); goto receive; } if (cnt<sizeof(AAAMessage *)){ if (cnt<0) LM_ERR("select_recv(): Error reading from send pipe\n"); goto receive; } LM_DBG("select_recv(): Send pipe says [%p] %d\n",msg,cnt); if (sp->tcp_socket<0){ LM_ERR("select_recv(): got a signal to send something, but the connection was not opened"); } else { while( (cnt=write(sp->tcp_socket,msg->buf.s,msg->buf.len))==-1 ) { if (errno==EINTR) continue; LM_ERR("select_recv(): [%.*s] write on socket [%d] returned error> %s... dropping\n", sp->p?sp->p->fqdn.len:0, sp->p?sp->p->fqdn.s:0, sp->tcp_socket, strerror(errno)); AAAFreeMessage(&msg); close(sp->tcp_socket); goto drop_peer; } if (cnt!=msg->buf.len){ LM_ERR("select_recv(): [%.*s] write on socket [%d] only wrote %d/%d bytes... dropping\n", sp->p?sp->p->fqdn.len:0, sp->p?sp->p->fqdn.s:0, sp->tcp_socket, cnt, msg->buf.len); AAAFreeMessage(&msg); close(sp->tcp_socket); goto drop_peer; } } AAAFreeMessage(&msg); //don't return, maybe there is something to read } receive: /* receive */ if (sp->tcp_socket>=0 && FD_ISSET(sp->tcp_socket,&rfds)) { errno=0; cnt = do_receive(sp); if (cnt<=0) { LM_INFO("select_recv(): [%.*s] read on socket [%d] returned %d > %s... dropping\n", sp->p?sp->p->fqdn.len:0, sp->p?sp->p->fqdn.s:0, sp->tcp_socket, cnt, errno?strerror(errno):""); goto drop_peer; } } //next_sp: /* go to next serviced peer */ sp=sp->next; continue; drop_peer: /* drop this serviced peer on error */ sp2 = sp->next; disconnect_serviced_peer(sp,0); if (sp->p && sp->p->is_dynamic) drop_serviced_peer(sp,0); sp = sp2; } } } } return 0; }