Esempio n. 1
0
int_t listen(int_t s, int_t backlog)
{
   error_t error;
   Socket *socket;

   //Make sure the socket descriptor is valid
   if(s < 0 || s >= SOCKET_MAX_COUNT)
   {
      socketError(NULL, ERROR_INVALID_SOCKET);
      return SOCKET_ERROR;
   }

   //Point to the socket structure
   socket = &socketTable[s];

   //Place the socket in the listening state
   error = socketListen(socket);

   //Any error to report?
   if(error)
   {
      socketError(socket, error);
      return SOCKET_ERROR;
   }

   //Successful processing
   return SOCKET_SUCCESS;
}
Esempio n. 2
0
static bool server()
{
    sockfd = socketListen(7000);
    if(sockfd <= 0)
    {
        return false;
    }

    struct sockaddr_in cli_addr;
    socklen_t clilen = sizeof(sockaddr_in);

    while(true)
    {
        int clientSocket = accept(sockfd, (struct sockaddr*) &cli_addr, &clilen);

        if(clientSocket < 0)
        {
            printf("accept failed\r\n");
        }
        else
        {
            pthread_t th;
            int *pClientSocket = (int*)malloc(sizeof(int));
            *pClientSocket = clientSocket;

            pthread_create(&th, nullptr, clientThreadEntry, pClientSocket);
        }
    }
}
void EthernetServer::begin()
{
	sockindex = socketBegin(SnMR::TCP, _port);
	if (sockindex < MAX_SOCK_NUM) {
		socketListen(sockindex);
		server_port[sockindex] = _port;
	}
}
Esempio n. 4
0
error_t tcpEchoStart(void)
{
   error_t error;
   Socket *socket;
   OsTask *task;

   //Debug message
   TRACE_INFO("Starting TCP echo service...\r\n");

   //Open a TCP socket
   socket = socketOpen(SOCKET_TYPE_STREAM, SOCKET_PROTOCOL_TCP);
   //Failed to open socket?
   if(!socket) return ERROR_OPEN_FAILED;

   //Start of exception handling block
   do
   {
      //Bind the newly created socket to port 7
      error = socketBind(socket, &IP_ADDR_ANY, ECHO_PORT);
      //Failed to bind the socket to the desired port?
      if(error) break;

      //Place the socket into listening mode
      error = socketListen(socket);
      //Any error to report?
      if(error) break;

      //Create a task to handle incoming connection requests
      task = osTaskCreate("TCP Echo Listener", tcpEchoListenerTask,
         socket, ECHO_SERVICE_STACK_SIZE, ECHO_SERVICE_PRIORITY);

      //Unable to create the task?
      if(task == OS_INVALID_HANDLE)
      {
         //Report an error to the calling function
         error = ERROR_OUT_OF_RESOURCES;
         break;
      }

      //End of exception handling block
   } while(0);

   //Any error to report?
   if(error)
   {
      //Clean up side effects...
      socketClose(socket);
   }

   //Return status code
   return error;
}
Esempio n. 5
0
bool socketOpen(const char *pPort, int pBacklog, int *pSocket)
{
  struct addrinfo *addressInfo = NULL;

  bool success = true;
  success = success && getAddressInfo(pPort, &addressInfo);
  success = success && createSocket(addressInfo, pSocket);
  success = success && socketAddressReuse(*pSocket, true);
  success = success && socketAddressBind(*pSocket, addressInfo);
  freeaddrinfo(addressInfo);
  success = success && socketListen(*pSocket, pBacklog);
  return success;
}
void manageSocketConnections() {
	conexionSockets = list_create();
	Socket* s = socketCreateServer(atoi(puertoEscucha));
	while (TRUE) {
		pthread_t socketConnection;
		log_info(umclog, "UMC: Escuchando conexiones del Kernel o CPUs.");
		socketListen(s);
		Socket* socketClient;
		socketClient = socketAcceptClient(s);
		if (socketClient != NULL) {
			log_info(umclog, "UMC: Alguien se conecto.");
			manageSocketConnection((void*) socketClient);

			list_add(conexionSockets, &socketConnection);
		}
	}

}
Esempio n. 7
0
int proxySplice()
{
	int serverFd = socketListen(7000);
	int connectFd = socketConnect("127.0.0.1", 7001);

	struct sockaddr_in cli_addr;
	socklen_t clilen = sizeof(sockaddr_in);
	int clientFd = accept(serverFd, (struct sockaddr*) &cli_addr, &clilen);


	int pipefd[2];

	if(pipe(pipefd) != 0)
	{
		perror("pipe failed");
		return -1;
	}


	while(true)
	{
		int nr = splice(clientFd, NULL, pipefd[1], NULL, 100000, 0);
		if(nr <= 0)
		{
			perror("splice failed");
			break;
		}
		do
		{
			int ret = splice(pipefd[0], NULL, connectFd, NULL, nr, 0);
			if (ret <= 0)
			{
				perror("splice failed");
				break;
			}

			nr -= ret;
		} while (nr);
	}
	close(pipefd[0]);
	close(pipefd[1]);

	return 0;
}
Esempio n. 8
0
int CHttpServer::start(int nSocketType, const char* cszAddr, short nPort)
{
	int nMsgId;

	nMsgId = initMessage(MSG_ID);
	if (-1 == nMsgId)
	{
		throwException("socket server create message id fail");
		return -1;
	}

	threadHandler->createThread(threadMessageReceive, NULL);

	if (AF_UNIX == nSocketType)
	{
		setDomainSocketPath(cszAddr);
	}
	else if (AF_INET == nSocketType)
	{
		if (-1 == setInetSocket(cszAddr, nPort))
		{
			_DBG("set INET socket address & port fail");
			return -1;
		}
	}

	if (-1 != createSocket(nSocketType))
	{
		if (-1 != socketBind())
		{
			if (-1 != socketListen(BACKLOG))
			{
				threadHandler->createThread(threadSocketAccept, NULL);
				return 0;
			}
		}
	}

	return -1;
}
Esempio n. 9
0
struct _Socket *SocketListen ( unsigned int port )
{
    struct _Socket *pOSSock; 
    
    pOSSock = (struct _Socket *) malloc(sizeof(*pOSSock));
    if (!pOSSock) {
            uiPrintf("ERROR::osSockListen: malloc failed for pOSSock \n");
            return NULL; 
    }

    pOSSock->port_num = port;
    pOSSock->sockDisconnect = 0;
    pOSSock->sockClose = 0;

    pOSSock->sockfd = socketListen(pOSSock);
    if (pOSSock->sockfd == -1) {
        uiPrintf("ERROR::Socket create failed \n");
        free(pOSSock);
        return NULL;
    }
    pOSSock->nbuffer=0;
    
    return pOSSock;
}
Esempio n. 10
0
int proxyCopy()
{
	int serverFd = socketListen(7000);
	int connectFd = socketConnect("127.0.0.1", 7001);

	struct sockaddr_in cli_addr;
	socklen_t clilen = sizeof(sockaddr_in);
	int clientFd = accept(serverFd, (struct sockaddr*) &cli_addr, &clilen);

	TransferRingBuffer buffer;
	buffer.init(100000);

	long long int sumRead = 0;
	int counter = 0;

	while(true)
	{
		void *data;
		int size;
		int bytes;

		if(buffer.startWrite(data, size))
		{
			bytes = read(clientFd, data, size);

			if(bytes <= 0)
			{
				printf("read <= 0\n");
				return -1;
			}

			buffer.endWrite(bytes);

			sumRead += bytes;
			++counter;

			if(counter>=10000)
			{
				printf("avg read: %lld\n", sumRead/counter);fflush(stdout);
				counter = 0;
				sumRead = 0;
			}
		}
		else
		{
			printf("startWrite failed\n");
			return -1;
		}

		if(buffer.startRead(data, size))
		{
			bytes = write(connectFd, data, size);

			if(bytes <= 0)
			{
				printf("write <= 0\n");
				return -1;
			}

			buffer.endRead(bytes);
		}
		else
		{
			printf("startRead failed\n");
			return -1;
		}
	}

	return 0;
}
Esempio n. 11
0
/*
	Non-blocking socket event handler
	Wait one time in select for events on any socket
	This will accept new connections, read and write to sockets that are
	connected, and close sockets as required.
 */
static int32 selectLoop(sslKeys_t *keys, SOCKET lfd)
{
	httpConn_t		*cp;
	psTime_t		now;
	DLListEntry		connsTmp;
	DLListEntry		*pList;
	
	fd_set			readfd, writefd;
	struct timeval	timeout;
	SOCKET			fd, maxfd;
	
	unsigned char	*buf;
	int32			rc, len, transferred, val;
	unsigned char	rSanity, wSanity, acceptSanity;
	
	DLListInit(&connsTmp);
	rc = PS_SUCCESS;
	maxfd = INVALID_SOCKET;
	timeout.tv_sec = SELECT_TIME / 1000;
	timeout.tv_usec = (SELECT_TIME % 1000) * 1000;
	FD_ZERO(&readfd);
	FD_ZERO(&writefd);
	
	/* Always set readfd for listening socket */
	FD_SET(lfd, &readfd);
	if (lfd > maxfd) {
		maxfd = lfd;
	}
/*	
	Check timeouts and set readfd and writefd for connections as required.
	We use connsTemp so that removal on error from the active iteration list
		doesn't interfere with list traversal 
 */
	psGetTime(&now);
	while (!DLListIsEmpty(&g_conns)) {
		pList = DLListGetHead(&g_conns);
		cp = DLListGetContainer(pList, httpConn_t, List);
		DLListInsertTail(&connsTmp, &cp->List);
		/*	If timeout != 0 msec ith no new data, close */
		if (cp->timeout && (psDiffMsecs(cp->time, now) > (int32)cp->timeout)) {
			closeConn(cp, PS_TIMEOUT_FAIL);
			continue;	/* Next connection */
		}
		/* Always select for read */
		FD_SET(cp->fd, &readfd);
		/* Select for write if there's pending write data or connection */
		if (matrixSslGetOutdata(cp->ssl, NULL) > 0) {
			FD_SET(cp->fd, &writefd);
		}
		/* Housekeeping for maxsock in select call */
		if (cp->fd > maxfd) {
			maxfd = cp->fd;
		}
	}
	
	/* Use select to check for events on the sockets */
	if ((val = select(maxfd + 1, &readfd, &writefd, NULL, &timeout)) <= 0) {
		/* On error, restore global connections list */
		while (!DLListIsEmpty(&connsTmp)) {
			pList = DLListGetHead(&connsTmp);
			cp = DLListGetContainer(pList, httpConn_t, List);
			DLListInsertTail(&g_conns, &cp->List);
		}
		/* Select timeout */
		if (val == 0) {
			return PS_TIMEOUT_FAIL;
		}
		/* Woke due to interrupt */
		if (SOCKET_ERRNO == EINTR) {
			return PS_TIMEOUT_FAIL;
		}
		/* Should attempt to handle more errnos, such as EBADF */
		return PS_PLATFORM_FAIL;
	}
	
	/* Check listener for new incoming socket connections */
	if (FD_ISSET(lfd, &readfd)) {
		for (acceptSanity = 0; acceptSanity < ACCEPT_QUEUE; acceptSanity++) {
			fd = accept(lfd, NULL, NULL);
			if (fd == INVALID_SOCKET) {
				break;	/* Nothing more to accept; next listener */
			}
			setSocketOptions(fd);
			cp = malloc(sizeof(httpConn_t));
			if ((rc = matrixSslNewServerSession(&cp->ssl, keys, certCb)) < 0) {
				close(fd); fd = INVALID_SOCKET;
				continue;
			}
			cp->fd = fd;
			fd = INVALID_SOCKET;
			cp->timeout = SSL_TIMEOUT;
			psGetTime(&cp->time);
			cp->parsebuf = NULL;
			cp->parsebuflen = 0;
			DLListInsertTail(&connsTmp, &cp->List);
			/* Fake that there is read data available, no harm if there isn't */
			FD_SET(cp->fd, &readfd);
/*			_psTraceInt("=== New Client %d ===\n", cp->fd); */
		}
	}
	
	/* Check each connection for read/write activity */
	while (!DLListIsEmpty(&connsTmp)) {
		pList = DLListGetHead(&connsTmp);
		cp = DLListGetContainer(pList, httpConn_t, List);
		DLListInsertTail(&g_conns, &cp->List);
		
		rSanity = wSanity = 0;
/*
		See if there's pending data to send on this connection
		We could use FD_ISSET, but this is more reliable for the current
			state of data to send.
 */
WRITE_MORE:
		if ((len = matrixSslGetOutdata(cp->ssl, &buf)) > 0) {
			/* Could get a EWOULDBLOCK since we don't check FD_ISSET */
			transferred = send(cp->fd, buf, len, MSG_DONTWAIT);
			if (transferred <= 0) {
#ifdef WIN32
				if (SOCKET_ERRNO != EWOULDBLOCK &&
					SOCKET_ERRNO != WSAEWOULDBLOCK) {

#else
				if (SOCKET_ERRNO != EWOULDBLOCK) {
#endif
					closeConn(cp, PS_PLATFORM_FAIL);
					continue;	/* Next connection */
				}
			} else {
				/* Indicate that we've written > 0 bytes of data */
				if ((rc = matrixSslSentData(cp->ssl, transferred)) < 0) {
					closeConn(cp, PS_ARG_FAIL);
					continue;	/* Next connection */
				}
				if (rc == MATRIXSSL_REQUEST_CLOSE) {
					closeConn(cp, MATRIXSSL_REQUEST_CLOSE);
					continue;	/* Next connection */
				} else if (rc == MATRIXSSL_HANDSHAKE_COMPLETE) {
					/* If the protocol is server initiated, send data here */
#ifdef ENABLE_FALSE_START					
					/* OR this could be a Chrome browser using 
						FALSE_START and the application data is already
						waiting in our inbuf for processing */
					if ((rc = matrixSslReceivedData(cp->ssl, 0,
								&buf, (uint32*)&len)) < 0) {
							closeConn(cp, 0);
							continue;	/* Next connection */
					}
					if (rc > 0) { /* There was leftover data */
						goto PROCESS_MORE;
					}
#endif /* ENABLE_FALSE_START  */
					
				}
				/* Update activity time */
				psGetTime(&cp->time);
				/* Try to send again if more data to send */
				if (rc == MATRIXSSL_REQUEST_SEND || transferred < len) {
					if (wSanity++ < GOTO_SANITY) goto WRITE_MORE;
				}
			}
		} else if (len < 0) {
			closeConn(cp, PS_ARG_FAIL);
			continue;	/* Next connection */
		}
		
/*
		Check the file descriptor returned from select to see if the connection
		has data to be read
 */
		if (FD_ISSET(cp->fd, &readfd)) {
READ_MORE:
			/* Get the ssl buffer and how much data it can accept */
			/* Note 0 is a return failure, unlike with matrixSslGetOutdata */
			if ((len = matrixSslGetReadbuf(cp->ssl, &buf)) <= 0) {
				closeConn(cp, PS_ARG_FAIL);
				continue;	/* Next connection */
			}
			if ((transferred = recv(cp->fd, buf, len, MSG_DONTWAIT)) < 0) {
				/* We could get EWOULDBLOCK despite the FD_ISSET on goto  */
#ifdef WIN32
				if (SOCKET_ERRNO != EWOULDBLOCK &&
					SOCKET_ERRNO != WSAEWOULDBLOCK) {

#else
				if (SOCKET_ERRNO != EWOULDBLOCK) {
#endif
					closeConn(cp, PS_PLATFORM_FAIL);
				}
				continue;	/* Next connection */
			}
			/* If EOF, remote socket closed. This is semi-normal closure.
			   Officially, we should close on closure alert. */
			if (transferred == 0) {
/*				psTraceIntInfo("Closing connection %d on EOF\n", cp->fd); */
				closeConn(cp, 0);
				continue;	/* Next connection */
			}
/*
			Notify SSL state machine that we've received more data into the
			ssl buffer retreived with matrixSslGetReadbuf.
 */
			if ((rc = matrixSslReceivedData(cp->ssl, (int32)transferred, &buf, 
											(uint32*)&len)) < 0) {
				closeConn(cp, 0);
				continue;	/* Next connection */
			}
			/* Update activity time */
			psGetTime(&cp->time);
			
PROCESS_MORE:
			/* Process any incoming plaintext application data */
			switch (rc) {
				case MATRIXSSL_HANDSHAKE_COMPLETE:
					/* If the protocol is server initiated, send data here */
					goto READ_MORE;
				case MATRIXSSL_APP_DATA:
					/* Remember, must handle if len == 0! */
					if ((rc = httpBasicParse(cp, buf, len)) < 0) {
						_psTrace("Couldn't parse HTTP data.  Closing conn.\n");
						closeConn(cp, PS_PROTOCOL_FAIL);
						continue; /* Next connection */
					}
					if (rc == HTTPS_COMPLETE) {
						if (httpWriteResponse(cp->ssl) < 0) {
							closeConn(cp, PS_PROTOCOL_FAIL);
							continue; /* Next connection */
						}
						/* For HTTP, we assume no pipelined requests, so we 
						 close after parsing a single HTTP request */
						/* Ignore return of closure alert, it's optional */
						matrixSslEncodeClosureAlert(cp->ssl);
						rc = matrixSslProcessedData(cp->ssl, &buf, (uint32*)&len);
						if (rc > 0) {
							/* Additional data is available, but we ignore it */
							_psTrace("HTTP data parsing not supported, ignoring.\n");
							closeConn(cp, PS_SUCCESS);
							continue; /* Next connection */
						} else if (rc < 0) {
							closeConn(cp, PS_PROTOCOL_FAIL);
							continue; /* Next connection */
						}
						/* rc == 0, write out our response and closure alert */
						goto WRITE_MORE;
					}
					/* We processed a partial HTTP message */
					if ((rc = matrixSslProcessedData(cp->ssl, &buf, (uint32*)&len)) == 0) {
						goto READ_MORE;
					}
					goto PROCESS_MORE;
				case MATRIXSSL_REQUEST_SEND:
					/* Prevent us from reading again after the write,
					 although that wouldn't be the end of the world */
					FD_CLR(cp->fd, &readfd);
					if (wSanity++ < GOTO_SANITY) goto WRITE_MORE;
					break;
				case MATRIXSSL_REQUEST_RECV:
					if (rSanity++ < GOTO_SANITY) goto READ_MORE; 
					break;
				case MATRIXSSL_RECEIVED_ALERT:
					/* The first byte of the buffer is the level */
					/* The second byte is the description */
					if (*buf == SSL_ALERT_LEVEL_FATAL) {
						psTraceIntInfo("Fatal alert: %d, closing connection.\n", 
									*(buf + 1));
						closeConn(cp, PS_PROTOCOL_FAIL);
						continue; /* Next connection */
					}
					/* Closure alert is normal (and best) way to close */
					if (*(buf + 1) == SSL_ALERT_CLOSE_NOTIFY) {
						closeConn(cp, PS_SUCCESS);
						continue; /* Next connection */
					}
					psTraceIntInfo("Warning alert: %d\n", *(buf + 1));
					if ((rc = matrixSslProcessedData(cp->ssl, &buf, (uint32*)&len)) == 0) {
						/* No more data in buffer. Might as well read for more. */
						goto READ_MORE;
					}
					goto PROCESS_MORE;

				default:
					/* If rc <= 0 we fall here */
					closeConn(cp, PS_PROTOCOL_FAIL);
					continue; /* Next connection */
			}
			/* Always try to read more if we processed some data */
			if (rSanity++ < GOTO_SANITY) goto READ_MORE;
		} /*  readfd handling */
	}	/* connection loop */
	return PS_SUCCESS;
}

/******************************************************************************/
/*
	Create an HTTP response and encode it to the SSL buffer
 */
#define	TEST_SIZE	16000
static int32 httpWriteResponse(ssl_t *cp)
{
	unsigned char	*buf;
	int32			available;
	
	if ((available = matrixSslGetWritebuf(cp, &buf, 
							strlen((char *)g_httpResponseHdr) + 1)) < 0) {
		return PS_MEM_FAIL;
	}
	strncpy((char *)buf, (char *)g_httpResponseHdr, available);
	if (matrixSslEncodeWritebuf(cp, strlen((char *)buf)) < 0) {
		return PS_MEM_FAIL;
	}
	return MATRIXSSL_REQUEST_SEND;
}

/******************************************************************************/
/*
	Main non-blocking SSL server
	Initialize MatrixSSL and sockets layer, and loop on select
 */
int32 main(int32 argc, char **argv)
{
	sslKeys_t		*keys;
	SOCKET			lfd;
	int32			err, rc;
#ifdef WIN32
	WSADATA			wsaData;
	WSAStartup(MAKEWORD(1, 1), &wsaData);
#endif


	keys = NULL;
	DLListInit(&g_conns);
	g_exitFlag = 0;
	lfd = INVALID_SOCKET;
	
#ifdef POSIX
	if (sighandlers() < 0) {
		return PS_PLATFORM_FAIL;
	}
#endif	/* POSIX */
	if ((rc = matrixSslOpen()) < 0) {
		_psTrace("MatrixSSL library init failure.  Exiting\n");
		return rc;
	}
	if (matrixSslNewKeys(&keys) < 0) {
		_psTrace("MatrixSSL library key init failure.  Exiting\n");
		return -1;
	}

#ifdef USE_HEADER_KEYS
/*
	In-memory based keys
*/
	if ((rc = matrixSslLoadRsaKeysMem(keys, certSrvBuf, sizeof(certSrvBuf),
				   privkeySrvBuf, sizeof(privkeySrvBuf), NULL, 0)) < 0) {
		_psTrace("No certificate material loaded.  Exiting\n");
		matrixSslDeleteKeys(keys);
		matrixSslClose();
		return rc;
	}
#else /* USE_HEADER_KEYS */
/*
	File based keys
*/
	if ((rc = matrixSslLoadRsaKeys(keys, certSrvFile, privkeySrvFile, NULL,
			NULL)) < 0) {
		_psTrace("No certificate material loaded.  Exiting\n");
		matrixSslDeleteKeys(keys);
		matrixSslClose();
		return rc;
	}
#endif /* USE_HEADER_KEYS */


	/* Create the listening socket that will accept incoming connections */
	if ((lfd = socketListen(HTTPS_PORT, &err)) == INVALID_SOCKET) {
		_psTraceInt("Can't listen on port %d\n", HTTPS_PORT);
		goto L_EXIT;
	}

	/* Main select loop to handle sockets events */
	while (!g_exitFlag) {
		selectLoop(keys, lfd);
	}

L_EXIT:
	if (lfd != INVALID_SOCKET) close(lfd);
	if (keys) matrixSslDeleteKeys(keys);
	matrixSslClose();
	
	return 0;
}
Esempio n. 12
0
int main(int argc, char **argv)
#endif
{
	sslConn_t		*cp;
	sslKeys_t		*keys;
	SOCKET			listenfd, fd;
	WSADATA			wsaData;
	unsigned char	buf[1024];
	unsigned char	*response, *c;
	int				responseHdrLen, acceptAgain, flags;
	int				bytes, status, quit, again, rc, err;
#if USE_MEM_CERTS
	unsigned char	*servBin, *servKeyBin, *caBin; 
	int				servBinLen, caBinLen, servKeyBinLen;
#endif

	cp = NULL;
/*
	Initialize Windows sockets (no-op on other platforms)
*/
	WSAStartup(MAKEWORD(1,1), &wsaData);
/*
	Initialize the MatrixSSL Library, and read in the public key (certificate)
	and private key.
*/
	if (matrixSslOpen() < 0) {
		fprintf(stderr, "matrixSslOpen failed, exiting...");
	}

#if USE_MEM_CERTS
/*
	Example of DER binary certs for matrixSslReadKeysMem
*/
	getFileBin("certSrv.der", &servBin, &servBinLen);
	getFileBin("privkeySrv.der", &servKeyBin, &servKeyBinLen);
	getFileBin("CACertCln.der", &caBin, &caBinLen);

	matrixSslReadKeysMem(&keys, servBin, servBinLen,
		servKeyBin, servKeyBinLen, caBin, caBinLen); 

	free(servBin);
	free(servKeyBin);
	free(caBin);
#else 
/*
	Standard PEM files
*/
	if (matrixSslReadKeys(&keys, certfile, keyfile, NULL, NULL) < 0)  {
		fprintf(stderr, "Error reading or parsing %s or %s.\n", 
			certfile, keyfile);
		goto promptAndExit;
	}
#endif /* USE_MEM_CERTS */
	fprintf(stdout, 
		"Run httpsClient or type https://127.0.0.1:%d into your local Web browser.\n",
		HTTPS_PORT);
/*
	Create the listen socket
*/
	if ((listenfd = socketListen(HTTPS_PORT, &err)) == INVALID_SOCKET) {
		fprintf(stderr, "Cannot listen on port %d\n", HTTPS_PORT);
		goto promptAndExit;
	}
/*
	Set blocking or not on the listen socket
*/
	setSocketBlock(listenfd);
/*
	Loop control initalization
*/
	quit = 0;
	again = 0;
	flags = 0;

	acceptAgain = 1;
/*
	Main connection loop
*/
	while (!quit) {

		if (acceptAgain) {
/*
			sslAccept creates a new server session
*/
			/* TODO - deadlock on blocking socket accept.  Should disable blocking here */
			if ((fd = socketAccept(listenfd, &err)) == INVALID_SOCKET) {
				fprintf(stdout, "Error accepting connection: %d\n", err);
				continue;
			}
			if ((rc = sslAccept(&cp, fd, keys, NULL, flags)) != 0) {
				socketShutdown(fd);
				continue;
			}

			flags = 0;
			acceptAgain = 0;
		}
/*
		Read response
		< 0 return indicates an error.
		0 return indicates an EOF or CLOSE_NOTIFY in this situation
		> 0 indicates that some bytes were read.  Keep reading until we see
		the /r/n/r/n from the GET request.  We don't actually parse the request,
		we just echo it back.
*/
		c = buf;
readMore:
		if ((rc = sslRead(cp, c, sizeof(buf) - (int)(c - buf), &status)) > 0) {
			c += rc;
			if (c - buf < 4 || memcmp(c - 4, "\r\n\r\n", 4) != 0) {
				goto readMore;
			}
		} else {
			if (rc < 0) {
				fprintf(stdout, "sslRead error.  dropping connection.\n");
			}
			if (rc < 0 || status == SSLSOCKET_EOF ||
					status == SSLSOCKET_CLOSE_NOTIFY) {
				socketShutdown(cp->fd);
				sslFreeConnection(&cp);
				acceptAgain = 1;
				continue;
			}
			goto readMore;
		}
/*
		Done reading.  If the incoming data starts with the quitString,
		quit the application after this request
*/
		if (memcmp(buf, quitString, min(c - buf, 
				(int)strlen(quitString))) == 0) {
			quit++;
			fprintf(stdout, "Q");
		}
/*
		If the incoming data starts with the againString,
		we are getting a pipeline request on the same session.  Don't
		close and wait for new connection in this case.
*/
		if (memcmp(buf, againString,
				min(c - buf, (int)strlen(againString))) == 0) {
			again++;
			fprintf(stdout, "A");
		} else {
			fprintf(stdout, "R");
			again = 0;
		}
/*
		Copy the canned response header and decoded data from socket as the
		response (reflector)
*/
		responseHdrLen = (int)strlen(responseHdr);
		bytes = responseHdrLen + (int)(c - buf);
		response = malloc(bytes);
		memcpy(response, responseHdr, responseHdrLen);
		memcpy(response + responseHdrLen, buf, c - buf); 
/*
		Send response.
		< 0 return indicates an error.
		0 return indicates not all data was sent and we must retry
		> 0 indicates that all requested bytes were sent
*/
writeMore:
		rc = sslWrite(cp, response, bytes, &status);
		if (rc < 0) {
			free(response);
			fprintf(stdout, "Internal sslWrite error\n");
			socketShutdown(cp->fd);
			sslFreeConnection(&cp);
			continue;
		} else if (rc == 0) {
			goto writeMore;
		}
		free(response);
/*
		If we saw an /again request, loop up and process another pipelined
		HTTP request.  The /again request is supported in the httpsClient
		example code.
*/
		if (again) {
			continue;
		}
/*
		Send a closure alert for clean shutdown of remote SSL connection
		This is for good form, some implementations just close the socket
*/
		sslWriteClosureAlert(cp);
/*
		Close the socket and wait for next connection (new session)
*/
		socketShutdown(cp->fd);
		sslFreeConnection(&cp);
		acceptAgain = 1;
	}
/*
	Close listening socket, free remaining items
*/
	if (cp && cp->ssl) {
		socketShutdown(cp->fd);
		sslFreeConnection(&cp);
	}
	socketShutdown(listenfd);

	matrixSslFreeKeys(keys);
	matrixSslClose();
	WSACleanup();
promptAndExit:
	fprintf(stdout, "\n\nPress return to exit...\n");
	getchar();
	return 0;
}
Esempio n. 13
0
error_t httpServerInit(HttpServerContext *context, const HttpServerSettings *settings)
{
   error_t error;
   uint_t i;

   //Debug message
   TRACE_INFO("Initializing HTTP server...\r\n");

   //Ensure the parameters are valid
   if(context == NULL || settings == NULL)
      return ERROR_INVALID_PARAMETER;

   //Check user settings
   if(settings->maxConnections == 0 || settings->connections == NULL)
      return ERROR_INVALID_PARAMETER;

   //Clear the HTTP server context
   memset(context, 0, sizeof(HttpServerContext));

   //Save user settings
   context->settings = *settings;
   //Client connections
   context->connections = settings->connections;

   //Create a semaphore to limit the number of simultaneous connections
   if(!osCreateSemaphore(&context->semaphore, context->settings.maxConnections))
      return ERROR_OUT_OF_RESOURCES;

   //Loop through client connections
   for(i = 0; i < context->settings.maxConnections; i++)
   {
      //Create an event object to manage connection lifetime
      if(!osCreateEvent(&context->connections[i].startEvent))
         return ERROR_OUT_OF_RESOURCES;
   }

#if (HTTP_SERVER_DIGEST_AUTH_SUPPORT == ENABLED)
   //Create a mutex to prevent simultaneous access to the nonce cache
   if(!osCreateMutex(&context->nonceCacheMutex))
      return ERROR_OUT_OF_RESOURCES;
#endif

   //Open a TCP socket
   context->socket = socketOpen(SOCKET_TYPE_STREAM, SOCKET_IP_PROTO_TCP);
   //Failed to open socket?
   if(!context->socket) return ERROR_OPEN_FAILED;

   //Set timeout for blocking functions
   error = socketSetTimeout(context->socket, INFINITE_DELAY);
   //Any error to report?
   if(error) return error;

   //Associate the socket with the relevant interface
   error = socketBindToInterface(context->socket, settings->interface);
   //Unable to bind the socket to the desired interface?
   if(error) return error;

   //Bind newly created socket to port 80
   error = socketBind(context->socket, &IP_ADDR_ANY, settings->port);
   //Failed to bind socket to port 80?
   if(error) return error;

   //Place socket in listening state
   error = socketListen(context->socket, settings->backlog);
   //Any failure to report?
   if(error) return error;

   //Successful initialization
   return NO_ERROR;
}
Esempio n. 14
0
/*
	Non-blocking socket event handler
	Wait one time in select for events on any socket
	This will accept new connections, read and write to sockets that are
	connected, and close sockets as required.
 */
static int32 selectLoop(sslKeys_t *keys, SOCKET lfd)
{
	httpConn_t		*cp;
	psTime_t		now;
	DLListEntry		connsTmp;
	DLListEntry		*pList;
	
	fd_set			readfd, writefd;
	struct timeval	timeout;
	SOCKET			fd, maxfd;
	
	unsigned char	*buf;
	int32			rc, len, transferred, val;
	unsigned char	rSanity, wSanity, acceptSanity;
	
	sslSessOpts_t	options;
	
	DLListInit(&connsTmp);
	rc = PS_SUCCESS;
	maxfd = INVALID_SOCKET;
	timeout.tv_sec = SELECT_TIME / 1000;
	timeout.tv_usec = (SELECT_TIME % 1000) * 1000;
	FD_ZERO(&readfd);
	FD_ZERO(&writefd);
	
	/* Always set readfd for listening socket */
	FD_SET(lfd, &readfd);
	if (lfd > maxfd) {
		maxfd = lfd;
	}
/*	
	Check timeouts and set readfd and writefd for connections as required.
	We use connsTemp so that removal on error from the active iteration list
		doesn't interfere with list traversal 
 */
	psGetTime(&now, NULL);
	while (!DLListIsEmpty(&g_conns)) {
		pList = DLListGetHead(&g_conns);
		cp = DLListGetContainer(pList, httpConn_t, List);
		DLListInsertTail(&connsTmp, &cp->List);
		/*	If timeout != 0 msec ith no new data, close */
		if (cp->timeout && (psDiffMsecs(cp->time, now, NULL) >
				(int32)cp->timeout)) {
			closeConn(cp, PS_TIMEOUT_FAIL);
			continue;	/* Next connection */
		}
		/* Always select for read */
		FD_SET(cp->fd, &readfd);
		/* Select for write if there's pending write data or connection */
		if (matrixSslGetOutdata(cp->ssl, NULL) > 0) {
			FD_SET(cp->fd, &writefd);
		}
		/* Housekeeping for maxsock in select call */
		if (cp->fd > maxfd) {
			maxfd = cp->fd;
		}
	}
	
	/* Use select to check for events on the sockets */
	if ((val = select(maxfd + 1, &readfd, &writefd, NULL, &timeout)) <= 0) {
		/* On error, restore global connections list */
		while (!DLListIsEmpty(&connsTmp)) {
			pList = DLListGetHead(&connsTmp);
			cp = DLListGetContainer(pList, httpConn_t, List);
			DLListInsertTail(&g_conns, &cp->List);
		}
		/* Select timeout */
		if (val == 0) {
			return PS_TIMEOUT_FAIL;
		}
		/* Woke due to interrupt */
		if (SOCKET_ERRNO == EINTR) {
			return PS_TIMEOUT_FAIL;
		}
		/* Should attempt to handle more errnos, such as EBADF */
		return PS_PLATFORM_FAIL;
	}
	
	/* Check listener for new incoming socket connections */
	if (FD_ISSET(lfd, &readfd)) {
		for (acceptSanity = 0; acceptSanity < ACCEPT_QUEUE; acceptSanity++) {
			fd = accept(lfd, NULL, NULL);
			if (fd == INVALID_SOCKET) {
				break;	/* Nothing more to accept; next listener */
			}
			setSocketOptions(fd);
			cp = malloc(sizeof(httpConn_t));
			memset(cp, 0x0, sizeof(httpConn_t));
			
			memset(&options, 0x0, sizeof(sslSessOpts_t));
			options.versionFlag = g_proto;
			options.userPtr = keys; /* Just a test */
			//options.truncHmac = -1;
			//options.maxFragLen = -1;
			//options.ecFlags |= SSL_OPT_SECP521R1;
			//options.ecFlags |= SSL_OPT_SECP224R1;
			//options.ecFlags |= SSL_OPT_SECP384R1;
			
			
			if ((rc = matrixSslNewServerSession(&cp->ssl, keys, certCb,
					&options)) < 0) {
				close(fd); fd = INVALID_SOCKET;
				continue;
			}
			
#ifdef USE_SERVER_NAME_INDICATION
			/* Register extension callbacks to manage client connection opts */
			matrixSslRegisterSNICallback(cp->ssl, SNI_callback);
#endif
#ifdef USE_ALPN
			matrixSslRegisterALPNCallback(cp->ssl, ALPN_callback);
#endif
			
			cp->fd = fd;
			fd = INVALID_SOCKET;
			cp->timeout = SSL_TIMEOUT;
			psGetTime(&cp->time, NULL);
			cp->parsebuf = NULL;
			cp->parsebuflen = 0;
			DLListInsertTail(&connsTmp, &cp->List);
			/* Fake that there is read data available, no harm if there isn't */
			FD_SET(cp->fd, &readfd);
/*			_psTraceInt("=== New Client %d ===\n", cp->fd); */
		}
	}
	
	/* Check each connection for read/write activity */
	while (!DLListIsEmpty(&connsTmp)) {
		pList = DLListGetHead(&connsTmp);
		cp = DLListGetContainer(pList, httpConn_t, List);
		DLListInsertTail(&g_conns, &cp->List);
		
		rSanity = wSanity = 0;
/*
		See if there's pending data to send on this connection
		We could use FD_ISSET, but this is more reliable for the current
			state of data to send.
 */
WRITE_MORE:
		if ((len = matrixSslGetOutdata(cp->ssl, &buf)) > 0) {
			/* Could get a EWOULDBLOCK since we don't check FD_ISSET */
			transferred = send(cp->fd, buf, len, MSG_DONTWAIT);
			if (transferred <= 0) {
#ifdef WIN32
				if (SOCKET_ERRNO != EWOULDBLOCK &&
					SOCKET_ERRNO != WSAEWOULDBLOCK) {

#else
				if (SOCKET_ERRNO != EWOULDBLOCK) {
#endif
					closeConn(cp, PS_PLATFORM_FAIL);
					continue;	/* Next connection */
				}
			} else {
				/* Indicate that we've written > 0 bytes of data */
				if ((rc = matrixSslSentData(cp->ssl, transferred)) < 0) {
					closeConn(cp, PS_ARG_FAIL);
					continue;	/* Next connection */
				}
				if (rc == MATRIXSSL_REQUEST_CLOSE) {
					closeConn(cp, MATRIXSSL_REQUEST_CLOSE);
					continue;	/* Next connection */
				} else if (rc == MATRIXSSL_HANDSHAKE_COMPLETE) {
					/* If the protocol is server initiated, send data here */
#ifdef ENABLE_FALSE_START					
					/* OR this could be a Chrome browser using 
						FALSE_START and the application data is already
						waiting in our inbuf for processing */
					if ((rc = matrixSslReceivedData(cp->ssl, 0,
								&buf, (uint32*)&len)) < 0) {
							closeConn(cp, 0);
							continue;	/* Next connection */
					}
					if (rc > 0) { /* There was leftover data */
						goto PROCESS_MORE;
					}
#endif /* ENABLE_FALSE_START  */
					
				}
				/* Update activity time */
				psGetTime(&cp->time, NULL);
				/* Try to send again if more data to send */
				if (rc == MATRIXSSL_REQUEST_SEND || transferred < len) {
					if (wSanity++ < GOTO_SANITY) goto WRITE_MORE;
				}
			}
		} else if (len < 0) {
			closeConn(cp, PS_ARG_FAIL);
			continue;	/* Next connection */
		}
		
/*
		Check the file descriptor returned from select to see if the connection
		has data to be read
 */
		if (FD_ISSET(cp->fd, &readfd)) {
READ_MORE:
			/* Get the ssl buffer and how much data it can accept */
			/* Note 0 is a return failure, unlike with matrixSslGetOutdata */
			if ((len = matrixSslGetReadbuf(cp->ssl, &buf)) <= 0) {
				closeConn(cp, PS_ARG_FAIL);
				continue;	/* Next connection */
			}
			if ((transferred = recv(cp->fd, buf, len, MSG_DONTWAIT)) < 0) {
				/* We could get EWOULDBLOCK despite the FD_ISSET on goto  */
#ifdef WIN32
				if (SOCKET_ERRNO != EWOULDBLOCK &&
					SOCKET_ERRNO != WSAEWOULDBLOCK) {

#else
				if (SOCKET_ERRNO != EWOULDBLOCK) {
#endif
					closeConn(cp, PS_PLATFORM_FAIL);
				}
				continue;	/* Next connection */
			}
			
			/* If EOF, remote socket closed. This is semi-normal closure.
			   Officially, we should close on closure alert. */
			if (transferred == 0) {
/*				psTraceIntInfo("Closing connection %d on EOF\n", cp->fd); */
				closeConn(cp, 0);
				continue;	/* Next connection */
			}
/*
			Notify SSL state machine that we've received more data into the
			ssl buffer retreived with matrixSslGetReadbuf.
 */
			if ((rc = matrixSslReceivedData(cp->ssl, (int32)transferred, &buf, 
											(uint32*)&len)) < 0) {
				closeConn(cp, 0);
				continue;	/* Next connection */
			}
			/* Update activity time */
			psGetTime(&cp->time, NULL);
			
PROCESS_MORE:
			/* Process any incoming plaintext application data */
			switch (rc) {
				case MATRIXSSL_HANDSHAKE_COMPLETE:
					/* If the protocol is server initiated, send data here */
					goto READ_MORE;
				case MATRIXSSL_APP_DATA:
				case MATRIXSSL_APP_DATA_COMPRESSED:
					//psTraceBytes("DATA", buf, len);
					/* Remember, must handle if len == 0! */
					if ((rc = httpBasicParse(cp, buf, len, 0)) < 0) {
						_psTrace("Couldn't parse HTTP data.  Closing conn.\n");
						closeConn(cp, PS_PROTOCOL_FAIL);
						continue; /* Next connection */
					}
					if (cp->parsebuf != NULL) {
						/* Test for one of our custom testing messages */
						if (strncmp((const char*)cp->parsebuf,
								"MATRIX_SHUTDOWN", 15) == 0) {
							g_exitFlag = 1;
							matrixSslEncodeClosureAlert(cp->ssl);
							_psTrace("Got MATRIX_SHUTDOWN.  Exiting\n");
							goto WRITE_MORE;
						}
						
					}
					/* reply to /bytes?<byte count> syntax */
					if (len > 11 &&
							strncmp((char *)buf, "GET /bytes?", 11) == 0) {
						cp->bytes_requested = atoi((char *)buf + 11);
						if (cp->bytes_requested <
								strlen((char *)g_httpResponseHdr) ||
								cp->bytes_requested > 1073741824) {
                			cp->bytes_requested =
								strlen((char *)g_httpResponseHdr);
            			}
						cp->bytes_sent = 0;
					}
					if (rc == HTTPS_COMPLETE) {
						if (httpWriteResponse(cp) < 0) {
							closeConn(cp, PS_PROTOCOL_FAIL);
							continue; /* Next connection */
						}
						/* For HTTP, we assume no pipelined requests, so we 
						 close after parsing a single HTTP request */
						/* Ignore return of closure alert, it's optional */
						matrixSslEncodeClosureAlert(cp->ssl);
						rc = matrixSslProcessedData(cp->ssl, &buf, (uint32*)&len);
						if (rc > 0) {
							/* Additional data is available, but we ignore it */
							_psTrace("HTTP data parsing not supported, ignoring.\n");
							closeConn(cp, PS_SUCCESS);
							continue; /* Next connection */
						} else if (rc < 0) {
							closeConn(cp, PS_PROTOCOL_FAIL);
							continue; /* Next connection */
						}
						/* rc == 0, write out our response and closure alert */
						goto WRITE_MORE;
					}
					/* We processed a partial HTTP message */
					if ((rc = matrixSslProcessedData(cp->ssl, &buf, (uint32*)&len)) == 0) {
						goto READ_MORE;
					}
					goto PROCESS_MORE;
				case MATRIXSSL_REQUEST_SEND:
					/* Prevent us from reading again after the write,
					 although that wouldn't be the end of the world */
					FD_CLR(cp->fd, &readfd);
					if (wSanity++ < GOTO_SANITY) goto WRITE_MORE;
					break;
				case MATRIXSSL_REQUEST_RECV:
					if (rSanity++ < GOTO_SANITY) goto READ_MORE; 
					break;
				case MATRIXSSL_RECEIVED_ALERT:
					/* The first byte of the buffer is the level */
					/* The second byte is the description */
					if (*buf == SSL_ALERT_LEVEL_FATAL) {
						psTraceIntInfo("Fatal alert: %d, closing connection.\n", 
									*(buf + 1));
						closeConn(cp, PS_PROTOCOL_FAIL);
						continue; /* Next connection */
					}
					/* Closure alert is normal (and best) way to close */
					if (*(buf + 1) == SSL_ALERT_CLOSE_NOTIFY) {
						closeConn(cp, PS_SUCCESS);
						continue; /* Next connection */
					}
					psTraceIntInfo("Warning alert: %d\n", *(buf + 1));
					if ((rc = matrixSslProcessedData(cp->ssl, &buf, (uint32*)&len)) == 0) {
						/* No more data in buffer. Might as well read for more. */
						goto READ_MORE;
					}
					goto PROCESS_MORE;

				default:
					/* If rc <= 0 we fall here */
					closeConn(cp, PS_PROTOCOL_FAIL);
					continue; /* Next connection */
			}
			/* Always try to read more if we processed some data */
			if (rSanity++ < GOTO_SANITY) goto READ_MORE;
		} /*  readfd handling */
	}	/* connection loop */
	return PS_SUCCESS;
}

/******************************************************************************/
/*
	Create an HTTP response and encode it to the SSL buffer
 */
#define	TEST_SIZE	16000
static int32 httpWriteResponse(httpConn_t *conn)
{
	unsigned char	*buf;
	ssl_t			*cp;
	int32			available, len, rc;

		
	cp = conn->ssl;
	if (conn->bytes_requested) {
		/* The /bytes? syntax */
		while (conn->bytes_sent < conn->bytes_requested) {
			len = conn->bytes_requested - conn->bytes_sent;
			if (len > RESPONSE_REC_LEN) {
				len = RESPONSE_REC_LEN;
    		}
			psAssert(len > 0);
			rc = matrixSslGetWritebuf(cp, &buf, len);
			if (rc < len) {
				len = rc; /* could have been shortened due to max_frag */
			}
			memset(buf, 'J', len);
			if (conn->bytes_sent == 0) {
				/* Overwrite first N bytes with HTTP header the first time */
				strncpy((char *)buf, (char *)g_httpResponseHdr,
					strlen((char*)g_httpResponseHdr));
			}
			if ((rc = matrixSslEncodeWritebuf(cp, len)) < 0) {
				printf("couldn't encode data %d\n", rc);
    		}
			conn->bytes_sent += len;
    	}
		return MATRIXSSL_REQUEST_SEND;
	}

	/* Usual reply */

	if ((available = matrixSslGetWritebuf(cp, &buf, 
			(uint32)strlen((char *)g_httpResponseHdr) + 1)) < 0) {
		return PS_MEM_FAIL;
	}
	strncpy((char *)buf, (char *)g_httpResponseHdr, available);
	//psTraceBytes("Replying", buf, (uint32)strlen((char *)buf));
	if (matrixSslEncodeWritebuf(cp, (uint32)strlen((char *)buf)) < 0) {
		return PS_MEM_FAIL;
	}
	return MATRIXSSL_REQUEST_SEND;
}

/******************************************************************************/
/*
	Main non-blocking SSL server
	Initialize MatrixSSL and sockets layer, and loop on select
 */
int32 main(int32 argc, char **argv)
{
	sslKeys_t		*keys;
	SOCKET			lfd;
	unsigned char	*CAstream;
	int32			err, rc, CAstreamLen;
#ifdef USE_STATELESS_SESSION_TICKETS
	unsigned char	randKey[16];
#endif

#ifdef WIN32
	WSADATA			wsaData;
	WSAStartup(MAKEWORD(1, 1), &wsaData);
#endif


	keys = NULL;
	DLListInit(&g_conns);
	g_exitFlag = 0;
	lfd = INVALID_SOCKET;
	
#ifdef POSIX
	if (sighandlers() < 0) {
		return PS_PLATFORM_FAIL;
	}
#endif	/* POSIX */
	if ((rc = matrixSslOpen()) < 0) {
		_psTrace("MatrixSSL library init failure.  Exiting\n");
		return rc;
	}

	if (matrixSslNewKeys(&keys, NULL) < 0) {
		_psTrace("MatrixSSL library key init failure.  Exiting\n");
		return -1;
	}
	
#ifdef USE_STATELESS_SESSION_TICKETS
	matrixSslSetSessionTicketCallback(keys, sessTicketCb);
	psGetEntropy(randKey, 16, NULL);
	if (matrixSslLoadSessionTicketKeys(keys, randKey,
			sessTicketSymKey, 32, sessTicketMacKey, 32) < 0) {
		_psTrace("Error loading session ticket encryption key\n");
	}
#endif

#ifdef USE_HEADER_KEYS
/*
	In-memory based keys
	Build the CA list first for potential client auth usage
*/
	CAstreamLen = 0;
#ifdef USE_RSA
	CAstreamLen += sizeof(RSACAS);
#ifdef USE_ECC
	CAstreamLen += sizeof(ECDHRSACAS);
#endif
#endif
#ifdef USE_ECC
	CAstreamLen += sizeof(ECCAS);
#endif
	CAstream = psMalloc(NULL, CAstreamLen);
	
	CAstreamLen = 0;
#ifdef USE_RSA
	memcpy(CAstream, RSACAS, sizeof(RSACAS));
	CAstreamLen += sizeof(RSACAS);
#ifdef USE_ECC
	memcpy(CAstream + CAstreamLen, ECDHRSACAS, sizeof(ECDHRSACAS));
	CAstreamLen += sizeof(ECDHRSACAS);
#endif
#endif
#ifdef USE_ECC
	memcpy(CAstream + CAstreamLen, ECCAS,	sizeof(ECCAS));
	CAstreamLen += sizeof(ECCAS);
#endif
		
#ifdef EXAMPLE_RSA_KEYS
	if ((rc = matrixSslLoadRsaKeysMem(keys, RSA1024, sizeof(RSA1024),
			RSA1024KEY, sizeof(RSA1024KEY), CAstream, CAstreamLen)) < 0) {
		_psTrace("No certificate material loaded.  Exiting\n");
		psFree(CAstream, NULL);
		matrixSslDeleteKeys(keys);
		matrixSslClose();
		return rc;
	}
#endif

#ifdef EXAMPLE_ECDH_RSA_KEYS
	if ((rc = matrixSslLoadEcKeysMem(keys, ECDHRSA256, sizeof(ECDHRSA256),
				   ECDHRSA256KEY, sizeof(ECDHRSA256KEY), CAstream,
				   CAstreamLen)) < 0) {
		_psTrace("No certificate material loaded.  Exiting\n");
		psFree(CAstream, NULL);
		matrixSslDeleteKeys(keys);
		matrixSslClose();
		return rc;
	}
#endif

#ifdef EXAMPLE_EC_KEYS
	if ((rc = matrixSslLoadEcKeysMem(keys, EC521, sizeof(EC521),
			EC521KEY, sizeof(EC521KEY), CAstream, CAstreamLen)) < 0) {
//	if ((rc = matrixSslLoadEcKeysMem(keys, EC256, sizeof(EC256),
//			EC256KEY, sizeof(EC256KEY), CAstream, CAstreamLen)) < 0) {
//	if ((rc = matrixSslLoadEcKeysMem(keys, EC192, sizeof(EC192),
//			EC192KEY, sizeof(EC192KEY), CAstream, CAstreamLen)) < 0) {
		_psTrace("No certificate material loaded.  Exiting\n");
		psFree(CAstream, NULL);
		matrixSslDeleteKeys(keys);
		matrixSslClose();
		return rc;
	}
#endif
	
#ifdef REQUIRE_DH_PARAMS
	if (matrixSslLoadDhParamsMem(keys, dhParamBuf1024, sizeof(dhParamBuf1024))
			< 0){
		_psTrace("Unable to load DH parameters\n");
	}
#endif /* DH_PARAMS */

	psFree(CAstream, NULL);
#else /* USE_HEADER_KEYS */
/*
	File based keys
	Build the CA list first for potential client auth usage
*/
	CAstreamLen = 0;
#ifdef USE_RSA
	CAstreamLen += (int32)strlen(rsaCAFile) + 1;
#ifdef USE_ECC
	CAstreamLen += (int32)strlen(ecdhRsaCAFile) + 1;
#endif
#endif
#ifdef USE_ECC
	CAstreamLen += (int32)strlen(ecCAFile) + 1;
#endif		
	CAstream = psMalloc(NULL, CAstreamLen);
	memset(CAstream, 0x0, CAstreamLen);
	
	CAstreamLen = 0;
#ifdef USE_RSA	
	memcpy(CAstream, rsaCAFile,	strlen(rsaCAFile));
	CAstreamLen += strlen(rsaCAFile);
#ifdef USE_ECC
	memcpy(CAstream + CAstreamLen, ";", 1); CAstreamLen++;
	memcpy(CAstream + CAstreamLen, ecdhRsaCAFile,  strlen(ecdhRsaCAFile));
	CAstreamLen += strlen(ecdhRsaCAFile);
#endif
#endif
#ifdef USE_ECC
	if (CAstreamLen > 0) {
		memcpy(CAstream + CAstreamLen, ";", 1); CAstreamLen++;
	}
	memcpy(CAstream + CAstreamLen, ecCAFile,  strlen(ecCAFile));
#endif
	
/* Load Identiy */	
#ifdef EXAMPLE_RSA_KEYS	
	if ((rc = matrixSslLoadRsaKeys(keys, rsaCertFile, rsaPrivkeyFile, NULL,
			(char*)CAstream)) < 0) {
		_psTrace("No certificate material loaded.  Exiting\n");
		psFree(CAstream, NULL);
		matrixSslDeleteKeys(keys);
		matrixSslClose();
		return rc;
	}
#endif	

#ifdef EXAMPLE_ECDH_RSA_KEYS
	if ((rc = matrixSslLoadEcKeys(keys, ecdhRsaCertFile, ecdhRsaPrivkeyFile,
			NULL, (char*)CAstream)) < 0) {
		_psTrace("No certificate material loaded.  Exiting\n");
		psFree(CAstream, NULL);
		matrixSslDeleteKeys(keys);
		matrixSslClose();
		return rc;
	}
#endif

#ifdef EXAMPLE_EC_KEYS
	if ((rc = matrixSslLoadEcKeys(keys, ecCertFile, ecPrivkeyFile, NULL,
			(char*)CAstream)) < 0) {
		_psTrace("No certificate material loaded.  Exiting\n");
		psFree(CAstream, NULL);
		matrixSslDeleteKeys(keys);
		matrixSslClose();
		return rc;
	}
#endif
	
#ifdef REQUIRE_DH_PARAMS
	if (matrixSslLoadDhParams(keys, dhParamFile) < 0){
		_psTrace("Unable to load DH parameters\n");
	}
#endif

	psFree(CAstream, NULL);
#endif /* USE_HEADER_KEYS */

#ifdef USE_PSK_CIPHER_SUITE
	/* The first one supports the 15-byte openssl PSK ID */
	matrixSslLoadPsk(keys, pskTable[0].key, sizeof(pskTable[0].key),
		pskTable[rc].id, 15);
	for (rc = 0; rc < 8; rc++) {   
		matrixSslLoadPsk(keys, pskTable[rc].key, sizeof(pskTable[rc].key),
			pskTable[rc].id, sizeof(pskTable[rc].id));
	}
#endif /* PSK */

	if (argc == 2) {
		switch (atoi(argv[1])) {
		case 0:
			g_proto = SSL_FLAGS_SSLV3;
			break;
		case 1:
			g_proto = SSL_FLAGS_TLS_1_0;
			break;
		case 2:
			g_proto = SSL_FLAGS_TLS_1_1;
			break;
		case 3:
			g_proto = SSL_FLAGS_TLS_1_2;
			break;
		default:
			g_proto = SSL_FLAGS_TLS_1_0;
			break;
		}
	} else {
		g_proto = 0;
	}
	/* Create the listening socket that will accept incoming connections */
	if ((lfd = socketListen(HTTPS_PORT, &err)) == INVALID_SOCKET) {
		_psTraceInt("Can't listen on port %d\n", HTTPS_PORT);
		goto L_EXIT;
	}

	/* Main select loop to handle sockets events */
	while (!g_exitFlag) {
		selectLoop(keys, lfd);
	}

L_EXIT:
	if (lfd != INVALID_SOCKET) close(lfd);
	if (keys) matrixSslDeleteKeys(keys);
	matrixSslClose();
	
	return 0;
}
Esempio n. 15
0
int main(int argc, char **argv)
#endif
{
	SOCKET			srv_fd;
	int				status;
	WSADATA			wsaData;
	
	// options
	char				*srv_host = NULL;
	int				srv_port = 0;
	char 				*keyfile = NULL; //"privkeySrv.pem";
	char 				*certfile = NULL; //"certSrv.pem";
	int				vlevel = 0;
	char 				*cpos,*opos;
	int tmpport;
	int c;
	int 			intarg;
 	
#if VXWORKS
	int					argc;
	char				**argv;
	parseCmdLineArgs(arg1, &argc, &argv);
#endif /* VXWORKS */

#if WINCE
	int					argc;
	char				**argv;
	char				args[256];

/*
 *	parseCmdLineArgs expects an ASCII string and CE is unicoded, so convert
 *	the command line.  args will get hacked up, so you can't pass in a
 *	static string.
 */
	WideCharToMultiByte(CP_ACP, 0, lpCmdLine, -1, args, 256, NULL, NULL);

/*
 *	Parse the command line into an argv array.  This allocs memory, so
 *	we have to free argv when we're done.
 */
	parseCmdLineArgs(args, &argc, &argv);
#endif /* WINCE */


/*
	prepare
*/
	
#ifndef USE_FORK
	memset(connections,0,MAXPROXYCOUNT*sizeof(struct proxyConnection));
#endif
	
/*
	getopt
*/
	/* Gemtek add +++ */
	if(argc == 1) usage(1);
	/* Gemtek add --- */
	
	for (;;) {
		c = getopt (argc, argv, "VD:P:fo:cd:r:p:A:v:h");
		if (c == -1) {
			break;
		}

		switch (c) {
			case 'c':
				// client mode
				isClient=1;
				break;
			
			case 'd':
				// daemon mode [host:]port
				cpos = NULL;
				tmpport = 0;
				if((cpos = strchr(optarg,':'))) {				
					*cpos = '\0';
					if(optarg && optarg[0])
						srv_host = optarg;
					optarg = ++cpos;
				}
				if(optarg && optarg[0]) {
					tmpport = (int)strtol(optarg, (char **)NULL, 0);
					if(tmpport) srv_port = tmpport;
				}
				break;
			
			case 'r':
				// remote [host:]port
				cpos = NULL;
				tmpport = 0;
				if((cpos = strchr(optarg,':'))) {				
					*cpos = '\0';
					if(optarg && optarg[0])
						dst_host = optarg;
					optarg = ++cpos;
				}
				if(optarg && optarg[0]) {
					tmpport = (int)strtol(optarg, (char **)NULL, 0);
					if(tmpport) dst_port = tmpport;
				}
				break;
				
			case 'p':
				// pemfile (requred in servermode)
				keyfile = optarg;
				break;
			
			case 'A':
				// CA file
				certfile = optarg;
				break;
			
			case 'v':
				// veryfication level
				if(optarg && optarg[0]) {
					vlevel = (int)strtol(optarg, (char **)NULL, 0);
					if(vlevel == 1 ) {
						cervalidator = certChecker;
					}
					else if(vlevel > 3 || vlevel < 0) {
						fprintf(stderr,"-v takes whole numbers between 0 and 3");
						exit(2);
					}
				}
				break;
			
			case 'P':
				// create a pidfile
				pidfile=optarg;
				break;
				
			case 'f':
				// run in foreground.
				nofork=1;
				nosysl=1;
				break;
				
			case 'o':
				// append logmessages to a file instead of stdout/syslog
				break;
				
			case 'O':
				// socket options. TODO
				break;
			
			case 'D':
				// debug level 0...7
				intarg=strtol(optarg,NULL,0);
				if(intarg<0 || intarg>7) {
					usage(1);
				}
				gLogLevel=intarg;
				break;
				
			case 'V':
				// version
				break;
				
			case '?':
			case 'h':
				usage(0);
				break;
			
			default:
				usage(1);
				break;
		}
	}


/* install handlers */
	signal( SIGPIPE, SIG_IGN );
	signal(SIGCHLD,sigchld_handler); /* ignore child */
	signal(SIGHUP,kill_handler); /* catch hangup signal */
	signal(SIGTERM,kill_handler); /* catch kill signal */
	
/*
	Initialize Windows sockets (no-op on other platforms)
*/
	WSAStartup(MAKEWORD(1,1), &wsaData);
	
	if(!nosysl) {
		openlog("matrixtunnel", LOG_PID, LOG_DAEMON);
		setlogmask(LOG_UPTO(gLogLevel));
	}
	
/*
	Initialize the MatrixSSL Library, and read in the public key (certificate)
	and private key.
*/
	if (matrixSslOpen() < 0) {
		ELOG("matrixSslOpen failed, exiting...");
		exit(1);
	}

/*
	Standard PEM files
*/
	if (matrixSslReadKeys(&keys, certfile, keyfile, NULL, NULL) < 0)  {
		ELOG("Error reading or parsing %s or %s, exiting...", 
			certfile, keyfile);
		exit(1);
	}

	// go to background
	if(!nofork) {
		daemonize();
	}

/*
	Create the listen socket
*/
	if ((srv_fd = socketListen(srv_port, &status)) == INVALID_SOCKET) {
		ELOG("Cannot listen on port %d, exiting...", srv_port);
		exit(1);
	}
/*
	Set blocking or not on the listen socket
*/
	setSocketBlock(srv_fd);

/*
	Main connection loop
*/
	struct proxyConnection	*cp=NULL;
	struct proxyConnection	*ncp;
	
	fd_set	rs, ws, es, cr;
	int			fdmax;
	struct timeval tv;
	int			res, dontClose;
	
	char		buf[4096];
	int pc, sc;
	
	int			ccount;
	
	while (!quit) {
		fdmax=srv_fd;
		ncp=NULL;
		
		FD_ZERO(&rs);
		FD_ZERO(&ws);
		FD_ZERO(&es);
		
		FD_SET(srv_fd,&rs);
		FD_SET(srv_fd,&ws);
		FD_SET(srv_fd,&es);
		ccount=0;
		
#ifndef USE_FORK
		DLOG("next select on fds: %d ",srv_fd);
		for(cp=connections;cp<&connections[MAXPROXYCOUNT];cp++) {
			if (cp->done) {
				closeProxyConnection(cp);
			}
			if (cp->secure_up) {
				FD_SET(cp->secure->fd,&rs);
				FD_SET(cp->secure->fd,&ws);
				FD_SET(cp->secure->fd,&es);

				if (fdmax < cp->secure->fd)
					fdmax = cp->secure->fd;
				
				DLOG("fd: %d",cp->secure->fd);
				ccount++;
			}
			if (cp->plain_up) {
				FD_SET(cp->plain,&rs);			
				FD_SET(cp->plain,&ws);
				FD_SET(cp->plain,&es);
					
				if (fdmax < cp->plain)
					fdmax = cp->plain;
				
				DLOG("fd: %d",cp->plain);
				ccount++;
			}
			if(!ncp && !cp->inuse){
				ncp=cp;
				memset(ncp,0,sizeof(struct proxyConnection));
			}
		}
#else
		struct proxyConnection	ncp_s;
		ncp=&ncp_s;
		memset(ncp,0,sizeof(struct proxyConnection));
#endif
		
		tv.tv_sec=10;
		tv.tv_usec=0;

		DLOG("main : select on %d open connections. fdmax: %d", ccount, fdmax);
		res=select(fdmax+1,&rs,NULL,&es,&tv);
		DLOG("select returned: %d %s", res , strerror(errno) );

		if(res<0) {
			perror("select");
			continue;
		}
		
		if(res==0)
			continue;

#ifndef USE_FORK
		// handle open connections
		for(cp=connections;cp<&connections[MAXPROXYCOUNT];cp++) {
			if (cp->secure_up && cp->plain_up) {
				if(FD_ISSET(cp->secure->fd,&es) || FD_ISSET(cp->plain,&es)) {
						closeProxyConnection(cp);
						continue;
				}
				
				if(secureReady(cp)) {
					sc=proxyReadwrite(cp,1);
					if(sc<0) {
						closeProxyConnection(cp);
						continue;
					}
				}
				
				if(plainReady(cp)) {
					pc=proxyReadwrite(cp,0);
					if(pc<0) {
						closeProxyConnection(cp);
						continue;
					}
				}
			}
		}
#endif

		// do we have new connections?
		if(FD_ISSET(srv_fd,&rs)) {
			proxyAccept(srv_fd,ncp);
		}			
	}

/*
	Close listening socket, free remaining items
*/
	socketShutdown(srv_fd);
	
#ifndef USE_FORK
	for(cp=connections;cp<&connections[MAXPROXYCOUNT];cp++) {
		closeProxyConnection(cp);
	}
#endif
	
	if(!nosysl) {
		closelog();
	}
	
	matrixSslFreeKeys(keys);
	matrixSslClose();
	WSACleanup();
	return 0;
}
Esempio n. 16
0
int CSocketServer::start(int nSocketType, const char* cszAddr, short nPort, int nStyle)
{
	int nMsgId = -1;

	if (-1 != externalEvent.m_nMsgId)
	{
		nMsgId = initMessage(externalEvent.m_nMsgId);
	}
	else
	{
		nMsgId = initMessage(m_nInternalFilter);
	}

	if (-1 == nMsgId)
	{
		throwException("socket server create message id fail");
		return -1;
	}

	threadHandler->createThread(threadSocketMessageReceive, this);

	if (AF_UNIX == nSocketType)
	{
		setDomainSocketPath(cszAddr);
	}
	else if (AF_INET == nSocketType)
	{
		if (-1 == setInetSocket(cszAddr, nPort))
		{
			_DBG("set INET socket address & port fail");
			return -1;
		}
	}

	if (-1 != createSocket(nSocketType, nStyle))
	{
		if (-1 != socketBind())
		{
			if (SOCK_STREAM == nStyle)
			{
				if (-1 == socketListen(BACKLOG))
				{
					perror("socket listen");
					socketClose();
					return -1;
				}

				threadHandler->createThread(threadSocketAccept, this);
			}
			else if (SOCK_DGRAM == nStyle)
			{
				if (udpClientData)
					delete udpClientData;
				udpClientData = new CDataHandler<struct sockaddr_in>;
				clientHandler(getSocketfd());
			}
			return 0;
		}
		else
		{
			socketClose();
		}
	}

	return -1;
}
int CSocketServer::start(int nSocketType, const char* cszAddr, short nPort, int nStyle)
{
	int nMsgId = -1;

	if(-1 != externalEvent.m_nMsgId)
	{
		nMsgId = initMessage(externalEvent.m_nMsgId, "CSocketServer");
	}
	else
	{
		nMsgId = initMessage(m_nInternalFilter, "CSocketServer");
	}

	if(-1 == nMsgId)
	{
		_log("[CSocketServer] Init Message Queue Fail");
		return -1;
	}

	if(0 != munRunThreadId)
	{
		threadHandler->threadCancel(munRunThreadId);
		threadHandler->threadJoin(munRunThreadId);
		munRunThreadId = 0;
	}

	threadHandler->createThread(threadServerMessageReceive, this);

	if( AF_UNIX == nSocketType)
	{
		setDomainSocketPath(cszAddr);
	}
	else if( AF_INET == nSocketType)
	{
		if(-1 == setInetSocket(cszAddr, nPort))
		{
			_log("set INET socket address & port fail");
			return -1;
		}
	}

	if(-1 != createSocket(nSocketType, nStyle))
	{
		if(-1 != socketBind())
		{
			if( SOCK_STREAM == nStyle)
			{
				if(-1 == socketListen( BACKLOG))
				{
					perror("socket listen");
					socketClose();
					return -1;
				}

				threadHandler->createThread(threadServerSocketAccept, this);
			}
			else if( SOCK_DGRAM == nStyle)
			{
				if(udpClientData)
					delete udpClientData;
				udpClientData = new CDataHandler<struct sockaddr_in>;
				dataHandler(getSocketfd());
			}
			return 0;
		}
		else
		{
			socketClose();
		}
	}

	return -1;
}
Esempio n. 18
0
error_t ftpOpenFile(FtpClientContext *context, const char_t *path, uint_t flags)
{
   error_t error;
   uint_t replyCode;
   IpAddr ipAddr;
   uint16_t port;

   //Invalid context?
   if(context == NULL)
      return ERROR_INVALID_PARAMETER;

   //Open data socket
   context->dataSocket = socketOpen(SOCKET_TYPE_STREAM, SOCKET_IP_PROTO_TCP);
   //Failed to open socket?
   if(!context->dataSocket)
      return ERROR_OPEN_FAILED;

   //Start of exception handling block
   do
   {
      //Bind the socket to a particular network interface?
      if(context->interface != NULL)
      {
         //Associate the socket with the relevant interface
         error = socketBindToInterface(context->dataSocket, context->interface);
         //Any error to report?
         if(error) break;
      }

      //Set timeout for blocking operations
      error = socketSetTimeout(context->dataSocket, FTP_CLIENT_DEFAULT_TIMEOUT);
      //Any error to report?
      if(error) break;

      //Check data transfer direction
      if(flags & (FTP_FOR_WRITING | FTP_FOR_APPENDING))
      {
         //Maximize transmission throughput by using a large buffer
         error = socketSetTxBufferSize(context->dataSocket,
            FTP_CLIENT_SOCKET_MAX_TX_BUFFER_SIZE);
         //Any error to report?
         if(error) break;

         //Use a small buffer for the reception path
         error = socketSetRxBufferSize(context->dataSocket,
            FTP_CLIENT_SOCKET_MIN_RX_BUFFER_SIZE);
         //Any error to report?
         if(error) break;
      }
      else
      {
         //Use a small buffer for the transmission path
         error = socketSetTxBufferSize(context->dataSocket,
            FTP_CLIENT_SOCKET_MIN_TX_BUFFER_SIZE);
         //Any error to report?
         if(error) break;

         //Maximize reception throughput by using a large buffer
         error = socketSetRxBufferSize(context->dataSocket,
            FTP_CLIENT_SOCKET_MAX_RX_BUFFER_SIZE);
         //Any error to report?
         if(error) break;
      }

      //Set representation type
      if(flags & FTP_TEXT_TYPE)
      {
         //Use ASCII type
         error = ftpSetType(context, 'A');
         //Any error to report?
         if(error) break;
      }
      else
      {
         //Use image type
         error = ftpSetType(context, 'I');
         //Any error to report?
         if(error) break;
      }

      //Check transfer mode
      if(!context->passiveMode)
      {
         //Place the data socket in the listening state
         error = socketListen(context->dataSocket, 1);
         //Any error to report?
         if(error) break;

         //Retrieve local IP address
         error = socketGetLocalAddr(context->controlSocket, &ipAddr, NULL);
         //Any error to report?
         if(error) break;

         //Retrieve local port number
         error = socketGetLocalAddr(context->dataSocket, NULL, &port);
         //Any error to report?
         if(error) break;

         //Set the port to be used in data connection
         error = ftpSetPort(context, &ipAddr, port);
         //Any error to report?
         if(error) break;
      }
      else
      {
         //Enter passive mode
         error = ftpSetPassiveMode(context, &port);
         //Any error to report?
         if(error) break;

         //Establish data connection
         error = socketConnect(context->dataSocket, &context->serverAddr, port);
         //Connection to server failed?
         if(error) break;
      }

      //Format the command
      if(flags & FTP_FOR_WRITING)
         sprintf(context->buffer, "STOR %s\r\n", path);
      else if(flags & FTP_FOR_APPENDING)
         sprintf(context->buffer, "APPE %s\r\n", path);
      else
         sprintf(context->buffer, "RETR %s\r\n", path);

      //Send the command to the server
      error = ftpSendCommand(context, context->buffer, &replyCode);
      //Any error to report?
      if(error) break;

      //Check FTP response code
      if(!FTP_REPLY_CODE_1YZ(replyCode))
      {
         //Report an error
         error = ERROR_UNEXPECTED_RESPONSE;
         break;
      }

      //Check transfer mode
      if(!context->passiveMode)
      {
         //Wait for the server to connect back to the client's data port
         Socket *socket = socketAccept(context->dataSocket, NULL, NULL);

         //No connection request?
         if(!socket)
         {
            //Report an error
            error = ERROR_FAILURE;
            break;
         }

         //Close the listening socket
         socketClose(context->dataSocket);
         //Save socket handle
         context->dataSocket = socket;

         //Set timeout for blocking operations
         error = socketSetTimeout(context->dataSocket, FTP_CLIENT_DEFAULT_TIMEOUT);
         //Any error to report?
         if(error) break;
      }

      //End of exception handling block
   } while(0);

   //Any error to report?
   if(error)
   {
      //Clean up side effects
      socketClose(context->dataSocket);
      context->dataSocket = NULL;
   }

   //Return status code
   return error;
}