void trick_error_set_send_hs_flag(TrickErrorHndlr * error_hndlr, /* Inout: Err handler data */ TrickErrorLevel level, /* In: Err report level stream to set */ int use_send_hs) { /* In: 1= use send_hs;else use fprintf */ /* Check for setting of default error handling object. */ if (error_hndlr == (TrickErrorHndlr *) NULL) { error_hndlr = &(trick_error_hndlr_default); } /* Check sanity of reporting level. */ if (level > TRICK_ERROR_SILENT) { trick_error_report(error_hndlr, TRICK_ERROR_ALERT, __FILE__, __LINE__, "Unknown error level for " "trick_error_set_send_hs_flag; level unchanged.\n"); return; } /* Set the appropriate use_send_hs flag */ error_hndlr->use_send_hs[level] = use_send_hs; /* warn the user that send_hs has been replaced with fprintf */ trick_error_report(error_hndlr, TRICK_ERROR_ALERT, __FILE__, __LINE__, "trick_error_set_send_hs_flag no longer supported. All printouts will use fprintf\n"); return; }
void trick_error_set_stream(TrickErrorHndlr * error_hndlr, /* INOUT: Error handler data */ TrickErrorLevel level, /* IN: Err report level stream to set */ FILE * stream) { /* IN: Err stream for report level */ /* Check for setting of default error handling object. */ if (error_hndlr == (TrickErrorHndlr *) NULL) { error_hndlr = &(trick_error_hndlr_default); } /* Check sanity of reporting level. */ if (level > TRICK_ERROR_SILENT) { trick_error_report(error_hndlr, TRICK_ERROR_ALERT, __FILE__, __LINE__, "Unknown error level for " "trick_error_set_stream; level unchanged.\n"); return; } /* Set the appropriate file stream pointer. */ if (stream == (FILE *) NULL) { error_hndlr->report_stream[level] = stderr; } else { error_hndlr->report_stream[level] = stream; } return; }
int tc_read_byteswap(TCDevice * device, char *buffer, int size, ATTRIBUTES * attr) { char local_byteorder; int ret = 0; static char swap[65536]; if (!device) { TrickErrorHndlr *temp_error_hndlr = NULL; trick_error_report(temp_error_hndlr, TRICK_ERROR_ALERT, __FILE__, __LINE__, "Trying to read_byteswap to a NULL device"); return (-1); } TRICK_GET_BYTE_ORDER(local_byteorder) if (device->byte_info[TC_BYTE_ORDER_NDX] != local_byteorder) { memset(swap, 0, (size_t) size); ret = tc_read(device, (char *) swap, size); trick_bswap_buffer(buffer, swap, attr, 0); return (ret); } else { return (tc_read(device, (char *) buffer, size)); } return 0; }
int tc_error(TCDevice * device, int on_off) { size_t size; if (!device) { TrickErrorHndlr *temp_error_hndlr = NULL; trick_error_report(temp_error_hndlr, TRICK_ERROR_ALERT, __FILE__, __LINE__, "Trying to set up error handler on NULL device"); return (-1); } /* If there is no error handler, initialize one */ if (device->error_handler == NULL) { size = sizeof(TrickErrorHndlr); device->error_handler = (TrickErrorHndlr *) malloc(size); trick_error_init(device->error_handler, NULL, NULL, TRICK_ERROR_ALL); } /* Now turn on/off */ if (on_off == 1) { device->error_handler->report_level = TRICK_ERROR_ALL; } else { device->error_handler->report_level = TRICK_ERROR_SILENT; } return 0; }
int tc_multiconnect(TCDevice * dev_ptr, char *my_tag, char *other_tag, TrickErrorHndlr * not_used) { int status; int num_try = 0; TCDevice *server_device; char name[80]; int size; char *cptr; /* Multicast vars */ struct sockaddr_in addr; int fd, nbytes; struct ip_mreq mreq; BC_INFO bc_info, *bc_copy; SEND_ME read_me; int i_am_client; int value; int num_attempts = 10; int found_conn; #ifdef __WIN32__ HANDLE thread; DWORD threadId; int curr_pid; WSADATA wsaData; #else pthread_t thread; pid_t curr_pid; #endif (void) not_used; /* unused */ if (!dev_ptr) { TrickErrorHndlr *temp_error_hndlr = NULL; trick_error_report(temp_error_hndlr, TRICK_ERROR_ALERT, __FILE__, __LINE__, "Trying to connect a NULL device"); return (-1); } if (dev_ptr->disabled != 0) { trick_error_report(dev_ptr->error_handler, TRICK_ERROR_ALERT, __FILE__, __LINE__, "[33m%s| cannot connect disabled device %s[00m\n", my_tag, other_tag); return (TC_SUCCESS); } trick_error_report(dev_ptr->error_handler, TRICK_ERROR_ADVISORY, __FILE__, __LINE__, "[36m%s| multiconnecting to %s[00m\n", my_tag, other_tag); /* Create a TrickComm listen device Determine port for listen device */ server_device = (TCDevice *) malloc(sizeof(TCDevice)); memset((void *) server_device, '\0', sizeof(TCDevice)); server_device->error_handler = dev_ptr->error_handler; server_device->port = 0; if ((status = tc_init(server_device)) != TC_SUCCESS) { trick_error_report(server_device->error_handler, TRICK_ERROR_ALERT, __FILE__, __LINE__, "could not open listen device!\n"); return (status); } /* * Initialize Broadcast Info Structure */ gethostname(name, (size_t) 80); strcpy(bc_info.send_me.addr, name); bc_info.send_me.port = server_device->port; bc_info.send_me.pid = curr_pid = getpid(); bc_info.send_me.conn_initiated = 0; if (my_tag != (char *) NULL) { strncpy(bc_info.send_me.my_tag, my_tag, (size_t) TC_TAG_LENGTH); bc_info.send_me.my_tag[TC_TAG_LENGTH - 1] = '\0'; } else { bc_info.send_me.my_tag[0] = '\0'; } if (other_tag != (char *) NULL) { strncpy(bc_info.send_me.other_tag, other_tag, (size_t) TC_TAG_LENGTH); bc_info.send_me.other_tag[TC_TAG_LENGTH - 1] = '\0'; } else { bc_info.send_me.other_tag[0] = '\0'; } bc_info.device = dev_ptr; #ifdef __WIN32__ /* Initiate use of the Windows socket DLL */ if (WSAStartup(0x202, &wsaData) == SOCKET_ERROR) { perror("tc_multiconnect: WSAStartup"); WSACleanup(); return (TC_COULD_NOT_ACCEPT); } #endif /* Create the broadcast socket */ if ((bc_info.fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { perror("tc_multiconnect socket"); } /* Set up destination address */ memset(&bc_info.addr, 0, sizeof(bc_info.addr)); bc_info.addr.sin_family = AF_INET; bc_info.addr.sin_addr.s_addr = inet_addr(TC_MULT_GROUP); bc_info.addr.sin_port = htons(TC_MULT_PORT); /* * Create socket to listen for connections */ if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { perror("tc_multiconnect socket"); } value = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &value, (socklen_t) sizeof(value)) < 0) { perror("setsockopt: reuseaddr"); } #ifdef SO_REUSEPORT if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (char *) &value, sizeof(value)) < 0) { perror("setsockopt: reuseport"); } #endif /* Set up destination address */ memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(INADDR_ANY); addr.sin_port = htons(TC_MULT_PORT); /* Bind to receive address */ if (bind(fd, (struct sockaddr *) &addr, (socklen_t) sizeof(addr)) < 0) { perror("tc_multiconnect bind"); } /* Use setsockopt() to request that the kernel join a multicast group */ mreq.imr_multiaddr.s_addr = inet_addr(TC_MULT_GROUP); mreq.imr_interface.s_addr = htonl(INADDR_ANY); size = sizeof(mreq); cptr = (char *) &mreq; if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, cptr, (socklen_t) size) < 0) { #ifdef __WIN32__ TCHAR szError[100]; // Error message string wsprintf(szError, TEXT("setsockopt failed! Error: %d"), WSAGetLastError()); MessageBox(NULL, szError, TEXT("Error"), MB_OK); #endif perror("setsockopt: ip_add_membership"); } /* Create thread that will continually broadcast connection info on multicast port for prospective clients. */ /* make a copy of info to broadcast */ bc_copy = (BC_INFO *) malloc(sizeof(BC_INFO)); memcpy(bc_copy, &bc_info, sizeof(BC_INFO)); #ifdef __WIN32__ thread = CreateThread(NULL, 0, tc_broadcast_conninfo, &bc_copy, 0, &threadId); #else pthread_create(&thread, NULL, tc_broadcast_conninfo, bc_copy); #endif /* Wait for other peers wanting to connect to me */ i_am_client = 0; found_conn = 0; while (found_conn == 0) { do { nbytes = recvfrom(fd, &read_me, sizeof(SEND_ME), 0, NULL, NULL); } while ((nbytes == -1) && (tc_errno == TRICKCOMM_EINTR)); if (nbytes == sizeof(read_me)) { /* * Read information from peer */ read_me.port = ntohl((uint32_t) read_me.port); read_me.pid = ntohl((uint32_t) read_me.pid); read_me.conn_initiated = ntohl((uint32_t) read_me.conn_initiated); /* May I connect with this peer? Rules: Don't connect to myself! Don't connect to someone with same tag as myself Do connect to someone with same "other tag" */ if (curr_pid != read_me.pid && strcmp(bc_info.send_me.my_tag, read_me.my_tag) && !strcmp(bc_info.send_me.other_tag, read_me.other_tag)) { /* Decide who will function as client Whoever has smaller pid will be the client If same pid, decide by a string compare */ if (curr_pid < read_me.pid) { i_am_client = 1; } else if (curr_pid == read_me.pid) { i_am_client = (strcmp(name, read_me.addr) > 0) ? 1 : 0; } /* * Client Peer initiates the connection */ if (i_am_client == 1) { /* Save off addr and port to connect */ size = strlen(read_me.addr) + 1; dev_ptr->hostname = (char *) malloc((size_t) size); strcpy(dev_ptr->hostname, read_me.addr); dev_ptr->port = read_me.port; read_me.conn_initiated = 1; read_me.port = htonl((uint32_t) read_me.port); read_me.pid = htonl((uint32_t) read_me.pid); read_me.conn_initiated = htonl((uint32_t) read_me.conn_initiated); sendto(bc_info.fd, (char *) &read_me, sizeof(SEND_ME), 0, (struct sockaddr *) &bc_info.addr, (socklen_t) sizeof(bc_info.addr)); found_conn = 1; } } else if (curr_pid == read_me.pid && !strcmp(bc_info.send_me.addr, read_me.addr) && !strcmp(bc_info.send_me.my_tag, read_me.my_tag) && !strcmp(bc_info.send_me.other_tag, read_me.other_tag) && read_me.conn_initiated == 1) { found_conn = 1; } } } if (other_tag != (char *) NULL) { strncpy(dev_ptr->client_tag, other_tag, (size_t) TC_TAG_LENGTH); dev_ptr->client_tag[TC_TAG_LENGTH - 1] = '\0'; } if (i_am_client == 1) { /* Client connects */ /* Disconnect unneeded listen device */ tc_disconnect(server_device); free((void *) server_device); tc_set_blockio_timeout_limit(dev_ptr, MAX_BLOCKIO_TIMEOUT_LIMIT); status = 1; while ((status != TC_SUCCESS) && (num_try < num_attempts)) { status = tc_connect(dev_ptr); #if __WIN32__ Sleep(200); #else usleep(200000); #endif num_try++; } } else { /* * Server accepts */ status = 1; while (status != TC_SUCCESS && (num_try < num_attempts)) { if (tc_listen(server_device)) { status = tc_accept(server_device, dev_ptr); if (dev_ptr != NULL) { tc_set_blockio_timeout_limit(dev_ptr, MAX_BLOCKIO_TIMEOUT_LIMIT); } } num_try++; #if __WIN32__ Sleep(200); #else usleep(200000); #endif } tc_disconnect(server_device); free((void *) server_device); } if (status != TC_SUCCESS) { trick_error_report(server_device->error_handler, TRICK_ERROR_ALERT, __FILE__, __LINE__, "could not open connection!\n"); return (status); } /* Shutdown the broadcast */ shutdown(bc_info.fd, 2); /* Return the pointer to the TCDevice as the tc_id. */ return (TC_SUCCESS); }
/* *Set a device to BLOCKIO or NOBLOCKIO - may be used as a toggle */ int tc_blockio(TCDevice * device, TCCommBlocking blockflag) { char client_str[TC_TAG_LENGTH + 256]; int on = 1; int off = 0; if (device == NULL) { return TC_EWOULDBLOCK; } /* Status message */ sprintf(client_str, "(ID = %d tag = %s)", device->client_id, device->client_tag); trick_error_report(device->error_handler, TRICK_ERROR_TRIVIAL, __FILE__, __LINE__, "%s blockflag = %d\n", client_str, blockflag); switch (blockflag) { case TC_COMM_BLOCKIO: /* Set socket to blocking */ if (IOCTL_SOCKET(device->socket, (unsigned long) FIONBIO, &off) < 0) { trick_error_report(device->error_handler, TRICK_ERROR_ALERT, __FILE__, __LINE__, "could not set socket to blocking\n"); return (TC_EWOULDBLOCK); } device->blockio_type = blockflag; break; case TC_COMM_NOBLOCKIO: /* Set socket to non-blocking */ if (IOCTL_SOCKET(device->socket, (unsigned long) FIONBIO, &on) < 0) { trick_error_report(device->error_handler, TRICK_ERROR_ALERT, __FILE__, __LINE__, "could not set socket to non-blocking\n"); return (TC_EWOULDBLOCK); } device->blockio_type = blockflag; break; case TC_COMM_TIMED_BLOCKIO: /* Set socket to non-blocking */ if (IOCTL_SOCKET(device->socket, (unsigned long) FIONBIO, &on) < 0) { trick_error_report(device->error_handler, TRICK_ERROR_ALERT, __FILE__, __LINE__, "could not set socket to software-blocking\n"); return (TC_EWOULDBLOCK); } device->blockio_type = blockflag; break; case TC_COMM_ALL_OR_NOTHING: /* Set socket to non-blocking */ if (IOCTL_SOCKET(device->socket, (unsigned long) FIONBIO, &on) < 0) { trick_error_report(device->error_handler, TRICK_ERROR_ALERT, __FILE__, __LINE__, "could not set socket to all_or nothing\n"); return (TC_EWOULDBLOCK); } device->blockio_type = blockflag; break; default: trick_error_report(device->error_handler, TRICK_ERROR_ALERT, __FILE__, __LINE__, "Invalid second argument." "Second argument should be one of the following:\n" " TC_COMM_BLOCKIO,\n" " TC_COMM_NOBLOCKIO,\n" " TC_COMM_TIMED_BLOCKIO,\n" " TC_COMM_ALL_OR_NOTHING\n\n"); return (TC_EWOULDBLOCK); } return (0); }
int tc_read_(TCDevice * device, char *buffer, int size, const char *file, int line) { long nbytes = 0; char client_str[TC_TAG_LENGTH + 20]; long tmp_nbytes = 0; long tmp_size = (long) size; void *data = (void *) buffer; double ref_time = 0; double delta = 0; int error = TC_SUCCESS; char error_str[512]; // To support UDP unsigned int cliLen = sizeof(struct sockaddr_in); if (!device) { TrickErrorHndlr *temp_error_hndlr = NULL; trick_error_report(temp_error_hndlr, TRICK_ERROR_ALERT, file, line, "tc_read: Trying to read from a NULL device"); return (-1); } if (device->disabled) { trick_error_report(device->error_handler, TRICK_ERROR_ALERT, file, line, "tc_read: Trying to read from a disabled device"); return (-1); } if (device->socket == TRICKCOMM_INVALID_SOCKET) { trick_error_report(device->error_handler, TRICK_ERROR_ALERT, file, line, "tc_read: Trying to read from an invalid socket"); return (-1); } sprintf(client_str, "(ID = %d tag = %s)", device->client_id, device->client_tag); trick_error_report(device->error_handler, TRICK_ERROR_ALL, file, line, "tc_read: %s reading %d bytes\n", client_str, size); /* If this is a software blocking read get the current time from the system */ if (device->blockio_type == TC_COMM_TIMED_BLOCKIO) { ref_time = tc_clock_init(); } /* * Spin until all requested data is * available, an error is returned from recv, or a timeout * limit has been reached. This code is needed for the * socket because sockets can return less * data than what was requested when data packets * cross block boundries. */ while (nbytes != size) { /* * recvfrom will return -1 with tc_errno set to TC_EWOULDBLOCK * if this is a non-blocking socket (blockio = NOBLOCKIO) * and no data is available. recvfrom will usually return 0 * for a broken connection. */ while ((tmp_nbytes = recvfrom(device->socket, data, (size_t) tmp_size, TC_NOSIGNAL, (struct sockaddr *) &device->cliAddr, &cliLen)) < 0 && tc_errno == TRICKCOMM_EINTR); /* if tmp_nbytes == 0, that is a broken pipe, break out */ if (tmp_nbytes == 0) { trick_error_report(device->error_handler, TRICK_ERROR_ALERT, file, line, "tc_read: %s Other side disconnected. (recvfrom returned 0)", client_str); tc_disconnect(device); return (nbytes); } else if (tmp_nbytes == -1) { error = tc_errno; if (error != TRICKCOMM_EAGAIN && error != TRICKCOMM_EWOULDBLOCK) { sprintf(error_str, "tc_read: %s %s (tc_errno = %d)", client_str, strerror(error), error); trick_error_report(device->error_handler, TRICK_ERROR_ALERT, file, line, error_str); tc_disconnect(device); return (nbytes); } } /* Keep track of total number of bytes read */ else if (tmp_nbytes > 0) { #if 0 /* This indicates the socket protocol: SOCK_STREAM (1) or SOCK_DGRAM (2). */ int proto_for_socket; int opt_len = 4; int retval; /* Get the socket protocol */ retval = getsockopt(device->socket, SOL_SOCKET, SO_TYPE, (void *) &proto_for_socket, (socklen_t *) & opt_len); if (retval < 0) { perror("tc_read: getsockopt"); trick_error_report(device->error_handler, TRICK_ERROR_ALERT, file, line, "Couldn't get the socket protocol. Assumed TCP/IP (not UDP)"); proto_for_socket = SOCK_STREAM; } #endif nbytes += tmp_nbytes; /* For UDP (SOCK_DGRAM) just return data with whatever number of bytes were received. */ if (device->socket_type == SOCK_DGRAM) break; } /* Adjust data pointers for partial reads */ if (tmp_nbytes > 0 && tmp_nbytes != tmp_size) { data = (void *) ((char *) data + tmp_nbytes); tmp_size -= tmp_nbytes; } if (device->blockio_type == TC_COMM_TIMED_BLOCKIO) { delta = tc_clock_time(ref_time); /* Check for timeouts; this prevents hanging here if the writer dies */ if (device->blockio_limit < delta && nbytes != size) { error = TC_READWRITE_TIMEOUT; break; } } else if (device->blockio_type == TC_COMM_ALL_OR_NOTHING) { /* If nothing read and nothing pending break out */ if (nbytes == 0 && tmp_nbytes == -1 && (tc_errno == TRICKCOMM_EWOULDBLOCK || tc_errno == TRICKCOMM_EAGAIN)) { nbytes = -1; error = TC_EWOULDBLOCK; break; } /* If something read release processor and loop back for more */ else if (tmp_nbytes == -1 && tc_errno == TRICKCOMM_EWOULDBLOCK) { /* Yield the processor so queued proceses may run */ TC_RELEASE(); } } else if (device->blockio_type == TC_COMM_NOBLOCKIO) { if (tmp_nbytes == -1 && (tc_errno == TRICKCOMM_EWOULDBLOCK || tc_errno == TRICKCOMM_EAGAIN)) { if (nbytes == 0) { nbytes = -1; } error = TC_EWOULDBLOCK; break; } } } /* If read doesn't capture all data, handle it. */ switch (error) { case TC_READWRITE_TIMEOUT: trick_error_report(device->error_handler, TRICK_ERROR_ADVISORY, file, line, "tc_read: %s Failed to read within the specified " "time limit of %f seconds. delta = %f", client_str, device->blockio_limit, delta); break; case TC_EWOULDBLOCK: trick_error_report(device->error_handler, TRICK_ERROR_ALL, file, line, "tc_read: %s %d of %d bytes read during " "non-blocking read.", client_str, nbytes, size); break; case TC_SUCCESS: trick_error_report(device->error_handler, TRICK_ERROR_ALL, file, line, "tc_read: %s: %d bytes successfully read\n", client_str, nbytes); break; } return ((int) nbytes); }