File transfer using Smack doesn't work - xmpp

I'm trying to use Smack to transfer a file between two PCs connected on the same XMPP server, but I get a weird error.
To summarize, the destination PC has a FileTransferListener registered, like so:
ftm.addFileTransferListener(new FileTransferListener() {
#Override
public void fileTransferRequest(FileTransferRequest request) {
System.out.println("Request received");
if (true) // Check to see if the request should be accepted
{
// Accept it
System.out.println("Entering FTListener because of FTRequest");
IncomingFileTransfer transfer = request.accept();
String id = request.getDescription();
String path = savePoint + System.getProperty("file.separator") + request.getFileName();
try
{
System.out.println("Receiving...");
transfer.recieveFile(new File(path));
// Information put in HashMap for later retrieval
System.out.println("IM - putting in path (" + id + "," + path + ")");
paths.put(id, path);
} catch (XMPPException e) {
logger.error("Error getting the VM file: " + e.getMessage());
}
}
else
{
// Reject it
request.reject();
logger.info("VM file transfer rejected");
}
}
});
The source PC uses an OutgoingFileTransfer like so:
try
{
String nick = destHost + "#" + this.conn.getServer() + "/Smack";
//destHost = destination host name, conn = XMPP connection
System.out.println("OFT to " + nick);
OutgoingFileTransfer.setResponseTimeout(10000);
OutgoingFileTransfer oft = ftm.createOutgoingFileTransfer(nick);
oft.sendFile(f, name); //f = file to send, name = a message
while (!oft.isDone())
{
if (oft.getStatus().equals(Status.error))
{
System.out.println("ERROR!!! " + oft.getError());
oft.cancel();
return false;
}
System.out.println(oft.getStatus());
System.out.println(oft.getProgress());
System.out.println("5 sec sleep");
Thread.sleep(5000);
}
if (oft.getStatus().equals(Status.complete))
{
System.out.println("Transfer done");
return true;
}
if (oft.getStatus().equals(Status.error))
System.out.println("Transfer failed: " + oft.getError());
return false;
} catch (XMPPException e) {
System.out.println("Error sending VM image file with the FTM : " + e.getMessage());
return false;
} catch (InterruptedException e) {
System.err.println("Error sleeping during OFT : " + e.getMessage());
return false;
}
When I try to send a file, the outgoing file transfer begins, and the destination PC receives the request, but the source PC cannot go further then the transfer negotiation.
This is seen in the source PC output...
Initial
0.0
2 sec sleep
Negotiating Transfer
0.0
2 sec sleep
Negotiating Stream
0.0
2 sec sleep
Transfer failed: null
I'm really annoyed because I don't even get a proper error message, so I don't really know what went wrong.
Has this ever happened to anyone else?

Looks like you are running into a known issue in Smack that will hopefully be fixed in the next release.
Update: This is now fixed and will be in version 3.2.1.

XMPP bytestreams are well specified, but are a rather complex topic, because there is more than one way to establish such a stream.
Your code looks right on a quick review. Now the next step would be to analyze the XMPP stanzas send between both clients and the server. This should give you a hint about the error cause. Also make sure to use smack 3.2.0 which has IBB support, which should increase the chance of a successful file transfer via XMPP.

Related

Unity Lobby/Relay - joining by code results in error 400 Bad Request

as a beginner I am trying to test new Unity Packages - Unity Lobby and Unity Relay to make multiplayer card game. Quick joining lobby and creating a lobby works fine but I have encountered a problem with joining lobby using Join Code. Here's the code:
public async void JoinByCode() {
string lobbyCode = InputField.text;
Debug.Log(lobbyCode);
Debug.Log("Searching for lobby with code " + lobbyCode + "...");
// UpdateState ?.Invoke("Searching for lobby with code " + lobbyCode + "...");
try {
JoinLobbyByCodeOptions options = new JoinLobbyByCodeOptions();
Lobby lobby = await Lobbies.Instance.JoinLobbyByCodeAsync(lobbyCode, options); //<--- results in error 400 - Bad Request
Debug.Log(lobby);
Debug.Log("Joined lobby: " + lobby.Id);
Debug.Log("Players in lobby: " + lobby.Players.Count);
//RelayCode
string joinCode = lobby.Data["joinCode"].Value;
Debug.Log("Kod dostępu: " + joinCode);
JoinAllocation allocation = await Relay.Instance.JoinAllocationAsync(joinCode);
//obiekt joindata
_joinData = new RelayJoinData {
Key = allocation.Key,
Port = (ushort) allocation.RelayServer.Port,
AllocationID = allocation.AllocationId,
AllocationIDBytes = allocation.AllocationIdBytes,
ConnectionData = allocation.ConnectionData,
HostConnectionData = allocation.HostConnectionData,
IPv4Address = allocation.RelayServer.IpV4
};
_joinData.JoinCode = await Relay.Instance.GetJoinCodeAsync(allocation.AllocationId);
NetworkManager.Singleton.GetComponent<UnityTransport>().SetClientRelayData(
_joinData.IPv4Address,
_joinData.Port,
_joinData.AllocationIDBytes,
_joinData.Key,
_joinData.ConnectionData,
_joinData.HostConnectionData
);
NetworkManager.Singleton.StartClient();
Debug.Log("Found lobby, code: " + joinCode);
UpdateState?.Invoke("Joining lobby, code: " + joinCode + ", players in lobby: " + lobby.Players.Count);
MatchFound?.Invoke();
} catch (LobbyServiceException e) {
Debug.Log("There's a problem finding lobby, try again. " + e);
}
}
In general: Join Code is passed from InputField, then to JoinLobbyByCodeAsync, then send player data to server. The problem is with variable lobby - when I am trying to test JoinByCode, it results with error:
There's a problem finding lobby, try again. Unity.Services.Lobbies.LobbyServiceException: request failed validation ---> Unity.Services.Lobbies.Http.HttpException`1[Unity.Services.Lobbies.Models.ErrorStatus]: HTTP/1.1 400 Bad Request
and I have no idea how to solve this problem. Yes, I was using Unity Documentation for Lobby and trying to find any info about error 400 in Lobby. I will be really grateful if someone could help me with this problem. Cheers!
I had a similar problem, in my case the input contained an extra character. Make sure that there are only 6 characters in your variable "lobbyCode" by checking it with lobbyCode.Length. Also make sure that you have activated the Lobby and Relay service in the dashboard.
My post to this problem:
https://forum.unity.com/threads/problem-joining-a-private-lobby-through-lobbycode-joinlobbybycodeasync.1287908/#post-8171102

Netty Client: request-response in same future

I'm trying to implement a Netty client which will send a TCP request and receive a response in the same Future. The code is below
public void sendMessage(String msg) {
Future<Channel> future = simpleChannelPool.acquire();
future.addListener((FutureListener<Channel>) f -> {
if (f.isSuccess()) {
Channel ch = f.getNow();
ChannelFuture channelFuture = ch.writeAndFlush((msg + " " + now() + lineSeparator()));
channelFuture.addListener(writeFuture -> {
if (writeFuture.isSuccess()) {
System.out.println("Channel write successful");
// how to READ data here?
}
});
// Release back to pool
simpleChannelPool.release(ch);
} else {
System.out.println("Failed to acquire a channel");
}
});
}
The part that I'm missing is how to read the data after successful write, line if (writeFuture.isSuccess()) {.... Basically I need to wait until next read is finished.
Also, given Netty's asynchronous nature, is it a right tool for request/response protocols?
Netty version used: 4.1.39.Final.
The complete code is available here.

Can’t write amount of data to kepware

When I write data to kepware server by milo, sometimes some data can not be written successfully. But the server returned
StatusCode{name=Good, value=0x00000000, quality=good}
The server did not display the data which I had written.
Thanks in advance for any help
Single thread did not work.
Create new client when start to write data.
There is only one client which responds to writing.
All of these failed.
mWriteClient = new OPCUAClientRunner(KSOPCUASubscription.this).createClient();
mWriteClient.connect().get();
} catch (Exception e) {
e.printStackTrace();
logger.error("OPCUAClient connect Exception", e);
return ;
}
logger.info("Wrote identifier: " + identifier);
List<NodeId> nodeIds = ImmutableList.of(new NodeId(namespaceIndex, identifier));//Int32"t|bbb"
Variant v = new Variant(value);
// don't write status or timestamps
DataValue dv = new DataValue(v, null, null);
logger.info("OPCUAClient begin write");
// write asynchronously....
CompletableFuture<List<StatusCode>> f =
mWriteClient.writeValues(nodeIds, ImmutableList.of(dv));
// ...but block for the results so we write in order
List<StatusCode> statusCodes = null;
try {
statusCodes = f.get();
} catch (InterruptedException e) {
e.printStackTrace();
logger.error("OPCUAClient write get response Exception", e);
} catch (ExecutionException e) {
e.printStackTrace();
logger.error("OPCUAClient write get response Exception", e);
}
StatusCode status = statusCodes.get(0);
logger.info("Wrote status: " + status.toString());
if (status.isGood()) {
logger.info("Wrote '{}' to nodeId={}", v, nodeIds.get(0));
}
Unless you're not actually writing the value you claim to be writing, a StatusCode of Good from the server means you're not doing anything wrong on the client side.
Maybe you can capture the exchange with Wireshark to further prove the issue is on the server side.

Email Fails to send with sms details

The following code listens for an incoming sms, takes all the spaces out of the sms then emails the edited sms. Everything works fine, except that the app fails to send an email. Can anyone see what I am doing wrong and help me?
new Thread() {
public void run() {
try {
DatagramConnection _dc =
(DatagramConnection)Connector.open("sms://");
for(;;) { //'For-Loop' used to listen continously for incoming sms's
Datagram d = _dc.newDatagram(_dc.getMaximumLength());
_dc.receive(d); //The sms is received
byte[] bytes = d.getData();
String address = d.getAddress(); //The address of the sms is put on a string.
String msg = new String(bytes); //The body of the sms is put on a string.
String msg2 = (replaceAll(msg, " ","")) ; //
Store store = Session.getDefaultInstance().getStore();
Folder[] folders = store.list(Folder.SENT);
Folder sentfolder = folders[0]; //Retrieve the sent folder
Message in = new Message(sentfolder);
Address recipients[] = new Address[1];
recipients[0]= new Address("me#yahoo.com", "user");
in.addRecipients(Message.RecipientType.TO, recipients);
in.setSubject("Incoming SMS"); //The subject of the message is added
in.setContent("You have just received an SMS from: " + address + "/n" + "Message: " + msg2); //Here the body of the message is formed
in.setPriority(Message.Priority.HIGH); //The priority of the message is set.
Transport.send(in); //The message is sent
in.setFlag(Message.Flag.OPENED, true);
Folder folder = in.getFolder(); //The message is deleted from the sent folder
folder.deleteMessage(in);
}
}catch (Exception me) { //All Exceptions are caught
}
}
};
public static String replaceAll(String front, String pattern, String back) {
if (front == null)
return "";
StringBuffer sb = new StringBuffer(); //A StringBufffer is created
int idx = -1;
int patIdx = 0;
while ((idx = front.indexOf(pattern, patIdx)) != -1) {
sb.append(front.substring(patIdx, idx));
sb.append(back);
patIdx = idx + pattern.length();
}
sb.append(front.substring(patIdx));
return sb.toString();
}
Thanks
This isn't really an answer to the problem, just an elaboration on my comment above, that might help.
Make sure do something in your exception catch block, so that problems in the code don't go unnoticed. It's possible that your code is not encountering any exceptions, but in order for us to help, we need to try to eliminate potential problems, and since you say the code isn't working, but you have an empty exception handler, that's an easy area to fix first.
the simplest handler is just:
try {
// try sending sms here
} catch (Exception e) {
e.printStackTrace();
}
If you can run this in the debugger (which I highly suggest), then you can now put a breakpoint on the e.printStackTrace() line, and see if it ever gets hit. If it does, inspect the value of e and tell us what it is.
Normally, in my programs, I don't actually use e.printStackTrace() in catch handlers, but I have a logging class that takes strings, and maybe a log level (e.g. info, warning, error, verbose), and writes to a log file. The log file can be attached to emails the users send to tech support, or can be disabled for production if you only want to use the feature while developing.
Anyway, start with a simple printStackTrace() and see if it ever gets hit. Then, report back.
Edit: from the symptoms you describe in the comments after your question, it seems like it's a possibility that
String msg2 = (replaceAll(msg, " ","")) ; //
is throwing an exception, and therefore never letting you get to where you'd send the email. I can't see anything wrong with your implementation of replaceAll() upon initial inspection, but that might be a place to look. Has that implementation been thoroughly unit-tested?
Also, I think you have a "/n" in your code where you probably want a "\n", right?

UCMA 3.0 API Conferencing Error : Cannot join a different conference after receiving a conference invitation or conference escalation request

We have a UCMA 3.0 based application/bot that matches end users with experts. It migrates incoming one-one chat requests from end users into a multi user conference and then invites experts into the resulting multi user conference. The application itself continues to be a participant in the conference. At any given time, there may be several such conferences being brokered by our application but only one per end user. However, a single expert may be participating in more than one conference at the same time.
In our application logs we occasionally see the following exception.
Error in Conference Migration conf call # 63809878 ,Address :sip:xxxxxx#xxx.com;gruu;opaque=app:conf:focus:id:TQRREACE System.InvalidOperationException: Cannot join a different conference after receiving a conference invitation or conference escalation request.
at Microsoft.Rtc.Collaboration.ConferenceSession.VerifyAndGetConferenceAddress(String conferenceUri, String parameterName)
at Microsoft.Rtc.Collaboration.ConferenceSession.BeginJoinCommon(String conferenceUri, ConferenceJoinOptions options, AsyncCallback userCallback, Object state)
at Microsoft.Rtc.Collaboration.ConferenceSession.BeginJoin(String conferenceUri, ConferenceJoinOptions options, AsyncCallback userCallback, Object state)
at a(String A_0, String A_1, String A_2, Boolean A_3, Boolean A_4)
Below is the code snippet used to make conference. Previously this site was an OCS 2007 R2 Installation and was migrated to Lync 2010 Server.
Site is running in mixed mode. It occurs only on production server and we are not able to generate this exception on dev server, we
have tested it after generating more than 15 conferences simultaniously but no luck.
private void CreateAdHohConf(string user1Uri, string user2uri, string subject)
{
Exception exception = null;
// Create conference scheduling details for the conference.
ConferenceScheduleInformation scheduleInfo = new ConferenceScheduleInformation();
// Restrict the conference to invited users only.
scheduleInfo.AccessLevel = ConferenceAccessLevel.Everyone;
// Set a subject for the conference.
scheduleInfo.Subject = subject;
scheduleInfo.Description = subject;
scheduleInfo.ConferenceId = ConferenceServices.GenerateConferenceId();
scheduleInfo.ExpiryTime = System.DateTime.Now.AddHours(8);
scheduleInfo.IsPasscodeOptional = true;
scheduleInfo.PhoneAccessEnabled = false;
// Don't automatically assign a leader.
scheduleInfo.AutomaticLeaderAssignment = AutomaticLeaderAssignment.Everyone;
// Add the caller and recipient as participants.
scheduleInfo.Participants.Add(new ConferenceParticipantInformation("sip:" + user1Uri, ConferencingRole.Leader));
scheduleInfo.Participants.Add(new ConferenceParticipantInformation("sip:" + user2uri, ConferencingRole.Leader));
scheduleInfo.Mcus.Add(new ConferenceMcuInformation(McuType.ApplicationSharing));
scheduleInfo.Mcus.Add(new ConferenceMcuInformation(McuType.InstantMessaging));
scheduleInfo.Mcus.Add(new ConferenceMcuInformation(McuType.AudioVideo));
scheduleInfo.Mcus.Add(new ConferenceMcuInformation(McuType.Meeting));
//Scheduling conference
ConferenceServices objLocalConfSvc = lyncAgent.LocalEndpoint.ConferenceServices;
Conference confSession = null;
objLocalConfSvc.BeginScheduleConference(scheduleInfo,
result =>
{
try
{
confSession = objLocalConfSvc.EndScheduleConference(result);
}
catch (RealTimeException rtex)
{
exception = rtex;
}
catch (Exception ex)
{
exception = ex;
}
finally
{
_waitForConferenceScheduling.Set();
}
}, objLocalConfSvc);
_waitForConferenceScheduling.WaitOne();
//Begin Join conference
ConferenceSession objLocalConfSession=this.call.Conversation.ConferenceSession;
try
{
ConferenceJoinOptions joinOptions = new ConferenceJoinOptions() { CanManageLobby = false, JoinMode = JoinMode.Default };
objLocalConfSession.BeginJoin(new RealTimeAddress(confSession.ConferenceUri).Uri, joinOptions,
result => {
try
{
objLocalConfSession.EndJoin(result);
}
catch (Exception ex)
{
exception = ex;
}
finally
{
//Again, for sync. reasons.
_waitForConferenceJoin.Set();
}
}
, this.call.Conversation.ConferenceSession);
// Wait until join completes.new RealTimeAddress(this._conference.ConferenceUri).Uri,
_waitForConferenceJoin.WaitOne();
}
catch (InvalidOperationException ioex)
{
exception = ioex;
}
catch (Exception ex)
{
exception = ex;
}
//Begin Escalation
Conversation objLocalConv= this.call.Conversation;
try
{
objLocalConv.BeginEscalateToConference(
result =>
{
try
{
objLocalConv.EndEscalateToConference(result);
}
catch (Exception ex)
{
exception = ex;
}
finally
{
//Sync It
_waitForEscalation.Set();
}
}
, objLocalConv);
// Wait until escalation completes.
_waitForEscalation.WaitOne();
}
catch (InvalidOperationException ioex)
{
exception = ioex;
}
catch (Exception ex)
{
exception = ex;
}
finally
{
if (exception != null)
{
lyncAgent.Logger.Error( "Error in Conference Migration conf call # " + GetHashCode() + " , Address :" + confSession.ConferenceUri , exception);
}
}
}
Please suggest what could be the possible problem on priority basis.
Thanks in advance.
Does this method reside in an object where it is possible that it will be called by multiple sources at the same time?
If so, using what appears to be a class level variable like _waitForConferenceScheduling could be problematic. Thread A could end up accidentally letting Thread B proceed before Thread B's async action is actually completed. So Thread B could call .BeginEscalate before .EndJoin was called.
When I write UCMA code, I generally use nested callbacks to prevent this type of thing from happening.
Other than that, I'd recommend you run OCSLogger on your application server and the Lync Front End server to gather SIPStack, S3 and Collaboration logs. Looking at the actual SIP messages in detail will provide some clues.
You'd be looking for an INVITE to the conference and the response back to that INVITE.
We managed to detect the reason. It happens if any one in the participant list have already added any contact for meeting in conversation with our endpoint.