| #include <errno.h> |
| #include <fcntl.h> |
| #include <string.h> |
| #include <stdlib.h> |
| #include "uemf.h" |
| #include "softap_log.h" |
| |
| extern socket_t **socketList; |
| extern int socketMax; |
| extern int socketHighestFd; |
| static int socketOpenCount = 0; |
| |
| static void socketAccept(socket_t *sp); |
| static int socketDoEvent(socket_t *sp); |
| static int tryAlternateConnect(int sock, struct sockaddr *sockaddr); |
| |
| int socketOpen() |
| { |
| if (++socketOpenCount > 1) { |
| return 0; |
| } |
| socketList = NULL; |
| socketMax = 0; |
| socketHighestFd = -1; |
| |
| return 0; |
| } |
| |
| int socketWaitForEvent(socket_t *sp, int handlerMask, int *errCode) |
| { |
| int mask; |
| |
| a_assert(sp); |
| |
| mask = sp->handlerMask; |
| sp->handlerMask |= handlerMask; |
| while (socketSelect(sp->sid, 1000)) { |
| if (sp->currentEvents & (handlerMask | SOCKET_EXCEPTION)) { |
| break; |
| } |
| } |
| sp->handlerMask = mask; |
| if (sp->currentEvents & SOCKET_EXCEPTION) { |
| return -1; |
| } else if (sp->currentEvents & handlerMask) { |
| return 1; |
| } |
| if (errCode) { |
| *errCode = errno = EWOULDBLOCK; |
| } |
| return 0; |
| } |
| |
| void socketClose() |
| { |
| int i; |
| |
| if (--socketOpenCount <= 0) { |
| for (i = socketMax; i >= 0; i--) { |
| if (socketList && socketList[i]) { |
| socketCloseConnection(i); |
| } |
| } |
| socketOpenCount = 0; |
| } |
| } |
| |
| int socketOpenConnection6(char *host, int port, socketAccept_t accept, int flags) |
| { |
| socket_t *sp; |
| struct sockaddr_in6 sockaddr; |
| int sid, dgram, rc; |
| if (port > SOCKET_PORT_MAX) { |
| return -1; |
| } |
| if ((sid = socketAlloc(NULL, port, accept, flags)) < 0) { |
| return -1; |
| } |
| sp = socketList[sid]; |
| a_assert(sp); |
| memset((char *) &sockaddr, '\0', sizeof(struct sockaddr_in6)); |
| sockaddr.sin6_family = AF_INET6; |
| sockaddr.sin6_port = htons((short) (port & 0xFFFF)); |
| dgram = sp->flags & SOCKET_DATAGRAM; |
| sp->sock = socket(AF_INET6, dgram ? SOCK_DGRAM: SOCK_STREAM, 0); |
| if (sp->sock < 0) { |
| socketFree(sid); |
| return -1; |
| } |
| if(fcntl(sp->sock, F_SETFD, FD_CLOEXEC) < 0) |
| { |
| slog(MISC_PRINT,SLOG_ERR, "fcntl return -1.\n"); |
| } |
| |
| socketHighestFd = max(socketHighestFd, sp->sock); |
| rc = 1; |
| // cov 3 CHECKED_RETURN |
| if(setsockopt(sp->sock, SOL_SOCKET, SO_REUSEADDR, (char *)&rc, sizeof(rc)) < 0){ |
| ; |
| } |
| if (bind(sp->sock, (struct sockaddr *) &sockaddr, |
| sizeof(sockaddr)) < 0) { |
| socketFree(sid); |
| return -1; |
| } |
| |
| if (! dgram) { |
| if (listen(sp->sock, SOMAXCONN) < 0) { |
| socketFree(sid); |
| return -1; |
| } |
| |
| sp->flags |= SOCKET_LISTENING; |
| } |
| sp->handlerMask |= SOCKET_READABLE; |
| |
| if (flags & SOCKET_BLOCK) { |
| socketSetBlock(sid, 1); |
| } else { |
| socketSetBlock(sid, 0); |
| } |
| return sid; |
| } |
| |
| void socketCloseConnection(int sid) |
| { |
| socket_t *sp; |
| |
| if ((sp = socketPtr(sid)) == NULL) { |
| return; |
| } |
| socketFree(sid); |
| } |
| |
| static void socketAccept(socket_t *sp) |
| { |
| struct sockaddr_in6 addr; |
| //socket_t *nsp; |
| size_t len; |
| char pString[40]={0}; |
| int newSock, nid; |
| |
| a_assert(sp); |
| len = sizeof(struct sockaddr_in6); |
| if ((newSock = accept(sp->sock, (struct sockaddr *) &addr, (int *) &len)) < 0) { |
| return; |
| } |
| if(fcntl(newSock, F_SETFD, FD_CLOEXEC) < 0) |
| { |
| slog(MISC_PRINT,SLOG_ERR, "fcntl return -1.\n"); |
| } |
| socketHighestFd = max(socketHighestFd, newSock); |
| |
| nid = socketAlloc(sp->host, sp->port, sp->accept, sp->flags); |
| //nsp = socketList[nid]; |
| a_assert(socketList[nid]); |
| if (socketList[nid] == NULL) { |
| close(newSock); |
| return; |
| } |
| socketList[nid]->sock = newSock; |
| socketList[nid]->flags &= ~SOCKET_LISTENING; |
| |
| socketSetBlock(nid, (socketList[nid]->flags & SOCKET_BLOCK) ? 1: 0); |
| |
| if (sp->accept != NULL) { |
| //pString = inet_ntoa(addr); |
| if(addr.sin6_addr.s6_addr32[0] == 0 |
| && addr.sin6_addr.s6_addr32[1] == 0 |
| && addr.sin6_addr.s6_addr32[2] == 0xffff0000) |
| inet_ntop(AF_INET,(void*)&addr.sin6_addr.s6_addr32[3],pString,sizeof(pString)); |
| else |
| inet_ntop(AF_INET6,(void*)&addr.sin6_addr,pString,sizeof(pString)); |
| if ((sp->accept)(nid, pString, ntohs(addr.sin6_port), sp->sid) < 0) { |
| socketFree(nid); |
| } |
| } |
| else |
| socketFree(nid); |
| } |
| |
| int socketGetInput(int sid, char *buf, int toRead, int *errCode) |
| { |
| struct sockaddr_in server; |
| socket_t *sp; |
| int len, bytesRead; |
| static int s_ErrorCnt = 0; |
| a_assert(buf); |
| a_assert(errCode); |
| |
| *errCode = 0; |
| |
| if ((sp = socketPtr(sid)) == NULL) { |
| return -1; |
| } |
| |
| if (sp->flags & SOCKET_EOF) { |
| return 0; |
| } |
| if (sp->flags & SOCKET_DATAGRAM) { |
| len = sizeof(server); |
| bytesRead = recvfrom(sp->sock, buf, toRead, 0, |
| (struct sockaddr *) &server, &len); |
| } else { |
| bytesRead = recv(sp->sock, buf, toRead, 0); |
| } |
| |
| if (bytesRead < 0) |
| { |
| *errCode = socketGetError(); |
| //printf("\n socketGetInput ERROR: bytesRead = %d, *errCode = %d! ", bytesRead, *errCode); |
| if (*errCode == ECONNRESET || s_ErrorCnt++ > 500) |
| { |
| sp->flags |= SOCKET_CONNRESET; |
| return 0; |
| } |
| return -1; |
| } |
| else |
| { |
| s_ErrorCnt = 0; |
| } |
| return bytesRead; |
| } |
| |
| void socketRegisterInterest(socket_t *sp, int handlerMask) |
| { |
| a_assert(sp); |
| |
| sp->handlerMask = handlerMask; |
| } |
| |
| int socketReady(int sid) |
| { |
| socket_t *sp; |
| int all; |
| |
| all = 0; |
| if (sid < 0) { |
| sid = 0; |
| all = 1; |
| } |
| |
| for (; sid < socketMax; sid++) { |
| if ((sp = socketList[sid]) == NULL) { |
| if (! all) { |
| break; |
| } else { |
| continue; |
| } |
| } |
| if (sp->flags & SOCKET_CONNRESET) { |
| socketCloseConnection(sid); |
| return 0; |
| } |
| if (sp->currentEvents & sp->handlerMask) { |
| return 1; |
| } |
| |
| if (sp->handlerMask & SOCKET_READABLE && socketInputBuffered(sid) > 0) { |
| socketSelect(sid, 0); |
| return 1; |
| } |
| if (! all) { |
| break; |
| } |
| } |
| return 0; |
| } |
| |
| int socketSelect(int sid, int timeout) |
| { |
| socket_t *sp; |
| struct timeval tv; |
| fd_mask *readFds, *writeFds, *exceptFds; |
| int all, len, nwords, index, bit, nEvents; |
| |
| nwords = (socketHighestFd + NFDBITS) / NFDBITS; |
| len = nwords * sizeof(int); |
| |
| readFds = balloc(B_L, len); |
| if(readFds == NULL) |
| return 0; |
| memset(readFds, 0, len); |
| writeFds = balloc(B_L, len); |
| if(writeFds == NULL){ |
| bfree(B_L, readFds); |
| return 0; |
| } |
| memset(writeFds, 0, len); |
| exceptFds = balloc(B_L, len); |
| if(exceptFds == NULL){ |
| bfree(B_L, readFds); |
| bfree(B_L, writeFds); |
| return 0; |
| } |
| memset(exceptFds, 0, len); |
| |
| tv.tv_sec = timeout / 1000; |
| tv.tv_usec = (timeout % 1000) * 1000; |
| |
| all = nEvents = 0; |
| |
| if (sid < 0) { |
| all++; |
| sid = 0; |
| } |
| |
| for (; sid < socketMax; sid++) { |
| if ((sp = socketList[sid]) == NULL) { |
| if (all == 0) { |
| break; |
| } else { |
| continue; |
| } |
| } |
| a_assert(sp); |
| |
| index = sp->sock / (NBBY * sizeof(fd_mask)); |
| bit = 1 << (sp->sock % (NBBY * sizeof(fd_mask))); |
| |
| if (sp->handlerMask & SOCKET_READABLE) { |
| readFds[index] |= bit; |
| nEvents++; |
| if (socketInputBuffered(sid) > 0) { |
| tv.tv_sec = 0; |
| tv.tv_usec = 0; |
| } |
| } |
| if (sp->handlerMask & SOCKET_WRITABLE) { |
| writeFds[index] |= bit; |
| nEvents++; |
| } |
| if (sp->handlerMask & SOCKET_EXCEPTION) { |
| exceptFds[index] |= bit; |
| nEvents++; |
| } |
| if (! all) { |
| break; |
| } |
| } |
| |
| nEvents = select(socketHighestFd + 1, (fd_set *) readFds, |
| (fd_set *) writeFds, (fd_set *) exceptFds, &tv); |
| |
| if (nEvents > 0) { |
| if (all) { |
| sid = 0; |
| } |
| for (; sid < socketMax; sid++) { |
| if ((sp = socketList[sid]) == NULL) { |
| if (all == 0) { |
| break; |
| } else { |
| continue; |
| } |
| } |
| |
| index = sp->sock / (NBBY * sizeof(fd_mask)); |
| bit = 1 << (sp->sock % (NBBY * sizeof(fd_mask))); |
| |
| if (readFds[index] & bit || socketInputBuffered(sid) > 0) { |
| sp->currentEvents |= SOCKET_READABLE; |
| } |
| if (writeFds[index] & bit) { |
| sp->currentEvents |= SOCKET_WRITABLE; |
| } |
| if (exceptFds[index] & bit) { |
| sp->currentEvents |= SOCKET_EXCEPTION; |
| } |
| if (! all) { |
| break; |
| } |
| } |
| } |
| |
| bfree(B_L, readFds); |
| bfree(B_L, writeFds); |
| bfree(B_L, exceptFds); |
| |
| return nEvents; |
| } |
| |
| void socketProcess(int sid) |
| { |
| socket_t *sp; |
| int all; |
| |
| all = 0; |
| if (sid < 0) { |
| all = 1; |
| sid = 0; |
| } |
| for (; sid < socketMax; sid++) { |
| if ((sp = socketList[sid]) == NULL) { |
| if (! all) { |
| break; |
| } else { |
| continue; |
| } |
| } |
| if (socketReady(sid)) { |
| socketDoEvent(sp); |
| } |
| if (! all) { |
| break; |
| } |
| } |
| } |
| |
| static int socketDoEvent(socket_t *sp) |
| { |
| ringq_t *rq; |
| int sid; |
| |
| a_assert(sp); |
| |
| sid = sp->sid; |
| if (sp->currentEvents & SOCKET_READABLE) { |
| if (sp->flags & SOCKET_LISTENING) { |
| socketAccept(sp); |
| sp->currentEvents = 0; |
| return 1; |
| } |
| |
| } else { |
| |
| if (sp->handlerMask & SOCKET_READABLE && socketInputBuffered(sid) > 0) { |
| sp->currentEvents |= SOCKET_READABLE; |
| } |
| } |
| |
| if (sp->currentEvents & SOCKET_WRITABLE) { |
| if (sp->flags & SOCKET_FLUSHING) { |
| rq = &sp->outBuf; |
| if (ringqLen(rq) > 0) { |
| socketFlush(sp->sid); |
| } else { |
| sp->flags &= ~SOCKET_FLUSHING; |
| } |
| } |
| } |
| |
| if (sp->handler && (sp->handlerMask & sp->currentEvents)) { |
| (sp->handler)(sid, sp->handlerMask & sp->currentEvents, |
| sp->handler_data); |
| |
| if (socketList && sid < socketMax && socketList[sid] == sp) { |
| sp->currentEvents = 0; |
| } |
| } |
| return 1; |
| } |
| |
| int socketSetBlock(int sid, int on) |
| { |
| socket_t *sp; |
| unsigned long flag; |
| int iflag; |
| int oldBlock; |
| struct timeval rcv_timeo; |
| |
| flag = iflag = !on; |
| |
| if ((sp = socketPtr(sid)) == NULL) { |
| a_assert(0); |
| return 0; |
| } |
| oldBlock = (sp->flags & SOCKET_BLOCK); |
| sp->flags &= ~(SOCKET_BLOCK); |
| if (on) { |
| sp->flags |= SOCKET_BLOCK; |
| } |
| |
| |
| if (sp->flags & SOCKET_BLOCK) { |
| |
| if(fcntl(sp->sock, F_SETFL, fcntl(sp->sock, F_GETFL) & ~O_NONBLOCK) < 0) |
| { |
| slog(MISC_PRINT,SLOG_ERR, "fcntl return -1.\n"); |
| } |
| |
| rcv_timeo.tv_sec = 60; |
| rcv_timeo.tv_usec = 0; |
| //printf("[zyl]set 60s send timeout\n"); |
| //ÉèÖÃ60Ãë·¢Ëͳ¬Ê± |
| // cov 3 CHECKED_RETURN |
| if(setsockopt(sp->sock, SOL_SOCKET,SO_SNDTIMEO, (void*)&rcv_timeo, sizeof(rcv_timeo)) < 0){ |
| ; |
| } |
| rcv_timeo.tv_sec = 1; |
| rcv_timeo.tv_usec = 0; |
| |
| //ÉèÖÃ1Ãë½ÓÊÕ³¬Ê± |
| // cov 3 CHECKED_RETURN |
| if(setsockopt(sp->sock, SOL_SOCKET,SO_RCVTIMEO, (void*)&rcv_timeo, sizeof(rcv_timeo)) < 0){ |
| ; |
| } |
| |
| } else { |
| if(fcntl(sp->sock, F_SETFL, fcntl(sp->sock, F_GETFL) | O_NONBLOCK) < 0) |
| { |
| slog(MISC_PRINT,SLOG_ERR, "fcntl return -1.\n"); |
| } |
| } |
| return oldBlock; |
| } |
| |
| int socketSockBuffered(int sock) |
| { |
| socket_t *sp; |
| int i; |
| |
| for (i = 0; i < socketMax; i++) { |
| if ((sp = socketList[i]) == NULL || sp->sock != sock) { |
| continue; |
| } |
| return socketInputBuffered(i); |
| } |
| return 0; |
| } |
| |