| /* SPDX-License-Identifier: MediaTekProprietary */ |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <stddef.h> |
| #include <string.h> |
| #include <errno.h> |
| #include <assert.h> |
| #include <unistd.h> |
| #include <fcntl.h> |
| #include <time.h> |
| #include <sys/types.h> |
| #include <sys/socket.h> |
| #include <sys/un.h> |
| #include <syslog.h> |
| #include "property.h" |
| #include "utility.h" |
| #include "request.h" |
| |
| /*******************************************************************************/ |
| /* REQUEST local definitions */ |
| /*******************************************************************************/ |
| |
| /*******************************************************************************/ |
| /* REQUEST local prototypes */ |
| /*******************************************************************************/ |
| |
| /*******************************************************************************/ |
| /* REQUEST local variables */ |
| /*******************************************************************************/ |
| |
| /*******************************************************************************/ |
| /* REQUEST local functions */ |
| /*******************************************************************************/ |
| static int pack_request_string(char **p, char **next, const char *roof) |
| { |
| if (*p == NULL) { |
| return 0; |
| } else { |
| size_t len = strlen(*p) + 1; |
| |
| if ((roof - *next) < (ptrdiff_t)len) { |
| return -1; |
| } else { |
| strcpy(*next, *p); |
| *next += len; |
| *p = (char *)0x12345678; |
| return 0; |
| } |
| } |
| } |
| |
| static int unpack_request_string(char **p, char **next, const char *roof) |
| { |
| if (*p == NULL) { |
| return 0; |
| } else if (*p == (char *)0x12345678) { |
| char *end = memchr(*next, '\0', roof - *next); |
| |
| if (end == NULL) { |
| return -1; |
| } else { |
| *p = *next; |
| *next = end + 1; |
| return 0; |
| } |
| } |
| return -1; |
| } |
| |
| /*******************************************************************************/ |
| /* REQUEST functions */ |
| /*******************************************************************************/ |
| int pack_request(struct sncfg_request *request) |
| { |
| int size; |
| char *next, *roof; |
| |
| next = request->string + request->reservedLen; |
| roof = next + sizeof(request->string); |
| |
| if (request->magic != SNCFG_REQUEST_MAGIC) { |
| return -1; |
| } |
| |
| if (request->type >= SNCFG_REQUEST_TYPE_RESERVED) { |
| return -1; |
| } |
| |
| if (pack_request_string(&request->key, &next, roof) < 0 || |
| pack_request_string(&request->value, &next, roof) < 0) { |
| return -1; |
| } |
| |
| size = next - (char *)request; |
| return size; |
| } |
| |
| int unpack_request(struct sncfg_request *request, int size) |
| { |
| char *next, *roof; |
| |
| next = request->string + request->reservedLen; |
| roof = (char *)request + size; |
| |
| if (roof < next) { |
| return -1; |
| } |
| |
| if (request->magic != SNCFG_REQUEST_MAGIC) { |
| return -1; |
| } |
| |
| if (request->type >= SNCFG_REQUEST_TYPE_RESERVED) { |
| return -1; |
| } |
| |
| if (unpack_request_string(&request->key, &next, roof) < 0 || |
| unpack_request_string(&request->value, &next, roof) < 0) { |
| return -1; |
| } |
| |
| return 0; |
| } |
| |
| int connect_request(void) |
| { |
| int sock; |
| struct sockaddr_un addr = { AF_UNIX, SNCFG_REQUEST_UNIX_SOCKET }; |
| |
| if (access(addr.sun_path, R_OK | W_OK) < 0) { |
| return -1; |
| } |
| |
| sock = socket(AF_UNIX, SOCK_STREAM, 0); |
| if (sock == -1) { |
| return -1; |
| } |
| |
| struct timeval tm; |
| tm.tv_sec = 8; /* 8 Secs Timeout */ |
| tm.tv_usec = 0; |
| |
| if (setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (const void *)&tm, sizeof(tm)) < 0) { |
| fprintf(stderr, "[LIBSNCFG][%d] Can't setsockopt SO_SNDTIMEO 8 seconds for connect ... %s !!\r\n", getpid(), strerror(errno)); |
| syslog(LOG_WARNING, "[LIBSNCFG][%d] Can't setsockopt SO_SNDTIMEO 8 seconds for connect ... %s !!", getpid(), strerror(errno)); |
| close(sock); |
| return -1; |
| } |
| if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (const void *)&tm, sizeof(tm)) < 0) { |
| fprintf(stderr, "[LIBSNCFG][%d] Can't setsockopt SO_RCVTIMEO 8 seconds for connect ... %s !!\r\n", getpid(), strerror(errno)); |
| syslog(LOG_WARNING, "[LIBSNCFG][%d] Can't setsockopt SO_RCVTIMEO 8 seconds for connect ... %s !!", getpid(), strerror(errno)); |
| close(sock); |
| return -1; |
| } |
| |
| if (connect(sock, (struct sockaddr *)&addr, |
| offsetof(struct sockaddr_un, sun_path) + strlen(addr.sun_path)) < 0) { |
| close(sock); |
| return -1; |
| } |
| |
| return sock; |
| } |
| |
| int accept_request(int sockfd) |
| { |
| int sock; |
| socklen_t addrlen; |
| struct sockaddr_un addr; |
| |
| addrlen = sizeof(addr); |
| sock = accept(sockfd, (struct sockaddr *)&addr, &addrlen); |
| if (sock == -1) { |
| return -1; |
| } |
| |
| if (fcntl(sock, F_SETFD, FD_CLOEXEC) < 0) { |
| close(sock); |
| return -1; |
| } |
| |
| struct timeval tm; |
| tm.tv_sec = 8; /* 8 Secs Timeout */ |
| tm.tv_usec = 0; |
| |
| if (setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (const void *)&tm, sizeof(tm)) < 0) { |
| fprintf(stderr, "[LIBSNCFG][%d] Can't setsockopt SO_SNDTIMEO 8 seconds for accept ... %s !!\r\n", getpid(), strerror(errno)); |
| syslog(LOG_WARNING, "[LIBSNCFG][%d] Can't setsockopt SO_SNDTIMEO 8 seconds for accept ... %s !!", getpid(), strerror(errno)); |
| close(sock); |
| return -1; |
| } |
| if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (const void *)&tm, sizeof(tm)) < 0) { |
| fprintf(stderr, "[LIBSNCFG][%d] Can't setsockopt SO_RCVTIMEO 8 seconds for accept ... %s !!\r\n", getpid(), strerror(errno)); |
| syslog(LOG_WARNING, "[LIBSNCFG][%d] Can't setsockopt SO_RCVTIMEO 8 seconds for accept ... %s !!", getpid(), strerror(errno)); |
| close(sock); |
| return -1; |
| } |
| |
| return sock; |
| } |
| |
| int request_for_sncfg(struct sncfg_request *request) |
| { |
| int sock, size; |
| |
| size = pack_request(request); |
| if (size < 0) { |
| return -1; |
| } |
| |
| sock = connect_request(); |
| if (sock < 0) { |
| return -1; |
| } |
| |
| if (safe_write(sock, request, size) != size) { |
| close(sock); |
| return -1; |
| } |
| |
| size = safe_read(sock, request, sizeof(struct sncfg_request)); |
| |
| if (size < 0 || |
| unpack_request(request, size) < 0 || |
| request->status < 0) { |
| /* request processing failed */ |
| close(sock); |
| return -1; |
| } |
| |
| close(sock); |
| return 0; |
| } |