/*Send Request Message and Receive Response Message Function Variable Definition: -- client_socket: socket connected to the server -- node: request message node Return Value: received response message from server */ char *sendAndRcvdMessage(int client_socket, struct request_message *node){ char *rcvd_buffer = (char*)malloc(sizeof(char) * (BUFFER_SIZE)); //received response message buffer ssize_t bytes = 0; //number of bytes //send request message to the server bytes = send(client_socket, node->message, node->message_length, MSG_NOSIGNAL); //Test the send is successful if (bytes < 0){ dieWithSystemMessage("send() failed!"); } else if (bytes != node->message_length){ dieWithUserMessage("send()", "sent unexpected number of bytes"); } //Receive Response Message from the server bytes = recv(client_socket, rcvd_buffer, BUFFER_SIZE - 1, 0); //Test the receive is successful if (bytes < 0){ dieWithSystemMessage("recv() failed!"); } else if (bytes == 0){ dieWithUserMessage("recv()", "connection closed prematurely"); } // NC: cool automated testing; you could also check the content of the result return rcvd_buffer; }
/*Handle Client Request Function Variable Definition: -- client_socket: socket connected to the client Return Value: NULL */ void handleClientRequest(int client_socket) { FILE *channel; //file stream for client socket char request_line[STRING_SIZE]; //client request line char *return_value; //each line header pointer //Initialize request_line buffer memset(request_line, 0, STRING_SIZE); //Create an input stream from the socket channel = fdopen(client_socket, "r"); if (channel == NULL) { dieWithSystemMessage("fdopen() failed"); } //Get client Request Line (Jump the blank line) do { return_value = fgets(request_line, STRING_SIZE, channel); } while (syntaxChecking(return_value, BLANK_LINE)); //Output the client_socket id and Request Line printf("Got a call on %d: request = %s", client_socket, request_line); //Get client Header Lines & Response the client request respondClientRequest(request_line, getHeaderLines(channel), client_socket); //Close client socket close(client_socket); //Close file stream fclose(channel); return; }
static int tioSioSocketInitTcp(unsigned short port) { struct sockaddr_in addr; /* Create server socket */ int sioSocketFd = socket(AF_INET, SOCK_STREAM, 0); if (sioSocketFd == -1) { dieWithSystemMessage("socket()"); } /* Construct server address, and make the connection */ memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = inet_addr(LOCALHOST_ADDR); addr.sin_port = htons(port); if (connect(sioSocketFd, (struct sockaddr *)&addr, sizeof(struct sockaddr)) == -1) { /* connection to sio_agent was not established */ close(sioSocketFd); sioSocketFd = -1; } return sioSocketFd; }
static int tioSioSocketInitUnix(const char *socketName) { struct sockaddr_un addr; /* Create server socket */ int sioSocketFd = socket(AF_UNIX, SOCK_STREAM, 0); if (sioSocketFd == -1) { dieWithSystemMessage("socket()"); } /* Construct server address, and make the connection */ memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; strncpy(addr.sun_path, socketName, sizeof(addr.sun_path)); addr.sun_path[sizeof(addr.sun_path) - 1] = '\0'; if (connect(sioSocketFd, (struct sockaddr *)&addr, sizeof(struct sockaddr)) == -1) { /* connection to sio_agent was not established */ close(sioSocketFd); sioSocketFd = -1; } return sioSocketFd; }
/*Setup Server Socket Function Variable Definition: -- service: socket service name or port number Return value: server socket number */ int setupServerSocket(const char *service){ struct addrinfo address_criteria; //criteria for address match struct addrinfo *server_address; //list of server addresses struct addrinfo *address; //pointer to addresses node struct sockaddr_storage local_address; //print local address socklen_t address_size; //address size int server_socket = -1; //socket descriptor for server int return_value; //return value //Construct the server address structure memset(&address_criteria, 0, sizeof(address_criteria)); //zero the address_criteria address_criteria.ai_family = AF_UNSPEC; //any address family address_criteria.ai_flags = AI_PASSIVE; //accept on any address/port address_criteria.ai_socktype = SOCK_STREAM; //only stream sockets address_criteria.ai_protocol = IPPROTO_TCP; //only tcp protocol //Get address/name information return_value = getaddrinfo(NULL, service, &address_criteria, &server_address); //Success returns zero if (return_value != 0){ dieWithUserMessage("getaddrinfo() failed!", gai_strerror(return_value)); } //Create socket for incoming connections for (address = server_address; address != NULL; address = address->ai_next){ //Initialize the server socket server_socket = -1; //Create socket for incoming connections server_socket = socket(server_address->ai_family, server_address->ai_socktype, server_address->ai_protocol); //if socket creation failed, try next address in the list if (server_socket < 0){ continue; } //Bind to the server local address and set socket to the list if ((bind(server_socket, server_address->ai_addr, server_address->ai_addrlen) == 0) && (listen(server_socket, MAX_PENDING) == 0)){ //Get address size address_size = sizeof(local_address); //Get socket name if (getsockname(server_socket, (struct sockaddr*)&local_address, &address_size) < 0){ dieWithSystemMessage("getsockname() failed!"); } //Output local address and port of socket(listening address and port) fputs("Binding to ", stdout); printSocketAddress((struct sockaddr*)&local_address, stdout); fputc('\n', stdout); //Bind and list successful break; } //Close and try again close(server_socket); } //Free address list allocated by getaddrinfo() freeaddrinfo(server_address); return server_socket; }
/*Accept Client Connection Function Variable Definition: -- server_socket: server socket number Return Value: connected client socket number */ int acceptConnection(int server_socket){ struct sockaddr_storage client_address; //client address socklen_t client_address_length; //length of client address structure int client_socket; //socket descriptor for client //Set length of client address structure client_address_length = sizeof(client_address); //Wait for a client to connect client_socket = accept(server_socket, (struct sockaddr*)&client_address, &client_address_length); if (client_socket < 0){ dieWithSystemMessage("accept() failed!"); } //Now, client_socket is connected to a client //Output the socket address and port fputs("Handling client ", stdout); printSocketAddress((struct sockaddr*)&client_address, stdout); fputc('\n', stdout); return client_socket; }
/*Construct Response Message to Client Function Variable Definition: -- client_socket: socket connected to the client -- stream: file stream of socket or server file -- status_code: response status code -- status_message: response status message -- cseq_number: cseq number -- transport: transport field -- last_modified_time: response last modified time field -- content_length: response content length field -- content_type: response content type field -- content: response entity body field Return Value: bytes of whole message */ int constructResponseMessage( int client_socket, FILE **stream, int status_code, const char *status_message, u_int32 cseq_number, const char *transport, const char *last_modified_time, int content_length, const char *content_type, const char *content) { FILE *channel; //file stream for client socket int bytes = 0; //bytes that send to client //Create an output stream to the socket channel = fdopen(client_socket, "w"); if (channel == NULL) { dieWithSystemMessage("fopen() failed"); } //Response Message Status Line bytes = fprintf(channel, "RTSP/1.0 %d %s%s", status_code, status_message, CRLF); //Response Cseq field if (cseq_number != 0) { bytes += fprintf(channel, "Cseq: %u%s", cseq_number, CRLF); } //Response Session field if (session_id != 0) { bytes += fprintf(channel, "Session: %u%s", session_id, CRLF); } //Response Transport field if (transport) { bytes += fprintf(channel, "Transport: %s%s", transport, CRLF); } //Response Date field bytes += fprintf(channel, "Date: %s%s", convertTimeFormat(getTimeInGMTFormat(NULL, 0), 1), CRLF); //Response Server field bytes += fprintf(channel, "Server: Data Communications & Networks: RTSP server by %s (Unix)%s", MY_NAME, CRLF); //Response Last-Modified field if (last_modified_time) { bytes += fprintf(channel, "Last-Modified: %s%s", last_modified_time, CRLF); } //Response Content-Length field if (content_length != 0) { bytes += fprintf(channel, "Content-Length: %d%s", content_length, CRLF); } //Response Message Content-Type field if (content_type) { bytes += fprintf(channel, "Content-Type: %s%s%s", content_type, CRLF, CRLF); } //Response Message Entity Body field if (content) { bytes += fprintf(channel, "%s%s", content, CRLF); } //Flush the channel fflush(channel); //Pass the stream if (stream) { *stream = channel; } else { //Close file stream fclose(channel); } return bytes; }
int main(int argc, char** argv) { const char *transFilePath = TIO_DEFAULT_TRANSLATION_FILE_PATH; unsigned refreshDelay = 0; /* in seconds, 0 = disabled */ const char *logFilePath = 0; /* * syslog isn't installed on the target so it's disabled in this program * by requiring an argument to -o|--log. */ int logToSyslog = 0; unsigned short sioPort = 0; /* 0 means use Unix socket */ unsigned short tioPort = 0; int daemonFlag = 0; int verboseFlag = 0; unsigned short mapSize = MAX_MSG_MAP_SIZE; /* allocate memory for progName since basename() modifies it */ const size_t nameLen = strlen(argv[0]) + 1; char arg0[nameLen]; memcpy(arg0, argv[0], nameLen); progName = basename(arg0); while (1) { static struct option longOptions[] = { { "daemon", no_argument, 0, 'd' }, { "file", required_argument, 0, 'f' }, { "map-size", optional_argument, 0, 'm' }, { "refresh", optional_argument, 0, 'r' }, { "sio_port", optional_argument, 0, 's' }, { "tio_port", optional_argument, 0, 't' }, { "verbose", no_argument, 0, 'v' }, { "help", no_argument, 0, 'h' }, { 0, 0, 0, 0 } }; int c = getopt_long(argc, argv, "df:m:r::s::t::vh?", longOptions, 0); if (c == -1) { break; // no more options to process } switch (c) { case 'd': daemonFlag = 1; break; case 'f': transFilePath = optarg; break; case 'm': mapSize = (optarg == 0) ? MAX_MSG_MAP_SIZE : atoi(optarg); break; case 'r': refreshDelay = (optarg == 0) ? DEFAULT_REFRESH_DELAY : atoi(optarg); break; case 's': sioPort = (optarg == 0) ? SIO_DEFAULT_AGENT_PORT : atoi(optarg); break; case 't': tioPort = (optarg == 0) ? TIO_DEFAULT_AGENT_PORT : atoi(optarg); break; case 'v': verboseFlag = 1; break; case 'h': case '?': default: tioDumpHelp(); exit(1); } } /* set up logging to syslog or file; will be STDERR not told otherwise */ LogOpen(progName, logToSyslog, logFilePath, verboseFlag); /* keep STDIO going for now */ if (daemonFlag) { if (daemon(0, 1) != 0) { dieWithSystemMessage("daemon() failed"); } } tioAgent(transFilePath, refreshDelay, tioPort, TIO_AGENT_UNIX_SOCKET, sioPort, SIO_AGENT_UNIX_SOCKET, mapSize); exit(EXIT_SUCCESS); }
static void tioAgent(const char *translatePath, unsigned refreshDelay, unsigned short tioPort, const char *tioSocketPath, unsigned short sioPort, const char *sioSocketPath, const unsigned short mapSize) { fd_set currFdSet; int connectedFd = -1; /* not currently connected */ time_t lastCheckTime = 0; time_t lastModTime = 0; int addressFamily = 0; TranslatorState *translatorState = GetTranslatorState(); initTranslations(translatorState, mapSize); { /* install a signal handler to remove the socket file */ struct sigaction a; memset(&a, 0, sizeof(a)); a.sa_handler = tioInterruptHandler; if (sigaction(SIGINT, &a, 0) != 0) { LogMsg(LOG_ERR, "[TIO] sigaction(SIGINT) failed, errno = %d\n", errno); exit(1); } if (sigaction(SIGTERM, &a, 0) != 0) { LogMsg(LOG_ERR, "[TIO] sigaction(SIGTERM) failed, errno = %d\n", errno); exit(1); } } /* buffers for collection characters from each side */ struct LineBuffer fromSio; fromSio.pos = 0; struct LineBuffer fromQv; fromQv.pos = 0; /* do initial load, may get reloaded in while loop, below */ lastModTime = loadTranslations(translatorState, translatePath, 0); lastCheckTime = time(0); /* * This is the select loop which waits for characters to be received on the * sio_agent descriptor and on either the listen socket (meaning an * incoming connection is queued) or on a connected socket descriptor. If * not connected to the sio_agent, make select() time out to keep trying to * open a connection to it. */ /* 100ms retry timeout for opening socket to sio_agent */ struct timeval timeout; int sioFd = -1; int listenFd = -1; int nfds = 0; keepGoing = 1; while (keepGoing) { /* try opening a connection to the sio_agent */ if (sioFd < 0) { sioFd = tioSioSocketInit(sioPort, sioSocketPath); if (sioFd >= 0) { FD_ZERO(&currFdSet); FD_SET(sioFd, &currFdSet); nfds = max(sioFd, (connectedFd >= 0) ? connectedFd : listenFd) + 1; /* open socket for qml viewer */ listenFd = tioQvSocketInit(tioPort, &addressFamily, tioSocketPath); if (listenFd < 0) { /* open failed, can't continue */ LogMsg(LOG_ERR, "[TIO] could not open server socket\n"); return; } FD_SET(listenFd, &currFdSet); nfds = listenFd + 1; } } /* figure out timeout value address */ struct timeval *pTimeout = 0; if (sioFd < 0) { /* Linux modifies the timeout value in select() so initialize it */ timeout.tv_sec = 0; timeout.tv_usec = 100000; pTimeout = &timeout; } fd_set readFdSet = currFdSet; const int sel = select(nfds, &readFdSet, 0, 0, pTimeout); if (sel == -1) { if (errno != EINTR) { dieWithSystemMessage("select() returned -1"); } /* else keepGoing was set to 0 in signal handler */ } else if (sel > 0) { /* check for a new connection to accept */ if (FD_ISSET(listenFd, &readFdSet)) { /* new connection is here, accept it */ connectedFd = tioQvSocketAccept(listenFd, addressFamily); if (connectedFd >= 0) { FD_CLR(listenFd, &currFdSet); FD_SET(connectedFd, &currFdSet); nfds = max(sioFd, connectedFd) + 1; } } /* see about auto reloading the translation file */ if ((refreshDelay > 0) && (time(0) > (lastCheckTime + refreshDelay))) { lastModTime = loadTranslations(translatorState, translatePath, lastModTime); lastCheckTime = time(0); } /* check for packet received from qml-viewer */ if ((connectedFd >= 0) && FD_ISSET(connectedFd, &readFdSet)) { /* connected qml-viewer has something to say */ char inMsg[READ_BUF_SIZE]; const int readCount = readLine2(connectedFd, inMsg, sizeof(inMsg), &fromSio, "qml-viewer"); if (readCount < 0) { /* socket closed, stop watching this file descriptor */ FD_CLR(connectedFd, &currFdSet); FD_SET(listenFd, &currFdSet); connectedFd = -1; nfds = max(sioFd, listenFd) + 1; } else if (readCount > 0) { if (sioFd >= 0) { /* * this is a normal message from qml-viewer, translate * it and send the result to sio_agent */ char outMsg[READ_BUF_SIZE]; translate_gui_msg(translatorState, inMsg, outMsg, sizeof(outMsg)); tioSioSocketWrite(sioFd, outMsg); tioSioSocketWrite(sioFd, "\r"); } } } /* check for anything from sio_agent connection */ if ((sioFd >= 0) && FD_ISSET(sioFd, &readFdSet)) { /* * sio_agent socket port has something to send to the * tio_agent, if connected */ char inMsg[READ_BUF_SIZE]; int readCount = readLine2(sioFd, inMsg, sizeof(inMsg), &fromQv, "sio-agent"); if (readCount < 0) { /* fall out of this loop to reopen connection to sio_agent */ FD_CLR(sioFd, &currFdSet); sioFd = -1; if(connectedFd >=0) { close(connectedFd); } connectedFd = -1; FD_CLR(connectedFd, &currFdSet); if(listenFd >=0) { close(listenFd); } listenFd = -1; FD_CLR(listenFd, &currFdSet); nfds = 0; } else if ((readCount > 0) && (connectedFd >= 0)) { char outMsg[READ_BUF_SIZE]; translate_micro_msg(translatorState, inMsg, outMsg, sizeof(outMsg)); tioQvSocketWrite(connectedFd, outMsg); tioQvSocketWrite(connectedFd, "\n"); } } } /* else timeout to retry opening sio_agent socket */ } LogMsg(LOG_INFO, "[TIO] cleaning up\n"); freeTranslations(translatorState); if (connectedFd >= 0) { close(connectedFd); } if (listenFd >= 0) { close(listenFd); } if (sioFd >= 0) { close(sioFd); } if (tioPort == 0) { /* best effort removal of socket */ const int rv = unlink(tioSocketPath); if (rv == 0) { LogMsg(LOG_INFO, "[TIO] socket file %s unlinked\n", tioSocketPath); } else { LogMsg(LOG_INFO, "[TIO] socket file %s unlink failed\n", tioSocketPath); } } }
/*Main Function Variable Definition: -- argc: the number of command arguments -- argv[]: each vairable of command arguments(argv[0] is the path of execution file forever) Return Value: Client exit number */ int main(int argc, char *argv[]){ //Test for correct number of arguments if (argc != 3){ dieWithUserMessage("Parameter(s)", "<Server Address/Name> <Server Port/Service>"); } struct sigaction handler; //signal handler const char *host = argv[1]; //first argument: host name/ip address const char *service = argv[2]; //second argument: server listening port number int rcvd_buffer_size = 50 * BUFFER_SIZE; //received buffer size //Initialize Pinger initPinger(); //Create a unreliable UDP socket client_socket = setupClientSocket(host, service); if (client_socket < 0){ dieWithSystemMessage("setupClientSocket() failed"); } //Set the received buffer size setsockopt(client_socket, SOL_SOCKET, SO_RCVBUF, &rcvd_buffer_size, sizeof(rcvd_buffer_size)); //Set signal handler for alarm signal handler.sa_handler = catchAlarm; //Blocking everything in handler if (sigfillset(&handler.sa_mask) < 0){ dieWithSystemMessage("sigfillset() failed"); } //No flags handler.sa_flags = 0; //Set the "SIGALRM" signal if (sigaction(SIGALRM, &handler, 0) < 0){ dieWithSystemMessage("sigaction() failed for SIGALRM"); } //Set the "SIGINT" signal if (sigaction(SIGINT, &handler, 0) < 0){ dieWithSystemMessage("sigaction() failed for SIGINT"); } //Output the title printf("PING %s (", host); printSocketAddress((struct sockaddr*)address->ai_addr, stdout); printf(") result:\n"); //Sleep for 1 second sleep(TIMEOUT); //Start to send ping message while (send_count < PING_SIZE){ sendPingMessage(); rcvdPingMessage(TIMEOUT); } //You should put sleep function inside the while loop and after rcvdPingMessage, and you should sleep for TIMEOUT - rtt value for this cycle #13 -4 //Determine that no more replies that comes in if (send_count != rcvd_count){ rcvdPingMessage(REPLY_TIMEOUT); } //SIGINT signal: construct ping statistics catchAlarm(SIGINT); return 0; }