Beispiel #1
0
/* Check the link status of all ports in up to 9s, and print them finally */
static void
check_all_ports_link_status()
{
#define CHECK_INTERVAL 100 /* 100ms */
#define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */
    uint8_t portid, count, all_ports_up, print_flag = 0;
    struct rte_eth_link link;

    LOG_RAW(INFO, "\nChecking link status");
    fflush(stdout);
    for (count = 0; count <= MAX_CHECK_TIME; count++) {
        if (sk.force_quit)
            return;
        all_ports_up = 1;

        for (int i = 0; i < sk.nr_ports; i++) {
            if (sk.force_quit)
                return;
            portid = (uint8_t )sk.port_ids[i];
            memset(&link, 0, sizeof(link));
            rte_eth_link_get_nowait(portid, &link);
            /* print link status if flag set */
            if (print_flag == 1) {
                if (link.link_status)
                    LOG_RAW(INFO,
                            "Port %d Link Up - speed %u "
                            "Mbps - %s\n", (uint8_t)portid,
                            (unsigned)link.link_speed,
                            (link.link_duplex == ETH_LINK_FULL_DUPLEX) ?
                            ("full-duplex") : ("half-duplex\n"));
                else
                    LOG_RAW(INFO, "Port %d Link Down\n", (uint8_t)portid);
                continue;
            }
            /* clear all_ports_up flag if any link down */
            if (link.link_status == ETH_LINK_DOWN) {
                all_ports_up = 0;
                break;
            }
        }
        /* after finally printing all link status, get out */
        if (print_flag == 1)
            break;

        if (all_ports_up == 0) {
            LOG_RAW(INFO, ".");
            fflush(sk.log_fp);
            rte_delay_ms(CHECK_INTERVAL);
        }

        /* set the print_flag if all ports up or timeout */
        if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) {
            print_flag = 1;
            LOG_RAW(INFO, "done\n");
        }
    }
}
Beispiel #2
0
/*----------------------------------------------------------------------------*/
int8_t demo_udp_socket_init(void) {


	/* The choice of server address determines its 6LoPAN header compression.
	* (Our address will be compressed Mode 3 since it is derived from our link-local address)
	* Obviously the choice made here must also be selected in udp-server.c.
	*
	* For correct Wireshark decoding using a sniffer, add the /64 prefix to the 6LowPAN protocol preferences,
	* e.g. set Context 0 to aaaa::.  At present Wireshark copies Context/128 and then overwrites it.
	* (Setting Context 0 to aaaa::1111:2222:3333:4444 will report a 16 bit compressed address of aaaa::1111:22ff:fe33:xxxx)
	*
	* Note the IPCMV6 checksum verification depends on the correct uncompressed addresses.
	*/
	/* We know destination IP address but we need to properly convert it */
	uip_ip6addr(&un_server_ipaddr, 	un_server_ipaddr.u16[0],un_server_ipaddr.u16[1],\
									un_server_ipaddr.u16[2],un_server_ipaddr.u16[3],\
									un_server_ipaddr.u16[4],un_server_ipaddr.u16[5],\
									un_server_ipaddr.u16[6],un_server_ipaddr.u16[7]);
	pst_conn = udp_new(NULL, UIP_HTONS(__SERVER_PORT), NULL);
	udp_bind(pst_conn, UIP_HTONS(__CLIENT_PORT));

	LOG_INFO("%s", "Create connection with the server ");
	//uip_debug_ipaddr_print(&un_server_ipaddr);
	LOG_RAW("\n\r");
	LOG_INFO("local/remote port %u/%u\n\r",
			UIP_HTONS(pst_conn->lport),
			UIP_HTONS(pst_conn->rport));
	//printf("Set dudp timer %p\n\r",&st_et);
	etimer_set(&st_et, SEND_INTERVAL, _demo_udp_callback);
	evproc_regCallback(EVENT_TYPE_TCPIP,_demo_udp_callback);
	return 1;
}/* demo_udp_init()  */
Beispiel #3
0
int main() {
    Func functions[] = {&test_config_new,
                        &test_new_matrix, 
                        &test_new_element,
                        &test_matrix_add_element,
                        &test_matrix_find_element,
                        &test_matrix_clear,
                        &test_matrix_update,
                        &test_matrix_print};
    unsigned len = sizeof(functions)/sizeof(functions[0]);
    int result = 0;

    for(int i = 0; i < len; i++) {
        if((*functions[i])() != 0)
            result = 1;
    }
    
    if(result == 0)
        LOG_RAW("success");
    else
        LOG_RAW("failed");
       
    return result;
}
Beispiel #4
0
static void log_packet(struct rte_mbuf *m) {
    char buf[4096];
    int offset = 0;
    int n;
    uint16_t ether_type;
    uint8_t ipproto;
    char *l3_h = NULL;
    struct ether_hdr *eth_h;
    struct ipv4_hdr *ipv4_h = NULL;
    struct ipv6_hdr *ipv6_h = NULL;
    struct udp_hdr  *udp_h = NULL;
    struct tcp_hdr  *tcp_h = NULL;
    char ip_src_str[INET6_ADDRSTRLEN];
    char ip_dst_str[INET6_ADDRSTRLEN];

    eth_h = rte_pktmbuf_mtod(m, struct ether_hdr *);
    ether_format_addr(buf+offset, ETHER_ADDR_FMT_SIZE, &eth_h->s_addr);
    offset += ETHER_ADDR_FMT_SIZE-1;

    strcpy(buf+offset, " -> ");
    offset += strlen(" -> ");

    ether_format_addr(buf+offset, ETHER_ADDR_FMT_SIZE, &eth_h->d_addr);
    offset += ETHER_ADDR_FMT_SIZE-1;

    strcpy(buf+offset, "\n");
    offset += strlen("\n");

    ether_type = rte_be_to_cpu_16(eth_h->ether_type);

    l3_h = (char *)(eth_h + 1);

    switch (ether_type) {
    case ETHER_TYPE_ARP:
        return;
    case ETHER_TYPE_IPv4:
        ipv4_h = (struct ipv4_hdr *)l3_h;
        ipproto = ipv4_h->next_proto_id;
        inet_ntop(AF_INET, &(ipv4_h->src_addr), ip_src_str, INET6_ADDRSTRLEN);
        inet_ntop(AF_INET, &(ipv4_h->dst_addr), ip_dst_str, INET6_ADDRSTRLEN);
        n = snprintf(buf+offset, 4096-offset,
                     "  IPV4 %s -> %s (ttl %d, id %d, tlen: %d, offset %d, flags(%s%s))\n",
                     ip_src_str, ip_dst_str, ipv4_h->time_to_live,
                     rte_be_to_cpu_16(ipv4_h->packet_id),
                     rte_be_to_cpu_16(ipv4_h->total_length),
                     (rte_be_to_cpu_16(ipv4_h->fragment_offset) & \
                      IPV4_HDR_OFFSET_MASK) * IPV4_HDR_OFFSET_UNITS,
                     (rte_be_to_cpu_16(ipv4_h->fragment_offset) & IPV4_HDR_DF_FLAG)? "DF":"",
                     (rte_be_to_cpu_16(ipv4_h->fragment_offset) & IPV4_HDR_MF_FLAG)? "MF":"");
        offset += n;
        break;
    case ETHER_TYPE_IPv6:
        ipv6_h = (struct ipv6_hdr *)l3_h;
        ipproto = ipv6_h->proto;

        inet_ntop(AF_INET6, &(ipv6_h->src_addr), ip_src_str, INET6_ADDRSTRLEN);
        inet_ntop(AF_INET6, &(ipv6_h->dst_addr), ip_dst_str, INET6_ADDRSTRLEN);
        n = snprintf(buf+offset, 4096-offset,
                     "  IPV6 %s -> %s (ttl %d)\n",
                     ip_src_str, ip_dst_str, ipv6_h->hop_limits);
        offset += n;
        break;
    default:
        return;
    }
    switch (ipproto) {
    case IPPROTO_UDP:
        udp_h = (struct udp_hdr *) (l3_h + m->l3_len);
        snprintf(buf+offset, 4096-offset, "    UDP %d -> %d\n",
                 rte_be_to_cpu_16(udp_h->src_port),
                 rte_be_to_cpu_16(udp_h->dst_port));
        break;
    case IPPROTO_TCP:
        tcp_h = (struct tcp_hdr *) (l3_h + m->l3_len);
        snprintf(buf+offset, 4096-offset, "    TCP %d -> %d\n",
                 rte_be_to_cpu_16(tcp_h->src_port),
                 rte_be_to_cpu_16(tcp_h->dst_port));
    default:
        return;
    }
    LOG_RAW(DEBUG, "%s", buf);
}
/*=================================================================================================*/
E_SERVER_FSM_RESULT ssl_server_entry(SSL_SERVER_PARS parameters)
{

	/* server parameters */
	uint8_t				echo			= parameters.echo;
	char *				pc_filename		= parameters.pc_filename;
	char *				pc_ciphersuites	= parameters.pc_ciphersuites;
	uint16_t			u_port			= parameters.u_port;
	e_sslVer_t			versmin			= parameters.versmin;
	e_sslVer_t			versmax			= parameters.versmax;
	char *				key				= parameters.key;
	e_sslKeyType_t		keyType			= parameters.keyType;
	char *				keyParameters	= parameters.keyParameters;
	char **				certs			= parameters.ppc_certs;
	char **				CAcerts			= parameters.ppc_CAcerts;
	e_sslAuthLevel_t	authlevel		= parameters.authlevel;


	char c_filebuf[SSL_WRITE_BLOCK_LEN];
	size_t n;

	char	c_mode = 1;

	en_gciResult_t err;

	/* Check the state of the server */
	switch (i_state) {
	case SSL_SERVER_INIT:
		/*============================================================================*/
		/*
		 * General SSL Initialisation
		 */
		/*============================================================================*/
		/* Initialises the SSL module */
		SSL_init();

		/* Initialises the crypto */
		//TODO sw - where to become the user name + password ??
		err = gciInit(NULL, 0, NULL, 0);

		//OLD-CW: cw_crypto_init();
//		{
//			/*
//			 * Use some "random" bytes to init the PRNG
//			 */
//			uint8_t c_rand[] = { 0x42, 0x72, 0x75, 0x63, 0x65, 0x20, 0x53, 0x63, 0x68, //TODO sw - this step in gci_init
//					0x6E, 0x65, 0x69, 0x65, 0x72, 0x21, 0x0D, 0x0A, 0x00 };
//			cw_prng_init(c_rand, sizeof(c_rand));
//		}

		/*
		 * Initialisation of keymanager for DHE and DHE private key generation
		 */
		km_dhe_init();

		/*============================================================================*/
		/*
		 * Initialization of the SSL settings for the demonstration SSL context
		 */
		/*============================================================================*/

		/* Initialises the SSL context */
		sslSoc_initSett(&s_sslSett, keyType);

		/*
		 * Init the time-function pointer implicit to NULL, this will disable
		 * checking of the validity of the used certificates
		 * (To enable 'getCurrentTime' function should be used)
		 */
		sslSoc_setTimeFunc(&s_sslSett, NULL);

		/* Setting up the SSL version */
		sslSoc_setVer(&s_sslSett, versmin, versmax);

		/* Setting up the SSL timeout value */
		sslSoc_setSessTimeout(&s_sslSett, 600);

		/* Setting up the SSL authentification behavior */
		sslSoc_setAuthLvl(&s_sslSett, authlevel);

		/* Setting up read and write fonctions */
		sslSoc_setReadWrite(&s_sslSett, sslTarget_read, sslTarget_write);

		/* Initialize server CA certificates */
		if (CAcerts != NULL) {
			init_server_CA_certs(CAcerts);

		}

		/* ===== Initialize Server Certificates and private key ===== */

		s_cdbCert_t cdb_tmp;
		s_sslCertList_t * list_head = sslSoc_getCertChainList(&s_sslSett);

		if (certs != NULL) {
			int i = 0;
			while (certs[i] != NULL) {
				/*
				printf("certs[%i] = '%s'\n", i, certs[i]);
				 */
				cdb_initCert_linear(&server_cdb_certs[i], certs[i]);
				list_head = sslCert_addToList(list_head,
						&server_cert_list[i], NULL, &server_cdb_certs[i]);
				i++;
			}
		} else {
			/* use static pre-defined certificates if
			 * no external certificate has been provided */
			/*
			int i;
			for (i = 0; i < SSL_SERVERCERTS_NUM; ++i) {
				cdb_initCert_linear(&server_cdb_certs[i], server_certificates_[i]);
				list_head = SSL_cert_list_add(list_head, &server_cert_list[i], NULL, &server_cdb_certs[i]);
			}
			 */
		}

		sslSoc_setCertChainList (&s_sslSett, list_head);

		if (key != NULL) {
			cdb_initCert_linear(&cdb_tmp, key);
		} else {
			/*cdb_initCert_linear(&cdb_tmp, ServerPrivateKey);*/
		}
		switch(keyType)
		{
		case E_SSL_KEY_EC:
			if (sslSoc_setECCPrivKey(&s_sslSett, &cdb_tmp) != E_SSL_OK) {
				printf(DBG_STRING "Import of ECC private key failed", __FILE__, __LINE__);
				return (E_SERVER_FSM_ERROR);
			} /* if */
			break;

		case E_SSL_KEY_RSA:
			if (sslSoc_setRsaPrivKey(&s_sslSett, &cdb_tmp) != E_SSL_OK) {
				printf(DBG_STRING "Import of RSA private key failed", __FILE__, __LINE__);
				return (E_SERVER_FSM_ERROR);
			} /* if */
			break;

		default:
			return (E_SERVER_FSM_ERROR);
			break;
		} /* switch */

	case SSL_SERVER_REINIT:

		/*============================================================================*/
		/*
		 * Initialize socket specific features
		 */
		/*============================================================================*/

		/* Creates a socket */
#ifdef _WIN32
		if((srv_socdesc = socket(AF_INET , SOCK_STREAM , 0 )) == INVALID_SOCKET)
		{
			printf("Could not create socket : %s\n" , WSAGetLastError());
			WSACleanup();
			return (E_SERVER_FSM_ERROR);
		}
#elif __linux
		if((srv_socdesc = socket(AF_INET , SOCK_STREAM , 0 )) < 0)
		{
			printf("Could not create socket : %s\n" , strerror(errno));
			return (E_SERVER_FSM_ERROR);
		}
#endif
		setsockopt(srv_socdesc, SOL_SOCKET, SO_REUSEADDR, &c_mode, sizeof(int));
		printf("\n\rSocket created.\n");

		/* Binding */
		server.sin_family = AF_INET;
		server.sin_addr.s_addr = INADDR_ANY;
		server.sin_port = htons(u_port);

#ifdef _WIN32
		if( bind(srv_socdesc ,(struct sockaddr *)&server , sizeof(server)) == INVALID_SOCKET)
		{
			printf("Bind failed with error code : %s\n" , WSAGetLastError());
			WSACleanup();
			return (E_SERVER_FSM_ERROR);
		}
#elif __linux
		if( bind(srv_socdesc ,(struct sockaddr *)&server , sizeof(server)) < 0)
		{
			printf("Bind failed with error code : %s\n" , strerror(errno));
			return (E_SERVER_FSM_ERROR);
		}
#endif



		puts("Bind done");

		/* Listening */
		listen(srv_socdesc , 3);
		puts("Waiting for incoming connections...");

		i_state = SSL_SERVER_LISTEN;
		break;
		/* SSL_SERVER_INIT */

	case SSL_SERVER_LISTEN:
		i_addr_len = sizeof(struct sockaddr_in);
		cli_socdesc = accept(srv_socdesc , (struct sockaddr *)&client, &i_addr_len);
		if (cli_socdesc == INVALID_SOCKET)
		{
			break;
		}

		/* Nonblocking mode */
#ifdef _WIN32
		ioctlsocket(cli_socdesc, FIONBIO, (u_long *)&c_mode);
#elif __linux
		fcntl(cli_socdesc, F_SETFL, O_NONBLOCK);
#endif
		printf("\n\rConnection accepted\n");
		/* Checks if a SSL context is available */
		if ((ps_sslCtx = sslSoc_new ( &s_sslSett )) == NULL)
		{
			/* Not available */
			i_state = SSL_SERVER_CLOSE_ERR;
		}
		else
		{
			/* Available */
			sslSoc_setCtxFd(ps_sslCtx, cli_socdesc);

			/* set supported ciphersuites if list is provided */
			if (strlen(pc_ciphersuites) > 0) {
				sslSoc_setCtxCipList(ps_sslCtx, pc_ciphersuites);
			}

			int i=0;
			switch(keyType)
			{
			case E_SSL_KEY_EC:
				//loop all cipher suites provided
				//Remove all non-ECDSA cipher suites, as certificate cannot handle non-ECDSA
				for(i=0; i<SSL_CIPSPEC_COUNT; i++)
				{
					if( //remove every ECDHE curve
						ps_sslCtx->s_sslGut.ae_cipSpecs[i] != TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA &&
						ps_sslCtx->s_sslGut.ae_cipSpecs[i] != TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA  &&
						ps_sslCtx->s_sslGut.ae_cipSpecs[i] != TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
					)
					{
						ps_sslCtx->s_sslGut.ae_cipSpecs[i] = TLS_NULL_WITH_NULL_NULL;
					}
				}


			break;
			case E_SSL_KEY_RSA:
			case E_SSL_KEY_UNDEFINED: //vpy: should be handled properly
				//Remove all ECDSA cipher suites, as certificate cannot handle ECDSA

				//loop all cipher suites provided
				for(i=0; i<SSL_CIPSPEC_COUNT; i++)
				{
					if( //remove every ECDHE curve
						ps_sslCtx->s_sslGut.ae_cipSpecs[i] == TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA ||
						ps_sslCtx->s_sslGut.ae_cipSpecs[i] == TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA  ||
						ps_sslCtx->s_sslGut.ae_cipSpecs[i] == TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
					)
					{
						ps_sslCtx->s_sslGut.ae_cipSpecs[i] = TLS_NULL_WITH_NULL_NULL;
					}
				}
				break;
			}


			i_state = SSL_SERVER_ACCEPT;
			LOG_OK("Accept");
		} /* if ... else */
		break;
		/* SSL_SERVER_LISTEN */

	case SSL_SERVER_ACCEPT:
		/* Operates the SSL Handshake */
		switch(sslSoc_accept (ps_sslCtx)) {
		case E_SSL_AGAIN:
			break;
		case E_SSL_OK:
			/* print some connection specifics */
			printf("\n>INFO::Ciphers: RX = 0x%.4X, TX = 0x%.4X\n",
					ps_sslCtx->s_sslGut.e_rxCipSpec,
					ps_sslCtx->s_sslGut.e_txCipSpec);
			printf("\n>INFO::Version: 0x%.4X\n", ps_sslCtx->e_ver);

			i_state = SSL_SERVER_READ;
			/* Reads the current system time */
			l_timeStart = fp_getCurTime();
			l_Start = l_timeStart;
			l_bytesRead = 0;
			break;
		case E_SSL_ERROR:
		default:
			LOG_ERR("sslSoc_accept error");
			i_state = SSL_SERVER_CLOSE_ERR;
			ps_sslCtx->e_socState = E_SSL_SOCKET_UNUSED;
			break;
		} /* switch */

		break;
		/* SSL_SERVER_ACCEPT */

		case SSL_SERVER_READ:
			l_bytes = 0;
			/* Just read and show on console. */
			/* Read */
			memset(c_readBuf, 0, sizeof(c_readBuf));

			/* read from SSL socket */
			l_bytes = sslSoc_read(ps_sslCtx, c_readBuf, sizeof(c_readBuf));
			if (l_bytes > 0) {
				if (echo != 0) {
					/* server echo: transmit received byte string */
					memcpy(c_writeBuf, c_readBuf, l_bytes);
					l_bytesWrite = l_bytes;
					i_state = SSL_SERVER_WRITE;
				} else if (strncmp(c_readBuf, "GET / HTTP/1.1\r\n\r\n", 16) == 0) {

					/* open file to transmit */
					fp = fopen(pc_filename, "rb");

					if (fp == NULL) {
						/* could not open file => send an error message */
						l_bytesWrite = sprintf(c_writeBuf, "HTTP/1.1 404 Not Found\r\n\r\n");
						i_state = SSL_SERVER_WRITE;
					} else {

						/* determine the number of bytes in the file to put
						 * that piece of information into the HTTP header */
						n = 0;
						while (fgetc(fp) != EOF) {
							n++;
						}
						rewind(fp);

						printf("Transmitting file: '%s'\n", pc_filename);

						/* prepare HTTP header */
						l_bytesWrite = sprintf(c_writeBuf,
								"HTTP/1.1 200 OK\r\n"\
								"Content-Type: application/octet-stream\r\n"\
								"Content-Length: %d\r\n\r\n", n);

						/* next step: read first chunk of bytes from file */
						i_state = SSL_SERVER_READ_FILE;
					}
				}
				break;
			} else if (l_bytes < 0) {
				switch(l_bytes) {
				case E_SSL_ERROR:
					i_state = SSL_SERVER_CLOSING;
					break;

				case E_SSL_WANT_WRITE:
					i_state = SSL_SERVER_FLUSH;
					break;

				default:
					break;
				}
			} else if (l_bytes == E_SSL_AGAIN) {
				break;
			}

			i_state = SSL_SERVER_CLOSE;
			break;
			/* SSL_SERVER_READ */

		case SSL_SERVER_READ_FILE:

			n = 0;
			if (fp != NULL) {
				/* read chunk of bytes from file and copy to write buffer */
				n = fread(c_filebuf, 1, SSL_WRITE_BLOCK_LEN - l_bytesWrite - 100, fp);
			}
			memcpy(&(c_writeBuf[l_bytesWrite]), c_filebuf, n);
			l_bytesWrite += n;

			if (n > 0) {
				/* next step: send data just read from file to peer */
				i_state = SSL_SERVER_WRITE;
			} else {
				/* we have reached the end of the file: close file and connection */
				if (fp != NULL) {
					fclose(fp);
				}
				i_state = SSL_SERVER_CLOSING;
			}

			break; /* case SSL_SERVER_READ_FILE */

		case SSL_SERVER_WRITE:

			/* send data to peer */
			l_bytes = sslSoc_write(ps_sslCtx, (char*)c_writeBuf, l_bytesWrite);
			if (l_bytes > 0) {
				i_state = SSL_SERVER_FLUSH;
			} else {
				switch(l_bytes) {
				case E_SSL_ERROR:
					printf(DBG_STRING " sslSoc_write error %s", __FILE__, __LINE__, sslDiag_getError(ps_sslCtx));
					i_state = SSL_SERVER_CLOSING;
					break;

				case E_SSL_WANT_AGAIN:
					i_state = SSL_SERVER_READ;
					break;

				default:
					break;
				}
			}

			/* need to reset l_bytesWrite to zero because otherwise step
			 * SSL_SERVER_READ_FILE would *append* new data (thinking
			 * previous chunk of bytes from file is the HTTP header) */
			l_bytesWrite = 0;

			break; /* case SSL_SERVER_WRITE */

		case SSL_SERVER_FLUSH: {

			switch(sslSoc_flush(ps_sslCtx)) {
			case E_SSL_OK:
				if (echo != 0) {
					/* in echo mode: start listening again */
					i_state = SSL_SERVER_READ;
				} else {
					/* in normal mode: read next chunk of bytes from file */
					i_state = SSL_SERVER_READ_FILE;
				}
				break;
				/*
				 * It is not, so we can fall thru
				 */
			case E_SSL_WANT_AGAIN:
				i_state = SSL_SERVER_READ;
				break;
			case E_SSL_AGAIN:
				break;
			case E_SSL_ERROR:
			default:
				i_state = SSL_SERVER_CLOSING;
				break;
			}

		}/* SSL_SERVER_FLUSH */
		break;

		case SSL_SERVER_CLOSING:

		case SSL_SERVER_CLOSING_ERR:

			LOG_RAW("Shutting down SSL connection...");
			do {
				l_bytes = sslSoc_shutdown(ps_sslCtx);
				printf("sslSoc_shutdown(...) returned: %d\n", l_bytes);
				if (l_bytes == E_SSL_OK && i_state == SSL_SERVER_CLOSING) {
					/* connection successfully closed (passive close) */
					i_state = SSL_SERVER_CLOSE;
				} else if (l_bytes != E_SSL_AGAIN) {
					/* connection successfully closed (error case) */
					i_state = SSL_SERVER_CLOSE_ERR;
				}
			} while (l_bytes != E_SSL_OK && l_bytes != E_SSL_ERROR);

			printf("done!\n");
			break;

		case SSL_SERVER_CLOSE:
		case SSL_SERVER_CLOSE_ERR:

			sslSoc_free(ps_sslCtx);

			close(srv_socdesc);
			puts("Socket closed");

			E_SERVER_FSM_RESULT retval =
					(i_state == SSL_SERVER_CLOSE_ERR) ? E_SERVER_FSM_ERROR : E_SERVER_FSM_DONE;

			i_state = SSL_SERVER_REINIT;

			return retval;
			break;

	} /* switch */

	/* server FSM would like to be re-entered again */
	return E_SERVER_FSM_AGAIN;
}