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
);
174 case CL_MSG_RING_REMOVE
:
175 DC(2, cl
, "delete ring %x", msg
->id
);
176 r
= client_ring_get_by_id(cl
, msg
->id
);
180 DC(2, cl
, "ring not found");
182 case CL_MSG_RING_NOTIFY
:
183 DC(3, cl
, "notify on ring %d", msg
->id
);
184 r
= client_ring_get_by_id(cl
, msg
->id
);
186 client_msg_notify(r
, msg
->notify_mask
);
188 DC(2, cl
, "local ring %d not found", msg
->id
);
190 case CL_MSG_GET_HANDLE
:
191 client_msg_get_handle(cl
);
192 DC(2, cl
, "get notify handle: %d", cl
->notify_id
);
194 case CL_MSG_RING_GET
:
195 DC(2, cl
, "get ring %x", msg
->id
);
196 client_msg_ring_get(cl
, msg
->id
);
199 DC(3, cl
, "Invalid message type %d", msg
->type
);
210 static void client_fd_cb(struct uloop_fd
*fd
, unsigned int events
)
212 struct client
*cl
= container_of(fd
, struct client
, fd
);
213 uint8_t fd_buf
[CMSG_SPACE(sizeof(int))] = {};
214 struct iovec iov
= {};
215 struct msghdr msg
= {
218 .msg_control
= fd_buf
,
219 .msg_controllen
= sizeof(fd_buf
),
221 struct cmsghdr
*cmsg
= CMSG_FIRSTHDR(&msg
);
222 size_t min_sz
= sizeof(cl
->rx_buf
.msg
) + sizeof(struct blob_attr
);
226 cmsg
->cmsg_type
= SCM_RIGHTS
;
227 cmsg
->cmsg_level
= SOL_SOCKET
;
228 cmsg
->cmsg_len
= CMSG_LEN(sizeof(int));
230 pfd
= (int *)CMSG_DATA(cmsg
);
231 msg
.msg_controllen
= cmsg
->cmsg_len
;
240 iov
.iov_base
= &cl
->rx_buf
;
241 iov
.iov_len
= min_sz
;
243 iov
.iov_base
= &cl
->rx_buf
.msg
;
244 iov
.iov_len
= min_sz
;
246 len
= recvmsg(fd
->fd
, &msg
, 0);
255 } else if (cl
->rx_ofs
>= min_sz
) {
256 iov
.iov_len
+= blob_pad_len(&cl
->rx_buf
.data
);
257 iov
.iov_len
-= sizeof(struct blob_attr
);
258 if (iov
.iov_len
> sizeof(cl
->rx_buf
)) {
264 iov
.iov_base
+= cl
->rx_ofs
;
265 iov
.iov_len
-= cl
->rx_ofs
;
267 len
= read(fd
->fd
, iov
.iov_base
, iov
.iov_len
);
275 client_parse_message(cl
);
280 static void client_get_info(struct client
*cl
)
283 socklen_t len
= sizeof(&cl
->pid
);
284 if (getsockopt(cl
->fd
.fd
, SOL_LOCAL
, LOCAL_PEERPID
, &cl
->pid
, &len
) < 0)
286 #elif defined(SO_PEERCRED)
288 socklen_t len
= sizeof(uc
);
289 if (getsockopt(cl
->fd
.fd
, SOL_SOCKET
, SO_PEERCRED
, &uc
, &len
) < 0)
296 static void client_get_procname(struct client
*cl
)
302 snprintf(buf
, sizeof(buf
), "/proc/%d/cmdline", cl
->pid
);
306 buf
[fread(buf
, 1, sizeof(buf
) - 1, f
)] = 0;
308 snprintf(cl
->proc_name
, sizeof(cl
->proc_name
), "%s", basename(buf
));
311 proc_name(cl
->pid
, cl
->proc_name
, sizeof(cl
->proc_name
) - 1);
315 void client_alloc(int fd
)
317 int sndbuf
= UDEBUG_SNDBUF
;
320 setsockopt(fd
, SOL_SOCKET
, SO_SNDBUF
, &sndbuf
, sizeof(sndbuf
));
322 cl
= calloc(1, sizeof(*cl
));
323 INIT_LIST_HEAD(&cl
->bufs
);
325 cl
->fd
.cb
= client_fd_cb
;
329 client_get_procname(cl
);
330 if (!cl
->proc_name
[0])
331 snprintf(cl
->proc_name
, sizeof(cl
->proc_name
), "<unknown>");
333 DC(2, cl
, "connect");
334 uloop_fd_add(&cl
->fd
, ULOOP_READ
);
335 list_add_tail(&cl
->list
, &clients
);