/** * @brief Add a socket object to a poll context. * * @param ctx Pointer to an already allocated poll context. * @param s A SSH socket handle * * @return 0 on success, < 0 on error */ int ssh_poll_ctx_add_socket (ssh_poll_ctx ctx, ssh_socket s) { ssh_poll_handle p_in, p_out; int ret; p_in=ssh_socket_get_poll_handle_in(s); if(p_in==NULL) return -1; ret = ssh_poll_ctx_add(ctx,p_in); if(ret != 0) return ret; p_out=ssh_socket_get_poll_handle_out(s); if(p_in != p_out) ret = ssh_poll_ctx_add(ctx,p_out); return ret; }
/** * @brief Free an event context. * * @param event The ssh_event object to free. * Note: you have to manually remove sessions and socket * fds before freeing the event object. * */ void ssh_event_free(ssh_event event) { int used, i; ssh_poll_handle p; if(event == NULL) { return; } if(event->ctx != NULL) { used = event->ctx->polls_used; for(i = 0; i < used; i++) { p = event->ctx->pollptrs[i]; if(p->session != NULL) { ssh_poll_ctx_remove(event->ctx, p); ssh_poll_ctx_add(p->session->default_poll_ctx, p); p->session = NULL; used = 0; } } ssh_poll_ctx_free(event->ctx); } #ifdef WITH_SERVER if(event->sessions != NULL) { ssh_list_free(event->sessions); } #endif free(event); }
/** * @brief Add a fd to the event and assign it a callback, * when used in blocking mode. * @param event The ssh_event * @param fd Socket that will be polled. * @param events Poll events that will be monitored for the socket. i.e. * POLLIN, POLLPRI, POLLOUT * @param cb Function to be called if any of the events are set. * The prototype of cb is: * int (*ssh_event_callback)(socket_t fd, int revents, * void *userdata); * @param userdata Userdata to be passed to the callback function. NULL if * not needed. * * @returns SSH_OK on success * SSH_ERROR on failure */ int ssh_event_add_fd(ssh_event event, socket_t fd, short events, ssh_event_callback cb, void *userdata) { ssh_poll_handle p; struct ssh_event_fd_wrapper *pw; if(event == NULL || event->ctx == NULL || cb == NULL || fd == SSH_INVALID_SOCKET) { return SSH_ERROR; } pw = malloc(sizeof(struct ssh_event_fd_wrapper)); if(pw == NULL) { return SSH_ERROR; } pw->cb = cb; pw->userdata = userdata; /* pw is freed by ssh_event_remove_fd */ p = ssh_poll_new(fd, events, ssh_event_fd_wrapper_callback, pw); if(p == NULL) { free(pw); return SSH_ERROR; } if(ssh_poll_ctx_add(event->ctx, p) < 0) { free(pw); ssh_poll_free(p); return SSH_ERROR; } return SSH_OK; }
/** * @brief remove the poll handle from session and assign them to a event, * when used in blocking mode. * * @param event The ssh_event object * @param session The session to add to the event. * * @returns SSH_OK on success * SSH_ERROR on failure */ int ssh_event_add_session(ssh_event event, ssh_session session) { unsigned int i; ssh_poll_handle p; #ifdef WITH_SERVER struct ssh_iterator *iterator; #endif if(event == NULL || event->ctx == NULL || session == NULL) { return SSH_ERROR; } if(session->default_poll_ctx == NULL) { return SSH_ERROR; } for(i = 0; i < session->default_poll_ctx->polls_used; i++) { p = session->default_poll_ctx->pollptrs[i]; ssh_poll_ctx_remove(session->default_poll_ctx, p); ssh_poll_ctx_add(event->ctx, p); } #ifdef WITH_SERVER iterator = ssh_list_get_iterator(event->sessions); while(iterator != NULL) { if((ssh_session)iterator->data == session) { /* allow only one instance of this session */ return SSH_OK; } iterator = iterator->next; } if(ssh_list_append(event->sessions, session) == SSH_ERROR) { return SSH_ERROR; } #endif return SSH_OK; }
/** * @brief Add a socket object to a poll context. * * @param ctx Pointer to an already allocated poll context. * @param s A SSH socket handle * * @return 0 on success, < 0 on error */ int ssh_poll_ctx_add_socket (ssh_poll_ctx ctx, ssh_socket s) { ssh_poll_handle p; int ret; p = ssh_socket_get_poll_handle(s); if (p == NULL) { return -1; } ret = ssh_poll_ctx_add(ctx,p); return ret; }
/** * @brief Remove a session object from an event context. * * @param event The ssh_event object. * @param session The session to remove. * * @returns SSH_OK on success * SSH_ERROR on failure */ int ssh_event_remove_session(ssh_event event, ssh_session session) { ssh_poll_handle p; register size_t i, used; int rc = SSH_ERROR; #ifdef WITH_SERVER struct ssh_iterator *iterator; #endif if(event == NULL || event->ctx == NULL || session == NULL) { return SSH_ERROR; } used = event->ctx->polls_used; for(i = 0; i < used; i++) { p = event->ctx->pollptrs[i]; if(p->session == session){ /* * ssh_poll_ctx_remove() decrements * event->ctx->polls_used */ ssh_poll_ctx_remove(event->ctx, p); p->session = NULL; ssh_poll_ctx_add(session->default_poll_ctx, p); rc = SSH_OK; /* * Restart the loop! * A session can initially have two pollhandlers. */ used = event->ctx->polls_used; i = 0; } } #ifdef WITH_SERVER iterator = ssh_list_get_iterator(event->sessions); while(iterator != NULL) { if((ssh_session)iterator->data == session) { ssh_list_remove(event->sessions, iterator); /* there should be only one instance of this session */ break; } iterator = iterator->next; } #endif return rc; }
/** * @brief remove the poll handle from session and assign them to a event, * when used in blocking mode. * * @param event The ssh_event object * @param session The session to add to the event. * * @returns SSH_OK on success * SSH_ERROR on failure */ int ssh_event_add_session(ssh_event event, ssh_session session) { ssh_poll_handle p; #ifdef WITH_SERVER struct ssh_iterator *iterator; #endif if(event == NULL || event->ctx == NULL || session == NULL) { return SSH_ERROR; } if(session->default_poll_ctx == NULL) { return SSH_ERROR; } while (session->default_poll_ctx->polls_used > 0) { p = session->default_poll_ctx->pollptrs[0]; /* * ssh_poll_ctx_remove() decrements * session->default_poll_ctx->polls_used */ ssh_poll_ctx_remove(session->default_poll_ctx, p); ssh_poll_ctx_add(event->ctx, p); /* associate the pollhandler with a session so we can put it back * at ssh_event_free() */ p->session = session; } #ifdef WITH_SERVER iterator = ssh_list_get_iterator(event->sessions); while(iterator != NULL) { if((ssh_session)iterator->data == session) { /* allow only one instance of this session */ return SSH_OK; } iterator = iterator->next; } if(ssh_list_append(event->sessions, session) == SSH_ERROR) { return SSH_ERROR; } #endif return SSH_OK; }
/** * @brief Remove a session object from an event context. * * @param event The ssh_event object. * @param session The session to remove. * * @returns SSH_OK on success * SSH_ERROR on failure */ int ssh_event_remove_session(ssh_event event, ssh_session session) { ssh_poll_handle p; register size_t i, used; int rc = SSH_ERROR; socket_t session_fd; #ifdef WITH_SERVER struct ssh_iterator *iterator; #endif if(event == NULL || event->ctx == NULL || session == NULL) { return SSH_ERROR; } session_fd = ssh_get_fd(session); used = event->ctx->polls_used; for(i = 0; i < used; i++) { if(session_fd == event->ctx->pollfds[i].fd) { p = event->ctx->pollptrs[i]; ssh_poll_ctx_remove(event->ctx, p); ssh_poll_ctx_add(session->default_poll_ctx, p); rc = SSH_OK; } } #ifdef WITH_SERVER iterator = ssh_list_get_iterator(event->sessions); while(iterator != NULL) { if((ssh_session)iterator->data == session) { ssh_list_remove(event->sessions, iterator); /* there should be only one instance of this session */ break; } iterator = iterator->next; } #endif return rc; }
/** * @brief Add a poll handle to the event. * * @param event the ssh_event * * @param p the poll handle * * @returns SSH_OK on success * SSH_ERROR on failure */ int ssh_event_add_poll(ssh_event event, ssh_poll_handle p) { return ssh_poll_ctx_add(event->ctx, p); }