| 1 | /* |
| 2 | * Copyright 6WIND S.A., 2014 |
| 3 | * |
| 4 | * This work is licensed under the terms of the GNU GPL, version 2 or |
| 5 | * (at your option) any later version. See the COPYING file in the |
| 6 | * top-level directory. |
| 7 | */ |
| 8 | |
| 9 | #ifndef IVSHMEM_CLIENT_H |
| 10 | #define IVSHMEM_CLIENT_H |
| 11 | |
| 12 | /** |
| 13 | * This file provides helper to implement an ivshmem client. It is used |
| 14 | * on the host to ask QEMU to send an interrupt to an ivshmem PCI device in a |
| 15 | * guest. QEMU also implements an ivshmem client similar to this one, they both |
| 16 | * connect to an ivshmem server. |
| 17 | * |
| 18 | * A standalone ivshmem client based on this file is provided for debug/test |
| 19 | * purposes. |
| 20 | */ |
| 21 | |
| 22 | #include <sys/select.h> |
| 23 | |
| 24 | #include "qemu/queue.h" |
| 25 | #include "hw/misc/ivshmem.h" |
| 26 | |
| 27 | /** |
| 28 | * Maximum number of notification vectors supported by the client |
| 29 | */ |
| 30 | #define IVSHMEM_CLIENT_MAX_VECTORS 64 |
| 31 | |
| 32 | /** |
| 33 | * Structure storing a peer |
| 34 | * |
| 35 | * Each time a client connects to an ivshmem server, it is advertised to |
| 36 | * all connected clients through the unix socket. When our ivshmem |
| 37 | * client receives a notification, it creates a IvshmemClientPeer |
| 38 | * structure to store the infos of this peer. |
| 39 | * |
| 40 | * This structure is also used to store the information of our own |
| 41 | * client in (IvshmemClient)->local. |
| 42 | */ |
| 43 | typedef struct IvshmemClientPeer { |
| 44 | QTAILQ_ENTRY(IvshmemClientPeer) next; /**< next in list*/ |
| 45 | int64_t id; /**< the id of the peer */ |
| 46 | int vectors[IVSHMEM_CLIENT_MAX_VECTORS]; /**< one fd per vector */ |
| 47 | unsigned vectors_count; /**< number of vectors */ |
| 48 | } IvshmemClientPeer; |
| 49 | |
| 50 | typedef struct IvshmemClient IvshmemClient; |
| 51 | |
| 52 | /** |
| 53 | * Typedef of callback function used when our IvshmemClient receives a |
| 54 | * notification from a peer. |
| 55 | */ |
| 56 | typedef void (*IvshmemClientNotifCb)( |
| 57 | const IvshmemClient *client, |
| 58 | const IvshmemClientPeer *peer, |
| 59 | unsigned vect, void *arg); |
| 60 | |
| 61 | /** |
| 62 | * Structure describing an ivshmem client |
| 63 | * |
| 64 | * This structure stores all information related to our client: the name |
| 65 | * of the server unix socket, the list of peers advertised by the |
| 66 | * server, our own client information, and a pointer the notification |
| 67 | * callback function used when we receive a notification from a peer. |
| 68 | */ |
| 69 | struct IvshmemClient { |
| 70 | char unix_sock_path[PATH_MAX]; /**< path to unix sock */ |
| 71 | int sock_fd; /**< unix sock filedesc */ |
| 72 | int shm_fd; /**< shm file descriptor */ |
| 73 | |
| 74 | QTAILQ_HEAD(, IvshmemClientPeer) peer_list; /**< list of peers */ |
| 75 | IvshmemClientPeer local; /**< our own infos */ |
| 76 | |
| 77 | IvshmemClientNotifCb notif_cb; /**< notification callback */ |
| 78 | void *notif_arg; /**< notification argument */ |
| 79 | |
| 80 | bool verbose; /**< true to enable debug */ |
| 81 | }; |
| 82 | |
| 83 | /** |
| 84 | * Initialize an ivshmem client |
| 85 | * |
| 86 | * @client: A pointer to an uninitialized IvshmemClient structure |
| 87 | * @unix_sock_path: The pointer to the unix socket file name |
| 88 | * @notif_cb: If not NULL, the pointer to the function to be called when |
| 89 | * our IvshmemClient receives a notification from a peer |
| 90 | * @notif_arg: Opaque pointer given as-is to the notification callback |
| 91 | * function |
| 92 | * @verbose: True to enable debug |
| 93 | * |
| 94 | * Returns: 0 on success, or a negative value on error |
| 95 | */ |
| 96 | int ivshmem_client_init(IvshmemClient *client, const char *unix_sock_path, |
| 97 | IvshmemClientNotifCb notif_cb, void *notif_arg, |
| 98 | bool verbose); |
| 99 | |
| 100 | /** |
| 101 | * Connect to the server |
| 102 | * |
| 103 | * Connect to the server unix socket, and read the first initial |
| 104 | * messages sent by the server, giving the ID of the client and the file |
| 105 | * descriptor of the shared memory. |
| 106 | * |
| 107 | * @client: The ivshmem client |
| 108 | * |
| 109 | * Returns: 0 on success, or a negative value on error |
| 110 | */ |
| 111 | int ivshmem_client_connect(IvshmemClient *client); |
| 112 | |
| 113 | /** |
| 114 | * Close connection to the server and free all peer structures |
| 115 | * |
| 116 | * @client: The ivshmem client |
| 117 | */ |
| 118 | void ivshmem_client_close(IvshmemClient *client); |
| 119 | |
| 120 | /** |
| 121 | * Fill a fd_set with file descriptors to be monitored |
| 122 | * |
| 123 | * This function will fill a fd_set with all file descriptors |
| 124 | * that must be polled (unix server socket and peers eventfd). The |
| 125 | * function will not initialize the fd_set, it is up to the caller |
| 126 | * to do this. |
| 127 | * |
| 128 | * @client: The ivshmem client |
| 129 | * @fds: The fd_set to be updated |
| 130 | * @maxfd: Must be set to the max file descriptor + 1 in fd_set. This value is |
| 131 | * updated if this function adds a greater fd in fd_set. |
| 132 | */ |
| 133 | void ivshmem_client_get_fds(const IvshmemClient *client, fd_set *fds, |
| 134 | int *maxfd); |
| 135 | |
| 136 | /** |
| 137 | * Read and handle new messages |
| 138 | * |
| 139 | * Given a fd_set filled by select(), handle incoming messages from |
| 140 | * server or peers. |
| 141 | * |
| 142 | * @client: The ivshmem client |
| 143 | * @fds: The fd_set containing the file descriptors to be checked. Note |
| 144 | * that file descriptors that are not related to our client are |
| 145 | * ignored. |
| 146 | * @maxfd: The maximum fd in fd_set, plus one. |
| 147 | * |
| 148 | * Returns: 0 on success, or a negative value on error |
| 149 | */ |
| 150 | int ivshmem_client_handle_fds(IvshmemClient *client, fd_set *fds, int maxfd); |
| 151 | |
| 152 | /** |
| 153 | * Send a notification to a vector of a peer |
| 154 | * |
| 155 | * @client: The ivshmem client |
| 156 | * @peer: The peer to be notified |
| 157 | * @vector: The number of the vector |
| 158 | * |
| 159 | * Returns: 0 on success, or a negative value on error |
| 160 | */ |
| 161 | int ivshmem_client_notify(const IvshmemClient *client, |
| 162 | const IvshmemClientPeer *peer, unsigned vector); |
| 163 | |
| 164 | /** |
| 165 | * Send a notification to all vectors of a peer |
| 166 | * |
| 167 | * @client: The ivshmem client |
| 168 | * @peer: The peer to be notified |
| 169 | * |
| 170 | * Returns: 0 on success, or a negative value on error (at least one |
| 171 | * notification failed) |
| 172 | */ |
| 173 | int ivshmem_client_notify_all_vects(const IvshmemClient *client, |
| 174 | const IvshmemClientPeer *peer); |
| 175 | |
| 176 | /** |
| 177 | * Broadcast a notification to all vectors of all peers |
| 178 | * |
| 179 | * @client: The ivshmem client |
| 180 | * |
| 181 | * Returns: 0 on success, or a negative value on error (at least one |
| 182 | * notification failed) |
| 183 | */ |
| 184 | int ivshmem_client_notify_broadcast(const IvshmemClient *client); |
| 185 | |
| 186 | /** |
| 187 | * Search a peer from its identifier |
| 188 | * |
| 189 | * Return the peer structure from its peer_id. If the given peer_id is |
| 190 | * the local id, the function returns the local peer structure. |
| 191 | * |
| 192 | * @client: The ivshmem client |
| 193 | * @peer_id: The identifier of the peer structure |
| 194 | * |
| 195 | * Returns: The peer structure, or NULL if not found |
| 196 | */ |
| 197 | IvshmemClientPeer * |
| 198 | ivshmem_client_search_peer(IvshmemClient *client, int64_t peer_id); |
| 199 | |
| 200 | /** |
| 201 | * Dump information of this ivshmem client on stdout |
| 202 | * |
| 203 | * Dump the id and the vectors of the given ivshmem client and the list |
| 204 | * of its peers and their vectors on stdout. |
| 205 | * |
| 206 | * @client: The ivshmem client |
| 207 | */ |
| 208 | void ivshmem_client_dump(const IvshmemClient *client); |
| 209 | |
| 210 | #endif /* IVSHMEM_CLIENT_H */ |