static void acceptNewClient ( void *pParam ) { osiSocklen_t addrSize; struct sockaddr_in addr; int status; addrSize = sizeof ( addr ); insock = epicsSocketAccept ( sock, (struct sockaddr *)&addr, &addrSize ); testOk(insock != INVALID_SOCKET && addrSize >= sizeof (addr), "Accepted new client"); status = fdmgr_add_callback(pfdctx, insock, fdi_read, readFromClient, NULL); testOk(status >= 0, "Client read configured"); }
/* * 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; } }
/* * * 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; } } } }
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; }
void BlockingTCPAcceptor::run() { // rise level if port is assigned dynamically char ipAddrStr[48]; ipAddrToDottedIP(&_bindAddress.ia, ipAddrStr, sizeof(ipAddrStr)); LOG(logLevelDebug, "Accepting connections at %s.", ipAddrStr); bool socketOpen = true; char strBuffer[64]; while(socketOpen) { { Lock guard(_mutex); if (_destroyed) break; } osiSockAddr address; osiSocklen_t len = sizeof(sockaddr); SOCKET newClient = epicsSocketAccept(_serverSocketChannel, &address.sa, &len); if(newClient!=INVALID_SOCKET) { // accept succeeded ipAddrToDottedIP(&address.ia, ipAddrStr, sizeof(ipAddrStr)); LOG(logLevelDebug, "Accepted connection from PVA client: %s.", ipAddrStr); // enable TCP_NODELAY (disable Nagle's algorithm) int optval = 1; // true int retval = ::setsockopt(newClient, IPPROTO_TCP, TCP_NODELAY, (char *)&optval, sizeof(int)); if(retval<0) { epicsSocketConvertErrnoToString(strBuffer, sizeof(strBuffer)); LOG(logLevelDebug, "Error setting TCP_NODELAY: %s.", strBuffer); } // enable TCP_KEEPALIVE retval = ::setsockopt(newClient, SOL_SOCKET, SO_KEEPALIVE, (char *)&optval, sizeof(int)); if(retval<0) { epicsSocketConvertErrnoToString(strBuffer, sizeof(strBuffer)); LOG(logLevelDebug, "Error setting SO_KEEPALIVE: %s.", strBuffer); } // do NOT tune socket buffer sizes, this will disable auto-tunning // get TCP send buffer size osiSocklen_t intLen = sizeof(int); int _socketSendBufferSize; retval = getsockopt(newClient, SOL_SOCKET, SO_SNDBUF, (char *)&_socketSendBufferSize, &intLen); if(retval<0) { epicsSocketConvertErrnoToString(strBuffer, sizeof(strBuffer)); LOG(logLevelDebug, "Error getting SO_SNDBUF: %s.", strBuffer); } /** * Create transport, it registers itself to the registry. */ detail::BlockingServerTCPTransportCodec::shared_pointer transport = detail::BlockingServerTCPTransportCodec::create( _context, newClient, _responseHandler, _socketSendBufferSize, _receiveBufferSize); // validate connection if(!validateConnection(transport, ipAddrStr)) { // TODO // wait for negative response to be sent back and // hold off the client for retrying at very high rate epicsThreadSleep(1.0); transport->close(); LOG( logLevelDebug, "Connection to PVA client %s failed to be validated, closing it.", ipAddrStr); continue; } LOG(logLevelDebug, "Serving to PVA client: %s.", ipAddrStr); }// accept succeeded else socketOpen = false; } // while }
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; }