void appSend() { char sendData[50]; uint8_t packetCounter = 0; char packetCounterStr[3]; int retVal = 0; mos_thread_sleep(30830); printf("Opening connection on port %d... \n", BASE_PORT); while (true) { retVal = connect(BASE_PORT, 0); if (retVal == CONNECT_OK) { // Successfully connected break; } // Else retry opening of connection } printf("Opened connection on port %d \n", BASE_PORT); while (true) { // Diagnostic data: // Data string type ("T" for tsoil) // RSSI (ETX) - stored in packet footer by CTP++ // Battery voltage - TBD // # hops and path - stored in packet footer by CTP++ // receive ratio for each node - printed by transport // Canned message of 45 bytes char testStr[] = "a_canned_message_containing_45_bytes_of_chars"; char dataTypeStr[] = "T"; // TBD - get battery voltage and append to data to send // Construct data to send to base memset(sendData, 0, sizeof(sendData)); strcpy(sendData, testStr); strcat(sendData, dataTypeStr); itoa(packetCounter, packetCounterStr, 10); strcat(sendData, packetCounterStr); printf("sendData: %s \n", sendData); packetCounter++; // Reset counter if (packetCounter > 255) { packetCounter = 0; } // Send data to base printf("Calling sendPacket() for: \n"); printf("%s \n", sendData); sendPacket(BASE_PORT, sendData, sizeof(sendData), 0); mos_thread_sleep(2500); } // Close connection to destination (last) node; port 0 closeConn(BASE_PORT, 0); printf("Closed connection on port %d \n", BASE_PORT); }
void getDomainInfo(int id, timeInfoNode infos) { virDomainPtr dom = NULL; virDomainInfo info; int ret; struct timeval realTime; int cpu_diff, real_diff; float usage; /* Find the domain of the given id */ dom = virDomainLookupByID(conn, id); if (dom == NULL) { fprintf(stderr, "Failed to find Domain %d\n", id); freeDom(dom); closeConn(); } /* Get the information of the domain */ ret = virDomainGetInfo(dom, &info); if (ret < 0) { fprintf(stderr, "Failed to get information for Domain %d\n", id); freeDom(dom); closeConn(); } /* get the end of realTime*/ if (gettimeofday(&realTime, NULL) == - 1) { fprintf(stderr, "Failed to get start time\n"); return; } /* calculate the usage of cpu */ cpu_diff = (info.cpuTime - infos.cpu_time) / 10000; real_diff = 1000 *(realTime.tv_sec - infos.real_time.tv_sec) + (realTime.tv_usec - infos.real_time.tv_usec); usage = cpu_diff / (float)(real_diff); /* print the results */ printf("%d\t%.3f%\t%lu\t%lu\t%hu\t%0X\t%s\n", id, usage, info.memory / 1024, info.maxMem / 1024, info.nrVirtCpu, info.state, virDomainGetName(dom)); freeDom(dom); }
/* The following function is responsible for initializing a connection */ static rsRetVal initConn(instanceData *pData, int bSilent) { DEFiRet; int iDrvrsLoaded; ASSERT(pData != NULL); ASSERT(pData->conn == NULL); if(bDbiInitialized == 0) { /* we need to init libdbi first */ # ifdef HAVE_DBI_R iDrvrsLoaded = dbi_initialize_r((char*) pData->dbiDrvrDir, &dbiInst); # else iDrvrsLoaded = dbi_initialize((char*) pData->dbiDrvrDir); # endif if(iDrvrsLoaded == 0) { errmsg.LogError(0, RS_RET_SUSPENDED, "libdbi error: libdbi or libdbi drivers not present on this system - suspending."); ABORT_FINALIZE(RS_RET_SUSPENDED); } else if(iDrvrsLoaded < 0) { errmsg.LogError(0, RS_RET_SUSPENDED, "libdbi error: libdbi could not be " "initialized (do you have any dbi drivers installed?) - suspending."); ABORT_FINALIZE(RS_RET_SUSPENDED); } bDbiInitialized = 1; /* we are done for the rest of our existence... */ } # ifdef HAVE_DBI_R pData->conn = dbi_conn_new_r((char*)pData->drvrName, dbiInst); # else pData->conn = dbi_conn_new((char*)pData->drvrName); # endif if(pData->conn == NULL) { errmsg.LogError(0, RS_RET_SUSPENDED, "can not initialize libdbi connection"); ABORT_FINALIZE(RS_RET_SUSPENDED); } else { /* we could get the handle, now on with work... */ /* Connect to database */ dbi_conn_set_option(pData->conn, "host", (char*) pData->host); dbi_conn_set_option(pData->conn, "username", (char*) pData->usrName); dbi_conn_set_option(pData->conn, "dbname", (char*) pData->dbName); if(pData->pwd != NULL) dbi_conn_set_option(pData->conn, "password", (char*) pData->pwd); if(dbi_conn_connect(pData->conn) < 0) { reportDBError(pData, bSilent); closeConn(pData); /* ignore any error we may get */ ABORT_FINALIZE(RS_RET_SUSPENDED); } pData->txSupport = dbi_conn_cap_get(pData->conn, "transaction_support"); } finalize_it: RETiRet; }
/* The following function writes the current log entry * to an established database connection. */ rsRetVal writeDB(uchar *psz, instanceData *pData) { DEFiRet; dbi_result dbiRes = NULL; ASSERT(psz != NULL); ASSERT(pData != NULL); /* see if we are ready to proceed */ if(pData->conn == NULL) { CHKiRet(initConn(pData, 0)); } /* try insert */ if((dbiRes = dbi_conn_query(pData->conn, (const char*)psz)) == NULL) { /* error occured, try to re-init connection and retry */ closeConn(pData); /* close the current handle */ CHKiRet(initConn(pData, 0)); /* try to re-open */ if((dbiRes = dbi_conn_query(pData->conn, (const char*)psz)) == NULL) { /* re-try insert */ /* we failed, giving up for now */ reportDBError(pData, 0); closeConn(pData); /* free ressources */ ABORT_FINALIZE(RS_RET_SUSPENDED); } } finalize_it: if(iRet == RS_RET_OK) { pData->uLastDBErrno = 0; /* reset error for error supression */ } if(dbiRes != NULL) dbi_result_free(dbiRes); RETiRet; }
SGSocket::~SGSocket() { closeConn(); if (serverIP) { free(serverIP); serverIP = NULL; } if ( responseBuf ) { free(responseBuf); responseBuf = NULL; } }
/* get the start time of each domain */ void getTimeInfo(int id, timeInfoNode * infos) { virDomainPtr dom = NULL; virDomainInfo info; int ret; /* Find the domain of the given id */ dom = virDomainLookupByID(conn, id); if (dom == NULL) { fprintf(stderr, "Failed to find Domain %d\n", id); freeDom(dom); closeConn(); } /* Get the information of the domain */ ret = virDomainGetInfo(dom, &info); if (ret < 0) { fprintf(stderr, "Failed to get information for Domain %d\n", id); freeDom(dom); closeConn(); } /* get the start of realTime*/ if (gettimeofday(&(infos->real_time), NULL) == - 1) { fprintf(stderr, "Failed to get start time\n"); return; } /* get the start of CPUTime*/ infos->cpu_time = info.cpuTime; /* nanosecond */ freeDom(dom); }
void genResponse(int cid) { int power = motor[motorA]; string tmpString; int index = 0; ubyte linebuff[20]; StringFromChars(tmpString,rxbuffer); index = StringFind(tmpString, "/"); StringDelete(tmpString, 0, index); index = StringFind(tmpString, "HTTP"); StringDelete(tmpString, index, strlen(tmpString)); writeDebugStreamLine("Request:%s", tmpString); nxtDisplayTextLine(2, "Request: "); nxtDisplayTextLine(3, tmpString); if (StringFind(tmpString, "MOTA") > 0) { StringDelete(tmpString, 0, 6); index = StringFind(tmpString, " "); if (index > -1) StringDelete(tmpString, index, strlen(tmpString)); //power = RC_atoix(tmpString); power = clip(RC_atoix(tmpString), -100, 100); writeDebugStreamLine("Power:%d", power); } else { writeDebugStreamLine("NO POWER: %s", tmpString); } sendHeader(cid); while(nxtHS_Status == HS_SENDING) wait1Msec(5); wait1Msec(100); index = 0; linebuff[0] = 27; // escape; linebuff[1] = 'S'; // the CID; linebuff[2] = (ubyte)cid + 48; // the CID; index = appendToBuff(buffer, index, linebuff, 3); StringFormat(tmpString, "MotorA=%d", power); memcpy(linebuff, tmpString, strlen(tmpString)); index = appendToBuff(buffer, index, linebuff, strlen(tmpString)); linebuff[0] = 27; // escape; linebuff[1] = 'E'; // the CID; index = appendToBuff(buffer, index, endmarker, 2); writeRawHS(buffer, index); motor[motorA] = power; closeConn(1); memset(rxbuffer, 0, sizeof(rxbuffer)); wait1Msec(100); clear_read_buffer(); }
int main(int argc, char **argv) { int fd; char cmd[1024]; if(argc < 2) { fprintf(stderr,"usage: %s <pdu data>\n",argv[0]); exit(1); } fd = initConn(115200); at(fd); sendStrCmd(fd, "AT+CMGF=0\r"); readResp(fd); sprintf(cmd, "AT+CMGS=%ld\r", strlen(argv[1])/2 - 1); sendStrCmd(fd, cmd); readResp(fd); sprintf(cmd,"%s\032",argv[1]); sendStrCmd(fd, cmd); readResp(fd); closeConn(fd); return 0; }
void genResponse(int cid) { int power = motor[motorA]; float temp = 0.0; string tmpString; int index = 0; ubyte linebuff[20]; StringFromChars(tmpString,rxbuffer); index = StringFind(tmpString, "/"); StringDelete(tmpString, 0, index); index = StringFind(tmpString, "HTTP"); StringDelete(tmpString, index, strlen(tmpString)); writeDebugStreamLine("Request:%s", tmpString); nxtDisplayTextLine(2, "Request: "); nxtDisplayTextLine(3, tmpString); if (StringFind(tmpString, "MOTA") > 0) { StringDelete(tmpString, 0, 6); index = StringFind(tmpString, " "); if (index > -1) StringDelete(tmpString, index, strlen(tmpString)); //power = RC_atoix(tmpString); power = clip(atoi(tmpString), -100, 100); writeDebugStreamLine("Power:%d", power); } else { writeDebugStreamLine("NO POWER: %s", tmpString); } sendHeader(cid); while(nxtHS_Status == HS_SENDING) wait1Msec(5); wait1Msec(100); index = 0; linebuff[0] = 27; // escape; linebuff[1] = 'S'; // the CID; linebuff[2] = (ubyte)cid + 48; // the CID; index = appendToBuff(buffer, index, linebuff, 3); StringFormat(tmpString, "MotorA=%d\n", power); memcpy(linebuff, tmpString, strlen(tmpString)); index = appendToBuff(buffer, index, linebuff, strlen(tmpString)); DTMPreadTemp(DTMP, temp); StringFormat(tmpString, "Temp: %2.2f C", temp); memcpy(linebuff, tmpString, strlen(tmpString)); index = appendToBuff(buffer, index, linebuff, strlen(tmpString)); linebuff[0] = 27; // escape; linebuff[1] = 'E'; // the CID; index = appendToBuff(buffer, index, endmarker, 2); writeRawHS(buffer, index); if (power != 0) nMotorEncoderTarget[motorA] = 2000; motor[motorA] = power; if (power > 0) SensorType[COLOUR] = sensorCOLORGREEN; else if (power < 0) SensorType[COLOUR] = sensorCOLORBLUE; else if (nMotorRunState[motorA] == runStateIdle) SensorType[COLOUR] = sensorCOLORRED; else SensorType[COLOUR] = sensorCOLORRED; wait1Msec(300); clear_read_buffer(); closeConn(1); memset(rxbuffer, 0, sizeof(rxbuffer)); //wait1Msec(100); Receive(); //clear_read_buffer(); }
/* 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; }
void appSend () { static uint8_t smpl_cnt = 10; //number of samples we take to average on each channel uint8_t count = 0; //temp counter for samples taken uint8_t i; uint8_t nchannels=1; uint8_t channels[1] = {INTERNAL_VOLTAGE}; //use only internal voltage for now uint16_t adc_raw[8]; uint8_t ledcount = 0; uint8_t ix; char sendData[12]; char testStr[] = "test"; char iStr[3]; uint16_t pause_time = 1000; // Avoid signal interference with default channel (26) and wi-fi cc2420_set_channel(24); // Set transmit power to low-power mode com_ioctl(IFACE_RADIO, CC2420_LOW_POWER_MODE); printf("Opening connection on port %d... \n", TRANSPORT_LISTENING_PORT); connect(TRANSPORT_LISTENING_PORT, 0); printf("Opened connection on port %d \n", TRANSPORT_LISTENING_PORT); //mos_thread_sleep(2000); while (true) { //--- MEASURING BATTERY VOLTAGE ---// //mos_led_display( (ledcount++)%8 ); //see explanation in test_adc.c adc_on(); //turn on the ADC/Vref mos_thread_sleep(20); //time to wait for the internal reference to settle in theory // Measure each channel, possibly with multiple samples for(ix=0; ix<nchannels; ix++) { //take 10 samples and average the result //split this value out as the final channel reading count = 0; //clear the samples counter adc_raw[ix]=0; // clear adc reading accum //For this channel, do as many samples as are 'requested' while(count < smpl_cnt) { adc_raw[ix] += adc_get_conversion16( channels[ix] ); count++; //increment the no. of readings counter } //end of samples loop for this channel } //end channels loop // Average the data for the samples taken on each channel for( ix=0; ix<nchannels; ix++ ) { adc_raw[ix] /= smpl_cnt; } // Report the results //printf("Raw voltage reading = %x\n", adc_raw[0]); adc_off(); //mos_thread_sleep(4000); //--- SENDING DATA ---// memset(sendData, 0, sizeof(sendData)); strcpy(sendData, testStr); itoa(i, iStr, 10); strcat(sendData, iStr); printf("Calling sendPacket() for: %s \n", sendData); sendPacket(TRANSPORT_LISTENING_PORT, sendData, sizeof(sendData), 0); i++; // Reset counter if (i >= 60) { i = 0; } // Get raw voltage reading printf("***** Raw voltage reading = %x *****\n", adc_raw[0]); // Adjust pause time (send rate) for each specific voltage if (adc_raw[0] > 0x950) { pause_time = 1000; } else if (adc_raw[0] > 0x925) { pause_time = 1500; } else if (adc_raw[0] > 0x900) { pause_time = 2000; } // and so on... // need to find the optimal values ... mos_thread_sleep(pause_time); //adaptive send rate // Close connection to destination (last) node; port 0 closeConn(0, 3); printf("Closed connection on port %d \n", TRANSPORT_LISTENING_PORT); } }
/* Make a secure HTTP request to a defined IP and port Connection is made in blocking socket mode The connection is considered successful if the SSL/TLS session is negotiated successfully, a request is sent, and a HTTP response is received. */ static int32 httpsClientConnection(sslKeys_t *keys, sslSessionId_t *sid) { int32 rc, transferred, len, complete; ssl_t *ssl; unsigned char *buf; httpConn_t cp; SOCKET fd; complete = 0; memset(&cp, 0x0, sizeof(httpConn_t)); fd = socketConnect(HTTPS_IP, HTTPS_PORT, &rc); if (fd == INVALID_SOCKET || rc != PS_SUCCESS) { _psTraceInt("Connect failed: %d. Exiting\n", rc); return PS_PLATFORM_FAIL; } rc = matrixSslNewClientSession(&ssl, keys, sid, 0, certCb, NULL, NULL); if (rc != MATRIXSSL_REQUEST_SEND) { _psTraceInt("New Client Session Failed: %d. Exiting\n", rc); close(fd); return PS_ARG_FAIL; } WRITE_MORE: while ((len = matrixSslGetOutdata(ssl, &buf)) > 0) { transferred = send(fd, buf, len, 0); if (transferred <= 0) { goto L_CLOSE_ERR; } else { /* Indicate that we've written > 0 bytes of data */ if ((rc = matrixSslSentData(ssl, transferred)) < 0) { goto L_CLOSE_ERR; } if (rc == MATRIXSSL_REQUEST_CLOSE) { closeConn(ssl, fd); return MATRIXSSL_SUCCESS; } if (rc == MATRIXSSL_HANDSHAKE_COMPLETE) { /* If we sent the Finished SSL message, initiate the HTTP req */ /* (This occurs on a resumption handshake) */ if (httpWriteRequest(ssl) < 0) { goto L_CLOSE_ERR; } goto WRITE_MORE; } /* SSL_REQUEST_SEND is handled by loop logic */ } } READ_MORE: if ((len = matrixSslGetReadbuf(ssl, &buf)) <= 0) { goto L_CLOSE_ERR; } if ((transferred = recv(fd, buf, len, 0)) < 0) { goto L_CLOSE_ERR; } /* If EOF, remote socket closed. But we haven't received the HTTP response so we consider it an error in the case of an HTTP client */ if (transferred == 0) { goto L_CLOSE_ERR; } if ((rc = matrixSslReceivedData(ssl, (int32)transferred, &buf, (uint32*)&len)) < 0) { goto L_CLOSE_ERR; } PROCESS_MORE: switch (rc) { case MATRIXSSL_HANDSHAKE_COMPLETE: #ifdef REHANDSHAKE_TEST /* Test rehandshake capabilities of server. If a successful session resmption rehandshake occurs, this client will be last to send handshake data and MATRIXSSL_HANDSHAKE_COMPLETE will hit on the WRITE_MORE handler and httpWriteRequest will occur there. NOTE: If the server doesn't support session resumption it is possible to fall into an endless rehandshake loop */ if (matrixSslEncodeRehandshake(ssl, NULL, NULL, 0, 0) < 0) { goto L_CLOSE_ERR; } #else /* We got the Finished SSL message, initiate the HTTP req */ if (httpWriteRequest(ssl) < 0) { goto L_CLOSE_ERR; } #endif goto WRITE_MORE; case MATRIXSSL_APP_DATA: if ((rc = httpBasicParse(&cp, buf, len)) < 0) { closeConn(ssl, fd); if (cp.parsebuf) free(cp.parsebuf); cp.parsebuf = NULL; cp.parsebuflen = 0; return MATRIXSSL_ERROR; } if (rc == HTTPS_COMPLETE) { rc = matrixSslProcessedData(ssl, &buf, (uint32*)&len); closeConn(ssl, fd); if (cp.parsebuf) free(cp.parsebuf); cp.parsebuf = NULL; cp.parsebuflen = 0; if (rc < 0) { return MATRIXSSL_ERROR; } else { if (rc > 0) { _psTrace("HTTP data parsing not supported, ignoring.\n"); } _psTrace("SUCCESS: Received HTTP Response\n"); return MATRIXSSL_SUCCESS; } } /* We processed a partial HTTP message */ if ((rc = matrixSslProcessedData(ssl, &buf, (uint32*)&len)) == 0) { goto READ_MORE; } goto PROCESS_MORE; case MATRIXSSL_REQUEST_SEND: goto WRITE_MORE; case MATRIXSSL_REQUEST_RECV: goto READ_MORE; 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)); goto L_CLOSE_ERR; } /* Closure alert is normal (and best) way to close */ if (*(buf + 1) == SSL_ALERT_CLOSE_NOTIFY) { closeConn(ssl, fd); if (cp.parsebuf) free(cp.parsebuf); cp.parsebuf = NULL; cp.parsebuflen = 0; return MATRIXSSL_SUCCESS; } psTraceIntInfo("Warning alert: %d\n", *(buf + 1)); if ((rc = matrixSslProcessedData(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 */ goto L_CLOSE_ERR; } L_CLOSE_ERR: _psTrace("FAIL: No HTTP Response\n"); matrixSslDeleteSession(ssl); close(fd); if (cp.parsebuf) free(cp.parsebuf); cp.parsebuf = NULL; cp.parsebuflen = 0; return MATRIXSSL_ERROR; }
int main(int argc, char** argv){ int sock = 0; // declaración del socket e inicializado a 0 int error = 0; /** declaramos una variable que nos servirá para detectar * errores */ socklen_t length = (socklen_t) sizeof (struct sockaddr_in); // tamaño del paquete struct sockaddr_in addr; // definimos el contenedor de la dirección unsigned int port = 5678; /** creamos la variable que identifica el puerto * de conexión, siendo el puerto por defecto 5678 */ int connPos = 0; // primera posición libre en el array de conexiones int connTam = 10; // tamaño actual del array de conexiones int connGrow = 10; // factor de crecimiento del array user* conn = NULL; // array de conexiones con los clientes room rooms[DIM]; user auxConn; // conexion auxiliar sms auxMsj; fd_set connList, connListCopy; // definimos un descriptor que contendrá nuestros sockets int nbytes = 0; // contador de bytes leidos y escritos int dbName = 0; // variable que nos permitirá configurar el nombre de la base de datos sqlite3* db = NULL; // descriptor de la base de datos char cert[DIM] = "cert"; // nombre del certificado del servidor char pkey[DIM] = "pkey"; // nombre del archivo con la clave privada // <editor-fold defaultstate="collapsed" desc="Interpretado de parámetros de entrada"> //analizamos los parámetros de entrada int i = 0; for(; i < argc; i++){ if(strcmp(argv[i], "-p") == 0){ // leemos el puerto if(argc <= i + 1 || isNum(argv[i+1]) == 0){ perror("Se esperaba un número después de -p"); exit(-1); }else{ PDEBUG("ARGS: Se detectó un puerto\n"); i++; port = atoi(argv[i]); } continue; }else if(strcmp(argv[i], "-ls") == 0){ // leemos el tamaño inicial de la lista if(argc <= i + 1 || isNum(argv[i+1]) == 0){ perror("Se esperaba un número después de -ls"); exit(-1); }else{ PDEBUG("ARGS: Se detectó un tamaño inicial\n"); i++; connTam = atoi(argv[i]); } continue; }else if(strcmp(argv[i], "-lg") == 0){ // leemos el factor de creciemiento de la lista de conexiones if(argc <= i + 1 || isNum(argv[i+1]) == 0){ perror("Se esperaba un número después de -lg\n"); exit(-1); }else{ PDEBUG("ARGS: Se detectó un crecimiento\n"); i++; connGrow = atoi(argv[i]); } continue; }else if(strcmp(argv[i], "-db") == 0){ // leemos el nombre de la base de datos que queremos utilizar if(argc <= i + 1){ perror("Se esperaba una cadena depués de -db\n"); exit(-1); }else{ PDEBUG("ARGS: Se detectó un crecimiento\n"); i++; dbName = i; } continue; }else if(strcmp(argv[i], "-cert") == 0){ // leemos el nombre del archivo del certificado if(argc <= i + 1){ perror("Se esperaba una cadena depués de -cert\n"); exit(-1); }else{ PDEBUG("ARGS: Se detectó un certificado\n"); i++; strcpy(cert, argv[i]); } continue; }else if(strcmp(argv[i], "-pkey") == 0){ // leemos el nombre del archivo de que contiene la clave privada if(argc <= i + 1){ perror("Se esperaba una cadena depués de -pkey\n"); exit(-1); }else{ PDEBUG("ARGS: Se detectó una clave privada\n"); i++; strcpy(pkey, argv[i]); } continue; } } //</editor-fold> db = db_open( (dbName == 0) ? "chat.db" : argv[dbName] ); PDEBUG("INFO: Convertimos el proceso en un demonio\n"); //make_daemon(); /*******************************SSL****************************************/ PDEBUG("INFO: Inicializando la libreria SSL\n"); SSL_library_init(); PDEBUG("INFO: Cargamos los algoritmos SSL y los mensajes de error\n"); OpenSSL_add_all_algorithms(); SSL_load_error_strings(); PDEBUG("INFO: Seleccionamos SSLv2, SSLv3 y TLSv1\n"); SSL_METHOD *method; method = SSLv23_server_method(); PDEBUG("INFO: Creamos el nuevo contexto\n"); SSL_CTX *ctx; ctx = SSL_CTX_new(method); if(ctx == NULL) { // error ERR_print_errors_fp(stderr); _exit(-1); } PDEBUG("INFO: Comprobando el certificado\n"); if ( SSL_CTX_use_certificate_chain_file(ctx, cert) <= 0) { ERR_print_errors_fp(stderr); _exit(-1); } PDEBUG("INFO: Comprobando la clav eprivada\n"); if ( SSL_CTX_use_PrivateKey_file(ctx, pkey, SSL_FILETYPE_PEM) <= 0) { ERR_print_errors_fp(stderr); _exit(-1); } PDEBUG("INFO: Comprobando que las claves pueden trabajar juntas\n"); if ( !SSL_CTX_check_private_key(ctx) ) { fprintf(stderr, "Clave privada incorrecta.\n"); _exit(-1); } /*******************************SSL****************************************/ //Creamos el socket PDEBUG("INFO: Creando el socket\n"); sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); //Comprobamos si ha ocurrido un error al crear el socket if(sock < 0){ write(2, strcat("ERROR: creación del socket {{socket()}}: %s\n", strerror(errno)), DIM); // terminamos la ejecución del programa exit(-1); } PDEBUG("INFO: Estableciendo el puerto, origenes,...\n"); addr.sin_family = AF_INET; // familia AF_INET addr.sin_port = htons(port); // definimos el puerto de conexión addr.sin_addr.s_addr = htonl(INADDR_ANY); // permitimos conexion de cualquiera /* hacemos este "apaño" porque según hemos leido, http://www.wlug.org.nz/EADDRINUSE * hay un timeout para liberar el socket */ unsigned int opt = 1; if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))==-1) { write(2, "ERROR: al permitir la reutiización del puerto {{setsockopt()}}\n", DIM); exit(-1); } // le asignamos una dirección al socket PDEBUG("INFO: Asignando una dirección al socket\n"); error = bind(sock, (struct sockaddr *)&addr, length); //Comprobamos si ha ocurrido un error al hacer el bind if(error < 0){ write(2, strcat("ERROR: {{bind()}}: %s\n", strerror(errno)), DIM); // terminamos la ejecución del programa exit(-1); } //Ponemos el servidor a escuchar para buscar nuevas conexiones PDEBUG("INFO: Comenzamos la escucha de l programa\n"); error = listen(sock, Q_DIM); //Comprobamos si ha ocurrido un error al ponernos a escuchar if(error < 0){ write(2, strcat("ERROR: al iniciar la escucha{{listen()}}: %s\n", strerror(errno)), DIM); // terminamos la ejecución del programa exit(-1); } // realizamos la asignación inicial de memoria PDEBUG("INFO: Realizando asignación inicial de memoria, tamaño inicial 10\n"); connTam = 10; conn = malloc(connTam * sizeof(user)); // rellenamos el array con -1 memset(conn, 0, connTam * sizeof(user)); //inicializamos la lista de conexiones FD_ZERO(&connList); // Inicio del bit descriptor connList con el valor de sock FD_SET (sock, &connList); PDEBUG("INFO: Creamos la sala de chat general\n"); bzero(rooms, DIM * sizeof(room)); strcpy(rooms[0].name, "general"); // <editor-fold defaultstate="collapsed" desc="Bucle de escucha"> //comenzamos a analizar conexiones PDEBUG("INFO: Comenzamos a analizar los sockets\n"); while(1){ // hacemos una copia de seguridad para asegurarnos de no perder los datos connListCopy = connList; // ¿Hay algún socket listo para leer? PDEBUG("INFO: ¿Hay algún socket listo para leer?\n"); error = select(connTam + 1, &connListCopy, NULL, NULL, NULL); //Comprobamos si ha ocurrido un error al ponernos a escuchar if(error < 0){ write(2, strcat("ERROR: al realizar la selección {{select()}}: %s\n" , strerror(errno)), DIM); // terminamos la ejecución del programa exit(-1); } // recorriendo los sockets para ver los que están activos PDEBUG("INFO: recorriendo los sockets para ver los que están activos\n"); int i = 0; // definimos un índice for (; i <= connTam; i++){ // este socket está preparado para leer los datos if(FD_ISSET(i, &connListCopy)){ // vemos si el socket preparado para leer es el de aceptar peticiones if(i == sock){ PDEBUG("INFO: Nuevo cliente detectado, comprobando...\n"); auxConn.sock = accept(sock, (struct sockaddr *) &addr, &length); if(auxConn.sock < 0){ write(2, "ERROR: al realizar la aceptación {{accept()}}: %s\n" , *strerror(errno)); // terminamos la ejecución del programa exit(-1); } /************************SSL*******************************/ PDEBUG("INFO: Creando conexion ssl\n"); PDEBUG("INFO: Creando conexion SSL\n"); auxConn.ssl = SSL_new(ctx); PDEBUG("INFO: Asignando la conexión a SSL\n"); SSL_set_fd(auxConn.ssl, auxConn.sock); PDEBUG("INFO: Aceptando la conexión SSL\n"); error = SSL_accept(auxConn.ssl); if(error < 0){ ERR_print_errors_fp(stderr); exit(-1); } /************************SSL*******************************/ PDEBUG("INFO: Conexión establecida, autenticando...\n"); memset(&auxMsj, 0, sizeof(auxMsj)); // incializamos la estructura PDEBUG("INFO: Solicitando autenticación\n"); strcpy(auxMsj.text, "Usuario: "); // establecemos el texto que queremos que se muestre auxMsj.flag = REQ_TEXT; // le indicamos que requerimos una respuesta con texto strcpy(auxMsj.name, SERVER); // nos identificamos como el servidor SSL_write(auxConn.ssl, &auxMsj, sizeof(sms)); // enviamos la información // metemos los datos de la conexión en nuestro array de conexiones strcpy((*(conn + connPos)).name, auxMsj.text); (*(conn + connPos)).sock = auxConn.sock; (*(conn + connPos)).ssl = auxConn.ssl; (*(conn + connPos)).prov = PROV; // Añadimos el socket a nuestra lista PDEBUG("INFO: Insertando socket en la lista de monitoreo\n"); FD_SET (auxConn.sock, &connList); // como la peticion se ha aceptado incrementamos el contador de conexiones PDEBUG("INFO: Cálculo del nuevo offset\n"); nextPos(conn, &connPos, &connTam, connGrow); }else{ // si no, es un cliente ya registrado PDEBUG("DATA: Nuevo mensaje detectado\n"); nbytes = SSL_read((*(conn+searchConn(conn, connTam, i))).ssl, &auxMsj, sizeof(sms)); if(nbytes > 0){ // si hemos leido más d eun byte... switch(auxMsj.flag){ case CLI_EXIT: // desconexión del cliente closeConn(conn, &connPos, connTam, i, &connList, db); break; case SERV_ADMIN: // parámetros que ha de ejecutr el servidor execParams(conn, connTam, auxMsj.text, i, sock, db, rooms, DIM); break; case MSJ: // mensaje multicast(conn, &connTam, auxMsj, i, db, (*(conn+searchConn(conn, connTam, i))).room); break; case REQ_AUTH: // vamos a leer el nombre de usuario auth(conn, &connTam, i, auxMsj, db, rooms, DIM); break; case CHECK_ROOM: // vamos a leer el nombre de usuario roomCheckIn(conn, &connTam, i, auxMsj, db, rooms, DIM); break; case CHECK_PASS: authPassword(conn, &connTam, i, auxMsj, db, rooms, DIM); break; case MP: mp(conn, &connTam, auxMsj, i, db); break; default: write(2, "ERROR: Recibido un mensaje mal formado\n", 39); break; } }else{ // hemos detectado una desconexión por el cerrado de la conexión closeConn(conn, &connPos, connTam, i, &connList, db); } } } } }//</editor-fold> return 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; }
int main() { int idCount; int i; int id; //int ids[MAXID]; int *ids; //timeInfoNode timeInfos[MAXID]; printf("--------------------------------------------------------\n"); printf(" XEN Domain Monitor \n"); printf("--------------------------------------------------------\n"); /* NULL means connect to local Xen hypervisor */ conn = virConnectOpenReadOnly(NULL); if (conn == NULL) { fprintf(stderr, "Failed to connect to hypervisor\n"); closeConn(); return 0; } /*char* caps; caps = virConnectGetCapabilities(conn); printf("Capabilities:\n%s\n",caps); free(caps);*/ char *host; host = virConnectGetHostname(conn); fprintf(stdout, "Hostname:%s\n",host); free(host); int vcpus; vcpus = virConnectGetMaxVcpus(conn,NULL); fprintf(stdout, "Maxmum support vcpus:%d\n",vcpus); unsigned long long node_free_memory; node_free_memory = virNodeGetFreeMemory(conn); fprintf(stdout, "free memory:%lld\n",node_free_memory); virNodeInfo nodeinfo; virNodeGetInfo(conn,&nodeinfo); fprintf(stdout, "Model: %s\n", nodeinfo.model); fprintf(stdout, "Memory size: %lukb\n", nodeinfo.memory); fprintf(stdout, "Number of CPUs: %u\n", nodeinfo.cpus); fprintf(stdout, "MHz of CPUs: %u\n", nodeinfo.mhz); fprintf(stdout, "Number of NUMA nodes: %u\n", nodeinfo.nodes); fprintf(stdout, "Number of CPU sockets: %u\n", nodeinfo.sockets); fprintf(stdout, "Number of CPU cores per socket: %u\n", nodeinfo.cores); fprintf(stdout, "Number of CPU threads per core: %u\n", nodeinfo.threads); fprintf(stdout, "Virtualization type: %s\n", virConnectGetType(conn)); unsigned long ver; virConnectGetVersion(conn, &ver); fprintf(stdout, "Version: %lu\n", ver); /*unsigned long Libver; virConnectGetLibVersion(conn, &Libver); fprintf(stdout, "Libvirt Version: %lu\n", Libver);*/ char *uri; uri = virConnectGetURI(conn); fprintf(stdout, "Canonical URI: %s\n", uri); free(uri); /* get the count of IDs and save these ID into ids[] */ idCount = virConnectNumOfDomains(conn); ids = malloc(sizeof(int) *idCount); idCount = virConnectListDomains(conn,ids,idCount); //idCount = virConnectListDomains(conn, &ids[0], MAXID); if (idCount < 0) { fprintf(stderr, "Failed to list the domains\n"); closeConn(); return 0; } timeInfoNode timeInfos[idCount]; printf("Domain Totals: %d\n", idCount); printf("ID\tCPU\tMEM\tMaxMEM\tVCPUs\tState\tNAME\n"); /* loop get the CPUtime info by IDs */ for (i = 0; i < idCount; i++) { id = ids[i]; getTimeInfo(id, &(timeInfos[i])); } sleep(1); /* loop print the domain info and calculate the usage of cpus*/ for (i = 0; i < idCount; i++) { id = ids[i]; getDomainInfo(id, timeInfos[i]); } free(ids); printf("--------------------------------------------------------\n"); closeConn(); return 0; }
void run_work(struct work_param* param) { if (pipe(param->pipes) != 0) { printf("Failed to create pipe! %s\n", strerror(errno)); return; } unsigned char wb; unsigned char* mbuf = xmalloc(1024); while (1) { pthread_rwlock_rdlock(¶m->conns->data_mutex); size_t cc = param->conns->count; struct pollfd fds[cc + 1]; struct conn* conns[cc]; int fdi = 0; for (int i = 0; i < param->conns->size; i++) { if (param->conns->data[i] != NULL) { conns[fdi] = (param->conns->data[i]); struct conn* conn = conns[fdi]; fds[fdi].fd = conns[fdi]->fd; fds[fdi].events = POLLIN | (conn->writeBuffer_size > 0 ? POLLOUT : 0); fds[fdi++].revents = 0; if (fdi == cc) break; } else conns[fdi] = NULL; } pthread_rwlock_unlock(¶m->conns->data_mutex); fds[cc].fd = param->pipes[0]; fds[cc].events = POLLIN; fds[cc].revents = 0; int cp = poll(fds, cc + 1, -1); if (param->mysql->mysql && param->mysql->complete && param->zone != param->mysql->czone) { if (param->zone != NULL) { freeZone(param->zone); } param->zone = param->mysql->czone; } if (cp < 0) { printf("Poll error in worker thread! %s\n", strerror(errno)); } else if (cp == 0) continue; else if ((fds[cc].revents & POLLIN) == POLLIN) { if (read(param->pipes[0], &wb, 1) < 1) printf("Error reading from pipe, infinite loop COULD happen here.\n"); if (cp-- == 1) continue; } for (int i = 0; i < cc; i++) { int re = fds[i].revents; struct conn* conn = conns[i]; if (conn == NULL) continue; if ((re & POLLERR) == POLLERR) { //printf("POLLERR in worker poll! This is bad!\n"); goto cont; } if ((re & POLLHUP) == POLLHUP) { closeConn(param, conn); conn = NULL; goto cont; } if ((re & POLLNVAL) == POLLNVAL) { printf("Invalid FD in worker poll! This is bad!\n"); closeConn(param, conn); conn = NULL; goto cont; } if ((re & POLLIN) == POLLIN) { size_t tr = 0; ioctl(fds[i].fd, FIONREAD, &tr); unsigned char* loc; if (conn->readBuffer == NULL) { conn->readBuffer = xmalloc(tr); // TODO: max upload? conn->readBuffer_size = tr; loc = conn->readBuffer; } else { conn->readBuffer_size += tr; conn->readBuffer = xrealloc(conn->readBuffer, conn->readBuffer_size); loc = conn->readBuffer + conn->readBuffer_size - tr; } ssize_t r = 0; if (r == 0 && tr == 0) { // nothing to read, but wont block. ssize_t x = 0; x = read(fds[i].fd, loc + r, tr - r); if (x <= 0) { closeConn(param, conn); conn = NULL; goto cont; } r += x; } while (r < tr) { ssize_t x = 0; x = read(fds[i].fd, loc + r, tr - r); if (x <= 0) { closeConn(param, conn); conn = NULL; goto cont; } r += x; } int p = 0; p = handleRead(conn, param, fds[i].fd); if (p == 1) { goto cont; } } if ((re & POLLOUT) == POLLOUT && conn != NULL) { ssize_t mtr = write(fds[i].fd, conn->writeBuffer, conn->writeBuffer_size); if (mtr < 0 && errno != EAGAIN) { closeConn(param, conn); conn = NULL; goto cont; } else if (mtr < 0) { goto cont; } else if (mtr < conn->writeBuffer_size) { memmove(conn->writeBuffer, conn->writeBuffer + mtr, conn->writeBuffer_size - mtr); conn->writeBuffer_size -= mtr; conn->writeBuffer = xrealloc(conn->writeBuffer, conn->writeBuffer_size); } else { conn->writeBuffer_size = 0; xfree(conn->writeBuffer); conn->writeBuffer = NULL; } if (conn->writeBuffer_size == 0 && conn->state == 1) { closeConn(param, conn); conn = NULL; goto cont; } } cont: ; if (--cp == 0) break; } } xfree(mbuf); }