#include #include #include #include #include "ipc.h" #if !defined(MSG_NOSIGNAL) && !defined(SO_NOSIGPIPE) #error "ipcsend requires MSG_NOSIGNAL or SO_NOSIGPIPE" #endif static void putlen(unsigned char p[Ipclensz], size_t n) { p[0] = n; p[1] = n >> 8; } static size_t getlen(const unsigned char p[Ipclensz]) { return p[0] | (p[1] << 8); } void ipcpackreq(unsigned char req[Ipcreqsz], int want, unsigned int mod, unsigned int key) { req[0] = want != 0; req[1] = mod; req[2] = key; req[3] = key >> 8; req[4] = key >> 16; req[5] = key >> 24; } void ipcunpackreq(const unsigned char req[Ipcreqsz], int *want, unsigned int *mod, unsigned int *key) { *want = req[0] != 0; *mod = req[1] & Mmask; *key = (unsigned int)req[2] | ((unsigned int)req[3] << 8) | ((unsigned int)req[4] << 16) | ((unsigned int)req[5] << 24); } int ipcpackresp(unsigned char *dst, size_t cap, int eaten, const char *commit, size_t ncommit, const char *preedit, size_t npreedit, int want) { size_t n; if(ncommit > Ipcfieldmax || npreedit > Ipcfieldmax) return -1; if((ncommit > 0 && commit == NULL) || (want && npreedit > 0 && preedit == NULL)) return -1; n = Ipcresphdrsz + ncommit + (want ? Ipclensz + npreedit : 0); if(dst == NULL || cap < n) return -1; dst[0] = eaten != 0; putlen(dst + 1, ncommit); if(ncommit > 0) memcpy(dst + Ipcresphdrsz, commit, ncommit); if(want){ putlen(dst + Ipcresphdrsz + ncommit, npreedit); if(npreedit > 0) memcpy(dst + Ipcresphdrsz + ncommit + Ipclensz, preedit, npreedit); } return n; } int ipcreadn(int fd, void *buf, size_t n) { unsigned char *p; ssize_t r; p = buf; while(n > 0){ r = read(fd, p, n); if(r < 0 && errno == EINTR) continue; if(r <= 0) return -1; p += r; n -= r; } return 0; } int ipcsend(int fd, const void *buf, size_t n) { const unsigned char *p; ssize_t r; int flags; #if !defined(MSG_NOSIGNAL) && defined(SO_NOSIGPIPE) int one, sr; #endif p = buf; #ifdef MSG_NOSIGNAL flags = MSG_NOSIGNAL; #else flags = 0; #ifdef SO_NOSIGPIPE one = 1; do sr = setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &one, sizeof one); while(sr < 0 && errno == EINTR); if(sr < 0) return -1; #endif #endif while(n > 0){ r = send(fd, p, n, flags); if(r < 0 && errno == EINTR) continue; if(r <= 0) return -1; p += r; n -= r; } return 0; } static int readfield(int fd, size_t n, char *dst, size_t cap) { unsigned char discard[128]; size_t keep, part; if(cap > 0 && dst == NULL) return -1; keep = 0; if(cap > 0) keep = n >= cap ? cap - 1 : n; if(keep > 0 && ipcreadn(fd, dst, keep) < 0) return -1; if(cap > 0) dst[keep] = '\0'; n -= keep; while(n > 0){ part = n < sizeof discard ? n : sizeof discard; if(ipcreadn(fd, discard, part) < 0) return -1; n -= part; } return 0; } int ipcreadresp(int fd, int want, char *commit, size_t ccap, char *preedit, size_t pcap, Ipcresp *resp) { unsigned char hdr[Ipcresphdrsz], npreedit[Ipclensz]; if(resp == NULL || (ccap > 0 && commit == NULL) || (pcap > 0 && preedit == NULL)) return -1; if(ccap > 0) commit[0] = '\0'; if(pcap > 0) preedit[0] = '\0'; memset(resp, 0, sizeof *resp); if(ipcreadn(fd, hdr, sizeof hdr) < 0) return -1; resp->eaten = hdr[0] != 0; resp->ncommit = getlen(hdr + 1); if(resp->ncommit > Ipcfieldmax) return -1; if(readfield(fd, resp->ncommit, commit, ccap) < 0) return -1; if(!want) return 0; if(ipcreadn(fd, npreedit, sizeof npreedit) < 0) return -1; resp->npreedit = getlen(npreedit); if(resp->npreedit > Ipcfieldmax) return -1; return readfield(fd, resp->npreedit, preedit, pcap); }