blob: 8e3292cf2178f850250b55f396ca3dd9b297f4b0 [file] [log] [blame]
#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;
}