/* call only from the single networking thread */ static UA_StatusCode ServerNetworkLayerTCP_add(ServerNetworkLayerTCP *layer, UA_Int32 newsockfd) { UA_Connection *c = malloc(sizeof(UA_Connection)); if(!c) return UA_STATUSCODE_BADINTERNALERROR; struct sockaddr_in addr; socklen_t addrlen = sizeof(struct sockaddr_in); getsockname(newsockfd, (struct sockaddr*)&addr, &addrlen); UA_LOG_INFO(layer->logger, UA_LOGCATEGORY_NETWORK, "New Connection %i over TCP from %s:%d", newsockfd, inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); UA_Connection_init(c); c->sockfd = newsockfd; c->handle = layer; c->localConf = layer->conf; c->send = socket_write; c->close = ServerNetworkLayerTCP_closeConnection; c->getSendBuffer = ServerNetworkLayerGetSendBuffer; c->releaseSendBuffer = ServerNetworkLayerReleaseSendBuffer; c->releaseRecvBuffer = ServerNetworkLayerReleaseRecvBuffer; c->state = UA_CONNECTION_OPENING; struct ConnectionMapping *nm; nm = realloc(layer->mappings, sizeof(struct ConnectionMapping)*(layer->mappingsSize+1)); if(!nm) { UA_LOG_ERROR(layer->logger, UA_LOGCATEGORY_NETWORK, "No memory for a new Connection"); free(c); return UA_STATUSCODE_BADINTERNALERROR; } layer->mappings = nm; layer->mappings[layer->mappingsSize] = (struct ConnectionMapping){c, newsockfd}; layer->mappingsSize++; return UA_STATUSCODE_GOOD; }
static void UA_Client_init(UA_Client* client, UA_ClientConfig config, UA_Logger logger) { client->state = UA_CLIENTSTATE_READY; UA_Connection_init(&client->connection); UA_SecureChannel_init(&client->channel); client->channel.connection = &client->connection; UA_String_init(&client->endpointUrl); client->requestId = 0; UA_NodeId_init(&client->authenticationToken); client->requestHandle = 0; client->logger = logger; client->config = config; client->scExpiresAt = 0; #ifdef ENABLE_SUBSCRIPTIONS client->monitoredItemHandles = 0; LIST_INIT(&client->pendingNotificationsAcks); LIST_INIT(&client->subscriptions); #endif }
/* call only from the single networking thread */ static UA_StatusCode ServerNetworkLayerTCP_add(ServerNetworkLayerTCP *layer, UA_Int32 newsockfd) { UA_Connection *c = malloc(sizeof(UA_Connection)); if(!c) return UA_STATUSCODE_BADINTERNALERROR; UA_Connection_init(c); c->sockfd = newsockfd; c->handle = layer; c->localConf = layer->conf; c->write = socket_write; c->close = ServerNetworkLayerTCP_closeConnection; c->getBuffer = ServerNetworkLayerGetBuffer; c->releaseBuffer = ServerNetworkLayerReleaseBuffer; c->state = UA_CONNECTION_OPENING; struct ConnectionMapping *nm = realloc(layer->mappings, sizeof(struct ConnectionMapping)*(layer->mappingsSize+1)); if(!nm) { free(c); return UA_STATUSCODE_BADINTERNALERROR; } layer->mappings = nm; layer->mappings[layer->mappingsSize] = (struct ConnectionMapping){c, newsockfd}; layer->mappingsSize++; return UA_STATUSCODE_GOOD; }
/* we have no networklayer. instead, attach the reusable buffer to the handle */ UA_Connection UA_ClientConnectionTCP(UA_ConnectionConfig localConf, const char *endpointUrl, UA_Logger logger) { UA_Connection connection; UA_Connection_init(&connection); connection.localConf = localConf; //socket_set_nonblocking(connection.sockfd); connection.send = socket_write; connection.recv = socket_recv; connection.close = ClientNetworkLayerClose; connection.getSendBuffer = ClientNetworkLayerGetBuffer; connection.releaseSendBuffer = ClientNetworkLayerReleaseBuffer; connection.releaseRecvBuffer = ClientNetworkLayerReleaseBuffer; size_t urlLength = strlen(endpointUrl); if(urlLength < 11 || urlLength >= 512) { UA_LOG_WARNING((*logger), UA_LOGCATEGORY_NETWORK, "Server url size invalid"); return connection; } if(strncmp(endpointUrl, "opc.tcp://", 10) != 0) { UA_LOG_WARNING((*logger), UA_LOGCATEGORY_NETWORK, "Server url does not begin with opc.tcp://"); return connection; } UA_UInt16 portpos = 9; UA_UInt16 port; for(port = 0; portpos < urlLength-1; portpos++) { if(endpointUrl[portpos] == ':') { char *endPtr = NULL; unsigned long int tempulong = strtoul(&endpointUrl[portpos+1], &endPtr, 10); if (ERANGE != errno && tempulong < UINT16_MAX && endPtr != &endpointUrl[portpos+1]) port = (UA_UInt16)tempulong; break; } } if(port == 0) { UA_LOG_WARNING((*logger), UA_LOGCATEGORY_NETWORK, "Port invalid"); return connection; } char hostname[512]; for(int i=10; i < portpos; i++) hostname[i-10] = endpointUrl[i]; hostname[portpos-10] = 0; #ifdef _WIN32 WORD wVersionRequested; WSADATA wsaData; wVersionRequested = MAKEWORD(2, 2); WSAStartup(wVersionRequested, &wsaData); if((connection.sockfd = socket(PF_INET, SOCK_STREAM,0)) == (UA_Int32)INVALID_SOCKET) { #else if((connection.sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { #endif UA_LOG_WARNING((*logger), UA_LOGCATEGORY_NETWORK, "Could not create socket"); return connection; } struct hostent *server = gethostbyname(hostname); if(!server) { UA_LOG_WARNING((*logger), UA_LOGCATEGORY_NETWORK, "DNS lookup of %s failed", hostname); return connection; } struct sockaddr_in server_addr; memset(&server_addr, 0, sizeof(server_addr)); memcpy((char *)&server_addr.sin_addr.s_addr, (char *)server->h_addr_list[0], server->h_length); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(port); connection.state = UA_CONNECTION_OPENING; if(connect(connection.sockfd, (struct sockaddr *) &server_addr, sizeof(server_addr)) < 0) { ClientNetworkLayerClose(&connection); UA_LOG_WARNING((*logger), UA_LOGCATEGORY_NETWORK, "Connection failed"); return connection; } #ifdef SO_NOSIGPIPE int val = 1; if(setsockopt(connection.sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void*)&val, sizeof(val)) < 0) { UA_LOG_WARNING((*logger), UA_LOGCATEGORY_NETWORK, "Couldn't set SO_NOSIGPIPE"); return connection; } #endif return connection; }
/* we have no networklayer. instead, attach the reusable buffer to the handle */ UA_Connection ClientNetworkLayerTCP_connect(UA_ConnectionConfig localConf, char *endpointUrl, UA_Logger *logger) { UA_Connection connection; UA_Connection_init(&connection); connection.localConf = localConf; #ifndef UA_MULTITHREADING connection.handle = UA_ByteString_new(); UA_ByteString_newMembers(connection.handle, localConf.maxMessageSize); #endif size_t urlLength = strlen(endpointUrl); if(urlLength < 11 || urlLength >= 512) { UA_LOG_WARNING((*logger), UA_LOGCATEGORY_COMMUNICATION, "Server url size invalid"); return connection; } if(strncmp(endpointUrl, "opc.tcp://", 10) != 0) { UA_LOG_WARNING((*logger), UA_LOGCATEGORY_COMMUNICATION, "Server url does not begin with opc.tcp://"); return connection; } UA_UInt16 portpos = 9; UA_UInt16 port = 0; for(;portpos < urlLength-1; portpos++) { if(endpointUrl[portpos] == ':') { port = atoi(&endpointUrl[portpos+1]); break; } } if(port == 0) { UA_LOG_WARNING((*logger), UA_LOGCATEGORY_COMMUNICATION, "Port invalid"); return connection; } char hostname[512]; for(int i=10; i < portpos; i++) hostname[i-10] = endpointUrl[i]; hostname[portpos-10] = 0; #ifdef _WIN32 WORD wVersionRequested; WSADATA wsaData; wVersionRequested = MAKEWORD(2, 2); WSAStartup(wVersionRequested, &wsaData); if((connection.sockfd = socket(PF_INET, SOCK_STREAM,0)) == (UA_Int32)INVALID_SOCKET) { #else if((connection.sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { #endif UA_LOG_WARNING((*logger), UA_LOGCATEGORY_COMMUNICATION, "Could not create socket"); return connection; } struct hostent *server = gethostbyname(hostname); if(server == NULL) { UA_LOG_WARNING((*logger), UA_LOGCATEGORY_COMMUNICATION, "DNS lookup of %s failed", hostname); return connection; } struct sockaddr_in server_addr; memset(&server_addr, 0, sizeof(server_addr)); memcpy((char *)&server_addr.sin_addr.s_addr, (char *)server->h_addr_list[0], server->h_length); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(port); connection.state = UA_CONNECTION_OPENING; if(connect(connection.sockfd, (struct sockaddr *) &server_addr, sizeof(server_addr)) < 0) { ClientNetworkLayerClose(&connection); UA_LOG_WARNING((*logger), UA_LOGCATEGORY_COMMUNICATION, "Connection failed"); return connection; } #ifdef SO_NOSIGPIPE int val = 1; if (setsockopt(connection.sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void*)&val, sizeof(val)) < 0) { UA_LOG_WARNING((*logger), UA_LOGCATEGORY_COMMUNICATION, "Couldn't set SO_NOSIGPIPE"); } #endif //socket_set_nonblocking(connection.sockfd); connection.write = socket_write; connection.recv = socket_recv; connection.close = ClientNetworkLayerClose; connection.getBuffer = ClientNetworkLayerGetBuffer; connection.releaseBuffer = ClientNetworkLayerReleaseBuffer; return connection; }
static UA_StatusCode ServerNetworkLayerUDP_start(ServerNetworkLayerUDP *layer, UA_Logger logger) { layer->layer.logger = logger; layer->serversockfd = socket(PF_INET, SOCK_DGRAM, 0); if(layer->serversockfd < 0) { UA_LOG_WARNING(layer->layer.logger, UA_LOGCATEGORY_COMMUNICATION, "Error opening socket"); return UA_STATUSCODE_BADINTERNALERROR; } const struct sockaddr_in serv_addr = {.sin_family = AF_INET, .sin_addr.s_addr = INADDR_ANY, .sin_port = htons(layer->port), .sin_zero = {0}}; int optval = 1; if(setsockopt(layer->serversockfd, SOL_SOCKET, SO_REUSEADDR, (const char *)&optval, sizeof(optval)) == -1) { UA_LOG_WARNING(layer->layer.logger, UA_LOGCATEGORY_COMMUNICATION, "Could not setsockopt"); CLOSESOCKET(layer->serversockfd); return UA_STATUSCODE_BADINTERNALERROR; } if(bind(layer->serversockfd, (const struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { UA_LOG_WARNING(layer->layer.logger, UA_LOGCATEGORY_COMMUNICATION, "Could not bind the socket"); CLOSESOCKET(layer->serversockfd); return UA_STATUSCODE_BADINTERNALERROR; } socket_set_nonblocking(layer->serversockfd); UA_LOG_WARNING(layer->layer.logger, UA_LOGCATEGORY_COMMUNICATION, "Listening for UDP connections on %s:%d", inet_ntoa(serv_addr.sin_addr), ntohs(serv_addr.sin_port)); return UA_STATUSCODE_GOOD; } static size_t ServerNetworkLayerUDP_getJobs(ServerNetworkLayerUDP *layer, UA_Job **jobs, UA_UInt16 timeout) { UA_Job *items = NULL; setFDSet(layer); struct timeval tmptv = {0, timeout}; UA_Int32 resultsize = select(layer->serversockfd+1, &layer->fdset, NULL, NULL, &tmptv); if(resultsize <= 0 || !FD_ISSET(layer->serversockfd, &layer->fdset)) { *jobs = items; return 0; } items = malloc(sizeof(UA_Job)*resultsize); // read from established sockets UA_Int32 j = 0; UA_ByteString buf = {-1, NULL}; if(!buf.data) { buf.data = malloc(sizeof(UA_Byte) * layer->conf.recvBufferSize); if(!buf.data) UA_LOG_WARNING(layer->layer.logger, UA_LOGCATEGORY_COMMUNICATION, "malloc failed"); } struct sockaddr sender; socklen_t sendsize = sizeof(sender); bzero(&sender, sizeof(sender)); buf.length = recvfrom(layer->serversockfd, buf.data, layer->conf.recvBufferSize, 0, &sender, &sendsize); if (buf.length <= 0) { } else { UDPConnection *c = malloc(sizeof(UDPConnection)); if(!c) return UA_STATUSCODE_BADINTERNALERROR; UA_Connection_init(&c->connection); c->from = sender; c->fromlen = sendsize; // c->sockfd = newsockfd; c->connection.getSendBuffer = GetMallocedBuffer; c->connection.releaseSendBuffer = ReleaseMallocedBuffer; c->connection.releaseRecvBuffer = ReleaseMallocedBuffer; c->connection.handle = layer; c->connection.send = sendUDP; c->connection.close = closeConnectionUDP; c->connection.localConf = layer->conf; c->connection.state = UA_CONNECTION_OPENING; items[j].type = UA_JOBTYPE_BINARYMESSAGE_NETWORKLAYER; items[j].job.binaryMessage.message = buf; items[j].job.binaryMessage.connection = (UA_Connection*)c; buf.data = NULL; j++; } if(buf.data) free(buf.data); if(j == 0) { free(items); *jobs = NULL; } else *jobs = items; return j; }