Beispiel #1
0
/*
 * 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;
}
Beispiel #3
0
/*
 * 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;
}
Beispiel #4
0
/*
 *
 *  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;
            }
        }
    }
}
Beispiel #5
0
/* 
 * 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 );
}
Beispiel #6
0
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;
}
Beispiel #7
0
/*
 * 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!!!!
}
Beispiel #13
0
/*
 * 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 ();
        }
    }
}
Beispiel #14
0
/*
 *  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);
}
Beispiel #16
0
/*
 *	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;
	}
}
Beispiel #17
0
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;
}