/* * Initializes all listening servers and their structures, * if the data is already initialized 0 is returned and the call * has no effect */ int SIOInit(int stdoutPort, int stderrPort) { int last_error; /* check for status */ if (sio_servers_initialized == 1) { return 0; } /* check port numbers */ if (stdoutPort < 0 && stderrPort < 0) { return 0; } else { /* provider should start must start both sockets so make sure values are correct */ if (stdoutPort < 0) { stdoutPort = 0; } if (stderrPort < 0) { stderrPort = 0; } } /* start WSA */ sio_debug("Starting WSA"); last_error = sio_init_WSA(); if (last_error != 0) { return last_error; } /* init servers */ sio_debug("Initializinig servers with ports %d and %d", stdoutPort, stderrPort); last_error = sio_init_server(&sio_stdout_server, stdoutPort); if (last_error != 0) { return last_error; } last_error = sio_init_server(&sio_stderr_server, stderrPort); if (last_error != 0) { return last_error; } /* start servers */ sio_debug("Starting servers"); last_error = sio_start_server(&sio_stdout_server); if (last_error != 0) { return last_error; } last_error = sio_start_server(&sio_stderr_server); if (last_error != 0) { return last_error; } sio_servers_initialized = 1; return 0; }
/* * Acquires the Mutex for current thread */ static void sio_lock_clients(SIO_SERVER * server) { DWORD wait_result; int last_error; wait_result = WaitForSingleObject(server->clients.mutex, INFINITE); while (wait_result != WAIT_OBJECT_0) { if (wait_result == WAIT_FAILED) { sio_handle_system_error("Canot obtain mutex lock"); return; } else { sio_debug("Failed to obtain lock with result %d. Trying again", wait_result); } wait_result = WaitForSingleObject(server->clients.mutex, INFINITE); } sio_debug("LOCK"); }
/* * Sends supplied data to all connected clients * This function acquires its own lock */ static int sio_send_data_to_clients(SIO_SERVER * server, char * data, int len) { int cli_iter, add_iter; int * log; /* prepare log */ sio_lock_clients(server); log = (int *) malloc(server->clients.count * sizeof(int)); /* send data to clients */ for ( cli_iter = 0; cli_iter < server->clients.count; cli_iter++ ) { if (send(server->clients.list[cli_iter], data, len, 0) == SOCKET_ERROR) { log[cli_iter] = sio_handle_WSA_error("Canot send data to client, closing"); } else { log[cli_iter] = 0; } } /* remove disfunctional sockets */ add_iter = 0; for ( cli_iter = 0; cli_iter < server->clients.count; cli_iter++ ) { if (log[cli_iter] == 0) { server->clients.list[add_iter] = server->clients.list[cli_iter]; add_iter++; } } free(log); server->clients.count = add_iter; sio_debug("Sent %d bytes to %d clients", len, server->clients.count); sio_unlock_clients(server); return 0; }
/* * Initializes the WSA Provider */ static int sio_init_WSA() { int error_code; error_code = WSAStartup(WINSOCK_VERSION, &sio_WSA_data); if (error_code != 0) { sio_debug("WSAStartup() failed with error code = %d", error_code); return error_code; } else { return 0; } }
/* * Reads port information from socket */ int sio_get_server_port(SIO_SERVER * server) { struct sockaddr_in address; int len = sizeof(address); if (getsockname(server->socket, (SOCKADDR*) &address, &len) == SOCKET_ERROR) { return sio_handle_WSA_error("Canot retrieve server address"); } else { server->port = ntohs(address.sin_port); sio_debug("Server started on port %d", server->port); return 0; } }
/* * Adds a client to active clients registry * Performs registry expansion if necessary * Current thread must hold the registry Mutex in order to guarantee * thread-security */ static void sio_add_client(SIO_SERVER * server, SOCKET client) { SOCKET * old_clients = NULL; int i = 0; /* expand if necessary */ if (server->clients.count == server->clients.length) { sio_debug("Expanding clients array"); old_clients = server->clients.list; server->clients.length += SIO_CLIENTS_DELTA; server->clients.list = (SOCKET *) malloc(server->clients.length * sizeof(SOCKET)); for (i = 0; i < server->clients.count; i++) { server->clients.list[i] = old_clients[i]; } free(old_clients); sio_debug("Done"); } /* add a client */ server->clients.list[server->clients.count] = client; server->clients.count++; sio_debug("Client added"); }
/* * Prints a debug error message for given error code with given * descrioption and error type */ static int sio_handle_error(char * type, char * msg, int error_code) { #ifdef SIO_DEBUG LPVOID message_buffer; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK, NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &message_buffer, 0, NULL ); sio_debug("%s Error occured: %s. Error: %d (%s).", type, msg, error_code, message_buffer); LocalFree(message_buffer); #endif return error_code; }
/* * Closes the listening socket and performs cleanup of alocated resources */ static int sio_stop_server(SIO_SERVER * server) { sio_cleanup_clients(server); /* close listening socket */ if (closesocket(server->socket) == SOCKET_ERROR) { return sio_handle_WSA_error("Canot close server socket"); } /* wait for listen thread to end */ WaitForSingleObject(server->thread, INFINITE); CloseHandle(server->thread); CloseHandle(server->clients.mutex); sio_debug("Server stopped"); return 0; }
/* * Accepts clients on a socked * If the socket is closed or WSA disabled the function shuts down */ static int sio_accept_clients(SIO_SERVER * server) { SOCKET new_client; int res = 0; sio_debug("Listener thread started"); while (1) { new_client = accept(server->socket, NULL, NULL); if (server->clients.length <= 0) { sio_debug("Server terminating."); closesocket(new_client); res = 0; break; } else if (new_client == INVALID_SOCKET) { res = sio_handle_WSA_error("Error while accepting client. Stopping server."); break; } else { sio_lock_clients(server); sio_add_client(server, new_client); sio_unlock_clients(server); } } sio_debug("Listener finished"); return res; }
void debug(void) { vlist_i *it; pipe_s *pit; int i = 1; fprintf(stderr, "pipes:\n\n"); vlist_debug(&pipes, stderr); for (it = pipes.head; it; it = it->next) { pit = (pipe_s *)it->data; fprintf(stderr, "sio[%d]:\n\n", i); sio_debug(&pit->sio, stderr); fprintf(stderr, "sock[%d]:\n\n", i); tcp_debug(&pit->sock, stderr); i++; } }
/* * Terminates all running servers * If the module was not started using sio_init * 0 is returned and nothing is done. */ int SIOStop() { int last_error = 0; /* check status */ if (sio_servers_initialized == 0) { return 0; } /* stop servers */ last_error = sio_stop_server(&sio_stdout_server); if (last_error != 0) { return last_error; } last_error = sio_stop_server(&sio_stderr_server); if (last_error != 0) { return last_error; } /* stop WSA */ if (sio_stop_WSA() != 0) { return sio_handle_WSA_error("Canot stop WSA provider"); } sio_servers_initialized = 0; sio_debug("Socket IO provider stopped"); return 0; }
/* * Releases Mutex acqired for current thread */ static void sio_unlock_clients(SIO_SERVER * server) { if (!ReleaseMutex(server->clients.mutex)) { sio_handle_system_error("Canot release mutex"); } sio_debug("UNLOCK"); }