/* * Clean up a socket on exit * This helps reduce problems with vxWorks when the IOC restarts */ static void cleanup (void *arg) { asynStatus status; ttyController_t *tty = (ttyController_t *)arg; if (!tty) return; status=pasynManager->lockPort(tty->pasynUser); if(status!=asynSuccess) asynPrint(tty->pasynUser, ASYN_TRACE_ERROR, "%s: cleanup locking error\n", tty->portName); if (tty->fd != INVALID_SOCKET) { asynPrint(tty->pasynUser, ASYN_TRACE_FLOW, "%s: shutdown socket\n", tty->portName); tty->flags |= FLAG_SHUTDOWN; /* prevent reconnect */ epicsSocketDestroy(tty->fd); tty->fd = INVALID_SOCKET; /* If this delay is not present then the sockets are not always really closed cleanly */ epicsThreadSleep(CLOSE_SOCKET_DELAY); } if(status==asynSuccess) pasynManager->unlockPort(tty->pasynUser); }
SOCKET BlockingTCPConnector::tryConnect(osiSockAddr& address, int tries) { char strBuffer[64]; ipAddrToDottedIP(&address.ia, strBuffer, sizeof(strBuffer)); for(int tryCount = 0; tryCount<tries; tryCount++) { LOG(logLevelDebug, "Opening socket to PVA server %s, attempt %d.", strBuffer, tryCount+1); SOCKET socket = epicsSocketCreate(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (socket == INVALID_SOCKET) { epicsSocketConvertErrnoToString(strBuffer, sizeof(strBuffer)); std::ostringstream temp; temp<<"Socket create error: "<<strBuffer; THROW_EXCEPTION2(std::runtime_error, temp.str()); } else { // TODO: use non-blocking connect() to have controllable timeout if(::connect(socket, &address.sa, sizeof(sockaddr))==0) { return socket; } else { epicsSocketConvertErrnoToString(strBuffer, sizeof(strBuffer)); char saddr[32]; sockAddrToDottedIP(&address.sa, saddr, sizeof(saddr)); epicsSocketDestroy (socket); std::ostringstream temp; temp<<"error connecting to "<<saddr<<" : "<<strBuffer; throw std::runtime_error(temp.str()); } } } return INVALID_SOCKET; }
/* * create_client () */ struct client * create_client ( SOCKET sock, int proto ) { struct client *client; int spaceAvailOnFreeList; size_t spaceNeeded; /* * stop further use of server if memory becomes scarse */ spaceAvailOnFreeList = freeListItemsAvail ( rsrvClientFreeList ) > 0 && freeListItemsAvail ( rsrvSmallBufFreeListTCP ) > 0; spaceNeeded = sizeof (struct client) + MAX_TCP; if ( ! ( osiSufficentSpaceInPool(spaceNeeded) || spaceAvailOnFreeList ) ) { epicsSocketDestroy ( sock ); epicsPrintf ("CAS: no space in pool for a new client (below max block thresh)\n"); return NULL; } client = freeListCalloc ( rsrvClientFreeList ); if ( ! client ) { epicsSocketDestroy ( sock ); epicsPrintf ("CAS: no space in pool for a new client (alloc failed)\n"); return NULL; } client->sock = sock; client->proto = proto; client->blockSem = epicsEventCreate ( epicsEventEmpty ); client->lock = epicsMutexCreate(); client->putNotifyLock = epicsMutexCreate(); client->chanListLock = epicsMutexCreate(); client->eventqLock = epicsMutexCreate(); if ( ! client->blockSem || ! client->lock || ! client->putNotifyLock || ! client->chanListLock || ! client->eventqLock ) { destroy_client ( client ); return NULL; } client->pUserName = NULL; client->pHostName = NULL; ellInit ( & client->chanList ); ellInit ( & client->chanPendingUpdateARList ); ellInit ( & client->putNotifyQue ); memset ( (char *)&client->addr, 0, sizeof (client->addr) ); client->tid = 0; if ( proto == IPPROTO_TCP ) { client->send.buf = (char *) freeListCalloc ( rsrvSmallBufFreeListTCP ); client->send.maxstk = MAX_TCP; client->send.type = mbtSmallTCP; client->recv.buf = (char *) freeListCalloc ( rsrvSmallBufFreeListTCP ); client->recv.maxstk = MAX_TCP; client->recv.type = mbtSmallTCP; } else if ( proto == IPPROTO_UDP ) { client->send.buf = malloc ( MAX_UDP_SEND ); client->send.maxstk = MAX_UDP_SEND; client->send.type = mbtUDP; client->recv.buf = malloc ( MAX_UDP_RECV ); client->recv.maxstk = MAX_UDP_RECV; client->recv.type = mbtUDP; } if ( ! client->send.buf || ! client->recv.buf ) { destroy_client ( client ); return NULL; } client->send.stk = 0u; client->send.cnt = 0u; client->recv.stk = 0u; client->recv.cnt = 0u; client->evuser = NULL; client->priority = CA_PROTO_PRIORITY_MIN; client->disconnect = FALSE; epicsTimeGetCurrent ( &client->time_at_last_send ); epicsTimeGetCurrent ( &client->time_at_last_recv ); client->minor_version_number = CA_UKN_MINOR_VERSION; client->recvBytesToDrain = 0u; return client; }
/* * * req_server() * * CA server task * * Waits for connections at the CA port and spawns a task to * handle each of them * */ static void req_server (void *pParm) { unsigned priorityOfSelf = epicsThreadGetPrioritySelf (); unsigned priorityOfBeacons; epicsThreadBooleanStatus tbs; struct sockaddr_in serverAddr; /* server's address */ osiSocklen_t addrSize; int status; SOCKET clientSock; epicsThreadId tid; int portChange; epicsSignalInstallSigPipeIgnore (); taskwdInsert ( epicsThreadGetIdSelf (), NULL, NULL ); rsrvCurrentClient = epicsThreadPrivateCreate (); if ( envGetConfigParamPtr ( &EPICS_CAS_SERVER_PORT ) ) { ca_server_port = envGetInetPortConfigParam ( &EPICS_CAS_SERVER_PORT, (unsigned short) CA_SERVER_PORT ); } else { ca_server_port = envGetInetPortConfigParam ( &EPICS_CA_SERVER_PORT, (unsigned short) CA_SERVER_PORT ); } if (IOC_sock != 0 && IOC_sock != INVALID_SOCKET) { epicsSocketDestroy ( IOC_sock ); } /* * Open the socket. Use ARPA Internet address format and stream * sockets. Format described in <sys/socket.h>. */ if ( ( IOC_sock = epicsSocketCreate (AF_INET, SOCK_STREAM, 0) ) == INVALID_SOCKET ) { errlogPrintf ("CAS: Socket creation error\n"); epicsThreadSuspendSelf (); } epicsSocketEnableAddressReuseDuringTimeWaitState ( IOC_sock ); /* Zero the sock_addr structure */ memset ( (void *) &serverAddr, 0, sizeof ( serverAddr ) ); serverAddr.sin_family = AF_INET; serverAddr.sin_addr.s_addr = htonl (INADDR_ANY); serverAddr.sin_port = htons ( ca_server_port ); /* get server's Internet address */ status = bind ( IOC_sock, (struct sockaddr *) &serverAddr, sizeof ( serverAddr ) ); if ( status < 0 ) { if ( SOCKERRNO == SOCK_EADDRINUSE ) { /* * enable assignment of a default port * (so the getsockname() call below will * work correctly) */ serverAddr.sin_port = ntohs (0); status = bind ( IOC_sock, (struct sockaddr *) &serverAddr, sizeof ( serverAddr ) ); } if ( status < 0 ) { char sockErrBuf[64]; epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); errlogPrintf ( "CAS: Socket bind error was \"%s\"\n", sockErrBuf ); epicsThreadSuspendSelf (); } portChange = 1; } else { portChange = 0; } addrSize = ( osiSocklen_t ) sizeof ( serverAddr ); status = getsockname ( IOC_sock, (struct sockaddr *)&serverAddr, &addrSize); if ( status ) { char sockErrBuf[64]; epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); errlogPrintf ( "CAS: getsockname() error %s\n", sockErrBuf ); epicsThreadSuspendSelf (); } ca_server_port = ntohs (serverAddr.sin_port); if ( portChange ) { errlogPrintf ( "cas warning: Configured TCP port was unavailable.\n"); errlogPrintf ( "cas warning: Using dynamically assigned TCP port %hu,\n", ca_server_port ); errlogPrintf ( "cas warning: but now two or more servers share the same UDP port.\n"); errlogPrintf ( "cas warning: Depending on your IP kernel this server may not be\n" ); errlogPrintf ( "cas warning: reachable with UDP unicast (a host's IP in EPICS_CA_ADDR_LIST)\n" ); } /* listen and accept new connections */ if ( listen ( IOC_sock, 20 ) < 0 ) { errlogPrintf ("CAS: Listen error\n"); epicsSocketDestroy (IOC_sock); epicsThreadSuspendSelf (); } tbs = epicsThreadHighestPriorityLevelBelow ( priorityOfSelf, &priorityOfBeacons ); if ( tbs != epicsThreadBooleanStatusSuccess ) { priorityOfBeacons = priorityOfSelf; } beacon_startStopEvent = epicsEventMustCreate(epicsEventEmpty); beacon_ctl = ctlPause; tid = epicsThreadCreate ( "CAS-beacon", priorityOfBeacons, epicsThreadGetStackSize (epicsThreadStackSmall), rsrv_online_notify_task, 0 ); if ( tid == 0 ) { epicsPrintf ( "CAS: unable to start beacon thread\n" ); } epicsEventMustWait(beacon_startStopEvent); epicsEventSignal(castcp_startStopEvent); while (TRUE) { struct sockaddr sockAddr; osiSocklen_t addLen = sizeof(sockAddr); while (castcp_ctl == ctlPause) { epicsThreadSleep(0.1); } clientSock = epicsSocketAccept ( IOC_sock, &sockAddr, &addLen ); if ( clientSock == INVALID_SOCKET ) { char sockErrBuf[64]; epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); errlogPrintf("CAS: Client accept error was \"%s\"\n", sockErrBuf ); epicsThreadSleep(15.0); continue; } else { epicsThreadId id; struct client *pClient; /* socket passed in is closed if unsuccessful here */ pClient = create_tcp_client ( clientSock ); if ( ! pClient ) { epicsThreadSleep ( 15.0 ); continue; } LOCK_CLIENTQ; ellAdd ( &clientQ, &pClient->node ); UNLOCK_CLIENTQ; id = epicsThreadCreate ( "CAS-client", epicsThreadPriorityCAServerLow, epicsThreadGetStackSize ( epicsThreadStackBig ), camsgtask, pClient ); if ( id == 0 ) { LOCK_CLIENTQ; ellDelete ( &clientQ, &pClient->node ); UNLOCK_CLIENTQ; destroy_tcp_client ( pClient ); errlogPrintf ( "CAS: task creation for new client failed\n" ); epicsThreadSleep ( 15.0 ); continue; } } } }
/* * destroy_client () */ void destroy_client ( struct client *client ) { if ( ! client ) { return; } if ( client->tid != 0 ) { taskwdRemove ( client->tid ); } if ( client->sock != INVALID_SOCKET ) { epicsSocketDestroy ( client->sock ); } if ( client->proto == IPPROTO_TCP ) { if ( client->send.buf ) { if ( client->send.type == mbtSmallTCP ) { freeListFree ( rsrvSmallBufFreeListTCP, client->send.buf ); } else if ( client->send.type == mbtLargeTCP ) { freeListFree ( rsrvLargeBufFreeListTCP, client->send.buf ); } else { errlogPrintf ( "CAS: Corrupt send buffer free list type code=%u during client cleanup?\n", client->send.type ); } } if ( client->recv.buf ) { if ( client->recv.type == mbtSmallTCP ) { freeListFree ( rsrvSmallBufFreeListTCP, client->recv.buf ); } else if ( client->recv.type == mbtLargeTCP ) { freeListFree ( rsrvLargeBufFreeListTCP, client->recv.buf ); } else { errlogPrintf ( "CAS: Corrupt recv buffer free list type code=%u during client cleanup?\n", client->send.type ); } } } else if ( client->proto == IPPROTO_UDP ) { if ( client->send.buf ) { free ( client->send.buf ); } if ( client->recv.buf ) { free ( client->recv.buf ); } } if ( client->eventqLock ) { epicsMutexDestroy ( client->eventqLock ); } if ( client->chanListLock ) { epicsMutexDestroy ( client->chanListLock ); } if ( client->putNotifyLock ) { epicsMutexDestroy ( client->putNotifyLock ); } if ( client->lock ) { epicsMutexDestroy ( client->lock ); } if ( client->blockSem ) { epicsEventDestroy ( client->blockSem ); } if ( client->pUserName ) { free ( client->pUserName ); } if ( client->pHostName ) { free ( client->pHostName ); } freeListFree ( rsrvClientFreeList, client ); }
void *ioc_alive_listen(void *data) { aliveRecord *prec = (aliveRecord *) data; struct rpvtStruct *prpvt; SOCKET tcp_sockfd; int sflag; SOCKET client_sockfd; struct sockaddr_in l_addr; osiSocklen_t socklen; char *q; // key and value lengths, key length of zero means it doesn't exist int env_len[ENV_CNT][2]; uint32_t msg32; uint16_t msg16, len16; uint8_t len8; int length; int number; int type; #if defined (vxWorks) BOOT_PARAMS bootparams; #endif #if defined (linux) || defined (darwin) char *user; char *group; char *hostname; char hostname_buffer[129]; #endif #if defined (_WIN32) char *user; char user_buffer[80]; char *machine; char machine_buffer[20]; #endif int i; prpvt = prec->rpvt; #if defined (vxWorks) type = 1; #elif defined (linux) type = 2; #elif defined (darwin) type = 3; #elif defined (_WIN32) type = 4; #else type = 0; #endif #ifdef vxWorks bzero( (char *) &l_addr, sizeof( struct sockaddr_in) ); l_addr.sin_len = sizeof( struct sockaddr_in); #else memset( &l_addr, 0, sizeof( struct sockaddr_in) ); #endif l_addr.sin_family = AF_INET; l_addr.sin_addr.s_addr = htonl(INADDR_ANY); l_addr.sin_port = htons(prpvt->orig_port); if( (tcp_sockfd = epicsSocketCreate(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET ) { perror("socket"); prec->ipsts = aliveIPSTS_INOPERABLE; monitor_field(prec, (void *) &prec->ipsts); return NULL; } sflag = 1; // not the end of the world if this option doesn't work setsockopt(tcp_sockfd, SOL_SOCKET, SO_REUSEADDR, (void *) &sflag, sizeof(sflag)); if( bind(tcp_sockfd, (struct sockaddr *) &l_addr, sizeof(struct sockaddr_in)) ) { perror("TCP bind"); prec->ipsts = aliveIPSTS_INOPERABLE; monitor_field(prec, (void *) &prec->ipsts); return NULL; } socklen = sizeof(struct sockaddr_in); if( getsockname( tcp_sockfd, (struct sockaddr *) &l_addr, &socklen) ) { perror("TCP getsockname"); prec->ipsts = aliveIPSTS_INOPERABLE; monitor_field(prec, (void *) &prec->ipsts); return NULL; } // wait to use result until we know listen() works if( listen(tcp_sockfd, 5) ) { perror("TCP listen"); prec->ipsts = aliveIPSTS_INOPERABLE; monitor_field(prec, (void *) &prec->ipsts); return NULL; } prec->iport = ntohs(l_addr.sin_port); monitor_field(prec, (void *) &prec->iport); prec->ipsts = aliveIPSTS_OPERABLE; monitor_field(prec, (void *) &prec->ipsts); // request remote read prpvt->flags |= ((uint16_t) 1); while(1) { struct sockaddr r_addr; osiSocklen_t r_len = sizeof( r_addr); client_sockfd = epicsSocketAccept( tcp_sockfd, &r_addr, &r_len); if (client_sockfd == INVALID_SOCKET) continue; // fault flag can't happen, but just in case if( prec->isup || prpvt->fault_flag || !prpvt->ready_flag || ( ((struct sockaddr_in *)&r_addr)->sin_addr.s_addr != prpvt->h_addr.sin_addr.s_addr) ) { epicsSocketDestroy(client_sockfd); continue; } // TCP protocol version msg16 = htons(PROTOCOL_VERSION); send( client_sockfd, (void *) &msg16, sizeof(uint16_t), 0); // IOC type, currently 1 = vxworks, 2 = linux, 3 = darwin msg16 = htons(type); send( client_sockfd, (void *) &msg16, sizeof(uint16_t), 0); number = 0; length = 10; // from version + type + number + length #if defined (vxWorks) memset( &bootparams, 0, sizeof( BOOT_PARAMS) ); bootStringToStruct( sysBootLine, &bootparams); // don't check to see if it returns EOS, as it's zeroed out length += 12; // bootparams.unitNum, bootparams.procNum, bootparams.flags length += 12; // 8-bit lengths below length += ((uint8_t) strlen(bootparams.bootDev) ); length += ((uint8_t) strlen(bootparams.hostName) ); length += ((uint8_t) strlen(bootparams.bootFile) ); length += ((uint8_t) strlen(bootparams.ead) ); length += ((uint8_t) strlen(bootparams.bad) ); length += ((uint8_t) strlen(bootparams.had) ); length += ((uint8_t) strlen(bootparams.gad) ); length += ((uint8_t) strlen(bootparams.usr) ); length += ((uint8_t) strlen(bootparams.passwd) ); length += ((uint8_t) strlen(bootparams.targetName) ); length += ((uint8_t) strlen(bootparams.startupScript) ); length += ((uint8_t) strlen(bootparams.other) ); #endif #if defined (linux) || defined (darwin) { uid_t user_id; gid_t group_id; struct passwd *passwd_entry; struct group *group_entry; user_id = getuid(); passwd_entry = getpwuid(user_id); if( passwd_entry != NULL) user = passwd_entry->pw_name; else user = NULL; group_id = getgid(); group_entry = getgrgid(group_id); if( group_entry != NULL) group = group_entry->gr_name; else group = NULL; if( gethostname( hostname_buffer, 128) ) hostname = NULL; else { hostname_buffer[128] = '\0'; hostname = hostname_buffer; } } // flag == 2 or 3 length += 1; // 8-bit string length if( user != NULL) length += ((uint8_t) strlen(user) ); length += 1; // 8-bit string length if( group != NULL) length += ((uint8_t) strlen(group) ); length += 1; // 8-bit string length if( hostname != NULL) length += ((uint8_t) strlen(hostname) ); #endif #if defined (_WIN32) { uint32_t size; length += 2; // two variable lengths size = 80; if (GetUserNameA(user_buffer, &size)) { user = user_buffer; length += ((uint8_t)strlen(user)); } else user = NULL; size = 20; if (GetComputerNameA(machine_buffer, &size)) { machine = machine_buffer; length += ((uint8_t)strlen(machine)); } else machine = NULL; } #endif for( i = 0; i < ENV_CNT; i++) { if( prpvt->env[i][0] == '\0') env_len[i][0] = 0; else { number++; length += 3; // 8-bit key & 16-bit value string lengths env_len[i][0] = strlen(prpvt->env[i]); length += env_len[i][0]; q = getenv(prpvt->env[i]); if( q == NULL) env_len[i][1] = 0; else { env_len[i][1] = strlen(q); // if size is greater that 16-bit max, truncate to zero if( env_len[i][1] > 65535) env_len[i][1] = 0; length += env_len[i][1]; } } } /* printf("%d\n", length); fflush(stdout); */ msg32 = htonl( length); send( client_sockfd, (void *) &msg32, sizeof(uint32_t), 0); msg16 = htons( number); send( client_sockfd, (void *) &msg16, sizeof(uint16_t), 0); for( i = 0; i < ENV_CNT; i++) { if( env_len[i][0] == 0) continue; len8 = env_len[i][0]; send( client_sockfd, (void *) &len8, sizeof(uint8_t), 0); send( client_sockfd, prpvt->env[i], len8, 0); q = getenv(prpvt->env[i]); len16 = env_len[i][1]; msg16 = htons( len16); send( client_sockfd, (void *) &msg16, sizeof(uint16_t), 0); if( len16) send( client_sockfd, q, len16, 0); } #ifdef vxWorks bootparam_send( client_sockfd, bootparams.bootDev); msg32 = htonl(bootparams.unitNum); send( client_sockfd, (void *) &msg32, sizeof(uint32_t), 0); msg32 = htonl(bootparams.procNum); send( client_sockfd, (void *) &msg32, sizeof(uint32_t), 0); bootparam_send( client_sockfd, bootparams.hostName); bootparam_send( client_sockfd, bootparams.bootFile); bootparam_send( client_sockfd, bootparams.ead); bootparam_send( client_sockfd, bootparams.bad); bootparam_send( client_sockfd, bootparams.had); bootparam_send( client_sockfd, bootparams.gad); bootparam_send( client_sockfd, bootparams.usr); bootparam_send( client_sockfd, bootparams.passwd); msg32 = htonl( bootparams.flags); send( client_sockfd, (void *) &msg32, sizeof(uint32_t), 0); bootparam_send( client_sockfd, bootparams.targetName); bootparam_send( client_sockfd, bootparams.startupScript); bootparam_send( client_sockfd, bootparams.other); #endif #if defined (linux) || defined (darwin) if( user == NULL) len8 = 0; else len8 = strlen( user); send( client_sockfd, (void *) &len8, sizeof(uint8_t), 0); if( user != NULL) send( client_sockfd, user, len8, 0); if( group == NULL) len8 = 0; else len8 = strlen( group); send( client_sockfd, (void *) &len8, sizeof(uint8_t), 0); if( group != NULL) send( client_sockfd, group, len8, 0); if( hostname == NULL) len8 = 0; else len8 = strlen( hostname); send( client_sockfd, (void *) &len8, sizeof(uint8_t), 0); if( hostname != NULL) send( client_sockfd, hostname, len8, 0); #endif #if defined (_WIN32) if (user == NULL) len8 = 0; else len8 = strlen(user); send(client_sockfd, (void *)&len8, sizeof(uint8_t), 0); if (user != NULL) send(client_sockfd, user, len8, 0); if (machine == NULL) len8 = 0; else len8 = strlen(machine); send(client_sockfd, (void *)&len8, sizeof(uint8_t), 0); if (machine != NULL) send(client_sockfd, machine, len8, 0); #endif epicsSocketDestroy( client_sockfd); // turn off request flag prpvt->flags &= ~((uint16_t) 1); // if itrigger was set, unset it if( prec->itrig) { prec->itrig = 0; monitor_field(prec, (void *) &prec->itrig); } } return NULL; }
/* * Create a link */ static asynStatus connectIt(void *drvPvt, asynUser *pasynUser) { ttyController_t *tty = (ttyController_t *)drvPvt; SOCKET fd; int i; /* * Sanity check */ assert(tty); asynPrint(pasynUser, ASYN_TRACE_FLOW, "Open connection to %s reason:%d fd:%d\n", tty->IPDeviceName, pasynUser->reason, tty->fd); if (tty->fd != INVALID_SOCKET) { epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, "%s: Link already open!", tty->IPDeviceName); return asynError; } else if(tty->flags & FLAG_SHUTDOWN) { epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, "%s: Link shutdown!", tty->IPDeviceName); return asynError; } /* If pasynUser->reason > 0) then use this as the file descriptor */ if (pasynUser->reason > 0) { fd = pasynUser->reason; } else { /* * Create the socket */ if ((fd = epicsSocketCreate(tty->farAddr.oa.sa.sa_family, tty->socketType, 0)) < 0) { epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, "Can't create socket: %s", strerror(SOCKERRNO)); return asynError; } /* * Enable broadcasts if so requested */ i = 1; if ((tty->flags & FLAG_BROADCAST) && (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (void *)&i, sizeof i) < 0)) { epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, "Can't set %s socket BROADCAST option: %s", tty->IPDeviceName, strerror(SOCKERRNO)); epicsSocketDestroy(fd); return asynError; } /* * Convert host name/number to IP address. * We delay doing this until now in case a device * has just appeared in a DNS database. */ if (tty->flags & FLAG_NEED_LOOKUP) { if(hostToIPAddr(tty->IPHostName, &tty->farAddr.oa.ia.sin_addr) < 0) { epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, "Unknown host \"%s\"", tty->IPHostName); epicsSocketDestroy(fd); return asynError; } tty->flags &= ~FLAG_NEED_LOOKUP; tty->flags |= FLAG_DONE_LOOKUP; } /* * Bind to the local IP address if it was specified. * This is a very unusual configuration */ if (tty->localAddrSize > 0) { if (bind(fd, &tty->localAddr.sa, tty->localAddrSize)) { epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, "unable to bind to local port: %s", strerror(SOCKERRNO)); epicsSocketDestroy(fd); return asynError; } } /* * Connect to the remote host * If the connect fails, arrange for another DNS lookup in case the * problem is just that the device has DHCP'd itself an new number. */ if (tty->socketType != SOCK_DGRAM) { if (connect(fd, &tty->farAddr.oa.sa, (int)tty->farAddrSize) < 0) { epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, "Can't connect to %s: %s", tty->IPDeviceName, strerror(SOCKERRNO)); epicsSocketDestroy(fd); if (tty->flags & FLAG_DONE_LOOKUP) tty->flags |= FLAG_NEED_LOOKUP; return asynError; } } } i = 1; if ((tty->socketType == SOCK_STREAM) && (tty->farAddr.oa.sa.sa_family == AF_INET) && (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (void *)&i, sizeof i) < 0)) { epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, "Can't set %s socket NODELAY option: %s", tty->IPDeviceName, strerror(SOCKERRNO)); epicsSocketDestroy(fd); return asynError; } #ifdef USE_POLL if (setNonBlock(fd, 1) < 0) { epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, "Can't set %s O_NONBLOCK option: %s", tty->IPDeviceName, strerror(SOCKERRNO)); epicsSocketDestroy(fd); return asynError; } #endif asynPrint(pasynUser, ASYN_TRACE_FLOW, "Opened connection to %s\n", tty->IPDeviceName); tty->fd = fd; return asynSuccess; }
int BlockingTCPAcceptor::initialize() { char ipAddrStr[48]; ipAddrToDottedIP(&_bindAddress.ia, ipAddrStr, sizeof(ipAddrStr)); int tryCount = 0; while(tryCount<2) { char strBuffer[64]; LOG(logLevelDebug, "Creating acceptor to %s.", ipAddrStr); _serverSocketChannel = epicsSocketCreate(AF_INET, SOCK_STREAM, IPPROTO_TCP); if(_serverSocketChannel==INVALID_SOCKET) { epicsSocketConvertErrnoToString(strBuffer, sizeof(strBuffer)); ostringstream temp; temp<<"Socket create error: "<<strBuffer; LOG(logLevelError, "%s", temp.str().c_str()); THROW_BASE_EXCEPTION(temp.str().c_str()); } else { //epicsSocketEnableAddressReuseDuringTimeWaitState(_serverSocketChannel); // try to bind int retval = ::bind(_serverSocketChannel, &_bindAddress.sa, sizeof(sockaddr)); if(retval<0) { epicsSocketConvertErrnoToString(strBuffer, sizeof(strBuffer)); LOG(logLevelDebug, "Socket bind error: %s.", strBuffer); if(_bindAddress.ia.sin_port!=0) { // failed to bind to specified bind address, // try to get port dynamically, but only once LOG( logLevelDebug, "Configured TCP port %d is unavailable, trying to assign it dynamically.", ntohs(_bindAddress.ia.sin_port)); _bindAddress.ia.sin_port = htons(0); } else { epicsSocketDestroy(_serverSocketChannel); break; // exit while loop } } else { // if(retval<0) // bind succeeded // update bind address, if dynamically port selection was used if(ntohs(_bindAddress.ia.sin_port)==0) { osiSocklen_t sockLen = sizeof(sockaddr); // read the actual socket info retval = ::getsockname(_serverSocketChannel, &_bindAddress.sa, &sockLen); if(retval<0) { // error obtaining port number epicsSocketConvertErrnoToString(strBuffer, sizeof(strBuffer)); LOG(logLevelDebug, "getsockname error: %s", strBuffer); } else { LOG( logLevelInfo, "Using dynamically assigned TCP port %d.", ntohs(_bindAddress.ia.sin_port)); } } retval = ::listen(_serverSocketChannel, 4); if(retval<0) { epicsSocketConvertErrnoToString(strBuffer, sizeof(strBuffer)); ostringstream temp; temp<<"Socket listen error: "<<strBuffer; LOG(logLevelError, "%s", temp.str().c_str()); THROW_BASE_EXCEPTION(temp.str().c_str()); } _thread.start(); // all OK, return return ntohs(_bindAddress.ia.sin_port); } // successful bind } // successfully obtained socket tryCount++; } // while ostringstream temp; temp<<"Failed to create acceptor to "<<ipAddrStr; THROW_BASE_EXCEPTION(temp.str().c_str()); }
// // udpiiu::udpiiu () // udpiiu::udpiiu ( epicsGuard < epicsMutex > & cacGuard, epicsTimerQueueActive & timerQueue, epicsMutex & cbMutexIn, epicsMutex & cacMutexIn, cacContextNotify & ctxNotifyIn, cac & cac, unsigned port, tsDLList < SearchDest > & searchDestListIn ) : recvThread ( *this, ctxNotifyIn, cbMutexIn, "CAC-UDP", epicsThreadGetStackSize ( epicsThreadStackMedium ), cac::lowestPriorityLevelAbove ( cac::lowestPriorityLevelAbove ( cac.getInitializingThreadsPriority () ) ) ), m_repeaterTimerNotify ( *this ), repeaterSubscribeTmr ( m_repeaterTimerNotify, timerQueue, cbMutexIn, ctxNotifyIn ), govTmr ( *this, timerQueue, cacMutexIn ), maxPeriod ( maxSearchPeriodDefault ), rtteMean ( minRoundTripEstimate ), rtteMeanDev ( 0 ), cacRef ( cac ), cbMutex ( cbMutexIn ), cacMutex ( cacMutexIn ), nBytesInXmitBuf ( 0 ), nTimers ( 0 ), beaconAnomalyTimerIndex ( 0 ), sequenceNumber ( 0 ), lastReceivedSeqNo ( 0 ), sock ( 0 ), repeaterPort ( 0 ), serverPort ( port ), localPort ( 0 ), shutdownCmd ( false ), lastReceivedSeqNoIsValid ( false ) { cacGuard.assertIdenticalMutex ( cacMutex ); if ( envGetConfigParamPtr ( & EPICS_CA_MAX_SEARCH_PERIOD ) ) { long longStatus = envGetDoubleConfigParam ( & EPICS_CA_MAX_SEARCH_PERIOD, & this->maxPeriod ); if ( ! longStatus ) { if ( this->maxPeriod < maxSearchPeriodLowerLimit ) { epicsPrintf ( "\"%s\" out of range (low)\n", EPICS_CA_MAX_SEARCH_PERIOD.name ); this->maxPeriod = maxSearchPeriodLowerLimit; epicsPrintf ( "Setting \"%s\" = %f seconds\n", EPICS_CA_MAX_SEARCH_PERIOD.name, this->maxPeriod ); } } else { epicsPrintf ( "EPICS \"%s\" wasnt a real number\n", EPICS_CA_MAX_SEARCH_PERIOD.name ); epicsPrintf ( "Setting \"%s\" = %f seconds\n", EPICS_CA_MAX_SEARCH_PERIOD.name, this->maxPeriod ); } } double powerOfTwo = log ( this->maxPeriod / minRoundTripEstimate ) / log ( 2.0 ); this->nTimers = static_cast < unsigned > ( powerOfTwo + 1.0 ); if ( this->nTimers > channelNode::getMaxSearchTimerCount () ) { this->nTimers = channelNode::getMaxSearchTimerCount (); epicsPrintf ( "\"%s\" out of range (high)\n", EPICS_CA_MAX_SEARCH_PERIOD.name ); epicsPrintf ( "Setting \"%s\" = %f seconds\n", EPICS_CA_MAX_SEARCH_PERIOD.name, (1<<(this->nTimers-1)) * minRoundTripEstimate ); } powerOfTwo = log ( beaconAnomalySearchPeriod / minRoundTripEstimate ) / log ( 2.0 ); this->beaconAnomalyTimerIndex = static_cast < unsigned > ( powerOfTwo + 1.0 ); if ( this->beaconAnomalyTimerIndex >= this->nTimers ) { this->beaconAnomalyTimerIndex = this->nTimers - 1; } this->ppSearchTmr.reset ( new epics_auto_ptr < class searchTimer > [ this->nTimers ] ); for ( unsigned i = 0; i < this->nTimers; i++ ) { this->ppSearchTmr[i].reset ( new searchTimer ( *this, timerQueue, i, cacMutexIn, i > this->beaconAnomalyTimerIndex ) ); } this->repeaterPort = envGetInetPortConfigParam ( &EPICS_CA_REPEATER_PORT, static_cast <unsigned short> (CA_REPEATER_PORT) ); this->sock = epicsSocketCreate ( AF_INET, SOCK_DGRAM, IPPROTO_UDP ); if ( this->sock == INVALID_SOCKET ) { char sockErrBuf[64]; epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); errlogPrintf ("CAC: unable to create datagram socket because = \"%s\"\n", sockErrBuf ); throwWithLocation ( noSocket () ); } int boolValue = true; int status = setsockopt ( this->sock, SOL_SOCKET, SO_BROADCAST, (char *) &boolValue, sizeof ( boolValue ) ); if ( status < 0 ) { char sockErrBuf[64]; epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); errlogPrintf ("CAC: IP broadcasting enable failed because = \"%s\"\n", sockErrBuf ); } #if 0 { /* * some concern that vxWorks will run out of mBuf's * if this change is made joh 11-10-98 * * bump up the UDP recv buffer */ int size = 1u<<15u; status = setsockopt ( this->sock, SOL_SOCKET, SO_RCVBUF, (char *)&size, sizeof (size) ); if (status<0) { char sockErrBuf[64]; epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); errlogPrintf ( "CAC: unable to set socket option SO_RCVBUF because \"%s\"\n", sockErrBuf ); } } #endif // force a bind to an unconstrained address so we can obtain // the local port number below static const unsigned short PORT_ANY = 0u; osiSockAddr addr; memset ( (char *)&addr, 0 , sizeof (addr) ); addr.ia.sin_family = AF_INET; addr.ia.sin_addr.s_addr = htonl ( INADDR_ANY ); addr.ia.sin_port = htons ( PORT_ANY ); status = bind (this->sock, &addr.sa, sizeof (addr) ); if ( status < 0 ) { char sockErrBuf[64]; epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); epicsSocketDestroy (this->sock); errlogPrintf ( "CAC: unable to bind to an unconstrained address because = \"%s\"\n", sockErrBuf ); throwWithLocation ( noSocket () ); } { osiSockAddr tmpAddr; osiSocklen_t saddr_length = sizeof ( tmpAddr ); status = getsockname ( this->sock, &tmpAddr.sa, &saddr_length ); if ( status < 0 ) { char sockErrBuf[64]; epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); epicsSocketDestroy ( this->sock ); errlogPrintf ( "CAC: getsockname () error was \"%s\"\n", sockErrBuf ); throwWithLocation ( noSocket () ); } if ( tmpAddr.sa.sa_family != AF_INET) { epicsSocketDestroy ( this->sock ); errlogPrintf ( "CAC: UDP socket was not inet addr family\n" ); throwWithLocation ( noSocket () ); } this->localPort = ntohs ( tmpAddr.ia.sin_port ); } /* * load user and auto configured * broadcast address list */ ELLLIST dest; ellInit ( & dest ); configureChannelAccessAddressList ( & dest, this->sock, this->serverPort ); while ( osiSockAddrNode * pNode = reinterpret_cast < osiSockAddrNode * > ( ellGet ( & dest ) ) ) { SearchDestUDP & searchDest = * new SearchDestUDP ( pNode->addr, *this ); _searchDestList.add ( searchDest ); free ( pNode ); } /* add list of tcp name service addresses */ _searchDestList.add ( searchDestListIn ); caStartRepeaterIfNotInstalled ( this->repeaterPort ); this->pushVersionMsg (); // start timers and receive thread for ( unsigned j =0; j < this->nTimers; j++ ) { this->ppSearchTmr[j]->start ( cacGuard ); } this->govTmr.start (); this->repeaterSubscribeTmr.start (); this->recvThread.start (); }
/* * caStartRepeaterIfNotInstalled () * * Test for the repeater already installed * * NOTE: potential race condition here can result * in two copies of the repeater being spawned * however the repeater detects this, prints a message, * and lets the other task start the repeater. * * QUESTION: is there a better way to test for a port in use? * ANSWER: none that I can find. * * Problems with checking for the repeater installed * by attempting to bind a socket to its address * and port. * * 1) Closed socket may not release the bound port * before the repeater wakes up and tries to grab it. * Attempting to bind the open socket to another port * also does not work. * * 072392 - problem solved by using SO_REUSEADDR */ void epicsShareAPI caStartRepeaterIfNotInstalled ( unsigned repeaterPort ) { bool installed = false; int status; SOCKET tmpSock; union { struct sockaddr_in ia; struct sockaddr sa; } bd; if ( repeaterPort > 0xffff ) { fprintf ( stderr, "caStartRepeaterIfNotInstalled () : strange repeater port specified\n" ); return; } tmpSock = epicsSocketCreate ( AF_INET, SOCK_DGRAM, IPPROTO_UDP ); if ( tmpSock != INVALID_SOCKET ) { ca_uint16_t port = static_cast < ca_uint16_t > ( repeaterPort ); memset ( (char *) &bd, 0, sizeof ( bd ) ); bd.ia.sin_family = AF_INET; bd.ia.sin_addr.s_addr = htonl ( INADDR_ANY ); bd.ia.sin_port = htons ( port ); status = bind ( tmpSock, &bd.sa, sizeof ( bd ) ); if ( status < 0 ) { if ( SOCKERRNO == SOCK_EADDRINUSE ) { installed = true; } else { fprintf ( stderr, "caStartRepeaterIfNotInstalled () : bind failed\n" ); } } } /* * turn on reuse only after the test so that * this works on kernels that support multicast */ epicsSocketEnableAddressReuseDuringTimeWaitState ( tmpSock ); epicsSocketDestroy ( tmpSock ); if ( ! installed ) { /* * This is not called if the repeater is known to be * already running. (in the event of a race condition * the 2nd repeater exits when unable to attach to the * repeater's port) */ /* * look for a caRepeater in the same directory as CA.DLL * and use this if present instead of a PATH search */ char carep_path[256]; strcpy(carep_path, "caRepeater"); #ifdef _WIN32 char caDLLPath[MAX_PATH]; HMODULE hmod = GetModuleHandle("CA.DLL"); if (hmod != NULL) { if (GetModuleFileName(hmod, caDLLPath, sizeof(caDLLPath)) > 0) { char* base_path = strrchr(caDLLPath, '\\'); if (base_path != NULL) { *base_path = '\0'; // caDLLPath is now the directory containing CA.DLL _snprintf(carep_path, sizeof(carep_path), "%s\\caRepeater.exe", caDLLPath); if (access(carep_path, 04) != 0) { strcpy(carep_path, "caRepeater"); // Not found, so will search PATH instead for caRepeater } } } } #endif /* _WIN32 */ osiSpawnDetachedProcessReturn osptr = osiSpawnDetachedProcess ( "CA Repeater", carep_path ); if ( osptr == osiSpawnDetachedProcessNoSupport ) { epicsThreadId tid; tid = epicsThreadCreate ( "CAC-repeater", epicsThreadPriorityLow, epicsThreadGetStackSize ( epicsThreadStackMedium ), caRepeaterThread, 0); if ( tid == 0 ) { fprintf ( stderr, "caStartRepeaterIfNotInstalled : unable to create CA repeater daemon thread\n" ); } } else if ( osptr == osiSpawnDetachedProcessFail ) { fprintf ( stderr, "caStartRepeaterIfNotInstalled (): unable to start CA repeater daemon detached process\n" ); } } }
Transport::shared_pointer BlockingTCPConnector::connect(std::tr1::shared_ptr<ClientChannelImpl> const & client, ResponseHandler::shared_pointer const & responseHandler, osiSockAddr& address, int8 transportRevision, int16 priority) { SOCKET socket = INVALID_SOCKET; char ipAddrStr[64]; ipAddrToDottedIP(&address.ia, ipAddrStr, sizeof(ipAddrStr)); Context::shared_pointer context = _context.lock(); TransportRegistry::Reservation rsvp(context->getTransportRegistry(), address, priority); // we are now blocking any connect() to this destination (address and prio) // concurrent connect() to other destination is allowed. // This prevents us from opening duplicate connections. Transport::shared_pointer transport = context->getTransportRegistry()->get(address, priority); if(transport.get()) { LOG(logLevelDebug, "Reusing existing connection to PVA server: %s.", ipAddrStr); if (transport->acquire(client)) return transport; } try { LOG(logLevelDebug, "Connecting to PVA server: %s.", ipAddrStr); socket = tryConnect(address, 3); LOG(logLevelDebug, "Socket connected to PVA server: %s.", ipAddrStr); // enable TCP_NODELAY (disable Nagle's algorithm) int optval = 1; // true int retval = ::setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (char *)&optval, sizeof(int)); if(retval<0) { char errStr[64]; epicsSocketConvertErrnoToString(errStr, sizeof(errStr)); LOG(logLevelWarn, "Error setting TCP_NODELAY: %s.", errStr); } // enable TCP_KEEPALIVE retval = ::setsockopt(socket, SOL_SOCKET, SO_KEEPALIVE, (char *)&optval, sizeof(int)); if(retval<0) { char errStr[64]; epicsSocketConvertErrnoToString(errStr, sizeof(errStr)); LOG(logLevelWarn, "Error setting SO_KEEPALIVE: %s.", errStr); } // TODO tune buffer sizes?! Win32 defaults are 8k, which is OK // create transport // TODO introduce factory // get TCP send buffer size osiSocklen_t intLen = sizeof(int); int _socketSendBufferSize; retval = getsockopt(socket, SOL_SOCKET, SO_SNDBUF, (char *)&_socketSendBufferSize, &intLen); if(retval<0) { char strBuffer[64]; epicsSocketConvertErrnoToString(strBuffer, sizeof(strBuffer)); LOG(logLevelDebug, "Error getting SO_SNDBUF: %s.", strBuffer); } // create() also adds to context connection pool _context->getTransportRegistry() transport = detail::BlockingClientTCPTransportCodec::create( context, socket, responseHandler, _receiveBufferSize, _socketSendBufferSize, client, transportRevision, _heartbeatInterval, priority); // verify if(!transport->verify(5000)) { LOG( logLevelDebug, "Connection to PVA server %s failed to be validated, closing it.", ipAddrStr); std::ostringstream temp; temp<<"Failed to verify TCP connection to '"<<ipAddrStr<<"'."; THROW_BASE_EXCEPTION(temp.str().c_str()); } LOG(logLevelDebug, "Connected to PVA server: %s.", ipAddrStr); return transport; } catch(std::exception&) { if(transport.get()) transport->close(); else if(socket!=INVALID_SOCKET) epicsSocketDestroy(socket); throw; } }
void* module_data_parser_thread(void* arg){ int is_autocal_data, reg_data,i,j,k,code_depth,err; unsigned short *local_buffer_ptr,*temp_us_ptr,*conv,*process_buf_ptr,*netbuffer,frame_header[HEADER_LENGHT]; unsigned short packet_tag,slot_id=0; unsigned char th_dac=0,loop_mode=0; unsigned short this_frame_has_aligment_errors; SOCKET data_socket; struct sockaddr_in sock_addr; int status; local_buffer_ptr=databuffer_allocation(PIXIEII_MODULES*MATRIX_DIM_WORDS*15);//la dimensione in byte di un intero frame if(local_buffer_ptr==NULL){ printf("PROC:error allocating buffers\n"); exit(-1);} else{ if(verbose>=2)printf("PROC:Processing Thread Started\n"); } /***TCP/IP monitor***************inizio********************dacounting_daq.cpp********************/ sock_addr.sin_family=AF_INET; // indico il protocollo utilizzato (TCP/IP) sock_addr.sin_port=htons(4444); //indico la porta a cui connettere il socket if (hostToIPAddr("127.0.0.1", &sock_addr.sin_addr) < 0) printf("PROC:hostToIPAddr failed\n"); // The following is not supported on Linux. Is it needed? //sock_addr.sin_addr.S_un.S_un_b.s_b1=127; // indico l'indirizzo IP //sock_addr.sin_addr.S_un.S_un_b.s_b2=0; //sock_addr.sin_addr.S_un.S_un_b.s_b3=0; //sock_addr.sin_addr.S_un.S_un_b.s_b4=1; netbuffer=databuffer_allocation((MATRIX_DIM_WORDS*PIXIEII_MODULES)+HEADER_LENGHT); /*****TCP/IP monitor****************fine********************dacounting_daq.cpp********************/ printf("PROC:data Parser Thread started\n"); conv=conversion_table_allocation(); while(1){ status = epicsMessageQueueReceive(ptr_list, &process_buf_ptr, sizeof(&process_buf_ptr)); printf("module_data_parser_thread: got process_buf_ptr=%p\n", process_buf_ptr); if (status <= 0){ printf("PROC: error epicsMessageQueueReceive returned %d\n", status); continue; } if (process_buf_ptr==NULL){ printf("PROC: error process_buf_ptr=NULL\n"); continue; } packet_tag=*(process_buf_ptr+PACKET_TAG_OFFSET*2); th_dac=(packet_tag>>(PIXIE_THDAC_OFFSET+DUMMY_0_OFFSET))&PIXIE_THDAC_MASK; loop_mode=(packet_tag>>(LOOP_MODE_OFFSET+DUMMY_1_OFFSET))&LOOP_MODE_MASK; if(verbose>=2)printf("\nPROC: packet_tag=%04xh\n",packet_tag); if(verbose>=2)printf("\nPROC: th_dac=%d, loop_mode=%02Xh\n",th_dac,loop_mode); slot_id=*((char*)process_buf_ptr+SLOT_ID_OFFSET)&SLOT_ID_MASK; if(verbose>=2)printf("PROC: slot_id=%04xh\n",slot_id); if(packet_tag & AUTOCAL_DATA){ if(verbose>=2)printf("\nPROC:Autocal"); code_depth=5; is_autocal_data=1; } else{ if(verbose>=2)printf("\nPROC:Counters"); code_depth=15; is_autocal_data=0; } if(packet_tag & REG_PACKET){ if(verbose>=2)printf("\nPROC:REG 1 data\n"); reg_data=1; } else{ if(verbose>=2)printf("\nPROC:REG 0 data\n"); reg_data=0; } if(packet_tag & FRAME_HAS_ALIGN_ERRORS){ this_frame_has_aligment_errors=1; } else{ this_frame_has_aligment_errors=0; } temp_us_ptr=process_buf_ptr+(PACKET_TAG_BYTES/2); if(verbose>=3)printf("local_buffer filling code_depth=%d\n",code_depth); for(i=0;i<PIXIEII_MODULES;i++) { for(j=0;j<COLS_PER_DOUT*PIXIE_ROWS;j++) { for(k=0;k<code_depth;k++){ my_bytes_swap(temp_us_ptr+i+(j*PIXIEII_MODULES*code_depth)+(k*PIXIEII_MODULES)); local_buffer_ptr[(i*COLS_PER_DOUT*PIXIE_ROWS*code_depth)+(j*code_depth)+k]= temp_us_ptr[i+(j*PIXIEII_MODULES*code_depth)+(k*PIXIEII_MODULES)]; } } } //printf("local_buffer has been filled with original data and data modules are grouped\n"); //memcpy(buff+PACKET_TAG_BYTES,process_buf_ptr+PACKET_TAG_BYTES,PIXIEII_MODULES*MATRIX_DIM_WORDS*code_depth); for(i=0;i<PIXIEII_MODULES;i++){ //printf("parsing %d module data\n",i); for(j=0;j<COLS_PER_DOUT*PIXIE_ROWS;j++) { convert_bit_stream_to_counts(code_depth, local_buffer_ptr+(i*COLS_PER_DOUT*PIXIE_ROWS*code_depth)+(j*code_depth), process_buf_ptr+(i*MATRIX_DIM_WORDS)+(j*PIXIE_DOUTS)+(PACKET_TAG_BYTES/2),PIXIE_DOUTS); } } //printf("data parsed\n"); for(i=0;i<PIXIEII_MODULES;i++){ //printf("processing module %d data\n,i); if(is_autocal_data==0 && convert_data==1) decode_pixie_data_buffer(conv,process_buf_ptr+(PACKET_TAG_BYTES/2)+i*MATRIX_DIM_WORDS); databuffer_sorting(process_buf_ptr+(PACKET_TAG_BYTES/2)+i*MATRIX_DIM_WORDS); map_data_buffer_on_pixie(process_buf_ptr+(PACKET_TAG_BYTES/2)+i*MATRIX_DIM_WORDS); } /*********************sendig data to TCPIP monitor*********************/ for(i=0;i<HEADER_LENGHT;i++) frame_header[i]=0x8000; frame_header[0]=BUFFER_HDR_TAG; frame_header[1]|=(unsigned short)(this_frame_has_aligment_errors); frame_header[2]|=(unsigned short)(is_autocal_data); frame_header[3]|=(sh_code & 0x1); frame_header[4]|=(unsigned short)ceil((double)shutter_duration_ms); frame_header[5]|=(unsigned short)slot_id; if(reg_data==0) frame_header[6]|=REG_0_BUFF_CODE; else frame_header[6]|=REG_1_BUFF_CODE; for(i=0;i<HEADER_LENGHT;i++) netbuffer[i]=frame_header[i]; for(i=0;i<MATRIX_DIM_WORDS*PIXIEII_MODULES;i++) netbuffer[i+HEADER_LENGHT]=process_buf_ptr[i+(PACKET_TAG_BYTES/2)]; data_socket=epicsSocketCreate(PF_INET,SOCK_STREAM,0); err=connect(data_socket,(struct sockaddr*)&sock_addr,sizeof(struct sockaddr)); if(!err) { if (verbose>=1)printf("\r\nI got Pixie!!"); } else if (verbose>=1)printf("\r\nGot error attempting to connect to pixie = %s",strerror(errno)); if(!err) send(data_socket,(const char*)netbuffer,(MATRIX_DIM*PIXIEII_MODULES)+(HEADER_LENGHT*2),0); if(!err)epicsSocketDestroy(data_socket); /*********************sendig data to TCPIP monitor*********************/ free(process_buf_ptr); if (verbose>=1)printf("PROC:pocessing buffer released\n"); } free(local_buffer_ptr);//qui non ci arriverà mai!!!! }
/* * CAST_SERVER * * service UDP messages * */ void cast_server(void *pParm) { struct sockaddr_in sin; int status; int count=0; struct sockaddr_in new_recv_addr; osiSocklen_t recv_addr_size; unsigned short port; osiSockIoctl_t nchars; if ( envGetConfigParamPtr ( &EPICS_CAS_SERVER_PORT ) ) { port = envGetInetPortConfigParam ( &EPICS_CAS_SERVER_PORT, (unsigned short) CA_SERVER_PORT ); } else { port = envGetInetPortConfigParam ( &EPICS_CA_SERVER_PORT, (unsigned short) CA_SERVER_PORT ); } recv_addr_size = sizeof(new_recv_addr); if( IOC_cast_sock!=0 && IOC_cast_sock!=INVALID_SOCKET ) { epicsSocketDestroy ( IOC_cast_sock ); } /* * Open the socket. * Use ARPA Internet address format and datagram socket. */ if ( ( IOC_cast_sock = epicsSocketCreate (AF_INET, SOCK_DGRAM, 0) ) == INVALID_SOCKET ) { epicsPrintf ("CAS: cast socket creation error\n"); epicsThreadSuspendSelf (); } /* * some concern that vxWorks will run out of mBuf's * if this change is made * * joh 11-10-98 */ #if 0 { /* * * this allows for faster connects by queuing * additional incomming UDP search frames * * this allocates a 32k buffer * (uses a power of two) */ int size = 1u<<15u; status = setsockopt (IOC_cast_sock, SOL_SOCKET, SO_RCVBUF, (char *)&size, sizeof(size)); if (status<0) { epicsPrintf ("CAS: unable to set cast socket size\n"); } } #endif epicsSocketEnableAddressUseForDatagramFanout ( IOC_cast_sock ); /* Zero the sock_addr structure */ memset((char *)&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_addr.s_addr = htonl(INADDR_ANY); sin.sin_port = htons(port); /* get server's Internet address */ if( bind(IOC_cast_sock, (struct sockaddr *)&sin, sizeof (sin)) < 0){ char sockErrBuf[64]; epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); epicsPrintf ("CAS: UDP server port bind error was \"%s\"\n", sockErrBuf ); epicsSocketDestroy ( IOC_cast_sock ); epicsThreadSuspendSelf (); } /* * setup new client structure but reuse old structure if * possible * */ while ( TRUE ) { prsrv_cast_client = create_client ( IOC_cast_sock, IPPROTO_UDP ); if ( prsrv_cast_client ) { break; } epicsThreadSleep(300.0); } casAttachThreadToClient ( prsrv_cast_client ); /* * add placeholder for the first version message should it be needed */ rsrv_version_reply ( prsrv_cast_client ); epicsEventSignal(casudp_startStopEvent); while (TRUE) { status = recvfrom ( IOC_cast_sock, prsrv_cast_client->recv.buf, prsrv_cast_client->recv.maxstk, 0, (struct sockaddr *)&new_recv_addr, &recv_addr_size); if (status < 0) { if (SOCKERRNO != SOCK_EINTR) { char sockErrBuf[64]; epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); epicsPrintf ("CAS: UDP recv error (errno=%s)\n", sockErrBuf); epicsThreadSleep(1.0); } } else if (casudp_ctl == ctlRun) { prsrv_cast_client->recv.cnt = (unsigned) status; prsrv_cast_client->recv.stk = 0ul; epicsTimeGetCurrent(&prsrv_cast_client->time_at_last_recv); prsrv_cast_client->minor_version_number = 0; prsrv_cast_client->seqNoOfReq = 0; /* * If we are talking to a new client flush to the old one * in case we are holding UDP messages waiting to * see if the next message is for this same client. */ if (prsrv_cast_client->send.stk>sizeof(caHdr)) { status = memcmp( (void *)&prsrv_cast_client->addr, (void *)&new_recv_addr, recv_addr_size); if(status){ /* * if the address is different */ cas_send_dg_msg(prsrv_cast_client); prsrv_cast_client->addr = new_recv_addr; } } else { prsrv_cast_client->addr = new_recv_addr; } if (CASDEBUG>1) { char buf[40]; ipAddrToDottedIP (&prsrv_cast_client->addr, buf, sizeof(buf)); errlogPrintf ("CAS: cast server msg of %d bytes from addr %s\n", prsrv_cast_client->recv.cnt, buf); } if (CASDEBUG>2) count = ellCount (&prsrv_cast_client->chanList); status = camessage ( prsrv_cast_client ); if(status == RSRV_OK){ if(prsrv_cast_client->recv.cnt != prsrv_cast_client->recv.stk){ char buf[40]; ipAddrToDottedIP (&prsrv_cast_client->addr, buf, sizeof(buf)); epicsPrintf ("CAS: partial (damaged?) UDP msg of %d bytes from %s ?\n", prsrv_cast_client->recv.cnt-prsrv_cast_client->recv.stk, buf); } } else { char buf[40]; ipAddrToDottedIP (&prsrv_cast_client->addr, buf, sizeof(buf)); epicsPrintf ("CAS: invalid (damaged?) UDP request from %s ?\n", buf); } if (CASDEBUG>2) { if ( ellCount (&prsrv_cast_client->chanList) ) { errlogPrintf ("CAS: Fnd %d name matches (%d tot)\n", ellCount(&prsrv_cast_client->chanList)-count, ellCount(&prsrv_cast_client->chanList)); } } } /* * allow messages to batch up if more are comming */ nchars = 0; /* supress purify warning */ status = socket_ioctl(IOC_cast_sock, FIONREAD, &nchars); if (status<0) { errlogPrintf ("CA cast server: Unable to fetch N characters pending\n"); cas_send_dg_msg (prsrv_cast_client); clean_addrq (); } else if (nchars == 0) { cas_send_dg_msg (prsrv_cast_client); clean_addrq (); } } }
/* * cas_send_bs_msg() * * (channel access server send message) */ void cas_send_bs_msg ( struct client *pclient, int lock_needed ) { int status; if ( CASDEBUG > 2 && pclient->send.stk ) { errlogPrintf ( "CAS: Sending a message of %d bytes\n", pclient->send.stk ); } if ( pclient->disconnect ) { if ( CASDEBUG > 2 ) { errlogPrintf ( "CAS: msg Discard for sock %d addr %x\n", pclient->sock, (unsigned) pclient->addr.sin_addr.s_addr ); } pclient->send.stk = 0u; return; } if ( lock_needed ) { SEND_LOCK ( pclient ); } while ( pclient->send.stk && ! pclient->disconnect ) { status = send ( pclient->sock, pclient->send.buf, pclient->send.stk, 0 ); if ( status >= 0 ) { unsigned transferSize = (unsigned) status; if ( transferSize >= pclient->send.stk ) { pclient->send.stk = 0; epicsTimeGetCurrent ( &pclient->time_at_last_send ); break; } else { unsigned bytesLeft = pclient->send.stk - transferSize; memmove ( pclient->send.buf, &pclient->send.buf[transferSize], bytesLeft ); pclient->send.stk = bytesLeft; } } else { int causeWasSocketHangup = 0; int anerrno = SOCKERRNO; char buf[64]; if ( pclient->disconnect ) { pclient->send.stk = 0u; break; } if ( anerrno == SOCK_EINTR ) { continue; } if ( anerrno == SOCK_ENOBUFS ) { errlogPrintf ( "CAS: Out of network buffers, retrying send in 15 seconds\n" ); epicsThreadSleep ( 15.0 ); continue; } ipAddrToDottedIP ( &pclient->addr, buf, sizeof(buf) ); if ( anerrno == SOCK_ECONNABORTED || anerrno == SOCK_ECONNRESET || anerrno == SOCK_EPIPE || anerrno == SOCK_ETIMEDOUT ) { causeWasSocketHangup = 1; } else { char sockErrBuf[64]; epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); errlogPrintf ( "CAS: TCP send to %s failed - %s\n", buf, sockErrBuf); } pclient->disconnect = TRUE; pclient->send.stk = 0u; /* * wakeup the receive thread */ if ( ! causeWasSocketHangup ) { enum epicsSocketSystemCallInterruptMechanismQueryInfo info = epicsSocketSystemCallInterruptMechanismQuery (); switch ( info ) { case esscimqi_socketCloseRequired: if ( pclient->sock != INVALID_SOCKET ) { epicsSocketDestroy ( pclient->sock ); pclient->sock = INVALID_SOCKET; } break; case esscimqi_socketBothShutdownRequired: { int status = shutdown ( pclient->sock, SHUT_RDWR ); if ( status ) { char sockErrBuf[64]; epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); errlogPrintf ("CAS: Socket shutdown error - %s\n", sockErrBuf ); } } break; case esscimqi_socketSigAlarmRequired: epicsSignalRaiseSigAlarm ( pclient->tid ); break; default: break; }; break; } } } if ( lock_needed ) { SEND_UNLOCK(pclient); } DLOG ( 3, ( "------------------------------\n\n" ) ); return; }
/* * Tests the log prefix code * The prefix is only applied to log messages as they go out to the socket, * so we need to create a server listening on a port, accept connections etc. * This code is a reduced version of the code in iocLogServer. */ static void testLogPrefix(void) { struct sockaddr_in serverAddr; int status; struct timeval timeout; struct sockaddr_in actualServerAddr; osiSocklen_t actualServerAddrSize; char portstring[16]; testDiag("Testing iocLogPrefix"); timeout.tv_sec = 5; /* in seconds */ timeout.tv_usec = 0; memset((void*)prefixmsgbuffer, 0, sizeof prefixmsgbuffer); /* Clear "errlog: <n> messages were discarded" status */ errlogPrintfNoConsole("."); errlogFlush(); sock = epicsSocketCreate(AF_INET, SOCK_STREAM, 0); if (sock == INVALID_SOCKET) { testAbort("epicsSocketCreate failed."); } /* We listen on a an available port. */ memset((void *)&serverAddr, 0, sizeof serverAddr); serverAddr.sin_family = AF_INET; serverAddr.sin_port = htons(0); status = bind (sock, (struct sockaddr *)&serverAddr, sizeof (serverAddr) ); if (status < 0) { testAbort("bind failed; all ports in use?"); } status = listen(sock, 10); if (status < 0) { testAbort("listen failed!"); } /* Determine the port that the OS chose */ actualServerAddrSize = sizeof actualServerAddr; memset((void *)&actualServerAddr, 0, sizeof serverAddr); status = getsockname(sock, (struct sockaddr *) &actualServerAddr, &actualServerAddrSize); if (status < 0) { testAbort("Can't find port number!"); } sprintf(portstring, "%d", ntohs(actualServerAddr.sin_port)); testDiag("Listening on port %s", portstring); /* Set the EPICS environment variables for logging. */ epicsEnvSet ( "EPICS_IOC_LOG_INET", "localhost" ); epicsEnvSet ( "EPICS_IOC_LOG_PORT", portstring ); pfdctx = (void *) fdmgr_init(); if (status < 0) { testAbort("fdmgr_init failed!"); } status = fdmgr_add_callback(pfdctx, sock, fdi_read, acceptNewClient, &serverAddr); if (status < 0) { testAbort("fdmgr_add_callback failed!"); } testOk1(iocLogInit() == 0); fdmgr_pend_event(pfdctx, &timeout); testPrefixLogandCompare(prefixactualmsg[0]); iocLogPrefix(prefixstring); testPrefixLogandCompare(prefixactualmsg[1]); testPrefixLogandCompare(prefixactualmsg[2]); epicsSocketDestroy(sock); }
/* * acceptNewClient() * */ static void acceptNewClient ( void *pParam ) { struct ioc_log_server *pserver = (struct ioc_log_server *) pParam; struct iocLogClient *pclient; osiSocklen_t addrSize; struct sockaddr_in addr; int status; osiSockIoctl_t optval; pclient = ( struct iocLogClient * ) malloc ( sizeof ( *pclient ) ); if ( ! pclient ) { return; } addrSize = sizeof ( addr ); pclient->insock = epicsSocketAccept ( pserver->sock, (struct sockaddr *)&addr, &addrSize ); if ( pclient->insock==INVALID_SOCKET || addrSize < sizeof (addr) ) { static unsigned acceptErrCount; static int lastErrno; int thisErrno; free ( pclient ); if ( SOCKERRNO == SOCK_EWOULDBLOCK || SOCKERRNO == SOCK_EINTR ) { return; } thisErrno = SOCKERRNO; if ( acceptErrCount % 1000 || lastErrno != thisErrno ) { fprintf ( stderr, "Accept Error %d\n", SOCKERRNO ); } acceptErrCount++; lastErrno = thisErrno; return; } /* * Set non blocking IO * to prevent dead locks */ optval = TRUE; status = socket_ioctl( pclient->insock, FIONBIO, &optval); if(status<0){ char sockErrBuf[64]; epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); fprintf(stderr, "%s:%d ioctl FBIO client er %s\n", __FILE__, __LINE__, sockErrBuf); epicsSocketDestroy ( pclient->insock ); free(pclient); return; } pclient->pserver = pserver; pclient->nChar = 0u; ipAddrToA (&addr, pclient->name, sizeof(pclient->name)); logTime(pclient); #if 0 status = fprintf( pclient->pserver->poutfile, "%s %s ----- Client Connect -----\n", pclient->name, pclient->ascii_time); if(status<0){ handleLogFileError(); } #endif /* * turn on KEEPALIVE so if the client crashes * this task will find out and exit */ { long true = 1; status = setsockopt( pclient->insock, SOL_SOCKET, SO_KEEPALIVE, (char *)&true, sizeof(true) ); if(status<0){ fprintf(stderr, "Keepalive option set failed\n"); } } status = shutdown(pclient->insock, SHUT_WR); if(status<0){ char sockErrBuf[64]; epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); fprintf (stderr, "%s:%d shutdown err %s\n", __FILE__, __LINE__, sockErrBuf); epicsSocketDestroy ( pclient->insock ); free(pclient); return; } status = fdmgr_add_callback( pserver->pfdctx, pclient->insock, fdi_read, readFromClient, pclient); if (status<0) { epicsSocketDestroy ( pclient->insock ); free(pclient); fprintf(stderr, "%s:%d client fdmgr_add_callback() failed\n", __FILE__, __LINE__); return; } }
int socketpair_compat(int af, int st, int p, SOCKET sd[2]) { SOCKET listener; int ret = -1; osiSockAddr ep[2]; osiSocklen_t slen = sizeof(ep[0]); if(st!=SOCK_STREAM) { SOCKERRNOSET(SOCK_EINVAL); return -1; } listener = epicsSocketCreate(AF_INET, SOCK_STREAM, 0); sd[0] = INVALID_SOCKET; sd[1] = shCreateSocket(AF_INET, SOCK_STREAM, 0); if(listener==INVALID_SOCKET || sd[1]==INVALID_SOCKET) { SOCKERRNOSET(SOCK_EMFILE); goto fail; } memset(ep, 0, sizeof(ep)); ep[0].ia.sin_family = AF_INET; ep[0].ia.sin_addr.s_addr = htonl(INADDR_LOOPBACK); if(bind(listener, &ep[0].sa, sizeof(ep[0]))) goto fail; if(getsockname(listener, &ep[0].sa, &slen)) goto fail; if(listen(listener, 2)) goto fail; /* we can't possibly succeed immediately */ if(connect(sd[1], &ep[0].sa, sizeof(ep[0]))!=-1) goto fail; if(SOCKERRNO!=SOCK_EINPROGRESS) goto fail; while(1) { int err; shSocket atemp; SOCKET temp; osiSocklen_t olen = sizeof(err); slen = sizeof(ep[1]); temp = epicsSocketAccept(listener, &ep[1].sa, &slen); if(temp==INVALID_SOCKET) { if(SOCKERRNO==SOCK_EINTR) continue; goto fail; } shSocketInit(&atemp); atemp.sd = sd[1]; if(shWaitFor(&atemp, SH_CANTX, 0)) { /* someone raced us and won... */ epicsSocketDestroy(temp); continue; } if(getsockopt(sd[1], SOL_SOCKET, SO_ERROR, (char*)&err, &olen)) goto fail; if(err) { SOCKERRNOSET(err); goto fail; } sd[0] = temp; break; } { /* restore blocking IO */ osiSockIoctl_t flag = 0; if(socket_ioctl(sd[1], FIONBIO, &flag)) goto fail; } epicsSocketDestroy(listener); return 0; fail: if(listener!=INVALID_SOCKET) epicsSocketDestroy(sd[0]); if(listener!=INVALID_SOCKET) epicsSocketDestroy(sd[0]); if(sd[1]!=INVALID_SOCKET) epicsSocketDestroy(sd[1]); return ret; }