4 #include <sys/socket.h>
14 #include <linux/sockios.h>
22 #define UDEBUG_SNDBUF 65536
24 static LIST_HEAD(clients
);
26 static void client_send_msg(struct client
*cl
, struct udebug_client_msg
*data
, int fd
)
28 uint8_t fd_buf
[CMSG_SPACE(sizeof(int))] = { 0 };
31 .iov_len
= sizeof(*data
),
34 .msg_control
= fd_buf
,
35 .msg_controllen
= sizeof(fd_buf
),
45 ioctl(cl
->fd
.fd
, SIOCOUTQ
, &buffered
);
46 #elif defined(__APPLE__)
47 socklen_t slen
= sizeof(buffered
);
48 getsockopt(cl
->fd
.fd
, SOL_SOCKET
, SO_NWRITE
, &buffered
, &slen
);
51 DC(3, cl
, "send msg type=%d len=%d, fd=%d",
52 data
->type
, (unsigned int)iov
.iov_len
, fd
);
54 if (buffered
> UDEBUG_SNDBUF
/ 2) {
55 DC(3, cl
, "skip message due to limited buffer size");
60 cmsg
= CMSG_FIRSTHDR(&msg
);
61 cmsg
->cmsg_type
= SCM_RIGHTS
;
62 cmsg
->cmsg_level
= SOL_SOCKET
;
63 cmsg
->cmsg_len
= CMSG_LEN(sizeof(int));
64 msg
.msg_controllen
= cmsg
->cmsg_len
;
66 pfd
= (int *)CMSG_DATA(cmsg
);
69 msg
.msg_control
= NULL
;
70 msg
.msg_controllen
= 0;
74 len
= sendmsg(cl
->fd
.fd
, &msg
, 0);
75 } while (len
< 0 && errno
== EINTR
);
78 static int client_alloc_notify_id(void)
83 list_for_each_entry(cl
, &clients
, list
)
84 if (cl
->notify_id
>= 0)
85 mask
|= 1 << cl
->notify_id
;
87 for (int i
= 0; i
< 32; i
++, mask
>>= 1)
94 static void client_msg_get_handle(struct client
*cl
)
96 struct udebug_client_msg msg
= {
97 .type
= CL_MSG_GET_HANDLE
,
100 if (cl
->notify_id
< 0 && cl
->uid
== 0)
101 cl
->notify_id
= client_alloc_notify_id();
103 msg
.id
= cl
->notify_id
;
104 client_send_msg(cl
, &msg
, -1);
107 static void client_msg_ring_get(struct client
*cl
, uint32_t id
)
109 struct udebug_client_msg msg
= {
110 .type
= CL_MSG_RING_GET
,
113 struct client_ring
*r
= ring_get_by_id(id
);
116 if (!r
|| cl
->uid
!= 0) {
117 DC(2, cl
, "could not get ring %x", id
);
122 msg
.ring_size
= r
->ring_size
;
123 msg
.data_size
= r
->data_size
;
126 client_send_msg(cl
, &msg
, fd
);
129 static void client_msg_notify(struct client_ring
*r
, uint32_t mask
)
131 struct udebug_client_msg msg
= {
132 .type
= CL_MSG_RING_NOTIFY
,
138 list_for_each_entry(cl
, &clients
, list
) {
139 if (cl
->notify_id
< 0 ||
140 !(mask
& (1 << cl
->notify_id
)))
143 client_send_msg(cl
, &msg
, -1);
147 static void client_free(struct client
*cl
)
149 struct client_ring
*r
;
151 while (!list_empty(&cl
->bufs
)) {
152 r
= list_first_entry(&cl
->bufs
, struct client_ring
, list
);
156 DC(2, cl
, "disconnect");
157 uloop_fd_delete(&cl
->fd
);
164 static void client_parse_message(struct client
*cl
)
166 struct udebug_client_msg
*msg
= &cl
->rx_buf
.msg
;
167 struct client_ring
*r
;
169 DC(3, cl
, "msg type=%d len=%d", msg
->type
, (unsigned int)cl
->rx_ofs
);
171 case CL_MSG_RING_ADD
:
172 client_ring_alloc(cl
);
173 client_send_msg(cl
, msg
, -1);
175 case CL_MSG_RING_REMOVE
:
176 DC(2, cl
, "delete ring %x", msg
->id
);
177 r
= client_ring_get_by_id(cl
, msg
->id
);
181 DC(2, cl
, "ring not found");
182 client_send_msg(cl
, msg
, -1);
184 case CL_MSG_RING_NOTIFY
:
185 DC(3, cl
, "notify on ring %d", msg
->id
);
186 r
= client_ring_get_by_id(cl
, msg
->id
);
188 client_msg_notify(r
, msg
->notify_mask
);
190 DC(2, cl
, "local ring %d not found", msg
->id
);
192 case CL_MSG_GET_HANDLE
:
193 client_msg_get_handle(cl
);
194 DC(2, cl
, "get notify handle: %d", cl
->notify_id
);
196 case CL_MSG_RING_GET
:
197 DC(2, cl
, "get ring %x", msg
->id
);
198 client_msg_ring_get(cl
, msg
->id
);
201 DC(3, cl
, "Invalid message type %d", msg
->type
);
212 static void client_fd_cb(struct uloop_fd
*fd
, unsigned int events
)
214 struct client
*cl
= container_of(fd
, struct client
, fd
);
215 uint8_t fd_buf
[CMSG_SPACE(sizeof(int))] = {};
216 struct iovec iov
= {};
217 struct msghdr msg
= {
220 .msg_control
= fd_buf
,
221 .msg_controllen
= sizeof(fd_buf
),
223 struct cmsghdr
*cmsg
= CMSG_FIRSTHDR(&msg
);
224 size_t min_sz
= sizeof(cl
->rx_buf
.msg
) + sizeof(struct blob_attr
);
228 cmsg
->cmsg_type
= SCM_RIGHTS
;
229 cmsg
->cmsg_level
= SOL_SOCKET
;
230 cmsg
->cmsg_len
= CMSG_LEN(sizeof(int));
232 pfd
= (int *)CMSG_DATA(cmsg
);
233 msg
.msg_controllen
= cmsg
->cmsg_len
;
242 iov
.iov_base
= &cl
->rx_buf
;
243 iov
.iov_len
= min_sz
;
245 iov
.iov_base
= &cl
->rx_buf
.msg
;
246 iov
.iov_len
= min_sz
;
248 len
= recvmsg(fd
->fd
, &msg
, 0);
257 } else if (cl
->rx_ofs
>= min_sz
) {
258 iov
.iov_len
+= blob_pad_len(&cl
->rx_buf
.data
);
259 iov
.iov_len
-= sizeof(struct blob_attr
);
260 if (iov
.iov_len
> sizeof(cl
->rx_buf
)) {
266 iov
.iov_base
+= cl
->rx_ofs
;
267 iov
.iov_len
-= cl
->rx_ofs
;
269 len
= read(fd
->fd
, iov
.iov_base
, iov
.iov_len
);
277 client_parse_message(cl
);
282 static void client_get_info(struct client
*cl
)
285 socklen_t len
= sizeof(&cl
->pid
);
286 if (getsockopt(cl
->fd
.fd
, SOL_LOCAL
, LOCAL_PEERPID
, &cl
->pid
, &len
) < 0)
288 #elif defined(SO_PEERCRED)
290 socklen_t len
= sizeof(uc
);
291 if (getsockopt(cl
->fd
.fd
, SOL_SOCKET
, SO_PEERCRED
, &uc
, &len
) < 0)
298 static void client_get_procname(struct client
*cl
)
304 snprintf(buf
, sizeof(buf
), "/proc/%d/cmdline", cl
->pid
);
308 buf
[fread(buf
, 1, sizeof(buf
) - 1, f
)] = 0;
310 snprintf(cl
->proc_name
, sizeof(cl
->proc_name
), "%s", basename(buf
));
313 proc_name(cl
->pid
, cl
->proc_name
, sizeof(cl
->proc_name
) - 1);
317 void client_alloc(int fd
)
319 int sndbuf
= UDEBUG_SNDBUF
;
322 setsockopt(fd
, SOL_SOCKET
, SO_SNDBUF
, &sndbuf
, sizeof(sndbuf
));
324 cl
= calloc(1, sizeof(*cl
));
325 INIT_LIST_HEAD(&cl
->bufs
);
327 cl
->fd
.cb
= client_fd_cb
;
331 client_get_procname(cl
);
332 if (!cl
->proc_name
[0])
333 snprintf(cl
->proc_name
, sizeof(cl
->proc_name
), "<unknown>");
335 DC(2, cl
, "connect");
336 uloop_fd_add(&cl
->fd
, ULOOP_READ
);
337 list_add_tail(&cl
->list
, &clients
);