void ssh_stream_fd_request(SshFdStream sdata) { unsigned int read_request, write_request; assert(!sdata->destroyed); if (sdata->read_has_failed) read_request = SSH_IO_READ; else read_request = 0; if (sdata->write_has_failed) write_request = SSH_IO_WRITE; else write_request = 0; if (sdata->readfd == sdata->writefd) { if (sdata->readfd >= 0) ssh_io_set_fd_request(sdata->readfd, read_request | write_request); } else { if (sdata->readfd >= 0) ssh_io_set_fd_request(sdata->readfd, read_request); if (sdata->writefd >= 0) ssh_io_set_fd_request(sdata->writefd, write_request); } }
/* Open interface to tls acceleration */ Boolean tls_accel_open(void (*rd_cb)(unsigned int, void *)) { #ifdef __linux__ const char *name = "/proc/quicksec/hwaccel"; if (device_fd >= 0) return TRUE; /* Try to open the device. */ device_fd = open(name, O_RDWR); device_rd_fd = open(name, O_RDWR); if (device_fd == -1 || device_rd_fd == -1) { SSH_DEBUG(1 , ("Hardware accelerator n/a")); tls_accel_close(); return FALSE; } registered = ssh_io_register_fd(device_rd_fd, rd_cb, NULL); if (!registered) { SSH_DEBUG(SSH_D_FAIL, ("ssh_io_register_fd failed")); tls_accel_close(); return FALSE; } ssh_io_set_fd_request(device_rd_fd, SSH_IO_READ); return TRUE; #else return FALSE; #endif /* __linux__ */ }
SshLocalListener ssh_local_make_listener(const char *path, SshLocalCallback callback, void *context) { int sock; struct sockaddr_un sunaddr; SshLocalListener listener; /* Create a socket for the listener. */ sock = socket(AF_UNIX, SOCK_STREAM, 0); if (sock < 0) { ssh_warning("Can not create local domain socket: %.200s", strerror(errno)); return NULL; } /* Initialize a unix-domain address structure. */ memset(&sunaddr, 0, sizeof(sunaddr)); sunaddr.sun_family = AF_UNIX; strncpy(sunaddr.sun_path, path, sizeof(sunaddr.sun_path)); /* Bind the socket to the address. This will create the socket in the file system, and will fail if the socket already exists. */ if (bind(sock, (struct sockaddr *)&sunaddr, AF_UNIX_SIZE(sunaddr)) < 0) { close(sock); ssh_warning("Can not bind local address %.200s: %.200s", path, strerror(errno)); return NULL; } /* Start listening for connections to the socket. */ if (listen(sock, 5) < 0) { close(sock); ssh_warning("Can not listen to local address %.200s: %.200s", path, strerror(errno)); return NULL; } /* Allocate and initialize the listener structure. */ listener = ssh_xmalloc(sizeof(*listener)); listener->sock = sock; listener->path = ssh_xstrdup(path); listener->callback = callback; listener->context = context; /* ssh_local_listen_callback will call the user supplied callback when after new connection is accepted. It also creates stream object for the new connection and calls callback. */ ssh_io_register_fd(sock, ssh_local_listen_callback, (void *)listener); ssh_io_set_fd_request(sock, SSH_IO_READ); return listener; }
void ssh_local_listen_callback(unsigned int events, void *context) { SshLocalListener listener = (SshLocalListener)context; int sock, addrlen; struct sockaddr_un sunaddr; if (events & SSH_IO_READ) { addrlen = sizeof(sunaddr); sock = accept(listener->sock, (struct sockaddr *)&sunaddr, &addrlen); if (sock < 0) { ssh_debug("ssh_local_listen_callback: accept failed"); return; } /* Re-enable requests on the listener. */ ssh_io_set_fd_request(listener->sock, SSH_IO_READ); /* Inform user callback of the new socket. Note that this might destroy the listener. */ (*listener->callback)(ssh_stream_fd_wrap(sock, TRUE), listener->context); } }
void ssh_local_connect_try(unsigned int events, void *context) { SshLocalConnect c = (SshLocalConnect)context; int ret; struct sockaddr_un sunaddr; /* Initialize the address to connect to. */ memset(&sunaddr, 0, sizeof(sunaddr)); sunaddr.sun_family = AF_UNIX; strncpy(sunaddr.sun_path, c->path, sizeof(sunaddr.sun_path)); /* Make a non-blocking connect attempt. */ ret = connect(c->sock, (struct sockaddr *)&sunaddr, AF_UNIX_SIZE(sunaddr)); if (ret >= 0 || errno == EISCONN) /* Connection is ready. */ { /* Successful connection. */ ssh_io_unregister_fd(c->sock, FALSE); (*c->callback)(ssh_stream_fd_wrap(c->sock, TRUE), c->context); ssh_xfree(c->path); ssh_xfree(c); return; } if (errno == EINPROGRESS || errno == EWOULDBLOCK || errno == EALREADY) { /* Connection still in progress. */ ssh_io_set_fd_request(c->sock, SSH_IO_WRITE); return; } /* Connection failed. */ ssh_io_unregister_fd(c->sock, FALSE); close(c->sock); (*c->callback)(NULL, c->context); ssh_xfree(c->path); ssh_xfree(c); }