PageRenderTime 36ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/servers/pfs/dev_uds.c

http://www.minix3.org/
C | 1180 lines | 623 code | 303 blank | 254 comment | 130 complexity | dd090844b1f5f734705b79918e3ef42d MD5 | raw file
Possible License(s): MIT, WTFPL, AGPL-1.0, BSD-3-Clause, GPL-3.0, LGPL-2.0, JSON, 0BSD
  1. /*
  2. * Unix Domain Sockets Implementation (PF_UNIX, PF_LOCAL)
  3. * This code handles requests generated by operations on /dev/uds
  4. *
  5. * The entry points into this file are...
  6. *
  7. * uds_open: handles the open(2) syscall on /dev/uds
  8. * uds_close: handles the close(2) syscall on /dev/uds
  9. * uds_select: handles the select(2) syscall on /dev/uds
  10. * uds_read: handles the read(2) syscall on /dev/uds
  11. * uds_write: handles the write(2) syscall on /dev/uds
  12. * uds_ioctl: handles the ioctl(2) syscall on /dev/uds
  13. * uds_status: handles status requests.
  14. * uds_cancel: handles cancelled syscalls.
  15. *
  16. * Also See...
  17. *
  18. * table.c, uds.c, uds.h
  19. *
  20. * Overview
  21. *
  22. * The interface to unix domain sockets is similar to the
  23. * the interface to network sockets. There is a character
  24. * device (/dev/uds) that uses STYLE_CLONE and this server
  25. * is a 'driver' for that device.
  26. */
  27. #define DEBUG 0
  28. #include "inc.h"
  29. #include "const.h"
  30. #include "glo.h"
  31. #include "uds.h"
  32. static int uds_perform_read(int minor, endpoint_t m_source, size_t
  33. size, int pretend);
  34. static int uds_perform_write(int minor, endpoint_t m_source, size_t
  35. size, int pretend);
  36. int uds_open(message *dev_m_in, message *dev_m_out)
  37. {
  38. message fs_m_in, fs_m_out;
  39. struct ucred ucred;
  40. int rc, i;
  41. int minor;
  42. #if DEBUG == 1
  43. static int call_count = 0;
  44. printf("(uds) [%d] uds_open() call_count=%d\n", uds_minor(dev_m_in),
  45. ++call_count);
  46. printf("Endpoint: 0x%x\n", dev_m_in->USER_ENDPT);
  47. #endif
  48. /*
  49. * Find a slot in the descriptor table for the new descriptor.
  50. * The index of the descriptor in the table will be returned.
  51. * Subsequent calls to read/write/close/ioctl/etc will use this
  52. * minor number. The minor number must be different from the
  53. * the /dev/uds device's minor number (currently 0).
  54. */
  55. minor = -1; /* to trap error */
  56. for (i = 1; i < NR_FDS; i++) {
  57. if (uds_fd_table[i].state == UDS_FREE) {
  58. minor = i;
  59. break;
  60. }
  61. }
  62. if (minor == -1) {
  63. /* descriptor table full */
  64. uds_set_reply(dev_m_out, DEV_OPEN_REPL, dev_m_in->USER_ENDPT,
  65. (cp_grant_id_t) dev_m_in->IO_GRANT, ENFILE);
  66. return ENFILE;
  67. }
  68. /*
  69. * We found a slot in uds_fd_table, now initialize the descriptor
  70. */
  71. /* mark this one as 'in use' so that it doesn't get assigned to
  72. * another socket
  73. */
  74. uds_fd_table[minor].state = UDS_INUSE;
  75. /* track the system call we are performing in case it gets cancelled */
  76. uds_fd_table[minor].call_nr = dev_m_in->m_type;
  77. uds_fd_table[minor].ioctl = 0;
  78. uds_fd_table[minor].syscall_done = 0;
  79. /* set the socket owner */
  80. uds_fd_table[minor].owner = dev_m_in->USER_ENDPT;
  81. uds_fd_table[minor].endpoint = dev_m_in->USER_ENDPT;
  82. /* setup select(2) framework */
  83. uds_fd_table[minor].selecting = 0;
  84. uds_fd_table[minor].select_proc = 0;
  85. uds_fd_table[minor].sel_ops_in = 0;
  86. uds_fd_table[minor].sel_ops_out = 0;
  87. uds_fd_table[minor].status_updated = 0;
  88. /* initialize the data pointer (pos) to the start of the PIPE */
  89. uds_fd_table[minor].pos = 0;
  90. /* the PIPE is initially empty */
  91. uds_fd_table[minor].size = 0;
  92. /* the default for a new socket is to allow reading and writing.
  93. * shutdown(2) will remove one or both flags.
  94. */
  95. uds_fd_table[minor].mode = S_IRUSR|S_IWUSR;
  96. /* In libc socket(2) sets this to the actual value later with the
  97. * NWIOSUDSTYPE ioctl().
  98. */
  99. uds_fd_table[minor].type = -1;
  100. /* Clear the backlog by setting each entry to -1 */
  101. for (i = 0; i < UDS_SOMAXCONN; i++) {
  102. /* initially no connections are pending */
  103. uds_fd_table[minor].backlog[i] = -1;
  104. }
  105. memset(&uds_fd_table[minor].ancillary_data, '\0', sizeof(struct
  106. ancillary));
  107. for (i = 0; i < OPEN_MAX; i++) {
  108. uds_fd_table[minor].ancillary_data.fds[i] = -1;
  109. }
  110. /* default the size to UDS_SOMAXCONN */
  111. uds_fd_table[minor].backlog_size = UDS_SOMAXCONN;
  112. /* the socket isn't listening for incoming connections until
  113. * listen(2) is called
  114. */
  115. uds_fd_table[minor].listening = 0;
  116. /* initially the socket is not connected to a peer */
  117. uds_fd_table[minor].peer = -1;
  118. /* there isn't a child waiting to be accept(2)'d */
  119. uds_fd_table[minor].child = -1;
  120. /* initially the socket is not bound or listening on an address */
  121. memset(&(uds_fd_table[minor].addr), '\0', sizeof(struct sockaddr_un));
  122. memset(&(uds_fd_table[minor].source), '\0', sizeof(struct sockaddr_un));
  123. memset(&(uds_fd_table[minor].target), '\0', sizeof(struct sockaddr_un));
  124. /* Initially the socket isn't suspended. */
  125. uds_fd_table[minor].suspended = UDS_NOT_SUSPENDED;
  126. /* and the socket doesn't have an I/O grant initially */
  127. uds_fd_table[minor].io_gr = (cp_grant_id_t) 0;
  128. /* since there is no I/O grant it effectively has no size either */
  129. uds_fd_table[minor].io_gr_size = 0;
  130. /* The process isn't suspended so we don't flag it as revivable */
  131. uds_fd_table[minor].ready_to_revive = 0;
  132. /* get the effective user id and effective group id from the endpoint */
  133. /* this is needed in the REQ_NEWNODE request to PFS. */
  134. rc = getnucred(uds_fd_table[minor].endpoint, &ucred);
  135. if (rc == -1) {
  136. /* roll back the changes we made to the descriptor */
  137. memset(&(uds_fd_table[minor]), '\0', sizeof(uds_fd_t));
  138. /* likely error: invalid endpoint / proc doesn't exist */
  139. uds_set_reply(dev_m_out, DEV_OPEN_REPL, dev_m_in->USER_ENDPT,
  140. (cp_grant_id_t) dev_m_in->IO_GRANT, errno);
  141. return errno;
  142. }
  143. /* Prepare Request to the FS side of PFS */
  144. fs_m_in.m_type = REQ_NEWNODE;
  145. fs_m_in.REQ_MODE = I_NAMED_PIPE;
  146. fs_m_in.REQ_DEV = NO_DEV;
  147. fs_m_in.REQ_UID = ucred.uid;
  148. fs_m_in.REQ_GID = ucred.gid;
  149. /* Request a new inode on the pipe file system */
  150. rc = fs_newnode(&fs_m_in, &fs_m_out);
  151. if (rc != OK) {
  152. /* roll back the changes we made to the descriptor */
  153. memset(&(uds_fd_table[minor]), '\0', sizeof(uds_fd_t));
  154. /* likely error: get_block() failed */
  155. uds_set_reply(dev_m_out, DEV_OPEN_REPL, dev_m_in->USER_ENDPT,
  156. (cp_grant_id_t) dev_m_in->IO_GRANT, rc);
  157. return rc;
  158. }
  159. /* Process the response */
  160. uds_fd_table[minor].inode_nr = fs_m_out.RES_INODE_NR;
  161. /* prepare the reply */
  162. uds_fd_table[minor].syscall_done = 1;
  163. uds_set_reply(dev_m_out, DEV_OPEN_REPL, dev_m_in->USER_ENDPT,
  164. (cp_grant_id_t) dev_m_in->IO_GRANT, minor);
  165. return minor;
  166. }
  167. int uds_close(message *dev_m_in, message *dev_m_out)
  168. {
  169. int minor;
  170. message fs_m_in, fs_m_out;
  171. int rc;
  172. #if DEBUG == 1
  173. static int call_count = 0;
  174. printf("(uds) [%d] uds_close() call_count=%d\n", uds_minor(dev_m_in),
  175. ++call_count);
  176. printf("Endpoint: 0x%x\n", dev_m_in->USER_ENDPT);
  177. #endif
  178. minor = uds_minor(dev_m_in);
  179. if (uds_fd_table[minor].state != UDS_INUSE) {
  180. /* attempted to close a socket that hasn't been opened --
  181. * something is very wrong :(
  182. */
  183. uds_set_reply(dev_m_out, DEV_CLOSE_REPL, dev_m_in->USER_ENDPT,
  184. (cp_grant_id_t) dev_m_in->IO_GRANT, EINVAL);
  185. return EINVAL;
  186. }
  187. /* no need to track the syscall in case of cancellation. close() is
  188. * atomic and can't be cancelled. no need to update the endpoint here,
  189. * we won't be needing it to kill the socket
  190. */
  191. /* if the socket is connected, disconnect it */
  192. if (uds_fd_table[minor].peer != -1) {
  193. /* set peer of this peer to -1 */
  194. uds_fd_table[uds_fd_table[minor].peer].peer = -1;
  195. /* error to pass to peer */
  196. uds_fd_table[uds_fd_table[minor].peer].err = ECONNRESET;
  197. /* if peer was blocked on I/O revive peer */
  198. if (uds_fd_table[uds_fd_table[minor].peer].suspended) {
  199. int peer = uds_fd_table[minor].peer;
  200. uds_fd_table[peer].ready_to_revive = 1;
  201. uds_unsuspend(dev_m_in->m_source, peer);
  202. }
  203. }
  204. if (uds_fd_table[minor].ancillary_data.nfiledes > 0) {
  205. clear_fds(minor, &(uds_fd_table[minor].ancillary_data));
  206. }
  207. /* Prepare Request to the FS side of PFS */
  208. fs_m_in.m_type = REQ_PUTNODE;
  209. fs_m_in.REQ_INODE_NR = uds_fd_table[minor].inode_nr;
  210. fs_m_in.REQ_COUNT = 1;
  211. /* set the socket back to its original UDS_FREE state */
  212. memset(&(uds_fd_table[minor]), '\0', sizeof(uds_fd_t));
  213. /* Request the removal of the inode from the pipe file system */
  214. rc = fs_putnode(&fs_m_in, &fs_m_out);
  215. if (rc != OK) {
  216. perror("fs_putnode");
  217. /* likely error: get_block() failed */
  218. return rc;
  219. }
  220. uds_set_reply(dev_m_out, DEV_CLOSE_REPL, dev_m_in->USER_ENDPT,
  221. (cp_grant_id_t) dev_m_in->IO_GRANT, OK);
  222. return OK;
  223. }
  224. int uds_select(message *dev_m_in, message *dev_m_out)
  225. {
  226. int i, bytes;
  227. int minor;
  228. #if DEBUG == 1
  229. static int call_count = 0;
  230. printf("(uds) [%d] uds_select() call_count=%d\n", uds_minor(dev_m_in),
  231. ++call_count);
  232. printf("Endpoint: 0x%x\n", dev_m_in->USER_ENDPT);
  233. #endif
  234. minor = uds_minor(dev_m_in);
  235. if (uds_fd_table[minor].state != UDS_INUSE) {
  236. /* attempted to close a socket that hasn't been opened --
  237. * something is very wrong :(
  238. */
  239. uds_sel_reply(dev_m_out, DEV_SEL_REPL1, minor, EINVAL);
  240. return EINVAL;
  241. }
  242. /* setup select(2) framework */
  243. uds_fd_table[minor].selecting = 1;
  244. uds_fd_table[minor].select_proc = dev_m_in->m_source;
  245. /* track the system call we are performing in case it gets cancelled */
  246. uds_fd_table[minor].call_nr = dev_m_in->m_type;
  247. uds_fd_table[minor].ioctl = 0;
  248. uds_fd_table[minor].syscall_done = 0;
  249. /* Can't update the process endpoint here, no info. */
  250. uds_fd_table[minor].sel_ops_in = dev_m_in->USER_ENDPT;
  251. uds_fd_table[minor].sel_ops_out = 0;
  252. /* check if there is data available to read */
  253. bytes = uds_perform_read(minor, dev_m_in->m_source, 1, 1);
  254. if (bytes > 0) {
  255. /* there is data in the pipe for us to read */
  256. uds_fd_table[minor].sel_ops_out |= SEL_RD;
  257. } else if (uds_fd_table[minor].listening == 1) {
  258. /* check for pending connections */
  259. for (i = 0; i < uds_fd_table[minor].backlog_size; i++) {
  260. if (uds_fd_table[minor].backlog[i] != -1) {
  261. uds_fd_table[minor].sel_ops_out |= SEL_RD;
  262. break;
  263. }
  264. }
  265. }
  266. /* check if we can write without blocking */
  267. bytes = uds_perform_write(minor, dev_m_in->m_source, PIPE_BUF, 1);
  268. if (bytes > 0) {
  269. uds_fd_table[minor].sel_ops_out |= SEL_WR;
  270. }
  271. uds_fd_table[minor].syscall_done = 1;
  272. uds_sel_reply(dev_m_out, DEV_SEL_REPL1, minor,
  273. uds_fd_table[minor].sel_ops_out);
  274. return uds_fd_table[minor].sel_ops_out;
  275. }
  276. static int uds_perform_read(int minor, endpoint_t m_source,
  277. size_t size, int pretend)
  278. {
  279. int rc;
  280. message fs_m_in;
  281. message fs_m_out;
  282. #if DEBUG == 1
  283. static int call_count = 0;
  284. printf("(uds) [%d] uds_perform_read() call_count=%d\n", minor,
  285. ++call_count);
  286. #endif
  287. /* skip reads and writes of 0 (or less!) bytes */
  288. if (size <= 0) {
  289. return 0;
  290. }
  291. /* check if we are allowed to read */
  292. if (!(uds_fd_table[minor].mode & S_IRUSR)) {
  293. /* socket is shutdown for reading */
  294. return EPIPE;
  295. }
  296. if (uds_fd_table[minor].size == 0) {
  297. if (pretend) {
  298. return SUSPEND;
  299. }
  300. /* maybe a process is blocked waiting to write? if
  301. * needed revive the writer
  302. */
  303. if (uds_fd_table[minor].peer != -1 &&
  304. uds_fd_table[uds_fd_table[minor].peer].suspended) {
  305. int peer = uds_fd_table[minor].peer;
  306. uds_fd_table[peer].ready_to_revive = 1;
  307. uds_unsuspend(m_source, peer);
  308. }
  309. #if DEBUG == 1
  310. printf("(uds) [%d] suspending read request\n", minor);
  311. #endif
  312. /* Process is reading from an empty pipe,
  313. * suspend it so some bytes can be written
  314. */
  315. uds_fd_table[minor].suspended = UDS_SUSPENDED_READ;
  316. return SUSPEND;
  317. }
  318. if (pretend) {
  319. return (size > uds_fd_table[minor].size) ?
  320. uds_fd_table[minor].size : size;
  321. }
  322. /* Prepare Request to the FS side of PFS */
  323. fs_m_in.m_type = REQ_READ;
  324. fs_m_in.REQ_INODE_NR = uds_fd_table[minor].inode_nr;
  325. fs_m_in.REQ_GRANT = uds_fd_table[minor].io_gr;
  326. fs_m_in.REQ_SEEK_POS_HI = 0;
  327. fs_m_in.REQ_SEEK_POS_LO = uds_fd_table[minor].pos;
  328. fs_m_in.REQ_NBYTES = (size > uds_fd_table[minor].size) ?
  329. uds_fd_table[minor].size : size;
  330. /* perform the read */
  331. rc = fs_readwrite(&fs_m_in, &fs_m_out);
  332. if (rc != OK) {
  333. perror("fs_readwrite");
  334. return rc;
  335. }
  336. /* Process the response */
  337. #if DEBUG == 1
  338. printf("(uds) [%d] read complete\n", minor);
  339. #endif
  340. /* move the position of the data pointer up to data we haven't
  341. * read yet
  342. */
  343. uds_fd_table[minor].pos += fs_m_out.RES_NBYTES;
  344. /* decrease the number of unread bytes */
  345. uds_fd_table[minor].size -= fs_m_out.RES_NBYTES;
  346. /* if we have 0 unread bytes, move the data pointer back to the
  347. * start of the buffer
  348. */
  349. if (uds_fd_table[minor].size == 0) {
  350. uds_fd_table[minor].pos = 0;
  351. }
  352. /* maybe a big write was waiting for us to read some data, if
  353. * needed revive the writer
  354. */
  355. if (uds_fd_table[minor].peer != -1 &&
  356. uds_fd_table[uds_fd_table[minor].peer].suspended) {
  357. int peer = uds_fd_table[minor].peer;
  358. uds_fd_table[peer].ready_to_revive = 1;
  359. uds_unsuspend(m_source, peer);
  360. }
  361. /* see if peer is blocked on select() and a write is possible
  362. * (from peer to minor)
  363. */
  364. if (uds_fd_table[minor].peer != -1 &&
  365. uds_fd_table[uds_fd_table[minor].peer].selecting == 1 &&
  366. (uds_fd_table[minor].size + uds_fd_table[minor].pos + 1
  367. < PIPE_BUF)) {
  368. int peer = uds_fd_table[minor].peer;
  369. /* if the peer wants to know about write being possible
  370. * and it doesn't know about it already, then let the peer know.
  371. */
  372. if ((uds_fd_table[peer].sel_ops_in & SEL_WR) &&
  373. !(uds_fd_table[peer].sel_ops_out & SEL_WR)) {
  374. /* a write on peer is possible now */
  375. uds_fd_table[peer].sel_ops_out |= SEL_WR;
  376. uds_fd_table[peer].status_updated = 1;
  377. uds_unsuspend(m_source, peer);
  378. }
  379. }
  380. return fs_m_out.RES_NBYTES; /* return number of bytes read */
  381. }
  382. static int uds_perform_write(int minor, endpoint_t m_source,
  383. size_t size, int pretend)
  384. {
  385. int rc, peer, i;
  386. message fs_m_in;
  387. message fs_m_out;
  388. #if DEBUG == 1
  389. static int call_count = 0;
  390. printf("(uds) [%d] uds_perform_write() call_count=%d\n", minor,
  391. ++call_count);
  392. #endif
  393. /* skip reads and writes of 0 (or less!) bytes */
  394. if (size <= 0) {
  395. return 0;
  396. }
  397. /* check if we are allowed to write */
  398. if (!(uds_fd_table[minor].mode & S_IWUSR)) {
  399. /* socket is shutdown for writing */
  400. return EPIPE;
  401. }
  402. if (size > PIPE_BUF) {
  403. /* message is too big to ever write to the PIPE */
  404. return EMSGSIZE;
  405. }
  406. if (uds_fd_table[minor].type == SOCK_STREAM ||
  407. uds_fd_table[minor].type == SOCK_SEQPACKET) {
  408. /* if we're writing with a connection oriented socket,
  409. * then it needs a peer to write to
  410. */
  411. if (uds_fd_table[minor].peer == -1) {
  412. if (uds_fd_table[minor].err == ECONNRESET) {
  413. uds_fd_table[minor].err = 0;
  414. return ECONNRESET;
  415. } else {
  416. return ENOTCONN;
  417. }
  418. } else {
  419. peer = uds_fd_table[minor].peer;
  420. }
  421. } else /* uds_fd_table[minor].type == SOCK_DGRAM */ {
  422. peer = -1;
  423. /* locate the "peer" we want to write to */
  424. for (i = 0; i < NR_FDS; i++) {
  425. /* look for a SOCK_DGRAM socket that is bound on
  426. * the target address
  427. */
  428. if (uds_fd_table[i].type == SOCK_DGRAM &&
  429. uds_fd_table[i].addr.sun_family == AF_UNIX &&
  430. !strncmp(uds_fd_table[minor].target.sun_path,
  431. uds_fd_table[i].addr.sun_path, UNIX_PATH_MAX)) {
  432. peer = i;
  433. break;
  434. }
  435. }
  436. }
  437. if (peer == -1) {
  438. if (pretend)
  439. return SUSPEND;
  440. return ENOENT;
  441. }
  442. /* check if write would overrun buffer. check if message
  443. * boundry preserving types (SEQPACKET and DGRAM) wouldn't write
  444. * to an empty buffer. check if connectionless sockets have a
  445. * target to write to.
  446. */
  447. if ((uds_fd_table[peer].pos+uds_fd_table[peer].size+size > PIPE_BUF) ||
  448. ((uds_fd_table[minor].type == SOCK_SEQPACKET ||
  449. uds_fd_table[minor].type == SOCK_DGRAM) &&
  450. uds_fd_table[peer].size > 0)) {
  451. if (pretend) {
  452. return SUSPEND;
  453. }
  454. /* if needed revive the reader */
  455. if (uds_fd_table[peer].suspended) {
  456. uds_fd_table[peer].ready_to_revive = 1;
  457. uds_unsuspend(m_source, peer);
  458. }
  459. #if DEBUG == 1
  460. printf("(uds) [%d] suspending write request\n", minor);
  461. #endif
  462. /* Process is reading from an empty pipe,
  463. * suspend it so some bytes can be written
  464. */
  465. uds_fd_table[minor].suspended = UDS_SUSPENDED_WRITE;
  466. return SUSPEND;
  467. }
  468. if (pretend) {
  469. return size;
  470. }
  471. /* Prepare Request to the FS side of PFS */
  472. fs_m_in.m_type = REQ_WRITE;
  473. fs_m_in.REQ_INODE_NR = uds_fd_table[peer].inode_nr;
  474. fs_m_in.REQ_GRANT = uds_fd_table[minor].io_gr;
  475. fs_m_in.REQ_SEEK_POS_HI = 0;
  476. fs_m_in.REQ_SEEK_POS_LO = uds_fd_table[peer].pos +
  477. uds_fd_table[peer].size;
  478. fs_m_in.REQ_NBYTES = size;
  479. /* Request the write */
  480. rc = fs_readwrite(&fs_m_in, &fs_m_out);
  481. if (rc != OK) {
  482. perror("fs_readwrite");
  483. return rc;
  484. }
  485. /* Process the response */
  486. #if DEBUG == 1
  487. printf("(uds) [%d] write complete\n", minor);
  488. #endif
  489. /* increase the count of unread bytes */
  490. uds_fd_table[peer].size += fs_m_out.RES_NBYTES;
  491. /* fill in the source address to be returned by recvfrom & recvmsg */
  492. if (uds_fd_table[minor].type == SOCK_DGRAM) {
  493. memcpy(&uds_fd_table[peer].source, &uds_fd_table[minor].addr,
  494. sizeof(struct sockaddr_un));
  495. }
  496. /* revive peer that was waiting for us to write */
  497. if (uds_fd_table[peer].suspended) {
  498. uds_fd_table[peer].ready_to_revive = 1;
  499. uds_unsuspend(m_source, peer);
  500. }
  501. /* see if peer is blocked on select()*/
  502. if (uds_fd_table[peer].selecting == 1 && fs_m_out.RES_NBYTES > 0) {
  503. /* if the peer wants to know about data ready to read
  504. * and it doesn't know about it already, then let the peer
  505. * know we have data for it.
  506. */
  507. if ((uds_fd_table[peer].sel_ops_in & SEL_RD) &&
  508. !(uds_fd_table[peer].sel_ops_out & SEL_RD)) {
  509. /* a read on peer is possible now */
  510. uds_fd_table[peer].sel_ops_out |= SEL_RD;
  511. uds_fd_table[peer].status_updated = 1;
  512. uds_unsuspend(m_source, peer);
  513. }
  514. }
  515. return fs_m_out.RES_NBYTES; /* return number of bytes written */
  516. }
  517. int uds_read(message *dev_m_in, message *dev_m_out)
  518. {
  519. int bytes;
  520. int minor;
  521. #if DEBUG == 1
  522. static int call_count = 0;
  523. printf("(uds) [%d] uds_read() call_count=%d\n", uds_minor(dev_m_in),
  524. ++call_count);
  525. printf("Endpoint: 0x%x | Position 0x%x\n", dev_m_in->USER_ENDPT,
  526. dev_m_in->POSITION);
  527. #endif
  528. minor = uds_minor(dev_m_in);
  529. if (uds_fd_table[minor].state != UDS_INUSE) {
  530. /* attempted to close a socket that hasn't been opened --
  531. * something is very wrong :(
  532. */
  533. uds_set_reply(dev_m_out, DEV_REVIVE, dev_m_in->USER_ENDPT,
  534. (cp_grant_id_t) dev_m_in->IO_GRANT, EINVAL);
  535. return EINVAL;
  536. }
  537. /* track the system call we are performing in case it gets cancelled */
  538. uds_fd_table[minor].call_nr = dev_m_in->m_type;
  539. uds_fd_table[minor].ioctl = 0;
  540. uds_fd_table[minor].syscall_done = 0;
  541. /* Update the process endpoint. */
  542. uds_fd_table[minor].endpoint = dev_m_in->USER_ENDPT;
  543. /* setup select(2) framework */
  544. uds_fd_table[minor].selecting = 0;
  545. /* save I/O Grant info */
  546. uds_fd_table[minor].io_gr = (cp_grant_id_t) dev_m_in->IO_GRANT;
  547. uds_fd_table[minor].io_gr_size = dev_m_in->COUNT;
  548. bytes = uds_perform_read(minor, dev_m_in->m_source,
  549. uds_fd_table[minor].io_gr_size, 0);
  550. uds_set_reply(dev_m_out, DEV_REVIVE, uds_fd_table[minor].endpoint,
  551. uds_fd_table[minor].io_gr, bytes);
  552. return bytes;
  553. }
  554. int uds_write(message *dev_m_in, message *dev_m_out)
  555. {
  556. int bytes;
  557. int minor;
  558. #if DEBUG == 1
  559. static int call_count = 0;
  560. printf("(uds) [%d] uds_write() call_count=%d\n", uds_minor(dev_m_in),
  561. ++call_count);
  562. printf("Endpoint: 0x%x | Position 0x%x\n", dev_m_in->USER_ENDPT,
  563. dev_m_in->POSITION);
  564. #endif
  565. minor = uds_minor(dev_m_in);
  566. if (uds_fd_table[minor].state != UDS_INUSE) {
  567. /* attempted to close a socket that hasn't been opened --
  568. * something is very wrong :(
  569. */
  570. uds_set_reply(dev_m_out, DEV_REVIVE, dev_m_in->USER_ENDPT,
  571. (cp_grant_id_t) dev_m_in->IO_GRANT, EINVAL);
  572. return EINVAL;
  573. }
  574. /* track the system call we are performing in case it gets cancelled */
  575. uds_fd_table[minor].call_nr = dev_m_in->m_type;
  576. uds_fd_table[minor].ioctl = 0;
  577. uds_fd_table[minor].syscall_done = 0;
  578. /* Update the process endpoint. */
  579. uds_fd_table[minor].endpoint = dev_m_in->USER_ENDPT;
  580. /* setup select(2) framework */
  581. uds_fd_table[minor].selecting = 0;
  582. /* save I/O Grant info */
  583. uds_fd_table[minor].io_gr = (cp_grant_id_t) dev_m_in->IO_GRANT;
  584. uds_fd_table[minor].io_gr_size = dev_m_in->COUNT;
  585. bytes = uds_perform_write(minor, dev_m_in->m_source,
  586. uds_fd_table[minor].io_gr_size, 0);
  587. uds_set_reply(dev_m_out, DEV_REVIVE, uds_fd_table[minor].endpoint,
  588. uds_fd_table[minor].io_gr, bytes);
  589. return bytes;
  590. }
  591. int uds_ioctl(message *dev_m_in, message *dev_m_out)
  592. {
  593. int rc, minor;
  594. #if DEBUG == 1
  595. static int call_count = 0;
  596. printf("(uds) [%d] uds_ioctl() call_count=%d\n", uds_minor(dev_m_in),
  597. ++call_count);
  598. printf("Endpoint: 0x%x | Position 0x%x\n", dev_m_in->USER_ENDPT,
  599. dev_m_in->POSITION);
  600. #endif
  601. minor = uds_minor(dev_m_in);
  602. if (uds_fd_table[minor].state != UDS_INUSE) {
  603. /* attempted to close a socket that hasn't been opened --
  604. * something is very wrong :(
  605. */
  606. uds_set_reply(dev_m_out, DEV_REVIVE, dev_m_in->USER_ENDPT,
  607. (cp_grant_id_t) dev_m_in->IO_GRANT, EINVAL);
  608. return EINVAL;
  609. }
  610. /* track the system call we are performing in case it gets cancelled */
  611. uds_fd_table[minor].call_nr = dev_m_in->m_type;
  612. uds_fd_table[minor].ioctl = dev_m_in->COUNT;
  613. uds_fd_table[minor].syscall_done = 0;
  614. /* setup select(2) framework */
  615. uds_fd_table[minor].selecting = 0;
  616. /* update the owner endpoint - yes it's really stored in POSITION */
  617. uds_fd_table[minor].owner = dev_m_in->POSITION;
  618. switch (dev_m_in->COUNT) { /* Handle the ioctl(2) command */
  619. case NWIOSUDSCONN:
  620. /* connect to a listening socket -- connect() */
  621. rc = do_connect(dev_m_in, dev_m_out);
  622. break;
  623. case NWIOSUDSACCEPT:
  624. /* accept an incoming connection -- accept() */
  625. rc = do_accept(dev_m_in, dev_m_out);
  626. break;
  627. case NWIOSUDSBLOG:
  628. /* set the backlog_size and put the socket into the
  629. * listening state -- listen()
  630. */
  631. rc = do_listen(dev_m_in, dev_m_out);
  632. break;
  633. case NWIOSUDSTYPE:
  634. /* set the type for this socket (i.e.
  635. * SOCK_STREAM, SOCK_DGRAM, etc) -- socket()
  636. */
  637. rc = do_socket(dev_m_in, dev_m_out);
  638. break;
  639. case NWIOSUDSADDR:
  640. /* set the address for this socket -- bind() */
  641. rc = do_bind(dev_m_in, dev_m_out);
  642. break;
  643. case NWIOGUDSADDR:
  644. /* get the address for this socket -- getsockname() */
  645. rc = do_getsockname(dev_m_in, dev_m_out);
  646. break;
  647. case NWIOGUDSPADDR:
  648. /* get the address for the peer -- getpeername() */
  649. rc = do_getpeername(dev_m_in, dev_m_out);
  650. break;
  651. case NWIOSUDSSHUT:
  652. /* shutdown a socket for reading, writing, or
  653. * both -- shutdown()
  654. */
  655. rc = do_shutdown(dev_m_in, dev_m_out);
  656. break;
  657. case NWIOSUDSPAIR:
  658. /* connect two sockets -- socketpair() */
  659. rc = do_socketpair(dev_m_in, dev_m_out);
  660. break;
  661. case NWIOSUDSPAIROLD:
  662. /* connect two sockets -- socketpair() */
  663. rc = do_socketpair_old(dev_m_in, dev_m_out);
  664. break;
  665. case NWIOGUDSSOTYPE:
  666. /* get socket type -- getsockopt(SO_TYPE) */
  667. rc = do_getsockopt_sotype(dev_m_in, dev_m_out);
  668. break;
  669. case NWIOGUDSPEERCRED:
  670. /* get peer endpoint -- getsockopt(SO_PEERCRED) */
  671. rc = do_getsockopt_peercred(dev_m_in, dev_m_out);
  672. break;
  673. case NWIOGUDSPEERCREDOLD:
  674. /* get peer endpoint -- getsockopt(SO_PEERCRED) */
  675. rc = do_getsockopt_peercred_old(dev_m_in, dev_m_out);
  676. break;
  677. case NWIOSUDSTADDR:
  678. /* set target address -- sendto() */
  679. rc = do_sendto(dev_m_in, dev_m_out);
  680. break;
  681. case NWIOGUDSFADDR:
  682. /* get from address -- recvfrom() */
  683. rc = do_recvfrom(dev_m_in, dev_m_out);
  684. break;
  685. case NWIOGUDSSNDBUF:
  686. /* get the send buffer size -- getsockopt(SO_SNDBUF) */
  687. rc = do_getsockopt_sndbuf(dev_m_in, dev_m_out);
  688. break;
  689. case NWIOSUDSSNDBUF:
  690. /* set the send buffer size -- setsockopt(SO_SNDBUF) */
  691. rc = do_setsockopt_sndbuf(dev_m_in, dev_m_out);
  692. break;
  693. case NWIOGUDSRCVBUF:
  694. /* get the send buffer size -- getsockopt(SO_SNDBUF) */
  695. rc = do_getsockopt_rcvbuf(dev_m_in, dev_m_out);
  696. break;
  697. case NWIOSUDSRCVBUF:
  698. /* set the send buffer size -- setsockopt(SO_SNDBUF) */
  699. rc = do_setsockopt_rcvbuf(dev_m_in, dev_m_out);
  700. break;
  701. case NWIOSUDSCTRL:
  702. /* set the control data -- sendmsg() */
  703. rc = do_sendmsg(dev_m_in, dev_m_out);
  704. break;
  705. case NWIOGUDSCTRL:
  706. /* set the control data -- recvmsg() */
  707. rc = do_recvmsg(dev_m_in, dev_m_out);
  708. break;
  709. default:
  710. /* the IOCTL command is not valid for /dev/uds --
  711. * this happens a lot and is normal. a lot of
  712. * libc functions determine the socket type with
  713. * IOCTLs. Any not for us simply get a EBADIOCTL
  714. * response.
  715. */
  716. rc = EBADIOCTL;
  717. }
  718. if (rc != SUSPEND)
  719. uds_fd_table[minor].syscall_done = 1;
  720. uds_set_reply(dev_m_out, DEV_REVIVE, dev_m_in->USER_ENDPT,
  721. (cp_grant_id_t) dev_m_in->IO_GRANT, rc);
  722. return rc;
  723. }
  724. int uds_unsuspend(endpoint_t m_source, int minor)
  725. {
  726. int r = OK, bytes;
  727. message m_out;
  728. uds_fd_t *fdp;
  729. fdp = &uds_fd_table[minor];
  730. if (fdp->status_updated == 1) {
  731. /* clear the status_updated flag */
  732. fdp->status_updated = 0;
  733. fdp->selecting = 0;
  734. /* prepare the response */
  735. uds_sel_reply(&m_out, DEV_SEL_REPL2, minor, fdp->sel_ops_out);
  736. } else if (fdp->ready_to_revive == 1) {
  737. /* clear the ready to revive flag */
  738. fdp->ready_to_revive = 0;
  739. switch (fdp->suspended) {
  740. case UDS_SUSPENDED_READ:
  741. bytes = uds_perform_read(minor, m_source,
  742. fdp->io_gr_size, 0);
  743. if (bytes == SUSPEND) {
  744. r = SUSPEND;
  745. break;
  746. }
  747. fdp->suspended = UDS_NOT_SUSPENDED;
  748. uds_set_reply(&m_out, DEV_REVIVE, fdp->endpoint,
  749. fdp->io_gr, bytes);
  750. break;
  751. case UDS_SUSPENDED_WRITE:
  752. bytes = uds_perform_write(minor, m_source,
  753. fdp->io_gr_size, 0);
  754. if (bytes == SUSPEND) {
  755. r = SUSPEND;
  756. break;
  757. }
  758. fdp->suspended = UDS_NOT_SUSPENDED;
  759. uds_set_reply(&m_out, DEV_REVIVE, fdp->endpoint,
  760. fdp->io_gr, bytes);
  761. break;
  762. case UDS_SUSPENDED_CONNECT:
  763. case UDS_SUSPENDED_ACCEPT:
  764. /* In both cases, the process
  765. * that send the notify()
  766. * already performed the connection.
  767. * The only thing to do here is
  768. * unblock.
  769. */
  770. fdp->suspended = UDS_NOT_SUSPENDED;
  771. uds_set_reply(&m_out, DEV_REVIVE, fdp->endpoint,
  772. fdp->io_gr, OK);
  773. break;
  774. default:
  775. return(OK);
  776. }
  777. }
  778. if (r == OK) reply(m_source, &m_out);
  779. return(r);
  780. }
  781. int uds_cancel(message *dev_m_in, message *dev_m_out)
  782. {
  783. int i, j;
  784. int minor;
  785. /* XXX: should become a noop? */
  786. #if DEBUG == 1
  787. static int call_count = 0;
  788. printf("(uds) [%d] uds_cancel() call_count=%d\n", uds_minor(dev_m_in),
  789. ++call_count);
  790. printf("Endpoint: 0x%x\n", dev_m_in->USER_ENDPT);
  791. #endif
  792. minor = uds_minor(dev_m_in);
  793. if (uds_fd_table[minor].state != UDS_INUSE) {
  794. /* attempted to close a socket that hasn't been opened --
  795. * something is very wrong :(
  796. */
  797. uds_set_reply(dev_m_out, DEV_NO_STATUS, dev_m_in->USER_ENDPT,
  798. (cp_grant_id_t) dev_m_in->IO_GRANT, EINVAL);
  799. return EINVAL;
  800. }
  801. /* Update the process endpoint. */
  802. uds_fd_table[minor].endpoint = dev_m_in->USER_ENDPT;
  803. /* setup select(2) framework */
  804. uds_fd_table[minor].selecting = 0;
  805. /* the system call was cancelled, so if the socket was suspended
  806. * (which is likely the case), then it is not suspended anymore.
  807. */
  808. uds_fd_table[minor].suspended = UDS_NOT_SUSPENDED;
  809. /* If there is a system call and it isn't complete, roll back */
  810. if (uds_fd_table[minor].call_nr && !uds_fd_table[minor].syscall_done) {
  811. if (uds_fd_table[minor].call_nr == DEV_IOCTL_S) {
  812. switch (uds_fd_table[minor].ioctl) {
  813. case NWIOSUDSACCEPT: /* accept() */
  814. /* partial accept() only changes
  815. * uds_fd_table[minorparent].child
  816. */
  817. for (i = 0; i < NR_FDS; i++) {
  818. if (uds_fd_table[i].child ==
  819. minor) {
  820. uds_fd_table[i].child = -1;
  821. }
  822. }
  823. break;
  824. case NWIOSUDSCONN: /* connect() */
  825. /* partial connect() sets addr
  826. * and adds minor to server backlog
  827. */
  828. for (i = 0; i < NR_FDS; i++) {
  829. /* find a socket that is in
  830. * use.
  831. */
  832. if (uds_fd_table[i].state ==
  833. UDS_INUSE) {
  834. /* see if minor is in
  835. * the backlog
  836. */
  837. for (j = 0; j < uds_fd_table[i].backlog_size; j++) {
  838. if (uds_fd_table[i].backlog[j] == minor) {
  839. /* remove from backlog */
  840. uds_fd_table[i].backlog[j] = -1;
  841. }
  842. }
  843. }
  844. }
  845. /* clear the address */
  846. memset(&(uds_fd_table[minor].addr),
  847. '\0',
  848. sizeof(struct sockaddr_un));
  849. break;
  850. case NWIOSUDSTADDR: /* sendto() */
  851. case NWIOSUDSADDR: /* bind() */
  852. case NWIOGUDSADDR: /* getsockname() */
  853. case NWIOGUDSPADDR: /* getpeername() */
  854. case NWIOSUDSTYPE: /* socket() */
  855. case NWIOSUDSBLOG: /* listen() */
  856. case NWIOSUDSSHUT: /* shutdown() */
  857. case NWIOSUDSPAIR: /* socketpair() */
  858. case NWIOGUDSSOTYPE: /* SO_TYPE */
  859. case NWIOGUDSPEERCRED: /* SO_PEERCRED */
  860. default:
  861. /* these are atomic, never suspend,
  862. * and can't be cancelled once called
  863. */
  864. break;
  865. }
  866. }
  867. /* DEV_READ_S or DEV_WRITE_S don't need to do anything
  868. * when cancelled. DEV_OPEN, DEV_REOPEN, DEV_SELECT,
  869. * DEV_CLOSE are atomic, never suspend, and can't
  870. * be cancelled once called.
  871. */
  872. uds_fd_table[minor].syscall_done = 1;
  873. }
  874. uds_set_reply(dev_m_out, DEV_NO_STATUS, dev_m_in->USER_ENDPT,
  875. (cp_grant_id_t) dev_m_in->IO_GRANT, EINTR);
  876. return EINTR;
  877. }